From e1b2c0ba1ba93139a42a2587a6a3f1946594941f Mon Sep 17 00:00:00 2001 From: daniel-c-harvey Date: Thu, 23 Jul 2026 14:01:28 -0400 Subject: [PATCH] Docs: reflect three-scope FX capture rework; add FX-scope invariant + send-isolation TODO Note the M7 four-mode -> three-FX-scope rework in COMPLETED.md; add the capture FX-scope precision invariant to CLAUDE.md; record the send/routing isolation TODO (coloring sends bleed into item captures) in PLAN.md open questions. --- CLAUDE.md | 1 + COMPLETED.md | 5 +++++ PLAN.md | 1 + 3 files changed, 7 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 821032c..cf696a0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -85,3 +85,4 @@ There is no hot-reload. Copy the built binary into REAPER's `UserPlugins/` folde - **Non-destructive:** capture never mutates source items or tracks; the realtime backend's temp track is created and removed cleanly, and source routing is restored. - **Exact bounds:** no rounding of the requested range; no added silence unless a tail is explicitly requested; channel count preserved (no silent stereo fold). - **Relative paths only** in the persisted `BankIndex`. +- **Capture FX scope:** item capture = item/take FX only; track capture = item + the track's own FX; master = full chain. For item/track, the out-of-scope chain (ancestors + master, plus the item's own track for item scope) is rendered with its FX, gain, and pan/width/pan-law/mode neutralized to unity — so captures are uncolored by, and independent of, the parent/folder/master chain. Range (time selection or razor) is orthogonal. diff --git a/COMPLETED.md b/COMPLETED.md index e796d2f..ab81d53 100644 --- a/COMPLETED.md +++ b/COMPLETED.md @@ -278,3 +278,8 @@ auto-inserts into the arrange. - Four **wet** bindable capture actions — master mix, selected tracks, selected items, razor area — registered under the `CEREBELLUM_REASAMPLER_CAPTURE_*` command-id prefix. Each routes to `OfflineRenderBackend` (RENDER_* snapshot/restore, dither/normalize off, 32-bit float), produces a `Sample`, adds it to the bank, persists, and calls `MarkProjectDirty`. The M3 spike action was retired. - **Wet-only decision (Daniel):** REAPER offline render has no true pre-FX "dry" bit — the only wet/dry-adjacent lever (`&8192` pre-fader stems) is post-FX. Approximate-dry action variants were removed rather than ship a "dry" that isn't. `CaptureRequest.wetDry` is retained as the seam for true dry (M10). - Pure `render_settings` module maps source mode → RENDER_SETTINGS bits and parses `P_RAZOREDITS` (union of track-audio areas), unit-tested. No capture path inserts into the arrange (load-bearing gate); non-destructive (selection/razor read-only). + +**Superseded / reworked (post-landing):** +- The four wet source-mode actions (master/tracks/items/razor) were replaced by **three FX-scope actions** — `capture item`, `capture track`, `capture master` — with range (razor-else-time-selection) inferred orthogonally. This fixed the defect where item captures were rendered through the parent FX chain. +- **FX-scope semantics:** item = item/take FX only; track = item FX + the selected track's own track FX; master = full chain. For item/track, the out-of-scope chain (ancestors + master, plus the item's own track for item scope) is neutralized during the render. +- **`FxBypassGuard` (RAII):** snapshot → neutralize (FX bypassed via `I_FXEN`; gain zeroed via `D_VOL`; pan/width/pan-law/mode set to unity via `D_PAN`/`D_WIDTH`/`D_PANLAW`/`I_PANMODE`) → render → restore. Non-destructive. This guard is the reusable mechanism M8 (realtime backend) and M10 (null-test / true dry) build on. diff --git a/PLAN.md b/PLAN.md index d0ed36e..5234ed4 100644 --- a/PLAN.md +++ b/PLAN.md @@ -78,6 +78,7 @@ landed milestone. `int64_t → int` via `static_cast` without a range check; integers that fit in int64 but exceed `INT_MAX` are implementation-defined. Hardening candidate — add bounds check before the cast when integer-field validation is in scope. +- **Capture send/routing isolation (TODO):** The FX-scope capture neutralizes out-of-scope FX, gain, and pan — but NOT aux **sends**. So a downstream coloring send (e.g. a folder → reverb-track send) still routes and blends the reverb into an item/track capture, past the intended isolation point. A true item-level capture should be taken at the isolated graph point — the target scope's output before out-of-scope track FX/gain/pan **and** before out-of-scope aux/parallel sends. The hard part: distinguish **source routing that must be preserved** (e.g. a MIDI send T1→T2 where T2's synth is where a MIDI item's audio is actually produced — the "item level" for that MIDI item is T2's synth output) from **coloring sends that must be excluded** (folder→reverb). Repro: folder F1; T1 (MIDI) sends MIDI to T2 (synth); T1+T2 → F1; F1 sends to reverb T3; capturing the MIDI item on T1 currently includes the reverb, should be isolated to T2's synth output pre-F1 with the MIDI send preserved and the reverb send excluded. Likely approach: snapshot + mute out-of-scope tracks' aux sends during the render while preserving the main/source signal path — needs a rule for which sends are load-bearing. ---