clef change in one staff adds unnecessary spacing in other staves

• Mar 7, 2019 - 16:13
Reported version
3.x-dev
Type
Functional
Frequency
Many
Severity
S3 - Major
Reproducibility
Always
Status
closed
Regression
Yes
Workaround
Yes
Project

Clefs added to one staff should not cause extra spacing in other staves. Observe the following music as it appears in MuseScore 3:

clef_spacing_ms3.png

The clef changes in the left hand staff cause huge, ugly gaps between the right hand notes. This problem wasn't nearly as bad in MuseScore 2, though it's still not perfect:

clef_spacing_ms2.png

Here is a screenshot from Finale, as an example of how it should look:

clef_spacing_finale.png

Here, you can see no spacing impact in the right hand as a result of the left hand clefs, except where necessary to maintain vertical beat alignment between the staves.

MuseScore files of these examples are attached.

OS: KDE neon User Edition 5.15, Arch.: x86_64, MuseScore version (64-bit): 3.1.0.21259, revision: c2d3822

Attachment Size
clef_spacing_ms3.mscz 5.89 KB
clef_spacing_ms2.mscz 6.14 KB

Comments

Workaround Yes No

I disagree that local relayout is a workaround. It doesn't do anything to help the added space at the end of beats 1 and 4, and beats 3 and 4 still take up more horizontal space than they should. Trying to reduce "leading space" on the clef is of no use either.

(I thought I had responded but don't see it, apologies if there ends up being a duplicate)

This seems related to https://musescore.org/en/node/281024#comment-897040 - elements that should be able to overlap each other because there is no actual collision, are not. I am fairly sure this was once working much better, not sure when that changed.

Meanwhile, I think it should be the case that disabling autoplace for the clef would remove it from the calculation. This isn't the case now, but I will look into making that happen as part of my PR for #278999: Need option to completely disable Auto Placement

FWIW, it is now the case in 3.1 that disabling autoplace for the clef makes the space go away, although it also makes the clef collide with the next note you also need a manual adjustment. And even then it's only as good as 2.3.2, not as good as Finale. Still, it's something.

What would the full fix look like? I am wondering about it myself, and maybe somebody has an idea, but I see it as follows:

  1. Layout notes without taking clefs into account. (I suspect this is already the case, but I am not sure.)
  2. Layout clefs without giving them any extra space. Just put them in front of the notes they should go.
  3. Check for collisions. If found, relayout the whole measure? system? (probably measure) so there is enough space for the biggest overlap to disappear, but the notes are still spaced evenly. This means doing step 1 again, but somehow ensuring that more space is left for each note in the system proportional to what it had for the first layout.

Am I on the right track?

After further investigation, I have a better understanding of what is happening, but not yet how to solve it.

The algorithm for deciding on the amount of space to leave from one segment to the next completely changed between 2 & 3. In most cases this is actually a very good thing. As I mentioned above, accidentals for instance no longer have this effect. Take your example above, remove the clef changes but then add sharps to all three notes of the first C major chord. You'll see MuseScore 2 adds unnecessary space, MuseScore 3 does not. That's because MuseScore 2 was actually much less sophisticated in general about this spacing. It just had code to special-case clefs, so while pretty much everything else added space unnecessarily, clefs did not. In MuseScore 3, we have more sophisticated spacing overall - based on "segment shapes" - that allows the accidentals in my example here to completely overlap the notes above. Unfortunately, this isn't working for clefs because of a change that appears to have been almost inadvertent, it was done to fix a display issue in the palette involving the vertical position of the clef:

https://github.com/musescore/MuseScore/commit/bf2f3774b32e10c246d7d7d2a…

to fix

#125566: all clefs in clef palette centered on top staff line

Basically, we had been right-aligning the clef within the segment as per the comment, but now we left-align it (so the comment is actually wrong). I have verified that simply reinstating the "-r.right()" as the "x" parameter in the call to setPos() when laying out for the score as opposed to the palette does work here. However, now in the years since that change was made, it seems there were other changes to clef layout that now depend on the left-alignment of the clef. So this change throws off spacing in the normal case (eg, a single staff, clef changes are now too far to the left.

No doubt there is a solution, but it's escaping me at the moment.

This is definitely an improvement, though in some cases, still not as good as MS2. Here is a measure in MS2:

clef_spacing2_ms2.png

And the same measure using the PR for this bug:

clef_spacing2_ms3.png

There is still a lot of unnecessary space. Also, something weird is going on with the continuation ties on the first LH chord. They are way too small. I made a simple test using the latest MuseScore nightly (66b30c3), which looks fine:

tie_continuation_MS3_66b30c3_Linux.png

Then I made the same test using the PR version for this bug report (5377c2d):

tie_continuation_MS3_5377c2d_Windows.png

That continuation tie at the beginning of the line is nearly invisible. Interestingly, the bug goes away if a key signature is present:

tie_continuation_MS3_5377c2d_Windows-with_key_signature.png

So, perhaps this regression is caused by the spacing change for clefs? Or some other change made over the past few days?

Yes, the continuation of the tie looks like a regression indeed, thanks for testing!

MuseScore 2, as mentioned, did some special casing for clefs, so it was indeed able to ignore their spacing effects across staves in specific ways that our current model doesn't - it uses "shapes" for the segment, which ware without semantics (eg, we dont know what a shape represents, just that it exists). So reproducing the exact effect of 2.0 isn't directly possible, although no doubt it might be possible to reimplement new special casing. However, in this case, I think it also possible the extra space is due to a line that automatically adds a notehead width to the space calculated, I guess to reduce the potential for overlap, when it probably could be a qMax instead. I will look at that too. I suspect that line is responsible for some other cases where we see more space than needed (not having to do with clefs) but probably also is necessary in some cases, so I may just change this the calculation of space before clefs.

The tie bug is definitely mine caused by the change to right-align the clefs. Although really, if the code calculating the length of that tie were smarter, it wouldn't have mattered. Still, I realize I need to left align the header clefs anyhow - if they are of different widths, it's important to all still left-align to the start of system. Also clefs that occur right after a barline. But all other clefs should be right aligned. That's easy enough to fix.

The remaining spacing issue is proving more challenging, but it's an interesting problem and I'm continuing to work on that.

Update:

I have convinced myself I am doing all I can within the context of what I have been doing, in that the distance I am returning zero distance which would in theory allowing the clef to overlap. What's getting in the way is a difference in the measure stretch algorithm, it seems. Here is what that measure looks like in 2.3.2 if I reduce its stretch to the minimum, then increase it on the next measure until it takes up the remainder of the extra space:

clef_stretch_2.png

And here is the result with my PR:

clef_stretch_3.png

As you can see, we are starting from a better position than 2.3.2 as far as this goes. But 2.3.2 seems to be more clever about distributing the stretch evenly between notes and skipping clefs. And the most relevant line in the stretch calculation is an absolute mystery to me:

              qreal str = 1.0 + 0.865617 * log(qreal(t.ticks()) / qreal(minTick.ticks())); // .6 * log(t / minTick.ticks()) / log(2);

Actually, I'm betting answer won't lie in the math, but in how we treat clefs and other zero-tick segments. Like, probably we need to not give the segment before the clef any stretch until the combined width of the two segments reaches the expected value. I'm trying, but uit's kind of scary code to mess with.

I've given up on the stretch issue, but pushed an update to fix the tie regression, improve the alignment of clefs (so they are left-aligned where they should be, right-aligned where they should be), and generally make the code a bit more robust.

Someday the stretch thing should definitely be looked at, but that code is kind of "black magic" to me right now.

Fix version
3.1.0