Spanner end cannot be set between notes in voice 2

• Feb 7, 2015 - 12:39
Type
Functional
Severity
S4 - Minor
Status
closed
Project

When the attached file SlurMS2.0b2 is opened in the current trunk, the hairpin end (right side) cannot be moved (by selecting it and using Cmd-arrow on the Mac) to the position between the E and F in the third measure or beyond. It gets stuck at the end of the third measure.

When the attached file is opened in beta 2, the hairpin end skips the position between the E and F in the third measure, but can be moved beyond the third measure.

Using the equivalent file SlurMS1.3 in MuseScore 1.3, the hairpin end can be moved to the position between the E and F in the third measure or beyond.

Could be related to #46716: [MusicXML import] testWedge2.xml failure

Attachment Size
SlurMS2.0b2.mscz 4.01 KB
SlurMS1.3.mscz 1.65 KB

Comments

Problem seems to be that LineSegment::edit() calls doLayout() part way through the job, and doLayout() - through calling computeEndElement() - is noticing that the end of the spanner (which at this point has been shortened) no longer matches the tick count. So it "fixes" the spanner (outputting "ticks changed" message to console), thus undoing the partial job we've done so far.

Not sure of fix yet, but will try.

BTW, this affects most lines - pedal, trills, ottavas, etc - everything but slurs. Basically, you can't attach the end of a line to a note in voice 2-4 - only a note in voice 1. When moving the endpoint to the right, voice 2 notes are skipped; when moving the endpoint to the left, it gets "stuck" and won't move further left.

I looked at this and made some progress, but am not sure about finishing the job.

I can say that computeEndElement() is the main problem here - it keeps forcing the line segment to the voice 1 note depsite the best efforts of LineSegment::edit(). We need to set endElement to the *shortest* CR in the segment before tick2(), whereas right now we always prefer voice 1. If we fix that, then the spanner can be edited, but the endpoint is still wrong in layout, since linePos() looks at track2(), and that is always voice 1. So I tried modifying LineSegment::edit() to set track2() when changing the either start or end grips, and that now makes editing and layout correct, but it's still wrong on copy & paste and/or save / reload, I assume because we need to write the "track2" tag for this approach to work. But I have doubt about this approach. Seems there was a deliberate decision not to use track2, and we manage to get the *start* grip right even though track is always set to voice 0.

So I'm hoping someone else can take it from here.

Not sure whether it is related, but I was experiencing a crash in that area yesterday, once again playing with my large album file (Marc knows what I'm talking about and has an older version of it).
Will try to repoduce and investigate, al least provide a stack trace...

I could imagine a crash somehow resulting from this, but it could also be unrelated.

Meanwhile, I think I see how to remove the dependency on track2 from the layout. We only really use to find the next relevant element after endElement, so we can draw the line up to (just before) that next element. But in a way, we had that information before we even calculated endElement - it's the segment pointed to by tick2. So instead of using endElement plus track2 to find the next relevant element, we could be getting that directly from tick2.

Since I already have the rest coded up and working, I'm giving it a shot, as I'd much rather not need to be maintaining (and read/writing) track2 unnecessarily.

Status (old) active patch (code needs review)

Here is is:

https://github.com/musescore/MuseScore/pull/1753

It seems this has been broken since shortly before beta *1*, although the specific symptom was different. Instead of backing up the end point getting "stuck" on the voice 2 note, it would just skip past it (but take two tries to do so). Either way, you couldn't get a hairpin or other line to end with a voice 2 note.