feat(S9/S8): bank-generation change-detection + instrument-side assignment reader

Extension stamps a monotonic bank_generation counter, bumped at content
mutations; the VST3 instrument polls it off-thread on an editor timer and
consumes assignment requests, refreshing playback hands-free.
This commit is contained in:
2026-07-26 23:46:06 -04:00
parent 725f3e7d3c
commit 66d47fb410
21 changed files with 838 additions and 36 deletions
+18 -5
View File
@@ -645,7 +645,9 @@ void doBankDelete() {
ShowConsoleMsg("ReaSampler: cannot delete that bank (the pool is un-deletable).\n");
return;
}
persistBankOp("ReaSampler: delete bank");
// S9: bump only when the deleted bank held samples — dropping them changes what a live
// instance referencing one could play. Deleting an EMPTY bank is purely organizational.
persistBankOp("ReaSampler: delete bank", /*bumpGeneration=*/members > 0);
}
// Evacuate a named bank: move every member back to the pool (index-only, collapse by
@@ -666,7 +668,8 @@ void doBankEvacuate() {
"destination, not a source).\n");
return;
}
persistBankOp("ReaSampler: evacuate bank");
// S9: evacuate moves members between banks (bank membership changes) -> bump.
persistBankOp("ReaSampler: evacuate bank", /*bumpGeneration=*/true);
}
// Cycle the active bank forward in ordinal order (pool -> named -> ... -> pool),
@@ -752,7 +755,9 @@ void doBankTransferSelected(bool copy) {
if (mutated) {
const std::string label =
std::string("ReaSampler: ") + verb + " sample(s)";
persistBankOp(label.c_str());
// S9: a move/copy changes bank membership (a sample arrives in / leaves a bank an
// instance may reference) -> bump so assigned instances refresh hands-free.
persistBankOp(label.c_str(), /*bumpGeneration=*/true);
}
}
@@ -794,7 +799,9 @@ void doBankRemoveSelected() {
}
// No-op guardrail (R-B): open an undo point only if the index actually mutated.
if (removed > 0) persistBankOp("ReaSampler: remove sample(s)");
// S9: a remove drops a sample from a bank (an instance referencing it must refresh — it
// will resolve to silence, per the stale-id policy) -> bump.
if (removed > 0) persistBankOp("ReaSampler: remove sample(s)", /*bumpGeneration=*/true);
}
// Prune bank folder — Phase R (Reclaim), R3: the guarded DESTRUCTIVE step, and the SOLE
@@ -884,8 +891,14 @@ void doBankPruneFolder() {
// change stands and persists on the user's next save; it just earns no undo point until
// there is a project to persist into (undo of an unsaved bank op has nothing to roll
// back to anyway). The Begin/End must still be balanced, hence the close-either-way.
void persistBankOp(const char* label) {
void persistBankOp(const char* label, bool bumpGeneration) {
Undo_BeginBlock2(nullptr);
// S9: bump the bank-generation counter INSIDE the block, before persistBook(), so the
// fresh generation rides the same ext-state write the persist makes (persistBook() ->
// saveToActiveProject() stamps bankGeneration()). Bumped only for content-changing verbs
// (the caller decides); a pure-organizational verb passes false and leaves the counter be,
// so a rename/activate does not needlessly refresh live instances.
if (bumpGeneration) g_session->bumpBankGeneration();
const bool persisted = persistBook();
if (persisted)
Undo_EndBlock2(nullptr, label, UNDO_STATE_MISCCFG);