CPJKU / partitura

A python package for handling modern staff notation of music
https://partitura.readthedocs.io
Apache License 2.0
247 stars 18 forks source link

Issue in MusicXML export #390

Open leleogere opened 1 month ago

leleogere commented 1 month ago

I'm not sure if it is related to Partitura or MuseScore, but I'm facing weird behavior when I try to extract a part of a score:

Here is the MusicXML rendered by MuseScore: MusicXML rendered by MuseScore

Here is the list of elements in the partitura Part object:

0--48 Note id=n264 voice=1 staff=1 type=half articulations=(accent) pitch=Eb5
0--48 Note id=n265 voice=1 staff=1 type=half pitch=Eb6
0--6 Note id=n280 voice=5 staff=2 type=16th pitch=C2
0--24 Beam
0--96 Slur start=n280 end=n295
0--96 Measure number=11 name=11
0-- TimeSignature 4/4                    <<< The time signature does start at 0 here <<<
0--42 IncreasingLoudnessDirection "crescendo" wedge
6--12 Note id=n281 voice=5 staff=2 type=16th pitch=G2
12--18 Note id=n282 voice=5 staff=2 type=16th pitch=C3
18--24 Note id=n283 voice=5 staff=2 type=16th pitch=D3
24--30 Note id=n284 voice=5 staff=2 type=16th pitch=Eb3
24--48 Beam
30--36 Note id=n285 voice=5 staff=2 type=16th pitch=G3
36--42 Note id=n286 voice=5 staff=2 type=16th pitch=C4
42--48 Note id=n287 voice=5 staff=2 type=16th pitch=D4
48--54 Note id=n288 voice=5 staff=2 type=16th pitch=Eb4
48--60 Rest id=n266 voice=1 staff=1 type=eighth
48--72 Beam
48--90 DecreasingLoudnessDirection "diminuendo" wedge
54--60 Note id=n289 voice=5 staff=2 type=16th pitch=D4
60--66 Note id=n290 voice=5 staff=2 type=16th pitch=C4
60--66 Rest id=n267 voice=1 staff=1 type=16th
60--156 ConstantLoudnessDirection "p"
66--72 Note id=n268 voice=1 staff=1 type=16th pitch=G4
66--72 Note id=n269 voice=1 staff=1 type=16th pitch=C5
66--72 Note id=n270 voice=1 staff=1 type=16th pitch=Eb5
66--72 Note id=n271 voice=1 staff=1 type=16th pitch=G5
66--72 Note id=n291 voice=5 staff=2 type=16th pitch=G3
66--90 IncreasingLoudnessDirection "crescendo" wedge
72--90 Note id=n272 voice=1 staff=1 type=eighth. pitch=G4
72--90 Note id=n273 voice=1 staff=1 type=eighth. pitch=C5
72--90 Note id=n274 voice=1 staff=1 type=eighth. pitch=Eb5
72--90 Note id=n275 voice=1 staff=1 type=eighth. pitch=G5
72--78 Note id=n292 voice=5 staff=2 type=16th pitch=Eb3
72--90 Beam
72--96 Beam
78--84 Note id=n293 voice=5 staff=2 type=16th pitch=D3
84--90 Note id=n294 voice=5 staff=2 type=16th pitch=C3
90--96 Note id=n276 voice=1 staff=1 type=16th pitch=G4
90--96 Note id=n277 voice=1 staff=1 type=16th pitch=C5
90--96 Note id=n278 voice=1 staff=1 type=16th pitch=Eb5
90--96 Note id=n279 voice=1 staff=1 type=16th pitch=G5
90--96 Note id=n295 voice=5 staff=2 type=16th pitch=G2

The TimeSignature object does start at 0, but when I open the MusicXML file in MuseScore, I get it in the middle of the measure, resulting in the two hands not being in sync and the measure containing apparently 8 beats.

Interestingly, it does not fail for every measure, for example, the measure 11 of this piece fails, but the 10 works as expected.

You can find the problematic MusicXML here.

Here is the code to reproduce the issue (the measure in question is the measure 11 from Chopin's Etude op10 no12):

import copy
from pathlib import Path

import partitura as pt
import partitura.score

score_path = Path("/home/user/nasap-dataset/Chopin/Etudes_op_10/12/xml_score.musicxml")

score = pt.load_musicxml(score_path).parts[0]

measure_idx = 11
measure = score.measures[measure_idx - 1]
extracted_measure = pt.score.Part(id="measure")

for obj in score.iter_all(start=measure.start, end=measure.end):
    print(obj)

    # Shift start and end to measure start
    start = None if obj.start is None else obj.start.t - measure.start.t
    end = None if obj.end is None else obj.end.t - measure.start.t

    # Add object to extracted_measure
    extracted_measure.add(copy.copy(obj), start=start, end=end)

# Add 4/4 time signature
extracted_measure.add(pt.score.TimeSignature(4, 4), start=0)

print("#" * 80)
for obj in extracted_measure.iter_all():
    print(obj)

pt.save_musicxml(extracted_measure, Path("/tmp/test.musicxml"))
sildater commented 1 month ago

Hi @leleogere Thanks for the issue and code to reproduce it! I can get it to work using a small change in your code and a patch to the export function:

sildater commented 1 month ago

image

leleogere commented 1 month ago

Thank you for your help! I'll use this patch for now as it fix the issue, and let you know if I can spot any abnormal behavior.

The fact that it does not happen on all measures is quite bizarre.