Cut core/wire and shell/persist comment bloat ~46% (comments only, zero code change)
This commit is contained in:
@@ -1,65 +1,25 @@
|
||||
// session.cpp — the ReaSamplerSession lifecycle half of the persist seam (Q-W5
|
||||
// split of the former persist.cpp; see session.h for the TU map): the poll-driven
|
||||
// identity-transition detection and the deferred undo/redo reload drain.
|
||||
// session.cpp — the ReaSamplerSession lifecycle half of the persist seam (see
|
||||
// session.h for the identity-transition design and the TU map).
|
||||
//
|
||||
// Compiled into the reaper_reasampler MODULE. Includes reaper_plugin_functions.h
|
||||
// Compiled into the reaper_reasampler module. Includes reaper_plugin_functions.h
|
||||
// WITHOUT REAPERAPI_IMPLEMENT — main.cpp is the one TU that defines the API
|
||||
// pointers; here they are extern (CLAUDE.md §contract).
|
||||
//
|
||||
// PROJECT-LOAD / SAVE-AS DETECTION (chosen mechanism):
|
||||
// Driven by REAPER's "timer" register (main.cpp). Each poll() reads the active
|
||||
// project (EnumProjects(-1)), its .rpp path, and the GUID we store in its ext
|
||||
// state. Identity is layered GUID-PRIMARY, with the ReaProject* pointer as the
|
||||
// secondary disambiguator (classifyProjectTransition owns the exact order):
|
||||
// * different stored GUID -> a different project of record -> LOAD its index;
|
||||
// NEVER relocate. Catches pointer RECYCLING (REAPER reuses a closed project's
|
||||
// address, so a reopened/new project can present the previous pointer with a
|
||||
// different GUID), new/unsaved<->saved, and switching between distinct saved
|
||||
// projects.
|
||||
// * SAME GUID, DIFFERENT object -> a forked sibling that copied our GUID via
|
||||
// Save-As -> LOAD its index; NEVER relocate; re-GUID it so the siblings
|
||||
// diverge going forward.
|
||||
// * SAME GUID, SAME object, .rpp path changed -> genuine Save-As to a new
|
||||
// location -> relocate the bank folder from the old dir to the new one, then
|
||||
// re-GUID.
|
||||
// Why GUID-primary (W12 fix): this layers the two prior designs. M4 (GUID-only)
|
||||
// broke Save-As forks — Save-As copies the whole .rpp incl. our stored GUID, so a
|
||||
// fork and its parent share a GUID on disk; switching between them read as a
|
||||
// Save-As and clobbered a bank. W10 (pointer-primary, GUID voided) broke pointer
|
||||
// RECYCLING — a reopened/new project reusing the previous project's address read
|
||||
// as NoOp/SaveAsRelocate and the bank never reloaded. Checking the GUID first
|
||||
// catches recycling; the pointer then separates a fork (same GUID, different
|
||||
// object -> Load) from a Save-As (same GUID, same object, new path -> relocate).
|
||||
// classifyProjectTransition (pure, capture_paths) takes a `sameProjectObject`
|
||||
// bool (poll() computes `proj == lastProject_`) so the decision stays REAPER-free
|
||||
// and testable; poll() executes the verdict.
|
||||
// classifyProjectTransition (pure, capture_paths) takes a `sameProjectObject`
|
||||
// bool so the decision stays REAPER-free and testable; poll() executes the
|
||||
// verdict. REAPER exposes no stable per-project GUID, so we mint one (genGuid/
|
||||
// guidToString) under kProjExtGuidKey; Save-As copies the whole .rpp including
|
||||
// our ext state, so the new project initially shares the old GUID, and poll()
|
||||
// re-GUIDs it after relocating (or on the forked-sibling Load branch).
|
||||
//
|
||||
// REAPER exposes no stable per-project GUID (GetSetProjectInfo_String has no
|
||||
// PROJECT_GUID desc; GetProjectStateChangeCount is a session-local counter, not
|
||||
// a cross-open identity), so we MINT one with genGuid/guidToString and store it
|
||||
// under kProjExtGuidKey (ext_state_io.cpp owns the minting helpers). On Save-As
|
||||
// REAPER copies the whole .rpp incl. our ext state, so the new project initially
|
||||
// shares the old GUID; poll() re-GUIDs it (after relocating, or on the forked-
|
||||
// sibling Load branch) so identities diverge.
|
||||
//
|
||||
// Rationale for the timer: the brief mandates ext-state storage (rules out the
|
||||
// projectconfig .rpp-line hook for STORAGE), and the timer composes cleanly with
|
||||
// ext-state while covering identity-transition load + Save-As detection in one
|
||||
// place.
|
||||
//
|
||||
// DIVISION OF LABOUR (R-B undo):
|
||||
// * Identity-transition poll (this file, classifyProjectTransition) owns
|
||||
// open / tab-switch / new / forked-sibling / Save-As-relocation — every case
|
||||
// where the project OF RECORD changes.
|
||||
// * The `projectconfig` hook (main.cpp registers project_config_extension_t;
|
||||
// BeginLoadProjectState with isUndo) owns UNDO/REDO — where the project
|
||||
// identity is unchanged but its ext state rolled back/forward on disk. The
|
||||
// identity poll sees NoOp there and would never re-read ext state, so the hook
|
||||
// requests a reload (requestReload) that poll() drains on the next tick, once
|
||||
// REAPER has restored the <EXTSTATE> block. See requestReload / the poll drain.
|
||||
// The hook fires on undo AND redo (isUndo true for both), and on normal open
|
||||
// (isUndo false) — but we set the reload flag ONLY for isUndo, so a normal open
|
||||
// flows solely through the identity-transition Load path and never double-loads.
|
||||
// Division of labour for undo/redo: the identity-transition poll (this file)
|
||||
// owns open/tab-switch/new/forked-sibling/Save-As. The `projectconfig` hook
|
||||
// (main.cpp, BeginLoadProjectState with isUndo) owns undo/redo, where identity
|
||||
// is unchanged but ext state rolled back/forward on disk — the identity poll
|
||||
// would see NoOp there, so the hook requests a reload that poll() drains next
|
||||
// tick, once REAPER has restored the <EXTSTATE> block. The hook fires on
|
||||
// undo, redo, AND normal open, but the reload flag is set only for isUndo, so
|
||||
// a normal open never double-loads.
|
||||
|
||||
#include "shell/persist/session.h"
|
||||
|
||||
@@ -91,9 +51,8 @@ bool ReaSamplerSession::consumeLoadSignal() {
|
||||
}
|
||||
|
||||
void ReaSamplerSession::requestReload() {
|
||||
// Set-only; poll() drains it on the next tick (see the poll() drain block for why
|
||||
// the read is deferred past the projectconfig callback). Cheap and idempotent —
|
||||
// multiple undo/redo callbacks before the next tick collapse to one reload.
|
||||
// Set-only; poll() drains it next tick. Idempotent — multiple undo/redo
|
||||
// callbacks before the next tick collapse to one reload.
|
||||
reloadRequested_ = true;
|
||||
}
|
||||
|
||||
@@ -116,19 +75,13 @@ void ReaSamplerSession::poll() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Undo/redo reload (owner: the projectconfig hook, NOT the identity classifier
|
||||
// below). An undo/redo keeps the SAME project identity — same ReaProject*, GUID,
|
||||
// and .rpp path — so classifyProjectTransition would return NoOp and never re-read
|
||||
// ext state, leaving book_/view_ stale after the on-disk ext state rolled back.
|
||||
// The projectconfig BeginLoadProjectState callback (isUndo) raised reloadRequested_
|
||||
// one or more ticks ago; by NOW REAPER has finished restoring the project's
|
||||
// <EXTSTATE> block, so GetProjExtState returns the POST-undo value. Reload from the
|
||||
// current active project and identity-adopt it (no relocation — the path is
|
||||
// unchanged), then return. loadFromProject raises loadPending_, so the existing
|
||||
// consumeLoadSignal() glue re-baselines the panel detector and reapplies the active
|
||||
// mode; bankPanelRefresh's fingerprint pass then repaints the restored book. This is
|
||||
// the ONLY undo/redo reload path — the timer never polls ext-state CONTENT to detect
|
||||
// an undo (Daniel's directive: the hook drives it, not a poll heuristic).
|
||||
// Undo/redo reload, owned by the projectconfig hook, not the identity
|
||||
// classifier below: an undo/redo keeps the same project identity, so
|
||||
// classifyProjectTransition would return NoOp and never re-read ext
|
||||
// state. By now REAPER has finished restoring the <EXTSTATE> block, so
|
||||
// GetProjExtState returns the post-undo value. Reload and identity-adopt
|
||||
// (no relocation — path unchanged). This is the ONLY undo/redo reload
|
||||
// path — the timer never polls ext-state content to detect an undo.
|
||||
if (reloadRequested_) {
|
||||
reloadRequested_ = false;
|
||||
loadFromProject(proj, projectDirOf(rppPath));
|
||||
@@ -150,20 +103,14 @@ void ReaSamplerSession::poll() {
|
||||
return;
|
||||
|
||||
case capture::ProjectTransition::Load: {
|
||||
// A different project of record is active (open / tab switch / new /
|
||||
// reopened / recycled pointer / forked sibling). Load ITS index; never
|
||||
// relocate.
|
||||
// A different project of record is active. Load its index; never relocate.
|
||||
//
|
||||
// Forked-sibling divergence: gate on `!sameProjectObject` so this fires
|
||||
// ONLY for a step-2 Load (same GUID, different object) — a Save-As fork
|
||||
// that copied our GUID and never re-saved (its fresh GUID was runtime-
|
||||
// only on the sibling we came from). A recycled-pointer Load (step 1:
|
||||
// currentGuid != lastGuid_) must NOT re-GUID — it is already a distinct
|
||||
// identity. currentGuid == lastGuid_ can only hold here when step 1 did
|
||||
// NOT fire, i.e. this is the fork case; the explicit !sameProjectObject
|
||||
// makes that intent load-bearing rather than incidental. Do this BEFORE
|
||||
// loadFromProject reads the index (order is irrelevant — GUID and
|
||||
// bank_index are distinct keys — but self-contained is clearest).
|
||||
// Forked-sibling re-GUID: gate on `!sameProjectObject` so this fires
|
||||
// only for the fork case (same GUID, different object) — a Save-As
|
||||
// fork that copied our GUID and never re-saved. A recycled-pointer
|
||||
// Load (currentGuid != lastGuid_) must NOT re-GUID — it is already
|
||||
// a distinct identity; currentGuid == lastGuid_ can only hold here
|
||||
// when that case did not fire.
|
||||
if (proj && !sameProjectObject && !currentGuid.empty() &&
|
||||
currentGuid == lastGuid_ && !rppPath.empty()) {
|
||||
const std::string fresh = genProjectGuidString();
|
||||
@@ -186,12 +133,10 @@ void ReaSamplerSession::poll() {
|
||||
}
|
||||
|
||||
case capture::ProjectTransition::SaveAsRelocate: {
|
||||
// SAME project object + new .rpp path: a genuine Save-As (the pointer
|
||||
// proves it — a fork tab-switch is a DIFFERENT object and took the Load
|
||||
// branch above). Relocate the bank folder from the old dir to the new
|
||||
// one so the wavs sit under the new .rpp and the index's relative paths
|
||||
// still resolve. Keep the in-memory bank as-is (Save-As copied our ext
|
||||
// state, the relative paths are unchanged) — do NOT reload.
|
||||
// Same project object, new .rpp path: a genuine Save-As. Relocate
|
||||
// the bank folder so the wavs sit under the new .rpp and the
|
||||
// index's relative paths still resolve. Keep the in-memory bank
|
||||
// as-is (Save-As copied our ext state) — do NOT reload.
|
||||
const std::string oldDir = projectDirOf(lastRppPath_);
|
||||
const std::string newDir = projectDirOf(rppPath);
|
||||
const capture::BankRelocation plan =
|
||||
@@ -200,11 +145,9 @@ void ReaSamplerSession::poll() {
|
||||
relocateBankFolder(plan.oldBankDir, plan.newBankDir);
|
||||
}
|
||||
|
||||
// Save-As duplicated our ext state, so the new project B currently
|
||||
// shares A's GUID. Mint a FRESH GUID for B and write it, so A and B
|
||||
// no longer collide on identity when reopened later. Adopt the fresh
|
||||
// GUID as our last-seen identity. Mark dirty so the fresh GUID flushes
|
||||
// to the new .rpp on the next normal save / close-prompt.
|
||||
// Save-As duplicated our ext state, so the new project shares the
|
||||
// old GUID; mint a fresh one and mark dirty so it flushes on the
|
||||
// next save, and A/B no longer collide on identity when reopened.
|
||||
const std::string fresh = genProjectGuidString();
|
||||
if (proj) {
|
||||
SetProjExtState(static_cast<ReaProject*>(proj), projExtNamespace(),
|
||||
|
||||
Reference in New Issue
Block a user