feat: support elisions in lyrics - #427
Merged
Merged
Conversation
rpatters1
force-pushed
the
lyric-elisions
branch
from
August 24, 2026 00:27
63f20b7 to
48addea
Compare
## Human Summary Adds support for elisions in lyrics. ## Summary A `<lyric>` occasionally splits one syllable's display text into more than one `<text>` run joined by `<elision>` -- for example when the source embeds a non-breaking space or an undertie between two words that are meant to be sung as one syllable. `mx::api` had nowhere to keep the extra runs: the reader flattened them into a single string (substituting an undertie glyph for empty elisions), and the writer never emitted `<elision>` at all, so any file using it lost that structure on round trip. `LyricData` gains `continuations`, a `std::vector<LyricTextSegment>` holding the runs after the first. Each `LyricTextSegment` carries its own `syllabic`, `text`, and the `<elision>` that joins it to the run before -- `elisionText` and `elisionSmufl`, both optional and independent of each other, since MusicXML only consults `smufl` when the text content is empty but does not forbid a source from setting both. `elisionSmufl` is a plain glyph-name string rather than a closed enum: the schema only requires a `lyrics`-prefixed name (`lyrics\c+`), not one of the three elision-specific glyphs. Non-breaking: two new fields on `LyricTextSegment`, one new vector field on `LyricData`, all empty/absent by default. ## Round-trip corpus Adds 2 files to `roundtrip-baseline.txt` (402 -> 404): `lysuite/ly61j_Lyrics_Elisions.xml` and `synthetic/lyric.3.0.xml`. Both previously failed with a flattened-text mismatch (e.g. `d‿e` in place of the elided `d` / `e` runs). ## Testing - [x] New `elidedSyllablesRoundTripThroughApi` test covers a mix of text-only, smufl-only, both-at-once, neither, and a non-elision `lyrics*` glyph name, verifying each round-trips independently - [x] `make api-test` (6357 assertions in 580 test cases) - [x] `make api-roundtrip` (404 passed, 0 failed of 404 pinned) - [x] `make api-roundtrip-discover` reports exactly the 2 new passes and no regressions Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
rpatters1
force-pushed
the
lyric-elisions
branch
from
August 24, 2026 02:09
48addea to
5f798da
Compare
webern
approved these changes
Aug 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Human Summary
Adds support for elisions in lyrics.
Summary
A
<lyric>occasionally splits one syllable's display text into more than one<text>run joined by<elision>-- for example when the source embeds a non-breaking space or an undertie between two words that are meant to be sung as one syllable.mx::apihad nowhere to keep the extra runs: the reader flattened them into a single string (substituting an undertie glyph for empty elisions), and the writer never emitted<elision>at all, so any file using it lost that structure on round trip.LyricDatagainscontinuations, astd::vector<LyricTextSegment>holding the runs after the first. EachLyricTextSegmentcarries its ownsyllabic,text, and the<elision>that joins it to the run before --elisionTextandelisionSmufl, both optional and independent of each other, since MusicXML only consultssmuflwhen the text content is empty but does not forbid a source from setting both.elisionSmuflis a plain glyph-name string rather than a closed enum: the schema only requires alyrics-prefixed name (lyrics\c+), not one of the three elision-specific glyphs.Non-breaking: two new fields on
LyricTextSegment, one new vector field onLyricData, all empty/absent by default.Testing
elidedSyllablesRoundTripThroughApitest covers a mix of text-only, smufl-only, both-at-once, neither, and a non-elisionlyrics*glyph name, verifying each round-trips independentlymake api-test(6357 assertions in 580 test cases)lysuite/ly61j_Lyrics_Elisions.xmlnow passes api-roundtrip (previously failed with a flattened-text mismatch)🤖 Generated with Claude Code