Make an FX reclaim step one whole track's chain: drop the resume cursor, yield only between tracks

This commit is contained in:
2026-08-06 20:48:17 -04:00
parent 5a35b71dc0
commit f04c704353
6 changed files with 134 additions and 274 deletions
-72
View File
@@ -240,74 +240,6 @@ static void testSlotKeyedRecordStillRestoresByPosition() {
CHECK(writeAt(res, 2, false));
}
// -- the resume point ---------------------------------------------------------
static void testResumePointSkipsWhatTheDrainAlreadyDid() {
ViewModeModel vm = parkedWithThreeFx();
CHECK(vm.setActiveMode(kDesignModeId));
std::vector<FxTrackWork> work = desiredFxState(vm, kDesignModeId, {"{T}"});
CHECK(work.size() == 1);
if (work.empty()) return;
work[0].resumeAfterFxGuid = "{FX-A}";
const FxRestoreResolution res = resolveFxWork(work[0], {"{FX-A}", "{FX-B}", "{FX-C}"});
CHECK(res.writes.size() == 2);
CHECK(!anyWriteAt(res, 0)); // A is done
CHECK(writeAt(res, 1, true));
CHECK(writeAt(res, 2, false));
// Resuming after the LAST identity leaves nothing owed — the item is finished.
work[0].resumeAfterFxGuid = "{FX-C}";
CHECK(resolveFxWork(work[0], {"{FX-A}", "{FX-B}", "{FX-C}"}).writes.empty());
}
static void testResumePointThatLeftTheChainRestartsRatherThanStrands() {
ViewModeModel vm = parkedWithThreeFx();
CHECK(vm.setActiveMode(kDesignModeId));
std::vector<FxTrackWork> work = desiredFxState(vm, kDesignModeId, {"{T}"});
CHECK(work.size() == 1);
if (work.empty()) return;
// The drain's cursor named a plugin the user has since deleted. Every write is
// compare-before-write, so re-walking the item is cheap and correct; honoring a
// cursor that matches nothing would strand the rest of the chain.
work[0].resumeAfterFxGuid = "{FX-GONE}";
const FxRestoreResolution res = resolveFxWork(work[0], {"{FX-A}", "{FX-B}", "{FX-C}"});
CHECK(res.writes.size() == 3);
CHECK(writeAt(res, 1, true));
// Same rule on the offline side, where the cursor keys into the live chain.
ViewModeModel parked = parkedWithThreeFx(); // Arrange active ⇒ {T} parks
std::vector<FxTrackWork> offlineWork = desiredFxState(parked, kArrangeModeId, {"{T}"});
CHECK(offlineWork.size() == 1);
if (offlineWork.empty()) return;
offlineWork[0].resumeAfterFxGuid = "{FX-A}";
CHECK(resolveFxWork(offlineWork[0], {"{FX-A}", "{FX-B}", "{FX-C}"}).writes.size() == 2);
offlineWork[0].resumeAfterFxGuid = "{FX-GONE}";
CHECK(resolveFxWork(offlineWork[0], {"{FX-A}", "{FX-B}", "{FX-C}"}).writes.size() == 3);
}
static void testResumeAfterUnidentifiedFxMakesForwardProgress() {
// The drain completed slot 1, an FX REAPER reports no GUID for. Before the
// slot-cursor fix, an empty resumeAfterFxGuid was indistinguishable from
// "nothing done yet" and this item would restart at slot 0 every tick,
// forever — the non-terminating drain this test pins against.
ViewModeModel parked = parkedWithThreeFx(); // Arrange active ⇒ {T} parks (Offline, slot-keyed)
std::vector<FxTrackWork> work = desiredFxState(parked, kArrangeModeId, {"{T}"});
CHECK(work.size() == 1);
if (work.empty()) return;
work[0].resumeAfterFxGuid = "";
work[0].resumeAfterSlot = 1;
const FxRestoreResolution res =
resolveFxWork(work[0], {"{FX-A}", "", "{FX-B}", "{FX-C}"});
CHECK(res.writes.size() == 2); // slots 2 and 3 only — 0 and 1 already done
CHECK(!anyWriteAt(res, 0));
CHECK(!anyWriteAt(res, 1));
CHECK(anyWriteAt(res, 2));
CHECK(anyWriteAt(res, 3));
}
int main() {
testActiveTrackIsOwedOnlineInactiveIsOwedOffline();
testOnlineWorkSortsBeforeOfflineWork();
@@ -321,10 +253,6 @@ int main() {
testAddedFxIsLeftAlone();
testSlotKeyedRecordStillRestoresByPosition();
testResumePointSkipsWhatTheDrainAlreadyDid();
testResumePointThatLeftTheChainRestartsRatherThanStrands();
testResumeAfterUnidentifiedFxMakesForwardProgress();
if (g_fail == 0) std::printf("All tests passed.\n");
return g_fail ? 1 : 0;
}