-
Notifications
You must be signed in to change notification settings - Fork 402
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
Fix #1633 #1636
base: master
Are you sure you want to change the base?
Fix #1633 #1636
Conversation
No longer create hidden rests while parsing forward tags in musicXML files, as this led to problems. If there are unfilled gaps, they will be filled later by makeRests anyways if required.
Inspired by cuthbertLab#991
We simply wait until staves have been separated before creating rests. testHiddenRestImpliedVoice is modified since we no longer import the empty forward tag as a trailing duration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @TimFelixBeyer thanks for submitting a patch. I want to suggest a different solution, which is not that we stop interpreting <forward>
tags as hidden rests but that we just infer the correct voice number after a <backup>
tag, i.e. that we make the solution from #1030 more robust. WDYT?
# Fill gaps with rests where needed | ||
for m in s[stream.Measure]: | ||
for v in m.voices: | ||
if v: # do not bother with empty voices | ||
# the musicDataMethods use insertCore, thus the voices need to run | ||
# coreElementsChanged | ||
v.coreElementsChanged() | ||
# Fill mid-measure gaps, and find end of measure gaps by ref to measure stream | ||
# https://github.com/cuthbertlab/music21/issues/444 | ||
v.makeRests(refStreamOrTimeRange=m, | ||
fillGaps=True, | ||
inPlace=True, | ||
hideRests=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is too presumptive on the part of the parser. We should be interpolating/inventing as few elements as possible that are not in the document.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree!
I just put the makeRests there because previously the parser also ran makeRests
(this block is basically just copy pasted from before), but I'd be more than happy to remove it.
change = opFrac(float(durationText) / self.divisions) | ||
self.offsetMeasureNote = opFrac(self.offsetMeasureNote - change) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a useful change that I'd be glad to accept in isolation.
I completely agree with your logic about not 'inventing' elements where possible. In my mind it would therefore follow that we should also not interpret elements as rests (since they aren't rests). |
I guess without getting into the ontology of nothingness 😰, I think the reason for the status quo is that creating hidden rests in notation programs (at least Finale) will be exported as forward tags. And there is a slight difference between an explicit nothing marked as "do not show" versus an implicit nothing "document silent/incomplete". |
I'm not super familiar with notation programs like finale, if forward tags are usually used to represent hidden rests, it totally makes sense to me to keep them. On the other hand if we decide that |
But makeRests() is only called on export, so gaps/silence can still be represented on import or on export with makeNotation=False. |
Maybe I’m missing something, but I don’t think this is accurate: music21/music21/musicxml/xmlToM21.py Line 2565 in fdb126c
|
Ah, but only in voices, not measures. I suppose the reason could be that incomplete voices are more likely to lead to display problems than incomplete measures but I suppose we could test out removing that call. |
The call to music21/music21/musicxml/test_xmlToM21.py Line 1245 in f457a2b
I think it just depends on what the preference of the |
I think a survey of other major musicxml writers would be helpful. What do MuseScore and Sibelius do? Dorico? |
In musicxml this is just "empty space". In fact, it is even less than that. Forward and Backward are just used to reposition a "cursor" so voices can also start mid-measure. If this is not handled, correct xml import is guaranteed to be wrong in a lot of cases as I illustrated in #1633 |
Sorry for the long delay. And thanks for the thoughtful responses. Agree we need to do something here, so I'll try to help suggest the least breaking change to get this in.
Actually it was there before, but #444 just extended the "gap finding" to apply two additional arguments in order to find mid-measure and trailing rests. (makeRests defaults to only finding leading rests for some reason).
Actually, that doesn't sound so bad. I bet we could just guard the fix for #444 under a check for the software tag, which has already been parsed (although somewhat inconveniently inserted with coreInsert(), so at this juncture has to be checked against _elements): (Pdb) self.parent.parent.stream._elements[0].software
('Finale v26.3 for Mac') Then #444 becomes something like: if finale:
v = makeRests(all four arguments)
else:
v = makeRests(the two arguments before #444) Then, @TimFelixBeyer you are right that removing the code in xmlForward to create leading hidden rests solves #1633, so I'm okay with that change and the related cleanups. (Finally, the leading hidden rest that remains once we put #444 under a Finale guard doesn't cause problems with parsing and showing #1633, so I don't think we need to deal with that here to get this change in. If we want to remove it eventually, we can discuss it separately.) Does that sound like a reasonable way to get #1633 fixed? LMK! |
Thanks for your reply! What do you think about this alternative: if finale:
v = makeRests(all four arguments)
else:
pass Or alternatively we just have two implementations for the forward tag, one for finale, which inserts hidden rests and one which doesn't do anything. Then we could skip all calls to |
Alright, I'm on board. Getting rid of makeRests altogether on import for non-Finale sounds good. |
Fixes #1633
No longer create hidden rests while parsing forward tags in musicXML files, as this led to problems. If there are unfilled gaps, they will be filled later by makeRests anyways if required.
testHiddenRestImpliedVoice
is modified since we no longer importthe empty forward tag as a trailing duration.
This also allows us to remove some code to deal with trailing rests.