Skip to content

Remove dead playlistDirty methods from Score/MasterScore#33784

Merged
mike-spa merged 18 commits into
musescore:mainfrom
cbjeukendrup:remove-playlist-dirty
Jun 15, 2026
Merged

Remove dead playlistDirty methods from Score/MasterScore#33784
mike-spa merged 18 commits into
musescore:mainfrom
cbjeukendrup:remove-playlist-dirty

Conversation

@cbjeukendrup

@cbjeukendrup cbjeukendrup commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Builds on #33658

@cbjeukendrup cbjeukendrup force-pushed the remove-playlist-dirty branch 4 times, most recently from f48f9a9 to 638d3b1 Compare June 12, 2026 10:34
@mathesoncalum mathesoncalum self-requested a review June 12, 2026 11:31
@cbjeukendrup cbjeukendrup force-pushed the remove-playlist-dirty branch from 638d3b1 to 5326a3f Compare June 12, 2026 12:46
It was already kind of, but not completely.
This might involve small behaviour changes, but those should be fine.
They were supposed to undo some transactions that are commented out
This `undo` parameter probably meant “whether this UndoableCommand currently lives in the undo stack or in the redo stack, but that’s difficult to understand. Rename it to `wasDone`, as in, “was not undone”.
The UndoStack constructor pushes one state entry onto `m_states`, so the state entry corresponding to the reopened UndoableCommand is at one index higher than the UndoableCommand.

Reported at musescore#33658 (comment) and musescore#33658 (review).
CodeRabbit was [concerned](musescore#33658 (comment)) about the fact that we never reset this flag. 

That’s half true: it is reset indirectly in `m_editData.clear()` in `doEndEditElement()`, which is called as soon as the drag-created hairpin is deselected; and that’s pretty soon, because just after dragging, the hairpin is deselected and a new (empty) dynamic is created. So in practice there is no reproducible bug.

However, it’s a small effort to reset the flag just where a reset would be expected. Just slightly more robust.
During score load, some operations *invalidate* the repeat list, and some operations *request* it, causing it to be updated and marked as valid, even while the score has not been fully loaded yet and thus will change. Because apparently not all operations that should invalidate the repeat list during score load *do* invalidate the repeat list, it is a bit hit-or-miss whether the repeat list is up to date (either invalidated, or rightfully updated) at the time of the last `connectTies` call, depending on whether the repeat list was by chance last invalidated or validated. Apparently the previous commit changed something about that, leading to a failure in partialtie_tests.cpp. Solution: make sure `connectTies` is called after the repeat list has been certainly invalidated after score load. Do this inside score read, so that it is always done, regardless of whether it’s via ScoreRW or EngravingProject.

Disclaimer: despite somewhat thorough investigation, I’m still not *completely* confident about this diagnosis of the problem, given how complex the jump points resolution is during score load (repeatedly resolving things based on incomplete apparently states). It feels like this is more complicated than it should be, and therefore so bug-prone.
Generated by Claude Opus 4.8:

Measure-anchored spanners (voltas,  ...) in the
location-based file format are split across two connectors: a start connector that carries the spanner and a <next> anchor, and an end connector with a <prev> anchor. In ConnectorInfoReader::readAddConnector,
the start branch called addSpanner(), which immediately computes the cached start/end elements. But at that point tick2/track2 are not set yet, so the end element was cached one measure too short (tick2 == tick). The end branch then set the real tick2/track2 via the direct setters, which bypass property-system invalidation, and never recomputed the end
element. Nothing else recomputed it until layout.

For voltas confined to a single staff this was masked, because StaffRead::readStaff calls Score::checkSpanner() per measure, which
recomputes every spanner's start/end. But voltas duplicated onto a non-top staff use a cross-staff connector resolved by reconnectBrokenConnectors() only after all staves are read, so checkSpanner never runs for them again and the stale (too-short) end
measure survived. As a result, RepeatList::collectRepeatListElements()
read a wrong Volta::endMeasure() and  produced an incorrect playback order until a layout pass recomputed the spanner end element.

Compute each anchor's element exactly when that anchor is finalized: defer the end computation in the start branch (addSpanner with computeStartEnd = false, then computeStartElement), and call
computeEndElement in the end branch once tick2/track2 are set. Both branches run back-to-back within a single addToScore pass, so each element is computed once, with correct values, and the previous wasted (wrong) end computation is removed.

Applied identically to read400, read410, read460 and read500.

(end of AI-generated message)

(I wonder if “cross staff voltas” are a valid concept, but apparently this file contains one, so…)
@cbjeukendrup cbjeukendrup force-pushed the remove-playlist-dirty branch from 5326a3f to 14efa02 Compare June 12, 2026 15:00
// matching end connector is processed (below). Computing it here would cache a wrong value
// (tick2 == tick) that nothing recomputes until layout. See readAddConnector end branch.
item->score()->addSpanner(sp, /*computeStartEnd=*/ false);
sp->computeStartElement();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no such thing as cross-staff voltas. But the AI generated message is probably correct about the fact that tick2 is only known later, which is yet another instalment of this saga and the completely insane way that we write spanners in our files.

@mike-spa mike-spa merged commit 3ef5acb into musescore:main Jun 15, 2026
13 of 14 checks passed
@cbjeukendrup cbjeukendrup deleted the remove-playlist-dirty branch June 15, 2026 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants