docs: record the bake-prints-limiter track and close Phase Gamma
This commit is contained in:
@@ -1249,6 +1249,51 @@ limiter. Until that lands this is a recorded, known limitation, not an oversight
|
|||||||
|
|
||||||
**Neither track has been verified in a running DAW; both are asserted in CTest only.**
|
**Neither track has been verified in a running DAW; both are asserted in CTest only.**
|
||||||
|
|
||||||
|
### Γ-W3-T3 — bake-prints-limiter
|
||||||
|
|
||||||
|
The bake's master stage now prints the limiter as well as the gain multiply, closing the
|
||||||
|
audible gap Γ-W3-T2 recorded and left open: a capture baked with the limiter engaged
|
||||||
|
returns limited audio rather than unlimited audio. `renderBake`
|
||||||
|
(`core/instrument/bake/bake_render.cpp`) instantiates its own `Limiter` — the same
|
||||||
|
bake-only-engine precedent its `VoiceEngine` already set — never linked into
|
||||||
|
`reaper_reasampler`; `src/app/CMakeLists.txt`'s exclusion comment names the limiter
|
||||||
|
alongside `sampler_core`/`pitch_shift`/the filter, so the extension's link graph gains no
|
||||||
|
new edge.
|
||||||
|
|
||||||
|
**The lookahead needed compensation, which was open at spec time.** The limiter delays its
|
||||||
|
output by `kLimiterLookaheadSeconds` (0.002 s = 96 samples at 48 kHz), so the render's
|
||||||
|
buffers carry `renderFrames() + flushFrames` frames, the extra span fed silence rather than
|
||||||
|
more rendered audio, and the capture is read out starting at `leadInFrames + flushFrames`
|
||||||
|
instead of `leadInFrames` alone — the file is the same frames it would be bypassed, not the
|
||||||
|
same capture shifted 2 ms late.
|
||||||
|
|
||||||
|
**A sequencing trap, recorded inline at the call site.** `Limiter::prepare()` ends by
|
||||||
|
calling `reset()`, which snaps to whatever the enable target already is, so the render calls
|
||||||
|
`setEnabled(true)` before `prepare()`. Reversed, the limiter would take its live-engage path
|
||||||
|
instead — `process()`'s prime-then-fade — muting and then fading in the first ~12 ms of
|
||||||
|
every capture (the delay-line prime plus `kLimiterMuteSeconds`, per `limiter.h`).
|
||||||
|
|
||||||
|
**The bypassed path is unchanged.** `test_bake_render.cpp` asserts bypass ≡ engaged
|
||||||
|
bit-for-bit under the ceiling (a ramp fixture at unity gain, verified against the source
|
||||||
|
sample for sample too) and separately confirms the printed-limiter path holds the ceiling
|
||||||
|
and stays stereo-linked under a DC fixture driven well past it; repeat bakes stay
|
||||||
|
bit-identical with the limiter engaged as well, since `renderBake` builds a fresh `Limiter`
|
||||||
|
per call and `prepare()` zeroes every one of its state fields.
|
||||||
|
|
||||||
|
**Double-limiting is a named boundary, not a defect** (`bake/CLAUDE.md`): a printed capture
|
||||||
|
replayed through an engaged limiter is limited twice. The post-bake reset ordinarily
|
||||||
|
prevents it, since `limiterEnabled` is not on the survive list.
|
||||||
|
|
||||||
|
**`bake/CLAUDE.md`'s invariant is corrected alongside the code.** The text Γ-W3-T2 left in
|
||||||
|
place ("the limiter is not printed") is replaced with "the whole chain is printed — voice,
|
||||||
|
master gain, then the limiter, in the processor's own order," and the track's three
|
||||||
|
`[propose at review]` open questions are answered inline in the same section: the bake
|
||||||
|
instantiates its own `Limiter`; the lookahead does need in-render compensation, exactly the
|
||||||
|
above; and yes, this track also corrects the invariant text rather than leaving it to a
|
||||||
|
later pass.
|
||||||
|
|
||||||
|
**Not verified in a running DAW — CTest-asserted only.**
|
||||||
|
|
||||||
### Γ-W4-T1 — vst3-parameter-set
|
### Γ-W4-T1 — vst3-parameter-set
|
||||||
|
|
||||||
The instrument now reports its automatable parameters to the host: 44 of 44 issue, under a
|
The instrument now reports its automatable parameters to the host: 44 of 44 issue, under a
|
||||||
|
|||||||
+19
-48
@@ -597,6 +597,9 @@ system's is in **`docs/product/parameter-automation.md` §§6–10**. Read §1.2
|
|||||||
table) and §7 (collisions) before dispatching any track here — every number in this phase is
|
table) and §7 (collisions) before dispatching any track here — every number in this phase is
|
||||||
derived there, and `docs/TODO.md`'s old deck-rework geometry is superseded.
|
derived there, and `docs/TODO.md`'s old deck-rework geometry is superseded.
|
||||||
|
|
||||||
|
**All four waves have landed — Phase Γ is complete.** W1 through W4 each carry their own
|
||||||
|
landed note below; see `docs/COMPLETED.md` for every track's full narrative.
|
||||||
|
|
||||||
**Fork state — SEVEN ruled, ONE OF THEM LATER REVERSED, NONE OPEN.** Indexed at spec §8,
|
**Fork state — SEVEN ruled, ONE OF THEM LATER REVERSED, NONE OPEN.** Indexed at spec §8,
|
||||||
folded into the tracks below:
|
folded into the tracks below:
|
||||||
- **Γ-F1** — `kEditorMinHeight` stays **680**.
|
- **Γ-F1** — `kEditorMinHeight` stays **680**.
|
||||||
@@ -1013,9 +1016,9 @@ than re-derived. **T2 depended on Phase Ξ** — `Ξ-W2-T1 (resample-bake-chain)
|
|||||||
first, the phase's only external gate — see `docs/COMPLETED.md` for the full narrative of each
|
first, the phase's only external gate — see `docs/COMPLETED.md` for the full narrative of each
|
||||||
landed track.
|
landed track.
|
||||||
|
|
||||||
**Two tracks have landed** — Γ-W3-T1 (`deck-reflow`) and Γ-W3-T2 (`bake-reset-amendment`) — see
|
**All three tracks have landed** — Γ-W3-T1 (`deck-reflow`), Γ-W3-T2
|
||||||
`docs/COMPLETED.md` for the full narrative of each. **A third track is now open and has not
|
(`bake-reset-amendment`), and Γ-W3-T3 (`bake-prints-limiter`) — see `docs/COMPLETED.md` for
|
||||||
run:** Γ-W3-T3 (`bake-prints-limiter`), added below on Daniel's ruling of 2026-08-02.
|
the full narrative of each.
|
||||||
|
|
||||||
**None of the three tracks takes a payload rung.** T1 was layout only; T2 changed a reset list,
|
**None of the three tracks takes a payload rung.** T1 was layout only; T2 changed a reset list,
|
||||||
not a format; T3 changes what the render's audio contains, not what is stored.
|
not a format; T3 changes what the render's audio contains, not what is stored.
|
||||||
@@ -1066,56 +1069,24 @@ field-by-field assertions over two independently-dialled fixtures, never struct
|
|||||||
mutation-verified spot-check sweep confirming both fixtures actually moved every asserted field
|
mutation-verified spot-check sweep confirming both fixtures actually moved every asserted field
|
||||||
off its default.
|
off its default.
|
||||||
|
|
||||||
**One invariant correction:** `bake/CLAUDE.md` had claimed the whole signal chain prints, master
|
**One invariant correction, at the time this track landed:** `bake/CLAUDE.md` had claimed the
|
||||||
gain included. It doesn't — the render's gain multiply is the only master-stage value it
|
whole signal chain prints, master gain included. It didn't yet — the render's gain multiply was
|
||||||
prints; the limiter runs in the processor's block, off the bake path entirely.
|
the only master-stage value it printed; the limiter ran in the processor's block, off the bake
|
||||||
|
path entirely, so a capture baked with the limiter engaged came back unlimited. **Γ-W3-T3
|
||||||
**Outstanding, not closed by this track.** A capture baked with the limiter engaged comes back
|
(below) has since closed that gap** — the limiter is printed too now, and `bake/CLAUDE.md`'s
|
||||||
unlimited — a real audible gap, and Daniel has ruled that a future track will change the bake to
|
invariant text is corrected again to match.
|
||||||
print the limiter. **That track is now Γ-W3-T3, below.**
|
|
||||||
|
|
||||||
**Neither track has been verified in a running DAW; both are asserted in CTest only.**
|
**Neither track has been verified in a running DAW; both are asserted in CTest only.**
|
||||||
|
|
||||||
#### Γ-W3-T3 — `bake-prints-limiter`
|
#### Γ-W3-T3 — `bake-prints-limiter`
|
||||||
|
|
||||||
**Not started. Opened by Daniel's ruling, 2026-08-02.**
|
**Landed** — see `docs/COMPLETED.md` for the full narrative. The bake's master stage now
|
||||||
|
prints the limiter as well as the gain multiply: `renderBake` instantiates its own `Limiter`
|
||||||
**Goal.** Print the limiter through the bake's master stage, so a capture baked with the
|
(the bake-only-engine precedent, never linked into `reaper_reasampler`), the lookahead is
|
||||||
limiter engaged returns limited audio rather than unlimited audio.
|
compensated inside the render (an extra `flushFrames` of silence past the window, the capture
|
||||||
|
read out at `leadInFrames + flushFrames`), and `bake/CLAUDE.md`'s invariant text is corrected
|
||||||
**Why this exists.** Γ-W3-T2's own finding disproved the premise
|
alongside the code. All three of the track's `[propose at review]` open questions are
|
||||||
`docs/product/instrument-control-surface.md` §3.4's reset classification rested on:
|
answered in that entry.
|
||||||
`renderBake` (`core/instrument/bake/bake_render.cpp`) prints only a flat master-gain multiply,
|
|
||||||
and the limiter (`core/instrument/engine/limiter`) runs in the processor's `process()` block,
|
|
||||||
off the bake path entirely. Until this track lands, this is a recorded, known limitation — see
|
|
||||||
`docs/COMPLETED.md`'s Γ-W3-T2 entry — not an oversight.
|
|
||||||
|
|
||||||
**Consolidates:** nothing from the seventeen. A correction, on the same footing as Γ-W3-T2 (see
|
|
||||||
"Work in this plan that is not one of the seventeen").
|
|
||||||
|
|
||||||
**Spec:** none yet written. This ruling postdates §3.4 and has no product-doc section of its
|
|
||||||
own; §3.4 is superseded on this one point, which a future scoping pass of this track should
|
|
||||||
correct there as well as here.
|
|
||||||
|
|
||||||
**Surface boundary — likely, not yet confirmed against a full scoping pass:** owns
|
|
||||||
`core/instrument/bake/bake_render` (the gain-multiply step, extended to also run the signal
|
|
||||||
through a limiter), consuming `core/instrument/engine/limiter` — not owned, not modified. Does
|
|
||||||
not own the processor's live block, the limiter DSP itself, the parameter surface, or
|
|
||||||
`bake_reset` (the limiter-enable reset classification is already Γ-W3-T2's, landed).
|
|
||||||
|
|
||||||
**Open questions — none of this is ruled yet, only the goal is:**
|
|
||||||
- **[propose at review]** Whether the bake instantiates its own `Limiter` — mirroring
|
|
||||||
`renderBake`'s existing bake-only `VoiceEngine`, off the audio thread, never linked into
|
|
||||||
`reaper_reasampler` — or reaches the limiter's settled behavior some other way. The
|
|
||||||
bake-only-engine precedent (`bake/CLAUDE.md`) argues for the former.
|
|
||||||
- **[propose at review]** Whether the limiter's lookahead needs any accommodation in an
|
|
||||||
offline, non-realtime render — the processor's `getLatencySamples()` PDC report exists for
|
|
||||||
the live block, and a bake is not on that clock, so this may be a non-issue; it has not been
|
|
||||||
checked.
|
|
||||||
- **[propose at review]** Whether this track also corrects `bake/CLAUDE.md`'s invariant text
|
|
||||||
("the limiter is not [printed]") alongside the code, once scoped in full.
|
|
||||||
- **No [Daniel] question on the goal itself** — the ruling above is the goal; what is open is
|
|
||||||
the mechanism, not whether to do it.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user