Add temporary undo-span tracing for the mid-drain Ctrl-Z bug
One switch (REASAMPLER_UNDO_TRACE) gates every line. Traces span open/close reasons, FX writes, UndoBlock depth, timer standoffs, and load-state hooks.
This commit is contained in:
+29
-5
@@ -38,6 +38,7 @@
|
||||
#include "shell/panel/panel_input.h" // bankPanelRefresh / bankPanelNotifyProjectLoaded
|
||||
#include "shell/panel/panel_window.h" // panel lifecycle (init/toggle/open-query/shutdown)
|
||||
#include "shell/persist/session.h" // ReaSamplerSession
|
||||
#include "shell/undo/undo_trace.h" // TEMPORARY — see undo_trace.h; revert together
|
||||
#include "shell/view/fx_reclaim.h" // the FX reclaimer's tick
|
||||
#include "shell/view/view.h" // applyMode
|
||||
#include "shell/view/view_lanes.h" // reconcileManagedLanes
|
||||
@@ -183,6 +184,12 @@ static void OnTimer()
|
||||
// the idle fast-path is a SINGLE POINTER TEST — drive only when a capture is live.
|
||||
if (capture::g_rtCapture) capture::DriveRealtimeCapture(g_session);
|
||||
|
||||
// TEMPORARY: captured in a local (rather than calling GetCurrentProjectInLoadSave()
|
||||
// twice) so the trace can report the value on every tick, standoff or not, with no
|
||||
// change to the call below. See undo_trace.h.
|
||||
ReaProject* const loadSaveProj = GetCurrentProjectInLoadSave();
|
||||
REASAMPLER_TRACE("[Timer] loadSaveProj=%p", (void*)loadSaveProj);
|
||||
|
||||
// A project load or save is IN FLIGHT, so this tick is running inside its own message
|
||||
// pump — a restore brings plugins online and a plugin load pumps. Everything below
|
||||
// would then act on a half-restored project: poll() reads the pre-load <EXTSTATE> that
|
||||
@@ -192,7 +199,10 @@ static void OnTimer()
|
||||
// the first tick after the load runs as if this one had never been due. Self-lowering
|
||||
// (reaper_plugin_functions.h:1584-1587), and placed after the realtime drive so that
|
||||
// fast path keeps its single-pointer-test shape. See src/shell/view/CLAUDE.md.
|
||||
if (GetCurrentProjectInLoadSave()) return;
|
||||
if (loadSaveProj) {
|
||||
REASAMPLER_TRACE("[Timer] STANDOFF guard=loadSaveProj");
|
||||
return;
|
||||
}
|
||||
|
||||
// poll()'s undo/redo-reload and project-switch Load branches call
|
||||
// loadFromProject, replacing g_session.view() wholesale — deferred here while
|
||||
@@ -202,8 +212,13 @@ static void OnTimer()
|
||||
// cheap to skip for one tick and resumes correctly, unlatched, on the next.
|
||||
// The reclaim drain is latched for the same reason and is the same window: it
|
||||
// holds that view model for the length of a plugin unload, which pumps.
|
||||
if (!reasampler::modeApplyInProgress() && !reasampler::fxReclaimDrainInProgress())
|
||||
if (!reasampler::modeApplyInProgress() && !reasampler::fxReclaimDrainInProgress()) {
|
||||
g_session.poll();
|
||||
} else {
|
||||
REASAMPLER_TRACE("[Timer] SKIP-POLL modeApply=%d drain=%d",
|
||||
reasampler::modeApplyInProgress() ? 1 : 0,
|
||||
reasampler::fxReclaimDrainInProgress() ? 1 : 0);
|
||||
}
|
||||
|
||||
// persist stays MODEL-ONLY (loads the saved view model but does not apply
|
||||
// visibility, to avoid coupling persist to the view shell); poll() raises a
|
||||
@@ -216,8 +231,15 @@ static void OnTimer()
|
||||
// signal is one-shot, a re-entered applyMode fails closed, and a reapply dropped here
|
||||
// is the saved mode never applied at all. Holding the whole block back one tick also
|
||||
// keeps the panel re-arm ahead of the reapply.
|
||||
if (!reasampler::modeApplyInProgress() && !reasampler::fxReclaimDrainInProgress() &&
|
||||
g_session.consumeLoadSignal()) {
|
||||
// TEMPORARY: split into locals + if/else-if so the skip can be traced without
|
||||
// calling consumeLoadSignal() (which has a side effect) a second time — same
|
||||
// short-circuit semantics as the original single `if`. See undo_trace.h.
|
||||
const bool loadGateModeApply = reasampler::modeApplyInProgress();
|
||||
const bool loadGateDraining = reasampler::fxReclaimDrainInProgress();
|
||||
if (loadGateModeApply || loadGateDraining) {
|
||||
REASAMPLER_TRACE("[Timer] SKIP-LOAD modeApply=%d drain=%d", loadGateModeApply ? 1 : 0,
|
||||
loadGateDraining ? 1 : 0);
|
||||
} else if (g_session.consumeLoadSignal()) {
|
||||
reasampler::bankPanelNotifyProjectLoaded();
|
||||
// Reconcile lane ownership against the live project's lanes (P_LANENAME,
|
||||
// the cross-session source of truth) BEFORE reapplying visibility. Never
|
||||
@@ -257,6 +279,8 @@ static void OnTimer()
|
||||
// forked-sibling re-GUID branch requesting a reload here would bypass.
|
||||
static void OnBeginLoadProjectState(bool isUndo, project_config_extension_t* /*reg*/)
|
||||
{
|
||||
REASAMPLER_TRACE("[Load] BeginLoadProjectState isUndo=%d", isUndo ? 1 : 0);
|
||||
|
||||
// UNBRANCHED, and the reason the terminator is a hook at all: this is REAPER's one
|
||||
// entry for a state load — "project load/undo", plus a new project
|
||||
// (reaper_plugin.h:1203-1205) — and the last moment before the restore. Why that
|
||||
@@ -343,7 +367,7 @@ extern "C" REAPER_PLUGIN_DLL_EXPORT int REAPER_PLUGIN_ENTRYPOINT(
|
||||
|
||||
// Same reason, for the reclaimer's undo span: a block left open here has no
|
||||
// owner left to close it and would swallow every edit the user makes after.
|
||||
reasampler::fxReclaimEndUndoSpan();
|
||||
reasampler::fxReclaimEndUndoSpan("extension unload");
|
||||
|
||||
g_rec->Register("-timer", (void*)&OnTimer);
|
||||
g_rec->Register("-projectconfig", (void*)&g_projectConfig);
|
||||
|
||||
Reference in New Issue
Block a user