Skip to content

api: header and layout round-trip: midi-name, defaults fonts, credit gaps, per-measure print#202

Merged
webern merged 4 commits into
mainfrom
issue-2-header
Jun 17, 2026
Merged

api: header and layout round-trip: midi-name, defaults fonts, credit gaps, per-measure print#202
webern merged 4 commits into
mainfrom
issue-2-header

Conversation

@webern

@webern webern commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Addresses issues found during an mx::api audit; sections 3 (#192), 2.4 (#189), 2.2 (#187), 2.1 (#186) of the checked-in audit doc.

Scope notes: credit-image valign uses the image-specific ValignImage vocabulary (not modeled); credit-symbol glyph not modeled (structure preserved). Per-measure print new-system/new-page/page-number/system-layout/page-layout already round-trip at score level keyed by measure index.

Test plan

  • MidiNameRoundTripTest.cpp, DefaultsFontsRoundTripTest.cpp, CreditRoundTripTest.cpp, PrintLayoutRoundTripTest.cpp (red before fix, green after)
  • make test green (229 cases), make check green, make test-api-roundtrip baseline unchanged

References

webern added 4 commits June 16, 2026 22:43
Summary
-------
The reader (PartReader::parseMidiInstrument) sets MidiData.name from
<midi-name>, but PartWriter never wrote it back, so a MIDI instrument
name was lost on round-trip. Add the writer side so <midi-name>
survives write -> read.

Test plan
---------
- Add MidiNameRoundTripTest: construct a ScoreData with a MIDI name,
  round-trip it through write+read, assert the name survives.
- make fmt / make check / make test all green.
- make test-api-roundtrip green.
Summary
-------
The <defaults> fonts <music-font>, <word-font>, and <lyric-font> were
not modeled in DefaultsData and were dropped on both read and write.
Reuse the existing FontData type:

- Add optional musicFont/wordFont (FontData) and a lyricFonts vector
  (new LyricFontData = FontData + number/name attributes) to
  DefaultsData.
- Wire the read side (LayoutFunctions::addDefaultsFonts core -> api)
  and write side (addDefaultsFonts api -> core), reusing the existing
  getFontData / setAttributesFromFontData helpers, which adapt to the
  core EmptyFont and LyricFont element shapes via SFINAE.

Test plan
---------
- Add DefaultsFontsRoundTripTest covering word/music font and multiple
  lyric fonts (with number/name) through write+read.
- make fmt / make check / make test all green.
- make test-api-roundtrip green.
Summary
-------
Three gaps in <credit> handling are addressed:

- credit-image: add api::PageImageData (source, type, width, height,
  page, position) and a ScoreData.pageImageItems vector; read and write
  <credit-image> credits. (Vertical alignment uses the credit-image
  specific ValignImage vocabulary and is intentionally not modeled.)
- no-words credits: a <credit> whose content is not <credit-words>
  (e.g. <credit-symbol>) was dropped on read. It is now preserved as a
  PageTextData (empty text + credit-types). On write, a credit-words
  element is always emitted so metadata-only credits survive.
- multiple credit-type: previously only the first <credit-type>
  survived. Add PageTextData.creditTypes (full list, document order);
  read and write all of them. The legacy  field still
  mirrors the first credit-type.

The two PageText read/write functions were unified into createCredits,
operating on ScoreData so they can populate both text and image items.

Test plan
---------
- Add CreditRoundTripTest: multiple credit-types, a no-words credit, and
  a credit-image (with size and position) through write+read.
- make fmt / make check / make test all green.
- make test-api-roundtrip green.
Summary
-------
Per-measure <print> layout was write-biased: MeasureWriter emitted a
<staff-layout> staff-distance, but the read side ignored it, so it was
lost on round-trip. (new-system, new-page, page-number, system-layout
and page-layout were already read at the score level via
ScoreReader::scanForSystemInfo / scanForPageInfo; MeasureReader::parsePrint
was a no-op.)

- Read: ScoreReader::scanForSystemInfo now also reads the per-measure
  <staff-layout> staff-distance into SystemData.layout.staffDistance.
- Write: MeasureWriter::writeSystemInfo now emits <staff-layout>
  staff-distance from SystemData.layout.staffDistance.
- parsePrint is documented to explain that per-measure print layout is
  captured at the score level (keyed by measure index), since the
  per-measure music-data hook has no api home of its own.

Test plan
---------
- Add PrintLayoutRoundTripTest: a per-measure print with staff-distance
  (and system-distance) survives write+read. Verified red before the
  read-side change and green after.
- make fmt / make check / make test all green.
- make test-api-roundtrip green.
@github-actions

Copy link
Copy Markdown

gen-quality gen/

gen-quality: 84.5 / 100   (floor 84.5, +0.0)

  structure     86.5  x0.50   [fn 90.5 / file 82.6]
  cyclomatic    88.4  x0.25
  cognitive     76.6  x0.25

  409 functions across 31 files, 7702 lines (largest file 1044)
  max cc 56  max cognitive 44  max fn loc 152

Worst offenders (top 5 per axis; full lists in score.json):
  cyclomatic gen/xsd/analyze.py:311     report                             56
  cyclomatic gen/plates/build.py:956    _validate_config_against_ir        35
  cyclomatic gen/press/context.py:145   plate_context                      34
  cyclomatic gen/__main__.py:46         _ir                                23
  cyclomatic gen/tests/test_ir.py:102   _check_references                  20
  cognitive  gen/xsd/analyze.py:311     report                             44
  cognitive  gen/ir/resolve.py:119      flat_elements                      40
  cognitive  gen/tests/test_ir.py:102   _check_references                  38
  cognitive  gen/press/context.py:145   plate_context                      37
  cognitive  gen/xsd/analyze.py:207     _sccs                              37
  size       gen/xsd/analyze.py:311     report                             152
  size       gen/press/context.py:145   plate_context                      96
  size       gen/plates/build.py:533    _value_plate                       89
  size       gen/plates/build.py:956    _validate_config_against_ir        89
  size       gen/ir/resolve.py:119      flat_elements                      78

Commit 754d165b6f362c0692a0adea1c36633549a26305.

@github-actions

Copy link
Copy Markdown

Coverage report

Core-dev coverage src/private/mx/core/

Metric Coverage Covered / Total
Lines 77.9% 28539 / 36620
Functions 74.4% 6360 / 8548
Branches 50.7% 22672 / 44725

API coverage src/private/mx/{api,impl,utility}/

Metric Coverage Covered / Total
Lines 69.1% 4839 / 6998
Functions 55.9% 1567 / 2802
Branches 40.8% 3968 / 9730

Core HTML report | API HTML report

Commit 754d165b6f362c0692a0adea1c36633549a26305.

@webern webern changed the title Header/layout round-trip: midi-name, defaults fonts, credit gaps, per-measure print (#192,#189,#187,#186) api: header and layout round-trip: midi-name, defaults fonts, credit gaps, per-measure print Jun 17, 2026
@webern webern merged commit 833b168 into main Jun 17, 2026
7 checks passed
@webern webern deleted the issue-2-header branch June 17, 2026 06:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant