#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. Track-granular so a drain may stop between tracks, // and resumable WITHIN a track by FX identity: a slot cursor would silently skip // or repeat a plugin if the chain were edited between two ticks. 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; // Identity of the last FX this item's drain completed; empty ⇒ none yet. An // optimisation only: every write is compare-before-write, so an identity that // has since left the chain safely restarts the item rather than stranding it. std::string resumeAfterFxGuid; bool operator==(const FxTrackWork& o) const { return trackGuid == o.trackGuid && kind == o.kind && targets == o.targets && resumeAfterFxGuid == o.resumeAfterFxGuid; } }; // 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. std::vector desiredFxState(const ViewModeModel& model, 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). Honors the resume point, then matches 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