Skip to content

NoteWriter infers <normal-type> from sibling notes instead of using DurationData::timeModificationNormalType #428

Description

@rpatters1

mx::impl::NoteWriter does not use api::DurationData::timeModificationNormalType. Instead it infers <normal-type> by scanning sibling notes for exactly one TupletStart and exactly one TupletStop. Two consequences follow, both measurable against Finale's own export of the same file.

Over-emission on ordinary tuplets. MusicXML reads an absent <normal-type> as the note's own <type>, so it only needs writing when the tuplet's normal note value differs. An author that sets the field only in that case still gets one on every note of every tuplet. For one Finale test document:

<normal-type> count
Requested through DurationData 11
Written to the file 253
Of those, merely repeating the note's own <type> 242
Finale's own export of the same music 4

Redundant rather than incorrect, but it makes a diff against a reference export unreadable, and it overrides a deliberate choice the API already lets the author express.

Silent omission on nested tuplets. When a note opens two tuplets the sibling search matches nothing, so no <normal-type> is written at all, regardless of what the API asked for. For a 3:2 eighth tuplet inside a 3:2 quarter tuplet the omission happens to be right, because the cumulative 9:4 is expressed in the eighths the notes already are. That is luck rather than design: nothing in the writer establishes it, and a nested tuplet whose normal value does differ from the note type has no way to say so.

DurationData already models the whole cumulative time modification:

timeModificationActualNotes
timeModificationNormalNotes
timeModificationNormalType
timeModificationNormalTypeDots

Since <time-modification> is cumulative across nesting while <tuplet> notations are per-tuplet and visual, the two should not be derived from each other.

Suggested shape

  • Write <normal-type> from DurationData::timeModificationNormalType (and its dots) when set, and omit it when unspecified. Treat the field as the author's statement rather than a hint.
  • Pair TupletStart / TupletStop by numberLevel instead of assuming one of each per note, so nested tuplets are handled rather than skipped.

Scope

This issue is <normal-type> only. Two neighbouring tuplet matters are separate and neither is caused by this one:

An earlier revision of this issue conflated the third point with #429; the comment below records that correction.

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