Repository navigation
fix(rendering): correct the minimum bar spacing and hammer-on/slide slur placement - #2943
Merged
Merged
Conversation
…minimum stretch force The pre-spring width of a bar's first spring is a fixed offset in front of the springs (calculateVoiceWidth, spaceToForce, buildOnTimePositions). Adding it to the first spring's required space as well inflated minStretchForce, and with it every beat of the bar, whenever the first beat carried accidentals or other pre-beat content.
…nt beats The minimum stretch force only reserved the ink of adjacent beats, so at the minimum spacing an accidental or grace group touched the previous notehead. The new EngravingSettings.beatContentPadding (1/2 stave-space, Behind Bars) is added between adjacent springs and before trailing grace groups.
… bar line The last spring only reserved the ink of the last beat, so flags and stems could touch the bar line at the minimum spacing. The new EngravingSettings.barlineContentPadding (1 stave-space, Behind Bars) is added to the last spring's required space.
The H-bar kept its natural width anchored at the start of the bar, so any additional bar width (e.g. the bar line padding) ended up on the right side only. Behind Bars shows the multiple-rest bar centred within the bar.
When a bar is squeezed below its minimum width, the end anchor of a tie or slur can end up before its start anchor. The slur height then took the log of a negative span and produced NaN control points (#2904). Ties and slurs now keep at least the beat content padding as span, centered on their anchors.
Bars which do not fit into the available width are compressed below the width their content needs, which leads to overlapping notation. The layout now logs one warning per layout pass listing the affected bars and the missing width.
…e the chord Effect slurs in standard notation started at whichever note of a chord was processed first, so they were often drawn inside the chord from the side of a notehead to the accidentals of the next chord. Like Guitar Pro, MuseScore and Behind Bars (all notes on one stem take a single slur) the slur now connects the outer notes of the start and end beat of the chain, centered on the noteheads.
…n ports Avoid a comparer sort on number arrays (unsupported in Kotlin), clamp the slice of reported bars (C# throws on out of range) and use a logger class instead of an object literal in the test.
… the stem end in multi-voice bars The beat-level effect slur chain breaks on beats without an effect (e.g. a tapped note on another string), which split a single hammer-on/pull-off slur into two. The slur now spans from the beat where note chains start to the furthest destination of these chains. In multi-voice bars the slur is placed on the stem side at the stem end (Behind Bars: never on the notehead side in double-stemmed writing), so the slurs of two voices no longer collide between them.
The staff line gap cache baked the x of the on-notes glyph into the gap positions. This x changes after the cache is built, e.g. when centered full-bar notes are shifted or shared pre-beat sizes are applied, which left the gaps at stale positions: lines were cut next to the fret numbers and ran through them. The gaps now read the current on-notes position.
…nd legato slides The arcs of a chord were merged by comparing against the tie direction before it was computed, which merged lower string arcs into the upper arc (losing them) and never merged arcs on the lower strings. Like Guitar Pro, a beat now gets one arc per side (above the upper strings, below the lower strings) from the outer note to the furthest destination of the chains starting on that side. Numbered notation keeps its previous merging.
2 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
AI-authored disclosure (
alphatab-ai-authored-v1)Portions of this content were authored by an AI agent. The agent has read
AGENTS.md and the human submitter accepts responsibility for
compliance with the rules in that document.
Issues
Fixes #2904
Proposed changes
#2904 reports a slur with
NaNcontrol points between two legato-slide chords at narrow widths. The root causeis not the slur: the bar gets far less width than its content needs (258px for a measured minimum of 809px at a
400px container), every spring is compressed linearly, the notation overlaps and the slur end anchor lands
before its start anchor. Looking into this showed that the minimum itself was wrong in two ways, and that the
effect slurs were anchored at positions which collide as soon as space gets tight.
Spacing minimum (
BarLayoutingInfo)minimum stretch force. A single accidental on the first beat inflated every beat of the bar (the Slur of a legato slide / hammer-on between two-note chords is not drawn in the standard notation staff when beats are tightly spaced (path with NaN) #2904 bar
needed 809px instead of 451px). It is a fixed offset in front of the springs and is no longer stretched in.
touched the previous notehead and flags touched the bar line. Two new engraving settings add the clearances
Behind Bars asks for, only where content would come closer:
EngravingSettings.beatContentPadding= ½ stave-space between adjacent beats (Behind Bars p. 41), includingtrailing grace groups.
EngravingSettings.barlineContentPadding= 1 stave-space between the last beat and the bar line (p. 43).equally spaced (p. 40). Bars which were only wide because of the double count get narrower, bars with
colliding content get the room they need.
Squeezed bars
crossed in a squeezed bar produced the
NaNpath (log of a negative span) or an inverted curve.Bar 1 does not fit into the available width and had to be compressed below the minimum size (up to 311px missing).No public API for the required width yet; that needs a proper design first.
Hammer-on, pull-off and legato slide slurs (cross-checked against Guitar Pro, MuseScore and Behind Bars)
and ran from that notehead to the accidentals of the next chord (the slur of Slur of a legato slide / hammer-on between two-note chords is not drawn in the standard notation staff when beats are tightly spaced (path with NaN) #2904). All notes on one stem
now take a single slur outside the chord, connecting the outer noteheads (p. 114). It spans from the beat
where note chains start to their furthest destination, so a chain continuing across a beat on another
string stays one slur.
double-stemmed writing), so the slurs of two voices no longer collide between them.
string arcs were merged into the upper arc and lost, arcs on the lower strings were never merged. A beat now
gets one arc per side (above the upper strings, below the lower strings) from the outer note to the furthest
chain end, matching Guitar Pro. Numbered notation keeps its previous behavior.
Tab staff lines
notes moved afterwards (centered full-bar notes, shared pre-beat sizes). Lines were cut next to the numbers
and ran through them. The gaps now read the current position.
Not in this PR
per chord segment; that is a larger layout change and will be explored separately.
Tests
NaNin the SVG output) and for the warning.mixed kinds, ties, chains across another string) and in multi-voice bars (plain and beamed).
Checklist
AI authorship disclosure
(
alphatab-ai-authored-v1) is present at the top of this body, and I havepersonally reviewed every change and can explain each one
Further details