Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ly/musicxml/ly2xml_mediator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions tests/test_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
15 changes: 15 additions & 0 deletions tests/test_xml_files/chord_duration.ly
Original file line number Diff line number Diff line change
@@ -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 | <d'' f'' a''>1 | e''1 }

% Duration shorthand after chord: 3 measures
\new Staff { \time 3/4 <e' f'>4 4 4 | 4 4 8 r8 | r4 a' g' }
>>
\layout { }
}
254 changes: 254 additions & 0 deletions tests/test_xml_files/chord_duration.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 2.0 Partwise//EN"
"http://www.musicxml.org/dtds/partwise.dtd">
<score-partwise version="3.0">
<identification>
<encoding>
<software>python-ly 0.9.9</software>
<encoding-date>2026-01-26</encoding-date>
</encoding>
</identification>
<part-list>
<score-part id="P1">
<part-name />
</score-part>
<score-part id="P2">
<part-name />
</score-part>
</part-list>
<part id="P1">
<measure number="1">
<attributes>
<divisions>2</divisions>
<time>
<beats>3</beats>
<beat-type>4</beat-type>
</time>
<clef>
<sign>G</sign>
<line>2</line>
</clef>
</attributes>
<note>
<pitch>
<step>C</step>
<octave>5</octave>
</pitch>
<duration>8</duration>
<voice>1</voice>
<type>whole</type>
</note>
<backup>
<duration>8</duration>
</backup>
</measure>
<measure number="2">
<note>
<pitch>
<step>D</step>
<octave>5</octave>
</pitch>
<duration>8</duration>
<voice>1</voice>
<type>whole</type>
</note>
</measure>
<measure number="3">
<note>
<chord />
<pitch>
<step>F</step>
<octave>5</octave>
</pitch>
<duration>8</duration>
<voice>1</voice>
<type>whole</type>
</note>
<note>
<chord />
<pitch>
<step>A</step>
<octave>5</octave>
</pitch>
<duration>8</duration>
<voice>1</voice>
<type>whole</type>
</note>
<note>
<pitch>
<step>E</step>
<octave>5</octave>
</pitch>
<duration>8</duration>
<voice>1</voice>
<type>whole</type>
</note>
</measure>
</part>
<part id="P2">
<measure number="1">
<attributes>
<divisions>2</divisions>
<time>
<beats>3</beats>
<beat-type>4</beat-type>
</time>
<clef>
<sign>G</sign>
<line>2</line>
</clef>
</attributes>
<note>
<pitch>
<step>E</step>
<octave>4</octave>
</pitch>
<duration>2</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<chord />
<pitch>
<step>F</step>
<octave>4</octave>
</pitch>
<duration>2</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<pitch>
<step>E</step>
<octave>4</octave>
</pitch>
<duration>2</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<chord />
<pitch>
<step>F</step>
<octave>4</octave>
</pitch>
<duration>2</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<pitch>
<step>E</step>
<octave>4</octave>
</pitch>
<duration>2</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<chord />
<pitch>
<step>F</step>
<octave>4</octave>
</pitch>
<duration>2</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<backup>
<duration>6</duration>
</backup>
</measure>
<measure number="2">
<note>
<pitch>
<step>E</step>
<octave>4</octave>
</pitch>
<duration>2</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<chord />
<pitch>
<step>F</step>
<octave>4</octave>
</pitch>
<duration>2</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<pitch>
<step>E</step>
<octave>4</octave>
</pitch>
<duration>2</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<chord />
<pitch>
<step>F</step>
<octave>4</octave>
</pitch>
<duration>2</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<pitch>
<step>E</step>
<octave>4</octave>
</pitch>
<duration>1</duration>
<voice>1</voice>
<type>eighth</type>
</note>
<note>
<chord />
<pitch>
<step>F</step>
<octave>4</octave>
</pitch>
<duration>1</duration>
<voice>1</voice>
<type>eighth</type>
</note>
<note>
<rest />
<duration>1</duration>
<voice>1</voice>
<type>eighth</type>
</note>
</measure>
<measure number="3">
<note>
<rest />
<duration>2</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<pitch>
<step>A</step>
<octave>4</octave>
</pitch>
<duration>2</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<pitch>
<step>G</step>
<octave>4</octave>
</pitch>
<duration>2</duration>
<voice>1</voice>
<type>quarter</type>
</note>
</measure>
</part>
</score-partwise>