#pragma once // What the FX chains SHOULD be, derived from view state: an ordered per-track // work list plus its resolution against a live chain. Derived, never persisted // and never in an undo record — the park record's captured FX half is the only // persisted half. Pure: FX identities are opaque strings the shell reads from // REAPER (TrackFX_GetFXGUID) and hands in. #include #include #include #include "core/view/fx_offline.h" #include "core/view/view_mode_model.h" namespace reasampler::view { enum class FxWorkKind { Online, // back to the park record's captured per-FX state, verbatim Offline, // reclaim: every live FX offline }; // One track's whole FX move, and the ATOMIC unit of work: a drain may stop // between items, never inside one, so an item is either untouched or complete // and no partial state survives a tick boundary. Do not reintroduce a // within-track resume cursor — carrying one across ticks meant reconciling it // against a chain the user may have edited in between, and the case an FX with // no reported identity forced (a cursor that reads as "nothing done yet" and // re-walks the item forever) was a live non-termination hazard. struct FxTrackWork { std::string trackGuid; FxWorkKind kind = FxWorkKind::Offline; // Online: the captured targets, verbatim — never a blanket "online", which is // exactly what would lose the plugins the USER had offline before the park. // Offline: empty. The live chain is the target set, and only the shell can // read it, so resolveFxWork synthesises the targets from what it is handed. std::vector targets; bool operator==(const FxTrackWork& o) const { return trackGuid == o.trackGuid && kind == o.kind && targets == o.targets; } }; // The whole project's FX work, from view state alone — no folder tree, because a // park record is only ever written for a track the planner already decided to // park (parents and show-both leaves never get one). // // ONLINE WORK SORTS FIRST: onlining restores state the user owns, offlining is // opportunistic reclaim that may be deferred indefinitely without losing // anything. Within a kind, GUID order — deterministic, so a drain's position in // the list survives a re-derivation. // // `targetMode` is explicit, mirroring planToggle, rather than read from // `model.activeModeId()`: applyMode sets the active mode LAST, after its park // and restore loops, so a caller reading it from inside or before that block // would classify every track against the OUTGOING mode instead. std::vector desiredFxState(const ViewModeModel& model, const std::string& targetMode, const std::set& liveTrackGuids); // One track's Online targets from its park record's FX half; empty when the // record holds none. Each target carries the record's keying, so a snapshot // lifted from a pre-identity project still restores by slot. std::vector fxRestoreTargets(const ViewModeModel& model, const std::string& trackGuid); // Resolves one work item against the chain as it stands, where `liveFxGuids[i]` // is the identity of the FX at slot `i` right now (empty when REAPER reported // none) — the item's WHOLE move, matched by identity: an identity that is not // live is DROPPED, never re-pointed at a slot. FxRestoreResolution resolveFxWork(const FxTrackWork& work, const std::vector& liveFxGuids); } // namespace reasampler::view