Rest Grouping in Pickup Measure

• Apr 8, 2020 - 15:39

When you create a pickup measure with three 8th notes, the grouping of the rests is off - a quarter rest followed by an eighth rest, whereas it should be an eighth rest followed by a quarter rest. This also causes other grouping problems with eighth and sixteenth notes. See the attachments. The first is what is the case, the second is what should be the case:

Attachment Size
Grouping_problem.png 12.29 KB
Grouping_problem_(2).png 11.74 KB

Comments

This is a known issue, but not really a bug. The problem is we really don't the difference between a pickup measure versus any other irregular measure. For instance, you might have a 4/4 (nominal) measure in a hymn that you are splitting into 3/8 (actual) at the end of one system and 5/8 (actual) at the start of the next because that's how the phrasing/lyrics works out. This 3/8 measure needs to start with the quarter, but the 5/8 measure needs to start with the eighth. We don't have any good way to know the difference - whether the partial measure is representing the first or second half of a split measure. And that's basically what a pickup is - the second half of a split measure. We can apply some heuristics to try to guess - like, say, assume any measure at the start of the score or immediately after a system, page, or section break should be treated as a second half, anything else as a first half. We actually do try things like this with regard to swing playback. but it's just kind of guessing really.

Anyhow, bottom line for now is, you need to enter the rests you want manually.

In reply to by Jojo-Schmitz

Right. Both are valid, I've seen people argue for each, with published examples. So for now at least I'm happy that is a way of getting whichever result one wants. But it does mean you can't necessarily rely on exclude always being applied to the second half of the measure.

On the other hand, it doesn't need to be perfect to be worth doing, just needs to be better. At least the current scheme has that going for it at least. But better is to be predictable and actually right more than half the time.

In reply to by Marc Sabatella

Pickup measure (at start of score and so by definition 2nd half and excluded from measure count) should be by far the more common than the case you have in mind with spit measure at system break but 2nd half not excluded from measure count just to see the measure number at the start of the system rather then the next measure.

In reply to by Marc Sabatella

"This 3/8 measure needs to start with the quarter, but the 5/8 measure needs to start with the eighth."

Does the 5/8 measure need to start with the eighth because its the second half, or because its 5/8? It would seem that it's because its the second half, and if that's the case, then the pickup measure should behave the same way - but it doesn't. The pickup starts with a quarter rest, not an eighth rest.

In reply to by pianocomposer321

rests have nothing to do with this (and, while the title says so, you sample images don't have any rests), only notes (shorter than quarter) that have beams do.

Rest grouping is an entirely different issue, with no solution anywhere, beaming though does have a solution (normally, in full measures) via the time signature properties

In reply to by Jojo-Schmitz

I see no reason the same code couldn't be used in the place where rest grouping is performed - it's a simple matter of calculating that offset and factoring it in to the calculations that are currently based on beat position.
A one-line change, add the calculated offset value to the beat position when generating rests. This is totally different than the problem of grouping of rests for compound versus simple meter. Same code I gues,s but totally different issue. Although FWIW, I don't think that's a hard problem either, it's just that no one has bothered to solve it yet.

In reply to by Jojo-Schmitz

No, like I said, the fix would need to be applied in both places. But it's the same fix. To be specific:

1) We develop a function that calculates the proper time offset for any given measure, perhaps based on the algorithm used for swing, or perhaps something better. The idea is that for any measure considered a "first half of measure", it returns 0, but for anything considered a "second half of measure", it returns the duration of the missing first half. The current swing algorithm subtracts the actual duration from the nominal duration, which makes as much sense as anything else to me.

2) Now that we can get the time offset for measure, we apply that offset in any calculations where we need to:

  • in the swing code, it gets factored in to the place where we decide which eighths are on the beat and which are off
  • in the beaming code, we factor it in to the place where we decide what beat each note is on
  • in the rest-generating code, we factor it in to the place we decide what beat we are starting on

The new function is at most half a dozen lines or so, the three places where I say we factor this value in are one or two line changes each.

None of this helps in any way with the completely unrelated problem of how we generate the rests in 6/8 or other compound meter. That isn't a problem of detecting the start beat; it's a problem of the code needing to actually generating a totally different sequence of rests, not just the same sequence it already does but starting from a different beat. That is, considering the case of a pickup of three eighths in 4/4, MuseScore already does know how to generate an eighth rest followed by a quarter rest if it understands it is trying to generate rests starting on the "and" of "3". If you enter a half note followed by an eighth note into a 4/4 measure, MuseScore absolutely gets this right. So all we are doing is telling MuseScore to treat the 3/8 pickup in the same way it treats that case. MuseScore knows "eighth quarter" is the right sequence for 4/4 when starting on beat 3&. it just doesn't know this pickup should be treated like it starts on beat 3& rather than beat one. So that's what the online change I mention will do - tell the rest-generation code, even though it looks like the beginning of the measure, it's really beat 3&, now do your thing the way you already know how.

