cuthbertLab / music21

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

About code hanging at stream.Score .write #1726

Open monetjoe opened 3 weeks ago

monetjoe commented 3 weeks ago

I wrote a script with music21 for slicing xmls as follow:

def slice_xml(in_xml_path: str, out_xmls_dir: str, measures_per_slice=20):
    slices = []
    current_measures = stream.Part()
    v1 = converter.parse(in_xml_path).parts[0]
    measures = v1.getElementsByClass(stream.Measure)[0:]
    for measure_id, element in enumerate(measures):
        current_measures.append(deepcopy(element))
        # Check if we've reached the desired number of measures
        if (measure_id + 1) % measures_per_slice == 0:
            slices.append(current_measures)
            current_measures = stream.Part()

        elif measure_id + 1 == len(measures):
            slices.append(current_measures)

    if slices and len(slices) > 1 and len(slices[-1]) < measures_per_slice * 0.5:
        for measure in slices[-1]:
            slices[-2].append(measure)

        slices = slices[:-1]

    filename_no_ext = rm_ext(os.path.basename(in_xml_path))
    for slice_id, piece in enumerate(slices):
        piece[-1].rightBarline = "final"
        xml_stream = stream.Score([piece])
        export_path = f"{out_xmls_dir}/{filename_no_ext}_{slice_id + 1}.musicxml"
        xml_stream.write("musicxml", fp=export_path, encoding="utf-8")

Its function is to slice the sheet music every 20 measures and export each slice as a MusicXML file, and it works well for normal scores.

However, the code hangs at the last line of the function (.write) without throwing an error or exiting, when processing the following sheet music: Q2_d2ac39b583bc66b1a397de2832ca05ec.zip

Please help identify what might be causing the .write method to hang.

music21 version

9.1.0

Problem summary

Steps to reproduce

Paste minimal code example here. Most issues can be reproduced with just a few elements.
Attach external files only after attempting to reproduce using a simple stream.

myStream1 = converter.parse('tinynotation: 4/4 c4 e4 g2')
myStream2 = stream.Stream()
myStream2.insert(note.Rest(0.5))

Expected vs. actual behavior

More information

mscuthbert commented 3 weeks ago

Hi Joe. Thanks for using the system. I'm afraid I'll need more than "the code I wrote doesn't work on a piece I found". What's different about this piece and what things have you tried and what errors remain ?

monetjoe commented 3 weeks ago

Hi Joe. Thanks for using the system. I'm afraid I'll need more than "the code I wrote doesn't work on a piece I found". What's different about this piece and what things have you tried and what errors remain ?

I have no idea about the difference of this piece, because all the scores come from one dataset called VGMIDI with paper, I batch slice the scores in this dataset, however, when processing this specific sheet music, the program enters an infinite loop and cannot move on to the next piece. I set breakpoints to investigate and found that the program gets stuck in an infinite loop after reaching the .write step. Removing this sheet music from the dataset can resolve the issue.

It doesn't show any error messages; it just gets stuck in an infinite loop inside the .write function. The sheet music causing the infinite loop has been identified and is included in the attached zip file.

monetjoe commented 2 weeks ago

I tried to change the slice measure number 20 to 35, the endless loop disappeared, but it showed a key error:

lib\site-packages\music21\stream\iterator.py", line 421, in __getitem__
    raise KeyError(k)
KeyError: '3'

which was raised at following line 421: image

It seems that the score piece causing endless loop locates at measure 21-34 of the musicxml I gave to you. By the way, the error KeyError: '3' happens very often, I jumped this error before, however, this score drops the program into the endless loop, that's why I pay attention to it at present.