From 5837f41a0bdfe297ec5e64e9bc2ec9ba268b854c Mon Sep 17 00:00:00 2001 From: hexbold <37342551+hexbold@users.noreply.github.com> Date: Mon, 26 Jan 2026 17:54:07 +0100 Subject: [PATCH] Fix MusicXML export losing measure boundaries with chords Chords were not incrementing the bar duration counter, causing measure boundaries to be lost in MusicXML export. A 3-bar piece with chords would incorrectly export as 2 bars. Two functions affected: - new_chordbase(): explicit chord notation - copy_prev_chord(): duration shorthand after chords (4 4) Added self.increase_bar_dura(duration) to both functions to match the behavior of regular notes. Fixes #171 --- ly/musicxml/ly2xml_mediator.py | 2 + tests/test_xml.py | 4 + tests/test_xml_files/chord_duration.ly | 15 ++ tests/test_xml_files/chord_duration.xml | 254 ++++++++++++++++++++++++ 4 files changed, 275 insertions(+) create mode 100644 tests/test_xml_files/chord_duration.ly create mode 100644 tests/test_xml_files/chord_duration.xml diff --git a/ly/musicxml/ly2xml_mediator.py b/ly/musicxml/ly2xml_mediator.py index e67004e0..5b18068f 100644 --- a/ly/musicxml/ly2xml_mediator.py +++ b/ly/musicxml/ly2xml_mediator.py @@ -564,6 +564,7 @@ def new_chordbase(self, note, duration, rel=False): self.current_note.set_duration(duration) self.current_lynote = note self.check_current_note(rel) + self.increase_bar_dura(duration) def new_chordnote(self, note, rel): chord_note = self.create_barnote_from_note(note) @@ -600,6 +601,7 @@ def copy_prev_chord(self, duration): cn.set_tie('stop') self.bar.add(cn) self.tied = False + self.increase_bar_dura(duration) def clear_chord(self): self.q_chord = self.current_chord diff --git a/tests/test_xml.py b/tests/test_xml.py index a3eb5df6..e5ca26bd 100644 --- a/tests/test_xml.py +++ b/tests/test_xml.py @@ -76,6 +76,10 @@ def test_no_barcheck(): compare_output('no_barcheck') +def test_chord_duration(): + compare_output('chord_duration') + + def ly_to_xml(filename): """Read Lilypond file and return XML string.""" writer = ly.musicxml.writer() diff --git a/tests/test_xml_files/chord_duration.ly b/tests/test_xml_files/chord_duration.ly new file mode 100644 index 00000000..df2dea39 --- /dev/null +++ b/tests/test_xml_files/chord_duration.ly @@ -0,0 +1,15 @@ +\version "2.24.0" + +% Test chord duration counting for bar boundaries (issue #171) +% Both explicit chords and duration shorthand must count toward measure duration + +\score { + << + % Explicit chord notation: 3 measures + \new Staff { c''1 | 1 | e''1 } + + % Duration shorthand after chord: 3 measures + \new Staff { \time 3/4 4 4 4 | 4 4 8 r8 | r4 a' g' } + >> + \layout { } +} diff --git a/tests/test_xml_files/chord_duration.xml b/tests/test_xml_files/chord_duration.xml new file mode 100644 index 00000000..0992e3e0 --- /dev/null +++ b/tests/test_xml_files/chord_duration.xml @@ -0,0 +1,254 @@ + + + + + + python-ly 0.9.9 + 2026-01-26 + + + + + + + + + + + + + + 2 + + + G + 2 + + + + + C + 5 + + 8 + 1 + whole + + + 8 + + + + + + D + 5 + + 8 + 1 + whole + + + + + + + F + 5 + + 8 + 1 + whole + + + + + A + 5 + + 8 + 1 + whole + + + + E + 5 + + 8 + 1 + whole + + + + + + + 2 + + + G + 2 + + + + + E + 4 + + 2 + 1 + quarter + + + + + F + 4 + + 2 + 1 + quarter + + + + E + 4 + + 2 + 1 + quarter + + + + + F + 4 + + 2 + 1 + quarter + + + + E + 4 + + 2 + 1 + quarter + + + + + F + 4 + + 2 + 1 + quarter + + + 6 + + + + + + E + 4 + + 2 + 1 + quarter + + + + + F + 4 + + 2 + 1 + quarter + + + + E + 4 + + 2 + 1 + quarter + + + + + F + 4 + + 2 + 1 + quarter + + + + E + 4 + + 1 + 1 + eighth + + + + + F + 4 + + 1 + 1 + eighth + + + + 1 + 1 + eighth + + + + + + 2 + 1 + quarter + + + + A + 4 + + 2 + 1 + quarter + + + + G + 4 + + 2 + 1 + quarter + + + +