cuthbertLab/music21

Musicxml import wrong for voices that don't span whole bar

Opened this issue · 4 comments

music21 version

8.3.0

Problem summary
When dealing with voices that don't span a whole bar, music21 wrongly interprets notes and voices. It adds rests that don't exist and causes simultaneous notes to be not on the same beat.

Steps to reproduce
consider the voices in the treble. I attached the xml file (one bar) to reproduce this.

from music21 import *

# load the musicxml file
file_path = 'test.musicxml'
score = converter.parse(file_path)
score.show()

for el in score.recurse():
    print(el)

corresponding file

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 3.1 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
<score-partwise version="3.1">
  <part-list>
    <score-part id="P1">
      <part-name>Piano</part-name>
      <score-instrument id="P1-I1">
        <instrument-name>Piano</instrument-name>
        </score-instrument>
      <midi-device id="P1-I1" port="1"></midi-device>
      <midi-instrument id="P1-I1">
        <midi-channel>1</midi-channel>
        <midi-program>1</midi-program>
        <volume>78.7402</volume>
        <pan>0</pan>
        </midi-instrument>
      </score-part>
    </part-list>
  <part id="P1">
    <measure number="1" width="295.92">
      <print>
        <system-layout>
          <system-margins>
            <left-margin>85.60</left-margin>
            <right-margin>0.00</right-margin>
            </system-margins>
          <top-system-distance>182.91</top-system-distance>
          </system-layout>
        <staff-layout number="2">
          <staff-distance>73.55</staff-distance>
          </staff-layout>
        </print>
      <attributes>
        <divisions>4</divisions>
        <key>
          <fifths>-3</fifths>
          </key>
        <time symbol="common">
          <beats>4</beats>
          <beat-type>4</beat-type>
          </time>
        <staves>2</staves>
        <clef number="1">
          <sign>F</sign>
          <line>4</line>
          </clef>
        <clef number="2">
          <sign>F</sign>
          <line>4</line>
          </clef>
        </attributes>
      <direction placement="below">
        <direction-type>
          <dynamics default-y="-40.00" relative-y="-40.00">
            <ff/>
            </dynamics>
          </direction-type>
        <staff>1</staff>
        <sound dynamics="124.44"/>
        </direction>
      <direction placement="above">
        <direction-type>
          <words default-x="-40.91" default-y="46.91" relative-y="20.00" font-weight="bold" font-family="Times New Roman" font-size="12">Largo</words>
          </direction-type>
        <staff>1</staff>
        <sound tempo="30"/>
        </direction>
      <note default-x="123.38" default-y="-5.00">
        <pitch>
          <step>G</step>
          <octave>3</octave>
          </pitch>
        <duration>4</duration>
        <voice>1</voice>
        <type>quarter</type>
        <stem>down</stem>
        <staff>1</staff>
        <notations>
          <slur type="start" placement="above" number="1"/>
          </notations>
        </note>
      <note default-x="123.38" default-y="10.00">
        <chord/>
        <pitch>
          <step>C</step>
          <octave>4</octave>
          </pitch>
        <duration>4</duration>
        <voice>1</voice>
        <type>quarter</type>
        <stem>down</stem>
        <staff>1</staff>
        </note>
      <note default-x="123.38" default-y="20.00">
        <chord/>
        <pitch>
          <step>E</step>
          <alter>-1</alter>
          <octave>4</octave>
          </pitch>
        <duration>4</duration>
        <voice>1</voice>
        <type>quarter</type>
        <stem>down</stem>
        <staff>1</staff>
        </note>
      <note default-x="123.38" default-y="30.00">
        <chord/>
        <pitch>
          <step>G</step>
          <octave>4</octave>
          </pitch>
        <duration>4</duration>
        <voice>1</voice>
        <type>quarter</type>
        <stem>down</stem>
        <staff>1</staff>
        </note>
      <note default-x="161.09" default-y="0.00">
        <pitch>
          <step>A</step>
          <alter>-1</alter>
          <octave>3</octave>
          </pitch>
        <duration>4</duration>
        <voice>1</voice>
        <type>quarter</type>
        <stem>down</stem>
        <staff>1</staff>
        </note>
      <note default-x="161.09" default-y="10.00">
        <chord/>
        <pitch>
          <step>C</step>
          <octave>4</octave>
          </pitch>
        <duration>4</duration>
        <voice>1</voice>
        <type>quarter</type>
        <stem>down</stem>
        <staff>1</staff>
        </note>
      <note default-x="161.09" default-y="20.00">
        <chord/>
        <pitch>
          <step>E</step>
          <alter>-1</alter>
          <octave>4</octave>
          </pitch>
        <duration>4</duration>
        <voice>1</voice>
        <type>quarter</type>
        <stem>down</stem>
        <staff>1</staff>
        </note>
      <note default-x="161.09" default-y="35.00">
        <chord/>
        <pitch>
          <step>A</step>
          <alter>-1</alter>
          <octave>4</octave>
          </pitch>
        <duration>4</duration>
        <voice>1</voice>
        <type>quarter</type>
        <stem>down</stem>
        <staff>1</staff>
        </note>
      <note default-x="198.80" default-y="20.00">
        <pitch>
          <step>E</step>
          <alter>-1</alter>
          <octave>4</octave>
          </pitch>
        <duration>3</duration>
        <voice>1</voice>
        <type>eighth</type>
        <dot/>
        <stem>up</stem>
        <staff>1</staff>
        <beam number="1">begin</beam>
        </note>
      <note default-x="198.80" default-y="30.00">
        <chord/>
        <pitch>
          <step>G</step>
          <octave>4</octave>
          </pitch>
        <duration>3</duration>
        <voice>1</voice>
        <type>eighth</type>
        <dot/>
        <stem>up</stem>
        <staff>1</staff>
        </note>
      <note default-x="232.25" default-y="15.00">
        <pitch>
          <step>D</step>
          <octave>4</octave>
          </pitch>
        <duration>1</duration>
        <voice>1</voice>
        <type>16th</type>
        <stem>up</stem>
        <staff>1</staff>
        <beam number="1">end</beam>
        <beam number="2">backward hook</beam>
        </note>
      <note default-x="232.25" default-y="25.00">
        <chord/>
        <pitch>
          <step>F</step>
          <octave>4</octave>
          </pitch>
        <duration>1</duration>
        <voice>1</voice>
        <type>16th</type>
        <stem>up</stem>
        <staff>1</staff>
        </note>
      <note default-x="256.61" default-y="-15.00">
        <pitch>
          <step>E</step>
          <alter>-1</alter>
          <octave>3</octave>
          </pitch>
        <duration>4</duration>
        <voice>1</voice>
        <type>quarter</type>
        <stem>down</stem>
        <staff>1</staff>
        <notations>
          <slur type="stop" number="1"/>
          </notations>
        </note>
      <note default-x="256.61" default-y="-5.00">
        <chord/>
        <pitch>
          <step>G</step>
          <octave>3</octave>
          </pitch>
        <duration>4</duration>
        <voice>1</voice>
        <type>quarter</type>
        <stem>down</stem>
        <staff>1</staff>
        </note>
      <note default-x="256.61" default-y="10.00">
        <chord/>
        <pitch>
          <step>C</step>
          <octave>4</octave>
          </pitch>
        <duration>4</duration>
        <voice>1</voice>
        <type>quarter</type>
        <stem>down</stem>
        <staff>1</staff>
        </note>
      <note default-x="256.61" default-y="20.00">
        <chord/>
        <pitch>
          <step>E</step>
          <alter>-1</alter>
          <octave>4</octave>
          </pitch>
        <duration>4</duration>
        <voice>1</voice>
        <type>quarter</type>
        <stem>down</stem>
        <staff>1</staff>
        </note>
      <backup>
        <duration>16</duration>
        </backup>
      <forward>
        <duration>8</duration>
        </forward>
      <note default-x="198.80" default-y="-5.00">
        <pitch>
          <step>G</step>
          <octave>3</octave>
          </pitch>
        <duration>4</duration>
        <voice>2</voice>
        <type>quarter</type>
        <stem>down</stem>
        <staff>1</staff>
        </note>
      <note default-x="198.80" default-y="5.00">
        <chord/>
        <pitch>
          <step>B</step>
          <octave>3</octave>
          </pitch>
        <duration>4</duration>
        <voice>2</voice>
        <type>quarter</type>
        <accidental>natural</accidental>
        <stem>down</stem>
        <staff>1</staff>
        </note>
      <backup>
        <duration>12</duration>
        </backup>
      <note default-x="123.38" default-y="-173.55">
        <pitch>
          <step>C</step>
          <octave>2</octave>
          </pitch>
        <duration>4</duration>
        <voice>5</voice>
        <type>quarter</type>
        <stem>up</stem>
        <staff>2</staff>
        </note>
      <note default-x="123.38" default-y="-138.55">
        <chord/>
        <pitch>
          <step>C</step>
          <octave>3</octave>
          </pitch>
        <duration>4</duration>
        <voice>5</voice>
        <type>quarter</type>
        <stem>up</stem>
        <staff>2</staff>
        </note>
      <note default-x="161.09" default-y="-193.55">
        <pitch>
          <step>F</step>
          <octave>1</octave>
          </pitch>
        <duration>4</duration>
        <voice>5</voice>
        <type>quarter</type>
        <stem>up</stem>
        <staff>2</staff>
        </note>
      <note default-x="161.09" default-y="-158.55">
        <chord/>
        <pitch>
          <step>F</step>
          <octave>2</octave>
          </pitch>
        <duration>4</duration>
        <voice>5</voice>
        <type>quarter</type>
        <stem>up</stem>
        <staff>2</staff>
        </note>
      <note default-x="198.80" default-y="-188.55">
        <pitch>
          <step>G</step>
          <octave>1</octave>
          </pitch>
        <duration>4</duration>
        <voice>5</voice>
        <type>quarter</type>
        <stem>up</stem>
        <staff>2</staff>
        </note>
      <note default-x="198.80" default-y="-153.55">
        <chord/>
        <pitch>
          <step>G</step>
          <octave>2</octave>
          </pitch>
        <duration>4</duration>
        <voice>5</voice>
        <type>quarter</type>
        <stem>up</stem>
        <staff>2</staff>
        </note>
      <note default-x="256.61" default-y="-173.55">
        <pitch>
          <step>C</step>
          <octave>2</octave>
          </pitch>
        <duration>4</duration>
        <voice>5</voice>
        <type>quarter</type>
        <stem>up</stem>
        <staff>2</staff>
        </note>
      <note default-x="256.61" default-y="-153.55">
        <chord/>
        <pitch>
          <step>G</step>
          <octave>2</octave>
          </pitch>
        <duration>4</duration>
        <voice>5</voice>
        <type>quarter</type>
        <stem>up</stem>
        <staff>2</staff>
        </note>
      <note default-x="256.61" default-y="-138.55">
        <chord/>
        <pitch>
          <step>C</step>
          <octave>3</octave>
          </pitch>
        <duration>4</duration>
        <voice>5</voice>
        <type>quarter</type>
        <stem>up</stem>
        <staff>2</staff>
        </note>
      </measure>   
    </part>
  </score-partwise>
´´´

With 9.1.0, I get this output for score.show('text'), which seems to be correct.
The display in MuseScore 4 looks identical too.
music21 automatically adds rests to gaps in voices, so the addition of new rests is expected behaviour (that should be better documented).
I agree that this might not always be the right thing to do and should probably be configurable.
If this is not what you see on your machine, you could try upgrading to version 9.1.0 to see if that fixes your problem.

{0.0} <music21.metadata.Metadata object at 0x...>
{0.0} <music21.stream.PartStaff P1-Staff1>
    {0.0} <music21.instrument.Piano 'P1: Piano: Piano'>
    {0.0} <music21.stream.Measure 1 offset=0.0>
        {0.0} <music21.expressions.TextExpression 'Largo'>
        {0.0} <music21.layout.SystemLayout>
        {0.0} <music21.clef.BassClef>
        {0.0} <music21.tempo.MetronomeMark Quarter=30 (playback only)>
        {0.0} <music21.key.KeySignature of 3 flats>
        {0.0} <music21.meter.TimeSignature 4/4>
        {0.0} <music21.stream.Voice 1>
            {0.0} <music21.chord.Chord G3 C4 E-4 G4>
            {0.0} <music21.note.Rest half>
            {1.0} <music21.chord.Chord A-3 C4 E-4 A-4>
            {2.0} <music21.chord.Chord E-4 G4>
            {2.75} <music21.chord.Chord D4 F4>
            {3.0} <music21.chord.Chord E-3 G3 C4 E-4>
        {0.0} <music21.stream.Voice 2>
            {0.0} <music21.note.Rest half>
            {2.0} <music21.chord.Chord G3 B3>
            {3.0} <music21.note.Rest quarter>
        {0.0} <music21.dynamics.Dynamic ff>
    {0.0} <music21.spanner.Slur <music21.chord.Chord G3 C4 E-4 G4><music21.chord.Chord E-3 G3 C4 E-4>>
{0.0} <music21.stream.PartStaff P1-Staff2>
    {0.0} <music21.instrument.Piano 'P1: Piano: Piano'>
    {0.0} <music21.stream.Measure 1 offset=0.0>
        {0.0} <music21.layout.SystemLayout>
        {0.0} <music21.layout.StaffLayout distance 73.55, staffNumber 2, staffSize None, staffLines None>
        {0.0} <music21.clef.BassClef>
        {0.0} <music21.key.KeySignature of 3 flats>
        {0.0} <music21.meter.TimeSignature 4/4>
        {0.0} <music21.stream.Voice 1>
            {0.0} <music21.note.Rest half>
        {0.0} <music21.stream.Voice 2>
            {0.0} <music21.note.Rest half>
            {3.0} <music21.note.Rest quarter>
        {0.0} <music21.stream.Voice 5>
            {0.0} <music21.chord.Chord C2 C3>
            {1.0} <music21.chord.Chord F1 F2>
            {2.0} <music21.chord.Chord G1 G2>
            {3.0} <music21.chord.Chord C2 G2 C3>
{0.0} <music21.layout.StaffGroup <music21.stream.PartStaff P1-Staff1><music21.stream.PartStaff P1-Staff2>>

