Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
Daniel63656 opened this issue Aug 18, 2023 · 4 comments · May be fixed by #1636
Open

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

Daniel63656 opened this issue Aug 18, 2023 · 4 comments · May be fixed by #1636

Comments

@Daniel63656
Copy link

Daniel63656 commented Aug 18, 2023

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>
´´´
@TimFelixBeyer
Copy link
Contributor

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>>

@Daniel63656
Copy link
Author

Daniel63656 commented Aug 20, 2023

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

@TimFelixBeyer
Copy link
Contributor

TimFelixBeyer commented Aug 20, 2023

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.

@TimFelixBeyer TimFelixBeyer linked a pull request Aug 20, 2023 that will close this issue
@Daniel63656
Copy link
Author

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)

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 a pull request may close this issue.

2 participants