Restore the bank fold and usage publish to the resume path, guard setActive against repeats, and make the meter fold's bound literal

The resume also hands back to a full reload when the fold moves the loaded capture's decode source, so the refs table and the audio cannot skew.
This commit is contained in:
2026-08-02 13:15:47 -04:00
parent 5c6525fb91
commit da14509ab5
15 changed files with 218 additions and 76 deletions
+24 -6
View File
@@ -17,12 +17,30 @@ separate: `setActive(false)` parks the decoded sample and destroys the voice sta
decode; sounding voices are still destroyed across it (a surviving `live_` would be displaced
into the drain slot and resurrect stale sustained voices as ghosts); an instance with nothing
decoded still routes through the full reload, which is where the pre-v10 legacy lift lives; and
`getLatencySamples()` still answers from the persisted enable, untouched by the cycle. The
build shared by the reload, the voice-param rebuild and the reactivation was factored to one
site so the three cannot drift on the generation stamp or the ring size. Daniel reversed the
deferral (*"I thought we agreed to decouple the unnecessary functions from the reactivation
path"*); Γ-F2 and Γ-F6 are untouched — dynamic latency ships, the deactivate/reactivate is
still the accepted cost of the toggle, just a much cheaper one.
`getLatencySamples()` still answers from the persisted enable, untouched by the cycle. The build
shared by the reload, the voice-param rebuild and the reactivation was factored to one site so the three cannot drift
on the generation stamp or the ring size. Daniel reversed the deferral (*"I thought we agreed
to decouple the unnecessary functions from the reactivation path"*); Γ-F2 and Γ-F6 are untouched
— dynamic latency ships, the deactivate/reactivate is still the accepted cost of the toggle,
just a much cheaper one.
**`reloadInstrument` did three things, not one, and the resume path had to keep all three.** The
first review pass discussed only the pre-v10 legacy lift; the other two were dropped silently and
restored in the follow-up. `refreshRefsFromBank` — the recapture sync — and `publishUsage` — the
`rsusage_` prune-protection write — are each a `GetProjExtState` plus a parse, neither disk nor
decode, so both run on the resume path and the spec's "no disk I/O and no WAV decode" still holds
exactly. This matters only with **no editor open**: `pollBankSync`, the only other route to
either, has exactly one caller and it is the editor's sync tick. Restoring the refresh alone
would have been worse than dropping it — the refs would name a recapture's new file while the
parked PCM still played the old one — so the resume compares the selected ref across the fold
(`sameDecodeSource`, `core/instrument/map/sample_map`) and hands back to the full reload when it
moved. The decode is eliminated in the case that matters and re-run in the case that needs it.
Three smaller consequences fell out of the same pass: `setActive` now treats a repeat of the
state it already holds as a no-op (the base is an empty stub, so a repeated deactivate would have
parked an empty optional over a still-valid sample); the park is disengaged before the build
rather than left moved-from, so a throwing build cannot publish permanent silence; and
`flushLatencyRestart` checks `restartComponent`'s `tresult` and rolls its announcement back on a
refusal, since a latch on a value the host never took would strand its delay compensation.
### Comment-reduction pass (tree-wide, twelve parallel tracks)