Skip to content

SpannerNumberResolver pools numbers per staff, but number-level scope is the part #350

Description

@rpatters1

Summary

SpannerNumberResolver (#320) pools spanner numbers per staff per class (occupied[staffIndex][number]), but MusicXML's number-level type scopes concurrency to the part: numbers distinguish "concurrent objects of the same type when the objects overlap in MusicXML document order." Its own piano example says a cross-staff slur "will need a separate number from the mid-measure slurs" even though they are on different staves.

Repro

Two-staff part, two identity slurs: staff 2 spanning m1 -> m2, staff 1 inside m2. Serialized order:

m1 staff 2:  <slur type="start" number="1"/>   (still open when the next start emits)
m2 staff 1:  <slur type="start" number="1"/>
m2 staff 1:  <slur type="stop"  number="1"/>
m2 staff 2:  <slur type="stop"  number="1"/>

The second slur must get a different number. Readers pair slur endpoints by number within the part, so this duplicate typically pairs the m1 start with the m2 staff-1 stop — a phantom cross-staff slur — and drops the rest.

Suggested fix

Drop the staff dimension from occupied and pool per part + class only. The cross-staff "reserve in every staff pool touched" logic then becomes unnecessary.

File containing this example.

(Note: this file was created by my new Finale exporter and MX because Finale's current exporter exports every staff as a different part. That means this file exhibits the bug.)

numberlev_2staffpart.musicxml.txt

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions