cuthbertLab / music21

music21 is a Toolkit for Computational Musicology
https://www.music21.org/
Other
2.09k stars 396 forks source link

stripTies() yields different results when called on part versus contained measure #1559

Open NeroBlackstone opened 1 year ago

NeroBlackstone commented 1 year ago

music21 version

8.1.0

Problem summary

Tie disappears after music21 converts musicxml to midi.

Steps to reproduce

File for reproduce: 1.zip

Step1. Use musescore 4.0.2 open 1.mscz, then convert to 1.musicxml Step2. Check 1.musicxml in musescore, 14th measure:

Screenshot from 2023-05-08 01-19-38

Step3: Execute xml_to_mid.py

from music21 import *

score = converter.parse("1.musicxml")

for p in score.parts:
    p.atSoundingPitch = False
    for m in p.getElementsByClass("Measure"):
        m.removeByClass("ChordSymbol")

piano_rh = score.parts[0]
piano_rh.write("midi","1_rh.mid")

It removes all chord symbol in every measure, and output the right-hand piano part to the midi file.

Expected vs. actual behavior

Expected behavior: Like the picture above, the "A" and "F" two notes should be sounding only once, since there is a tie.

Actual behavior: Midi opened by musescore: Screenshot from 2023-05-08 01-30-34

Tie disappears, and these two notes sound twice.

Midi opened by MIDI Visualizer:

Screenshot from 2023-05-08 01-35-11

Sounding twice. It is not what we want apparently.

More information

OS: Linux 6.1 LTS Python version: 3.11

Big thanks: Music21 is an amazing package, I respect all the maintainers of Music21, thanks all your contribution.

jacobtylerwalls commented 1 year ago

Thanks for the report. I noticed that exporting the measure you referred to works correctly, so it's an issue with the way the Part is prepared for MIDI export by stripTies().

Because it does not directly contain voices, the part is flattened. That happens to place the rest in your first screenshot between the two A-F dyads, causing the tie to be broken.

stripTies should probably operate measure per part, just as it does part per score and voice per measure before it calls flatten().