Skip to content

Add SMuFL payloads for MusicXML other-* marks and expose other-notation #381

Description

@rpatters1

Problem

MusicXML provides several extension elements for notation that does not have a dedicated element:

  • <other-dynamics>
  • <other-articulation>
  • <other-technical>
  • <other-ornament>
  • <other-notation>

Each of these elements can carry a smufl attribute naming one specific SMuFL glyph. This lets applications exchange the precise symbol while optionally retaining text content as a fallback or description.

mx::core models these elements and their SMuFL attributes, but mx::api does not expose that information. For the first four elements, MarkData::name carries the element text while the reader drops smufl and the writer cannot emit it. <other-notation> is not exposed at all: NoteFunctions ignores it during import and the API writer has no corresponding representation.

This prevents a consumer from preserving or authoring a precise fallback component such as the z in an ffz dynamic:

  <other-dynamics smufl="dynamicZ">z</other-dynamics>

The same loss occurs when a note-attached symbol is only representable as an other-articulation, other-technical, other-ornament, or general other-notation.

Ordered dynamic components

Although one smufl attribute names only one glyph, MusicXML's <dynamics> type contains an unbounded ordered choice of dynamic children. This is how a mark such as ffz, for which MusicXML has no dedicated <ffz/> element, can combine a classified dynamic with a SMuFL fallback:

<dynamics>
  <ff/>
  <other-dynamics smufl="dynamicZ">z</other-dynamics>
</dynamics>

The same mark may instead be represented entirely as individually named glyph components:

<dynamics>
  <other-dynamics smufl="dynamicFF">ff</other-dynamics>
  <other-dynamics smufl="dynamicZ">z</other-dynamics>
</dynamics>

mx::core::Dynamics preserves this ordered sequence. The current API translation does not: DynamicsReader examines only choice().front(), and DynamicsWriter constructs one dynamics choice from one MarkData. Consequently, mx::api cannot preserve a multi-component <dynamics> mark even apart from the missing smufl attribute.

Context

This work was intentionally deferred during the mx::impl port; see the SMuFL glyph-name migration notes. That section records the pre-MusicXML-4.0 workaround of putting canonical glyph names in element text, notes that the generated core has the proper smufl attribute, and leaves the public-API and compatibility policy for later design.

The deferral appears to have been about sequencing the port rather than a decision that the feature should remain unsupported. There is now a concrete downstream need: exporters must currently downgrade precise Finale articulation and dynamic glyphs to text-valued other-* elements, split or flatten compound dynamics, or substitute less accurate semantic notation.

The existing design questions remain relevant:

  • How should SMuFL glyph names be represented in mx::api without adding fields that are meaningless for most marks?
  • How should the API represent the ordered children of one <dynamics> element, including mixtures of semantic and other-dynamics components?
  • Should legacy element text that looks like a SMuFL name ever be promoted automatically, or should migration remain the consumer's responsibility?
  • How should fallback text and a canonical SMuFL name coexist for compatibility with readers that ignore the attribute?
  • Should the legacy customAccentTenuto sentinel path be retained, migrated, or handled separately?

Desired outcome

Design and implement an mx::api representation that can read and write:

  • the SMuFL glyph name on the existing other-* mark categories;
  • the ordered components of a MusicXML <dynamics> mark; and
  • MusicXML's general <other-notation> element.

The result should:

  • preserve optional SMuFL glyph names through XML -> API -> XML;
  • preserve the number, kind, and order of children within one <dynamics> element;
  • support API-authored glyph-only elements as well as elements containing fallback text;
  • preserve the meaningful other-notation attributes supported by mx::core;
  • remain compatible with existing API-authored other-* marks that do not supply a SMuFL glyph;
  • define an explicit policy for legacy glyph names stored in element text; and
  • include unit and corpus round-trip coverage using the existing data/synthetic/other-*.3.0.xml and other-*.3.1.xml fixtures where applicable, plus a fixture containing multiple dynamic children.

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