Revert "Merge Ω-W2-T4: split the deferred FX-park drain by kind"
This reverts commit70bd29dc89, reversing changes made to84afd1b545.
This commit is contained in:
@@ -22,30 +22,15 @@
|
||||
#define REAPERAPI_WANT_TrackFX_SetOffline
|
||||
#define REAPERAPI_WANT_ValidatePtr2
|
||||
#define REAPERAPI_WANT_guidToString
|
||||
#define REAPERAPI_WANT_time_precise
|
||||
#include "reaper_plugin_functions.h"
|
||||
|
||||
namespace reasampler {
|
||||
|
||||
namespace {
|
||||
|
||||
// How long a fresh park intent waits before its first FX moves. Long enough to
|
||||
// swallow a rapid A→B→A flip whole — that flip's restore then cancels the park
|
||||
// outright and the plugins never move at all — and short enough that the window
|
||||
// in which a user could add an FX to the track the switch just hid, and so miss
|
||||
// the pre-park snapshot, stays implausible. Seconds, not minutes; this is ONE
|
||||
// term of the hazard's width — see tickDeferredFxParks for the other.
|
||||
constexpr double kParkCoalesceSeconds = 1.0;
|
||||
|
||||
FxParkQueue g_queue;
|
||||
ReaProject* g_owner = nullptr; // the project the pending intents were enqueued against
|
||||
bool g_draining = false;
|
||||
// The gate is GLOBAL, not per-track: a park enqueued for track Z re-arms this
|
||||
// same stamp even though it does nothing to an already-partial park on track A.
|
||||
// Benign — that track's FX are already I_FXEN=0/B_MAINSEND=0 from the
|
||||
// synchronous half, so only its CPU reclaim (not correctness) is delayed — but
|
||||
// this is not a per-intent debounce.
|
||||
double g_parkReadyAt = 0.0; // parkReadyAt() stamp; re-armed by every enqueued park
|
||||
|
||||
// Makes "one drain at a time" explicit rather than implied by the call sites.
|
||||
// RAII because an apply can throw and a stuck flag would silence the queue for
|
||||
@@ -76,43 +61,9 @@ void setOfflineIfChanged(MediaTrack* tr, int fx, bool offline) {
|
||||
TrackFX_SetOffline(tr, fx, offline);
|
||||
}
|
||||
|
||||
// The park's next unit of work, or -1 when the track is fully parked. Derived
|
||||
// from the live chain rather than a stored cursor so a chain edited between two
|
||||
// ticks cannot leave the park writing past the end of it or skipping a slot.
|
||||
int firstOnlineFx(MediaTrack* tr) {
|
||||
void applyPark(MediaTrack* tr) {
|
||||
const int fxCount = TrackFX_GetCount(tr);
|
||||
for (int fx = 0; fx < fxCount; ++fx)
|
||||
if (!TrackFX_GetOffline(tr, fx)) return fx;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// One track by GUID, resolved afresh every tick — caching the handle across
|
||||
// ticks is exactly the dangle ValidatePtr2 is here to prevent. Still O(tracks),
|
||||
// still one guidString() per track per tick; a per-tick unordered_map keyed by
|
||||
// GUID would cost the same enumeration to build for a single lookup, so the only
|
||||
// thing avoided by NOT building one is that allocation.
|
||||
MediaTrack* findTrack(ReaProject* proj, const std::string& guid) {
|
||||
const int count = CountTracks(proj);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
MediaTrack* tr = GetTrack(proj, i);
|
||||
if (tr && guidString(tr) == guid) return tr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Shared entry gate for both drains: nothing pending, someone already draining,
|
||||
// or a queue belonging to a project that is no longer current — the last of
|
||||
// which discards. Catches only a DIFFERENT live pointer; a REAPER-recycled
|
||||
// address is caught upstream, by the caller discarding on the session's own load
|
||||
// transition.
|
||||
bool drainGateOpen() {
|
||||
if (g_queue.empty()) return false;
|
||||
if (g_draining) return false; // re-entered mid-apply: those intents are the next pass's
|
||||
if (g_owner != currentProject()) {
|
||||
discardDeferredFxParks();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
for (int fx = 0; fx < fxCount; ++fx) setOfflineIfChanged(tr, fx, true);
|
||||
}
|
||||
|
||||
// Restores per-FX offline from the plan verbatim — never a blanket "online".
|
||||
@@ -173,9 +124,6 @@ PreParkFx snapshotFxOffline(MediaTrack* tr, const std::vector<FxOfflineOp>& canc
|
||||
|
||||
std::vector<FxOfflineOp> deferFxPark(ReaProject* proj, const std::string& guid) {
|
||||
adoptOwner(proj);
|
||||
// Re-armed, not set once: while switches keep arriving the park keeps
|
||||
// waiting, which is the whole point of coalescing them.
|
||||
g_parkReadyAt = parkReadyAt(time_precise(), kParkCoalesceSeconds);
|
||||
return g_queue.park(guid);
|
||||
}
|
||||
|
||||
@@ -189,8 +137,19 @@ void discardDeferredFxParks() {
|
||||
g_owner = nullptr;
|
||||
}
|
||||
|
||||
void drainDeferredFxRestores() {
|
||||
if (!drainGateOpen()) return;
|
||||
void drainDeferredFxParks() {
|
||||
if (g_queue.empty()) return;
|
||||
if (g_draining) return; // re-entered mid-apply: those intents are the outer drain's next pass
|
||||
|
||||
if (g_owner != currentProject()) {
|
||||
// The project the intents were planned against was closed or switched
|
||||
// away from: its tracks are not ours to write and its handles may be
|
||||
// gone. Discard rather than apply. This catches only a DIFFERENT live
|
||||
// pointer; a REAPER-recycled address is caught upstream, by the caller
|
||||
// discarding on the session's own load transition.
|
||||
discardDeferredFxParks();
|
||||
return;
|
||||
}
|
||||
|
||||
ReaProject* const proj = g_owner;
|
||||
const DrainScope scope;
|
||||
@@ -199,8 +158,7 @@ void drainDeferredFxRestores() {
|
||||
// the message loop (plugins load and unload), so a re-entrant switch can
|
||||
// enqueue while this runs. Everything defensive below rests on that one
|
||||
// assumption; each piece is correct regardless of whether it holds.
|
||||
const std::vector<FxParkIntent> draining = g_queue.takeRestores();
|
||||
if (draining.empty()) return; // parks only — not this half's work
|
||||
const std::vector<FxParkIntent> draining = g_queue.take();
|
||||
|
||||
std::unordered_map<std::string, MediaTrack*> byGuid;
|
||||
const int count = CountTracks(proj);
|
||||
@@ -227,6 +185,10 @@ void drainDeferredFxRestores() {
|
||||
if (!ValidatePtr2(nullptr, proj, "ReaProject*")) return;
|
||||
if (!ValidatePtr2(proj, it->second, "MediaTrack*")) continue;
|
||||
|
||||
if (intent.park) {
|
||||
applyPark(it->second);
|
||||
continue;
|
||||
}
|
||||
const FxRestoreDrops d = applyRestore(it->second, intent.restoreOps);
|
||||
if (d.total() > 0) {
|
||||
drops.add(d);
|
||||
@@ -243,39 +205,4 @@ void drainDeferredFxRestores() {
|
||||
if (!fxDropMsg.empty()) ShowConsoleMsg(("!SHOW:" + fxDropMsg).c_str());
|
||||
}
|
||||
|
||||
void tickDeferredFxParks() {
|
||||
if (!drainGateOpen()) return;
|
||||
if (!parkIsReady(time_precise(), g_parkReadyAt)) return; // still coalescing
|
||||
|
||||
const std::string guid = g_queue.nextParkGuid();
|
||||
if (guid.empty()) return; // restores only — not this half's work
|
||||
|
||||
ReaProject* const proj = g_owner;
|
||||
const DrainScope scope;
|
||||
|
||||
// Validated before the enumeration below reads the project, and again for the
|
||||
// track it resolves — same gate, and the same reason, as the restore drain's
|
||||
// per-intent re-validation: a longer park window makes a deleted track
|
||||
// likelier, not less.
|
||||
if (!ValidatePtr2(nullptr, proj, "ReaProject*")) return;
|
||||
MediaTrack* tr = findTrack(proj, guid);
|
||||
if (!tr || !ValidatePtr2(proj, tr, "MediaTrack*")) {
|
||||
g_queue.finishPark(guid); // track deleted since the switch — prune
|
||||
return;
|
||||
}
|
||||
|
||||
const int fx = firstOnlineFx(tr);
|
||||
if (fx < 0) {
|
||||
g_queue.finishPark(guid); // fully parked
|
||||
return;
|
||||
}
|
||||
|
||||
// BEFORE the write, not after: the write may pump the message loop, and a
|
||||
// restore arriving in that window has to supersede this park rather than
|
||||
// cancel it outright — the FX about to go offline would otherwise be left
|
||||
// there with the only record of its prior state dropped.
|
||||
g_queue.markPartial(guid);
|
||||
TrackFX_SetOffline(tr, fx, true);
|
||||
}
|
||||
|
||||
} // namespace reasampler
|
||||
|
||||
Reference in New Issue
Block a user