Skip to content

MIDI export: keep lyrics with their notes under swing - #34714

Open
hashimh4 wants to merge 1 commit into
musescore:mainfrom
hashimh4:fix-32288-swing-lyrics
Open

MIDI export: keep lyrics with their notes under swing#34714
hashimh4 wants to merge 1 commit into
musescore:mainfrom
hashimh4:fix-32288-swing-lyrics

Conversation

@hashimh4

Copy link
Copy Markdown

Resolves: #32288

Swing moves the offbeat notes later, but the lyric meta events kept the unadjusted chord tick, so the syllables landed on ticks where no note starts. MIDI import matches a lyric to a note by exact onset, so those syllables were dropped on a round trip. The lyric tick now takes the same swing offset the renderer applies to the notes, computed with the same shared helper and the same conditions, so staves without swing, tuplets, and chords with user-defined play events are unaffected.

Not addressed here: a swung chord that also carries grace notes still will not have its lyric exactly on the onset, because the grace offset is a separate term. That gap is unchanged in size by this PR.

Built in CI; I tested the resulting Windows build against a swung score with lyrics, and byte-compared its exports against a build differing only by this change.

  • I signed the CLA as hashimh4
  • The title of the PR describes the problem it addresses.
  • Each commit's message describes its purpose and effects, and references the issue it resolves. If changes are extensive, there is a sequence of easily reviewable commits.
  • The code in the PR follows the coding rules.
  • I understand all aspects of the code I'm contributing and I'm able to explain it if requested.
  • The code compiles and runs on my machine, preferably after each commit individually. I have manually tested and verified that my changes fulfil their intended purpose.
  • No prior attempts to resolve this problem exist, or if they do, I listed them in my PR description and described how I avoided repeating past mistakes.
  • There are no unnecessary changes.
  • I created a unit test or vtest to verify the changes I made (if applicable).

Swing shifts the offbeat notes later, but the lyric meta events kept the
unadjusted chord tick. The syllables ended up on ticks where no note starts, and
MIDI import matches a lyric to a note by exact onset, so half of them were
dropped on a round trip.

createPlayEvents() applies swing through Swing::swingAdjustParams(), which raises
the chord's ontime, and the note-on tick becomes tick1 + ticks * ontime / 1000.
The lyric tick was built from the chord tick alone. Both pass through the same
pause mapping afterwards, so the gap survived into the file.

swingTickOffset() recomputes that one term using the same shared helper and the
same conditions the renderer applies, so a lyric cannot drift from its note. It
returns 0 for rests, for staves with no swing setting, for tuplets, and for
chords whose play events are user-defined, because createPlayEvents() discards
the swung list in that case and the notes do not move either.

Reading the rendered ontime back off the note would be shorter, but it also
carries the grace note and arpeggio offsets, and moving those lyrics is a
separate question.

Resolves: musescore#32288
@coderabbitai

coderabbitai Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7fab5fdd-0ead-4764-a9c3-227a53eaea5f

📥 Commits

Reviewing files that changed from the base of the PR and between a2f0158 and d3dfd1f.

📒 Files selected for processing (5)
  • src/importexport/midi/internal/midiexport/exportmidi.cpp
  • src/importexport/midi/tests/midiexport_data/testSwingLyrics.mscx
  • src/importexport/midi/tests/midiexport_data/testSwingLyricsRepeat.mscx
  • src/importexport/midi/tests/midiexport_data/testSwingLyricsUserEvents.mscx
  • src/importexport/midi/tests/midiexport_tests.cpp

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

The MIDI exporter now applies staff swing timing to lyric events for eligible automatic, non-tuplet chords. Three MuseScore fixtures cover standard swing lyrics, user events, and repeated measures. Tests parse exported MIDI files and verify that lyric events occur at the expected note-on ticks.

Merge Risk: ⚪ Minimal · up to d3dfd

The change keeps lyric events aligned with swung note onsets and adds focused regression coverage for affected cases; no actionable merge-blocking risk remains beyond normal checks and review.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 2 files. (3 skipped: 3… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: preserving lyric alignment with notes during MIDI export under swing.
Description check ✅ Passed The description explains the defect, implementation, scope limits, testing, linked issue, and all required checklist items are completed.
Linked Issues check ✅ Passed The changes address issue #32288 by applying the note swing offset to lyric MIDI event ticks. Tests cover swung lyrics, user events, and repeats.
Out of Scope Changes check ✅ Passed The implementation, test fixtures, and MIDI export tests are directly related to preserving lyric associations under swing. No unrelated changes are identified.
Full details: Docstring Coverage

Explanation

Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 2 files. (3 skipped: 3 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Linked repositories: Public OSS repositories can only analyze public repositories installed in this organization. No linked repositories were analyzed; skipped musescore/muse_framework.git.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MuseScore drops syllables when exporting Swing to midi

2 participants