Clear the park snapshot where the restore is planned, not where it drains; make the drain re-entrant and reload-aware
This commit is contained in:
@@ -15,8 +15,6 @@ class ReaProject;
|
||||
|
||||
namespace reasampler {
|
||||
|
||||
class ViewModeModel;
|
||||
|
||||
// The chain as it stands now: identity by current slot. Snapshot, park and
|
||||
// restore all address FX through this one plain 0..TrackFX_GetCount-1
|
||||
// enumeration — never the 0x1000000/0x2000000 input-FX or container forms — so
|
||||
@@ -39,15 +37,24 @@ struct FxParkIntent {
|
||||
// observably wrong.
|
||||
class FxParkQueue {
|
||||
public:
|
||||
void park(const std::string& guid) {
|
||||
// Returns the ops of a pending restore this park CANCELLED, empty otherwise.
|
||||
// The caller needs them: that restore never ran, so the live chain still
|
||||
// reads the PARKED offline states and is no longer a source for a fresh
|
||||
// pre-park snapshot (see preParkFxFromCancelledRestore).
|
||||
std::vector<FxOfflineOp> park(const std::string& guid) {
|
||||
FxParkIntent* held = find(guid);
|
||||
if (!held) {
|
||||
pending_.push_back(FxParkIntent{guid, true, {}});
|
||||
} else if (!held->park) {
|
||||
erase(held);
|
||||
return {};
|
||||
}
|
||||
if (held->park) return {};
|
||||
std::vector<FxOfflineOp> cancelled = std::move(held->restoreOps);
|
||||
erase(held);
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
// A restore cancelling a pending park is COMPLETE at that point — the park
|
||||
// never ran, so no drain will ever come for this GUID.
|
||||
void restore(const std::string& guid, std::vector<FxOfflineOp> ops) {
|
||||
FxParkIntent* held = find(guid);
|
||||
if (!held) {
|
||||
@@ -65,6 +72,17 @@ public:
|
||||
bool empty() const { return pending_.empty(); }
|
||||
void clear() { pending_.clear(); }
|
||||
|
||||
// Detaches everything pending, leaving the queue able to accept intents
|
||||
// enqueued WHILE the caller applies what it took. Applying loads/unloads
|
||||
// plugins, which pumps the message loop, so a re-entrant switch can enqueue
|
||||
// mid-apply: iterating the live queue would dangle on the push_back, and
|
||||
// clearing it afterwards would discard whatever arrived during the apply.
|
||||
std::vector<FxParkIntent> take() {
|
||||
std::vector<FxParkIntent> taken;
|
||||
taken.swap(pending_);
|
||||
return taken;
|
||||
}
|
||||
|
||||
private:
|
||||
FxParkIntent* find(const std::string& guid) {
|
||||
for (FxParkIntent& i : pending_)
|
||||
@@ -78,18 +96,49 @@ private:
|
||||
std::vector<FxParkIntent> pending_;
|
||||
};
|
||||
|
||||
// The FX half of a snapshot, with the keying it must be read back under.
|
||||
struct PreParkFx {
|
||||
std::vector<FxOfflineState> states;
|
||||
FxKeying keying = FxKeying::Identity;
|
||||
};
|
||||
|
||||
// The FX half a fresh pre-park snapshot must carry when the park CANCELLED a
|
||||
// pending restore: those ops are the only surviving record of the pre-park
|
||||
// state, because the chain still reads the parked values until that restore
|
||||
// drains — and it never will, the cancel dropped it. Empty in (nothing was
|
||||
// cancelled) means the caller reads the live chain instead. The restore's own
|
||||
// keying travels with it so a slot-keyed snapshot lifted from a legacy
|
||||
// view_state does not silently become an identity-keyed one with no identities.
|
||||
inline PreParkFx preParkFxFromCancelledRestore(const std::vector<FxOfflineOp>& cancelled) {
|
||||
PreParkFx out;
|
||||
if (cancelled.empty()) return out;
|
||||
out.keying = cancelled.front().keying;
|
||||
out.states.reserve(cancelled.size());
|
||||
for (const FxOfflineOp& op : cancelled)
|
||||
out.states.push_back(FxOfflineState{op.fxGuid, op.offline ? 1 : 0});
|
||||
return out;
|
||||
}
|
||||
|
||||
// The FX half of a fresh pre-park snapshot for `tr`: whatever the accompanying
|
||||
// park cancelled, else a live read of the chain.
|
||||
PreParkFx snapshotFxOffline(MediaTrack* tr, const std::vector<FxOfflineOp>& cancelled);
|
||||
|
||||
// Enqueue against `proj` (nullptr = current project). An enqueue naming a
|
||||
// different project than the pending intents discards those unapplied.
|
||||
void deferFxPark(ReaProject* proj, const std::string& guid);
|
||||
// different project than the pending intents discards those unapplied. The park
|
||||
// returns whatever pending restore it cancelled, per FxParkQueue::park.
|
||||
std::vector<FxOfflineOp> deferFxPark(ReaProject* proj, const std::string& guid);
|
||||
void deferFxRestore(ReaProject* proj, const std::string& guid, std::vector<FxOfflineOp> ops);
|
||||
|
||||
// Applies every pending intent, then clears each drained restore's snapshot
|
||||
// from `model` — the snapshot is consumed when the restore actually lands, not
|
||||
// when it was planned, so a second switch arriving first re-parks against the
|
||||
// still-true captured state instead of re-capturing parked values. Discards the
|
||||
// queue unapplied if the project it was enqueued against is no longer current
|
||||
// (close / switch); an intent whose track is gone is pruned. Idle cost is one
|
||||
// empty-queue test.
|
||||
void drainDeferredFxParks(ViewModeModel& model);
|
||||
// Applies every pending intent. Touches NO model state — a restore's snapshot is
|
||||
// dropped where the restore is planned (applyMode). Discards the queue unapplied
|
||||
// if the project it was enqueued against is no longer current (close / switch);
|
||||
// an intent whose track is gone is pruned. Idle cost is one empty-queue test.
|
||||
void drainDeferredFxParks();
|
||||
|
||||
// Drops every pending intent without applying it. Called when the model the
|
||||
// intents were planned against has been replaced (project load/switch, undo/redo
|
||||
// state restore) — applying them then would write the pre-reload plan over the
|
||||
// project that replaced it.
|
||||
void discardDeferredFxParks();
|
||||
|
||||
} // namespace reasampler
|
||||
|
||||
Reference in New Issue
Block a user