In reply to by Marc Sabatella

I know this is somewhat unrelated, and I'll start a new issue if that would be better, but is there any way I can help contribute this code? I've been learning a few programming languages (mostly python and C++; MuseScore is written in C++, is it not?) for some time now, and I really would like to contribute to a worthwhile open source project, and MuseScore is about as worthwhile as it gets if you ask me ;-).

In reply to by pianocomposer321

Yes, that would be awesome :-) Click "Contribute" above, then "Development", and you'll see some good info. Somewhere within that is the info on joining the developer chat on Telegram, which is probably the single most useful bit of info there, except maybe the instructions on the Git workflow and how to compile MuseScore.

Oh, and yes, MuseScore is in C++. Since I just outlined exactly what needs to happen, it probably would not be hard for you to take that and run with it, we'd just need to show you where the relevant parts of the beam-grouping and rest-generating code are, and Telegram is a good place for that kind of discussion.

In reply to by Marc Sabatella

My web filtering software is blocking telegram b/c its a chat website. I may be able to get it unblocked later, but for now, could you just point me to the correct file on GitHub? I'll at least take a look at it and if it looks like more than I can tackle without asking other devs, I'll wait until Telegram is unblocked.

Thanks

In reply to by pianocomposer321

FWIW Telegram has native pss for most platforms too, that's what I use on Windows, Chromebook (maybe using the Linux app? I forget) and my iPhone.

Anyhow, libmscore is the folder for everything relating to score rendering. rendermidi.cpp is where you'll find the function I mentioned that does the offset calculation for swing playback, literally a handful of lines of code whose bottom line is calculating the value of a variable called "offset", and then adding that value to the "tick" (time position) of the chord it is trying to decide what to do with.

So, with a function that takes a measure as a parameter (or, more to the point, a method of Measure class, defined in measure.h/measure.cpp) returning a Fraction to use as the offset (eg, 5/8 would be the returned offset for a 3/8 pickup in 4/4 time because it's logically the second half of the measure, but somehow still returning 0 for a 3/8 partial measure at the end of a system because it's logically the first half of a measure, I have no opinion on random 3/8 partial measures elsewhere), you would need to call that function and use that value in the following places:

1) groups.cpp, in endBeam(), which decides if a chord ends a beam group. The calculation is based on the tick of the chord, we'd need to add the calculated measure offset. Probably everywhere you see cr->tick(), replace with a new local variable adjustedTick, which you'd calculate at the top as cr->tick() + the return value from your function. Might be other places too, but that might turn out to be it, not sure. Certainly it's relevant though.

2) edit.cpp, the function setRest(). Here the tick is passed in as a parameter, and then for some reason immediately copied to a local. I literally think all you need to is add the calculated measure offset during that assignment. But I'm not sure why that originally parameter was passed by reference, could be something non-obvious going on.

In reply to by Marc Sabatella

Hey marc, sorry I haven't started working on this yet, I just decided to get started. Re-reading your posts here I can't figure out how I'm supposed to determine whether the measure is the first or second half. All I can find you explaining is how to calculate the offset if it is the second half. Am I missing something?

BTW, I will join the telegram group asap.

In reply to by pianocomposer321

Hello! The most relevant part of what I wrote before was this: "We can apply some heuristics to try to guess - like, say, assume any measure at the start of the score or immediately after a system, page, or section break should be treated as a second half, anything else as a first half. We actually do try things like this with regard to swing playback. but it's just kind of guessing really." It's not going to be an exact science, there really is no way to know in general. But this is the basic approach sued by the swing playback code, the same approach could be used here.

In reply to by pianocomposer321

Indeed, pickup measure is second half of measure, and all second-halves-of-measures should behave the same way. The problem is there is no totally way to tell if a measure really is meant as a second half - best we can do is guess based on the sorts of things we are discussing (presence of breaks, use of exclude from measure count, etc). BTW, another reason not to rely on the exclude from measure count option is tons of people don't use it - they number their pickups 1. Not saying it's right, but it's common.

BTW, unless I'm mistaken, the basic issue is identical for rests as for beaming The code might differ, but the basic issue is the same. And as I mention, for swing playback. We partially solved it there, I think, and if I'm remembering and reading the code right, we just used the line break methods (see Score::swingAdjustParameters() in rendermidi.cpp, where the comment says "adjust for anacrusis"). Probably there should be a single function that handles this and gets used for swing, for beaming, and for rest grouping.

Do you still have an unanswered question? Please log in first to post your question.