Skip to content

feat: harmony print-frame and empty kind text in mx::api - #467

Merged
webern merged 1 commit into
mainfrom
m/mxdev-harmframe
Nov 1, 2026
Merged

webern merged 1 commit into
mainfrom
m/mxdev-harmframe

Conversation

@webern

@webern webern commented Oct 28, 2026 •

Copy link
Copy Markdown
Owner

Summary

Two harmony attributes were lost on a round trip through mx::api.

  • <harmony print-frame="no"> had no api home, so a chord symbol whose fretboard diagram is meant
    to be hidden came back without that instruction. ChordData gains printFrame, a tri-state
    Bool that applies to the whole <harmony>. The reader copies it onto every chord in the
    harmony; the writer emits it from the first chord that sets it, whether or not the chord has
    frame data.
  • <kind text="">major</kind> (the kind spelled with nothing, so C major prints as just "C")
    lost its empty text, because an empty string was treated as absent. ChordData::text becomes
    std::optional<std::string>, so empty and absent are different.

The second change is source-breaking for code that reads ChordData::text as a string; such
callers need text.value_or(""). Assigning "" now writes text=""; leave text as
std::nullopt to omit the attribute. Default-constructed chords behave as before.

Six more corpus files round-trip and are pinned in the baseline:

  • lysuite/ly46g_PickupMeasure_Chordnames_FiguredBass.xml
  • lysuite/ly71g_MultipleChordnames.xml
  • musetrainer/Happy_Birthday_To_You_C_Major.xml
  • musuite/testChordDiagrams1.xml
  • musuite/testHarmony1.xml
  • musuite/testHarmony2.xml

Testing

  • New cases in HarmonyExtrasApiTest.cpp cover print-frame yes/no/unspecified, print-frame
    without frame data, multiple chords in one harmony, and empty vs absent kind text
  • make api-test passes (6102 assertions in 704 test cases)
  • make api-roundtrip passes, 441 of 441 pinned files
  • make api-roundtrip-discover: 441 pass (was 435), no file that passed before now fails
  • make fmt-check passes

References

@webern webern added feature new feature request breaking fixes or implementation that require breaking changes api Affects the mx::api layer impl Affects the mx::impl layer ai Issues opened by, or through, a coding agent. labels Oct 28, 2026
@webern
webern added this pull request to stack #475 October 28, 2026 20:08
@webern
webern marked this pull request as ready for review October 29, 2026 07:06
@webern webern changed the title feat: round-trip harmony print-frame and empty kind text in mx::api feat: harmony print-frame and empty kind text in mx::api Oct 29, 2026
@webern webern changed the title feat: harmony print-frame and empty kind text in mx::api feat: harmony print-frame and empty kind text in mx::api Oct 29, 2026
<harmony print-frame> had no api home, so a chord symbol whose diagram was
hidden lost that instruction on write. <kind text=""> (the kind spelled with
nothing) lost its empty text, because an empty string was treated as absent.

ChordData gains printFrame, a Bool that applies to the whole harmony. The
writer emits it from the first chord that sets it, with or without frame
data. ChordData::text becomes std::optional<std::string> so an empty string
is different from an absent one.

This is a source-breaking change to ChordData::text. Callers that read it as
a string now need text.value_or(""). Assigning "" now writes text=""; leave
text as std::nullopt to omit the attribute.

Six more corpus files now round-trip and are pinned in the baseline.
@webern
webern force-pushed the m/mxdev-harmframe branch from fbcfccd to ed5b346 Compare October 30, 2026 08:15
@webern
webern merged commit 2874fc1 into main Nov 1, 2026
8 checks passed
@webern
webern deleted the m/mxdev-harmframe branch November 1, 2026 14:09
webern added a commit that referenced this pull request Nov 1, 2026
## Summary

`<key print-object="no">` (a key signature that applies to the music but
is not drawn) had no api
home, so it was written back as a plain `<key>` and the signature became
visible.

`KeyData` gains `printObject`, a tri-state `Bool` that mirrors
`ClefData::printObject`. The reader
fills it for traditional and non-traditional keys;
`PropertiesWriter::writeKey`, the one place a
`<key>` is built, emits it when it is not unspecified. The default
leaves output unchanged.
`data/api.features.xml` marks key `print-object` as supported.

`musuite/testInvisibleElements.xml` now round-trips and is pinned in the
baseline.

Not addressed here: the non-traditional key reader branch still does not
set `staffIndex` or
`tickTimePosition`, and other `<key>` attributes (color, position, font)
are still dropped.

## Testing

- [x] New `PrintObject*` cases in `KeyDataTest.cpp`: no, yes,
unspecified (omitted), non-traditional,
  per-staff, and equality
- [x] `make api-test` passes (6141 assertions in 710 test cases)
- [x] `make api-roundtrip` passes, 442 of 442 pinned files
- [x] `make api-roundtrip-discover`: 442 pass, no file that passed
before now fails
- [x] `make fmt-check` passes

## References

- Stacked on #467
webern added a commit that referenced this pull request Nov 1, 2026
## Summary

The barline documentation in the schema (complexType `barline`) says the
location attribute must
match where the barline occurs in the musical data, and that a left
barline "should be the first
element in the measure, aside from the print, bookmark, and link
elements."

`MeasureWriter` broke both halves of that:

- A left barline was written ahead of the measure's `<print>`. It now
follows the `<print>` (and
  still precedes `<attributes>`).
- A `location="middle"` barline was written at the end of the measure.
It is now written when the
write position reaches its tick: before a `<backup>`/`<forward>` that
moves past it, and after one
that lands on it. A middle barline whose tick no note reaches is still
written at the end.

Right barlines and barlines with no location are written where they were
before. No api change.
This also resolves the old TODO in `MeasureWriter.cpp` about barlines
landing in the wrong place.

Two corpus files now round-trip and are pinned:

- lysuite/ly46b_MidmeasureBarline.xml
- musetrainer/Bella_Ciao.xml (also relies on the harmony print-frame
change in #467)

The left-barline change removes a reorder from 7 of the 16 corpus files
that have
`<print>` followed by a left barline; the rest still fail for other
reasons.

Known limits, none of which occur in the corpus: a source that puts a
middle barline after a
`<backup>` gets it written in the earlier voice at the same tick (valid,
not byte-identical), and
a middle barline at the very end of a multi-voice measure is written
before the `<backup>`.

## Testing

- [x] New `MeasureWriterTest` cases: left barline after print, left
barline without print, middle
barline at its tick, after a forward, before a backup, unspecified
location stays last, and a
  middle barline no note reaches is written once at the end
- [x] `make api-test` passes (6212 assertions in 723 test cases)
- [x] `make api-roundtrip` passes, 447 of 447 pinned files
- [x] `make api-roundtrip-discover`: 447 pass, against 445 on the commit
below; no file lost its pass
- [x] `make fmt-check` passes

## References

- Stacked on #469
- Related to #208 (api round-trip pass-list coverage)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai Issues opened by, or through, a coding agent. api Affects the mx::api layer breaking fixes or implementation that require breaking changes feature new feature request impl Affects the mx::impl layer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant