Docs: reconcile to two-scope capture model (master removed)

Update the CLAUDE.md FX-scope invariant to item+track only; note master
removal in COMPLETED.md; drop master references from the tail spec and PLAN
Milestone T; realtime now taps the selected track.
This commit is contained in:
2026-07-23 16:42:42 -04:00
parent 2ae4c420c5
commit 92762e2b6c
4 changed files with 15 additions and 16 deletions
+1 -1
View File
@@ -85,4 +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.
- **Capture FX scope:** two scopes only — item = item/take FX only; track = item FX + the selected track's own track FX. There is no master scope (to capture the master, render a track instead). For both scopes, the out-of-scope chain (ancestors + master track, plus the item's own track for item scope) has its FX, gain, and pan/width/pan-law/mode neutralized to unity — the master track is bypassed as out-of-scope chain, not captured as a scope. Range (time selection or razor) is orthogonal.
+2 -1
View File
@@ -281,5 +281,6 @@ auto-inserts into the arrange.
**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.
- **FX-scope semantics (initial rework):** 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.
- **Master scope subsequently removed:** capture is now **two scopes — item and track only**. `CAPTURE_MASTER` and `CAPTURE_MASTER_REALTIME` are retired (to capture the master, render a track instead). The master track is still neutralized as out-of-scope chain for both item and track captures; it is a bypass target, not a capture scope. The realtime backend taps the selected track (track scope only; item realtime deferred).
- **`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.
+6 -6
View File
@@ -142,12 +142,12 @@ then trims at the -72 dB decay point (± inherent realtime tolerance); realtime
frame, rewrite the file truncated (new I/O the backend does not do today).
## Milestone T open questions
- **Auto as the shipped-action default?** Whether `CAPTURE_ITEM`/`CAPTURE_TRACK`/
`CAPTURE_MASTER` (currently all TailMode::None) flip to Auto, gain a "…with tail"
variant, or take a modifier. Product call for Daniel; **leaning** paired variant /
toggle over silently changing the exact-bounds default. Not blocking T1 (the
request-level three-state contract is independent). (touches `render_settings.cpp`
action table + `actions`.)
- **Auto as the shipped-action default?** Whether `CAPTURE_ITEM`/`CAPTURE_TRACK`
(currently all TailMode::None) flip to Auto, gain a "…with tail" variant, or take
a modifier. Product call for Daniel; **leaning** paired variant / toggle over
silently changing the exact-bounds default. Not blocking T1 (the request-level
three-state contract is independent). (touches `render_settings.cpp` action table +
`actions`.)
---
+6 -8
View File
@@ -173,7 +173,7 @@ as configurable — noted below — not to let a single request uncap it.)
The request already has `renderTail: bool` + `tailMs: double`. The auto-trim mode
adds a third state, so the wiring is a small enum, not a bool:
- **None** (default for null-test / verify captures, and the current three-scope
- **None** (default for null-test / verify captures, and the current two-scope
action defaults): `RENDER_TAILFLAG = 0`, `RENDER_TAILMS = 0`, normalize =
disable-all. Exact bounds. Byte-identical to today.
- **Auto** (the new user-facing default for tail-on captures): tailFlag `1`,
@@ -194,8 +194,8 @@ applies the returned values.
## The realtime path (parallel, follow-on)
The M8 `RealtimeRecordBackend` (`src/capture_realtime.cpp`) does **not** drive
`RENDER_*` at all — it records the master send into a hidden temp track over a time
selection. So none of the offline tail machinery reaches it. It needs a **parallel**
`RENDER_*` at all — it taps the selected track's own output (post-fader, pre-parent)
into a hidden temp track over a time selection (track scope only). So none of the offline tail machinery reaches it. It needs a **parallel**
tail path, and it is explicitly a **follow-on to the offline tail** (offline lands
first; realtime tail is a later increment).
@@ -260,7 +260,7 @@ held to bit-identical repeats.
dry no-tail capture re-inserted at its source position must null against the
source; a tail would extend the file past the source region and break the null.
**The tail must be OFF for null-test and verification captures** — this is a hard
rule, not a default. (The three-scope capture *actions* may default to a tail once
rule, not a default. (The two capture *actions* may default to a tail once
this ships; the *verify* action never does.)
- **Determinism holds for offline.** The offline auto-trim path is deterministic:
fixed threshold + fixed cap + a boundary-only trim = two identical requests
@@ -270,8 +270,6 @@ held to bit-identical repeats.
The tail render still goes through `FxBypassGuard` for track/item scopes
(`render_settings.h §FxBypassPlan`, `CLAUDE.md §Capture FX scope`). This is
exactly what we want: the tail is the *in-scope FX decay*.
- **Master scope:** whole chain in scope → the tail is the full master-chain
reverb/release decay. Correct.
- **Track scope:** the track's own FX are in scope, ancestors/master bypassed →
the tail is **the track's own reverb/delay decay**, not the parent bus's. A track
with a reverb plugin captures that reverb's tail; a track feeding a folder reverb
@@ -386,8 +384,8 @@ Neither is in scope now; both are single-constant seams so promotion is cheap.
trailing edge, and the tail is appended after `ENDPOS`. But a range that itself
ends in near-silence before a loud transient is the edge case to check the trim
doesn't over-eat.)
- **Auto as the action default?** Should the three shipped capture actions
(`CAPTURE_ITEM` / `CAPTURE_TRACK` / `CAPTURE_MASTER`, currently all TailMode::None
- **Auto as the action default?** Should the two shipped capture actions
(`CAPTURE_ITEM` / `CAPTURE_TRACK`, currently all TailMode::None
per `render_settings.cpp §captureActionTable`) flip to Auto tail by default once
this ships, or should tail be a separate action variant / a modifier? Product call
for Daniel. **Leaning:** a per-action-family toggle or a paired "…​with tail"