Yes, I have the same, but this is not correct. The half rest in voice1 is wrong in particular. This becomes also apparent if you render the score with show(), where this erroneous half rest causes chaos. In the original, the bar spans a whole note and in the music21 read score, the additional rest causes voice1 to extend the bar.

output

and correct one (in MuseScore 4):
Unbenannt

I see your problem now!
I think Music21 doesn't parse forward tags correctly if they immediately follow a backup tag.
There are two options for you to fix this:

you can replace

<backup>
  <duration>16</duration>
</backup>
<forward>
  <duration>8</duration>
</forward>

with

<backup>
  <duration>8</duration>
</backup>

or you can change xmlForward in music21/musicxml/xmlToM21.py to:

def xmlForward(self, mxObj: ET.Element):
        '''
        Parse a forward tag by changing :attr:`offsetMeasureNote`.
        '''
        mxDuration = mxObj.find('duration')
        if durationText := strippedText(mxDuration):
            change = opFrac(float(durationText) / self.divisions)
            # Allow overfilled measures for now -- TODO(someday): warn?
            self.offsetMeasureNote = opFrac(self.offsetMeasureNote + change)
            self.endedWithForwardTag = None

this is just a quick fix that may break other scores though (#991 )
I created a PR to completely fix this issue, but it may take a while for it get accepted.

Is there any progress on that matter? I need to decide whether I use music21 or my own interpreter (which works in these cases but is in Java)