fx_reclaim: use GetCurrentProjectInLoadSave for the save hook, stop disarming ReleaseFlush on one write, validate project before cached-track lookup
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
|
||||
#define REAPERAPI_MINIMAL
|
||||
#define REAPERAPI_WANT_EnumProjects
|
||||
#define REAPERAPI_WANT_GetCurrentProjectInLoadSave
|
||||
#define REAPERAPI_WANT_ShowConsoleMsg
|
||||
#define REAPERAPI_WANT_TrackFX_GetCount
|
||||
#define REAPERAPI_WANT_TrackFX_GetOffline
|
||||
@@ -50,13 +51,10 @@ struct DrainLatch {
|
||||
|
||||
// Resolved fresh from the GUID rather than held across a write, for the same pump
|
||||
// premise: a plugin load can run arbitrary REAPER code, and a handle taken before it
|
||||
// is not one this code may trust after it. The tick's own project pointer is
|
||||
// validated once at entry, before any write has run; every call here happens AFTER
|
||||
// at least one prior pumping write might have, so the project itself — not just the
|
||||
// track — needs its own re-check, or CountTracks/GetTrack below run on a project that
|
||||
// may have closed mid-drain.
|
||||
// is not one this code may trust after it. The caller (ReclaimHost::resolveForStep)
|
||||
// re-validates `proj` itself before calling this, on every arm, so this scan can
|
||||
// assume a live project.
|
||||
MediaTrack* resolveFresh(ReaProject* proj, const std::string& guid) {
|
||||
if (!ValidatePtr2(nullptr, proj, "ReaProject*")) return nullptr;
|
||||
TrackHandles handles;
|
||||
readFolderEntries(proj, handles);
|
||||
for (const auto& kv : handles)
|
||||
@@ -86,9 +84,14 @@ struct ReclaimHost {
|
||||
std::string cachedGuid_;
|
||||
MediaTrack* cachedTrack_ = nullptr;
|
||||
|
||||
// A track is validated IN a project (reaper_plugin_functions.h:7898); the null form
|
||||
// is defined only where the pointer is itself a project.
|
||||
// Re-checks the project on EVERY call, both arms: the cached-track fast path used
|
||||
// to hand `project` straight to ValidatePtr2 without re-validating it first, and a
|
||||
// prior pumping write can have closed it since the tick's own entry check ran.
|
||||
// (reaper_plugin_functions.h:7898 says `proj` is IGNORED when the pointer passed
|
||||
// IS itself a project — not that passing one is only valid when it is; passing the
|
||||
// project here is still right, just not for the reason once claimed.)
|
||||
MediaTrack* resolveForStep(const std::string& guid) {
|
||||
if (!ValidatePtr2(nullptr, project, "ReaProject*")) return nullptr;
|
||||
if (guid == cachedGuid_ && cachedTrack_ &&
|
||||
ValidatePtr2(project, cachedTrack_, "MediaTrack*"))
|
||||
return cachedTrack_;
|
||||
@@ -214,14 +217,19 @@ void fxReclaimTick(ReaSamplerSession& session, ReaProject* proj) {
|
||||
}
|
||||
|
||||
void fxReclaimFlushRelease(ReaSamplerSession& session) {
|
||||
// The save hook is handed no project, so the active one is the only candidate; a
|
||||
// mismatch means the release belongs to a tab this save is not writing, and skipping
|
||||
// leaves the arm standing for that tab's own save.
|
||||
if (!g_releaseFlush.pendingFor(EnumProjects(-1, nullptr, 0))) return;
|
||||
// GetCurrentProjectInLoadSave() names the project THIS hook is being asked to save
|
||||
// (reaper_plugin_functions.h:1582-1587) -- not merely the active tab, which a
|
||||
// Save-All or a background-project save can diverge from. EnumProjects(-1, ...) used
|
||||
// to stand in for it here and was wrong on both of those: it could skip the flush for
|
||||
// the project actually being written, or match the arm against the active tab while a
|
||||
// different project saved and write into that wrong project's ext state.
|
||||
ReaProject* saving = GetCurrentProjectInLoadSave();
|
||||
if (!g_releaseFlush.pendingFor(saving)) return;
|
||||
// Promptless, unlike design_view_actions' persistViewState, which can open a modal
|
||||
// Save-As. Disarm only on a write that was ISSUED — a never-saved project writes
|
||||
// nothing, and dropping the arm there would strand the spend for the whole session.
|
||||
if (session.flushViewState()) g_releaseFlush.clear();
|
||||
// Save-As. [verify — DAW] whether this write reaches the <EXTSTATE> block of the
|
||||
// file being saved right now, or lands one save late (see ReleaseFlush) — either
|
||||
// way the arm is deliberately left standing rather than cleared on this one issue.
|
||||
session.flushViewState(saving);
|
||||
}
|
||||
|
||||
} // namespace reasampler
|
||||
|
||||
Reference in New Issue
Block a user