Skip to content

feat: figured-bass extend lines in mx::api - #472

Merged
webern merged 1 commit into
m/mxdev-dirbackupfrom
m/mxdev-figextend
Nov 1, 2026
Merged

webern merged 1 commit into
m/mxdev-dirbackupfrom
m/mxdev-figextend

Conversation

@webern

@webern webern commented Oct 28, 2026 •

Copy link
Copy Markdown
Owner

Summary

A figured-bass <figure> can end with <extend/>, the continuation line that carries a figure
across the bass notes that follow. mx::api dropped it on read, so a figure holding only an
extend came back as an empty <figure/>.

FigureData gains std::optional<FigureExtend> extend. Absent means no line.
FigureExtend::type is a FigureExtendType whose unspecified value is a bare <extend/>;
start, continue_ and stop write the matching type attribute. Additive; existing callers are
unaffected.

Why this shape: "no line" and "a line with no type" are different facts (every extend in the
corpus file is the bare kind), AGENTS.md rules out std::optional<SomeEnum>, and a
hasExtend + type pair like LyricData's can contradict itself. The one-field struct leaves room
for the <extend> position and color attributes, which are not modeled yet (none appear in the
corpus). FigureExtendType repeats LyricExtendType's values rather than reusing a lyric-named
type.

musuite/testFiguredBass2.xml now round-trips and is pinned. It also needs #471, which puts a
later staff's leading <figured-bass> after the <backup>.

Testing

  • New FiguredBassApiTest cases: round trip, extend-only figure, all four types, written XML
    for every form plus no extend, and equality
  • make api-test passes (6271 assertions in 735 test cases)
  • make api-roundtrip passes, 452 of 452 pinned files
  • make api-roundtrip-discover: 452 pass, against 451 on the commit below; no file lost its pass
  • make fmt-check passes

References

@webern webern added feature new feature request non-breaking fixes or implementation that do not 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 changed the title feat: round-trip figured-bass extend lines in mx::api feat: figured-bass extend lines in mx::api Oct 30, 2026
@webern
webern marked this pull request as ready for review October 30, 2026 08:00
A figured-bass <figure> can end with <extend/>, the continuation line that
carries a figure across the bass notes that follow. mx::api dropped it on
read, so a figure holding only an extend came back as an empty <figure/>.

FigureData gains std::optional<FigureExtend> extend. Absent means no line.
FigureExtend::type is a FigureExtendType whose unspecified value is a bare
<extend/>; start, continue_ and stop write the matching type attribute.

musuite/testFiguredBass2.xml now round-trips and is pinned in the baseline.
@webern
webern force-pushed the m/mxdev-figextend branch from 0b73025 to 47453af Compare October 30, 2026 08:15
@webern
webern merged commit 8c14b19 into main Nov 1, 2026
8 of 16 checks passed
@webern
webern deleted the m/mxdev-figextend branch November 1, 2026 14:09
webern added a commit that referenced this pull request Nov 1, 2026
## Summary

`<notehead>` lost its `parentheses` and `color` attributes, and on a
normal notehead the whole
element vanished, because the writer only emitted
`<notehead>normal</notehead>` when `filled` or a
SMuFL glyph was set.

`NoteData` gains two fields next to `noteheadFilled` and
`noteheadSmufl`:

- `Bool noteheadParentheses` (unspecified writes nothing; yes/no are
written as given)
- `std::optional<ColorData> noteheadColor` (empty means the notehead
takes the note's color),
following the newer optional-color precedent (`DampData`, `TempoData`,
...)

`NoteWriter::setNotehead` still skips the element when nothing is set,
and now writes a normal
notehead when either new field is set. Additive; plain fields rather
than a notehead struct,
because grouping would break the released `noteheadFilled` and
`noteheadSmufl`.

`data/api.features.xml` marks notehead `parentheses` as supported, and
corrects `filled` from
partial to yes (stale since `noteheadFilled` was added).

Two corpus files now round-trip and are pinned:

- lysuite/ly22d_Parenthesized_Noteheads.xml
- musuite/testNoteheads.xml

Still not modeled: notehead font attributes (which keep
`synthetic/notehead.*` failing), and an
explicit `<notehead>normal</notehead>` with no attributes is still
dropped (`ly22a`).

## Testing

- [x] New `NoteDataTest` cases for parentheses yes/no (including
`parentheses="no"` on a normal
notehead), color on normal and non-normal noteheads, and equality;
default and synthetic-file
  tests extended
- [x] `make api-test` passes (6300 assertions in 740 test cases)
- [x] `make api-roundtrip` passes, 454 of 454 pinned files
- [x] `make api-roundtrip-discover`: 454 pass, against 452 on the commit
below; no file lost its pass
- [x] `make fmt-check` passes

## References

- Stacked on #472
- Related to #183 (earlier notehead values in `mx::api`)
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 feature new feature request impl Affects the mx::impl layer non-breaking fixes or implementation that do not require breaking changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant