-
Notifications
You must be signed in to change notification settings - Fork 434
Description
music21 version
7.0.5
Problem summary
stripTies(inPlace=True) leaves behind broken beams when it deletes notes, such as a stop beam lacking a start. These broken beams are then written out to musicxml, since makeNotation during musicXML export queries a temporary stream of measures and gets its streamStatus .beams value by doing a fresh scan through all elements for the presence of any beam, and uses that result to skip making beams..streamStatus.beams is already True, and makeNotation during musicXML export uses that flag to skip making beams.
stripTies(inPlace=False) starts fresh with a new stream, no beams. Good—it doesn’t have the above problem. makeNotation during musicxml export makes beams for the first time.
But BOTH flavors of stripTies have this downstream problem:
- In musicxml export,
makeNotation()runs beforesplitAtDurations(), so we make some of the beams that need to be made, but too early to catch needed beams involving split durations (e.g. the 0.5 on a 2.5 QL note).
Either way, if you're using stripTies/chordify to annotate a score (add lyrics, etc), the beams will need some manual corrections.
Steps to reproduce
p = converter.parse('tinyNotation: c2~ c8 c8 c8 c8')
p.makeNotation(inPlace=True) # makeBeams and set streamStatus.beams = True
p.stripTies(inPlace=True)
for n in p.recurse().notes:
print(n.offset, n.beams)
Actual behavior
0.0 <music21.beam.Beams>
2.5 <music21.beam.Beams <music21.beam.Beam 1/stop>> # broken
3.0 <music21.beam.Beams <music21.beam.Beam 1/start>>
3.5 <music21.beam.Beams <music21.beam.Beam 1/stop>>
MuseScore display (Finale does some automagic fixing, but the beam tags we are writing suggest this output):

Workarounds
Deliberately calling makeBeams() afterward, but before musicxml export, will remove the broken beam, and should allow the deepcopy/makenotation musicxml export pipeline to start fresh with new beams. Calling Stream.splitAtDurations() should handle the other issue too, but this is too involved -- no reason we can't just incorporate these steps, it seems to me.
Suggested approach
stripTies(inPlace=False)could just set streamStatus.beams = False so that they can get remade during the makeNotation/musicxml export pipeline, and so we don’t have to document callingmakeBeams()afterstripTies(). This avoids imposing making beams when users are still doing transformations inside music21.- musicxml export should split durations using our newfangled
Stream.splitAtDurations()somewhere early likefixupNotationMeasured()rather than note by note inparseOneElement().