Ξ-W2-T1 remediation: print master gain into the bake, derive the window from the dialed sound, reset play mode to Trigger
This commit is contained in:
@@ -18,26 +18,35 @@ decision about what the render made obsolete.
|
||||
can neither be observed nor disturbed by a bake, and a repeated bake of one dialed sound
|
||||
is byte-identical because nothing outside the passed value can vary between runs.
|
||||
- **The window bounds the render; the envelope does not.** Termination is structural — the
|
||||
loop runs to `BakePlan::totalFrames` and stops. That is why a Gate bake with a sustain
|
||||
loop runs to `BakePlan::renderFrames()` and stops. That is why a Gate bake with a sustain
|
||||
loop active terminates: the gate is released at `noteOffFrame` so the tail is real, but
|
||||
even a pathological envelope cannot run past the window.
|
||||
- **The block size is fixed here, not taken from the host.** A block boundary is where the
|
||||
engine re-observes state, so pinning it is part of what makes two bakes on two hosts
|
||||
produce the same bytes.
|
||||
- **A degenerate window is refused, not rendered.** `planBake` returns nullopt for a
|
||||
collapsed window, a non-positive rate, or a window that rounds to no frames.
|
||||
- **The whole signal chain is printed, master gain included.** `renderBake` scales its
|
||||
output by the dialed post-mixer gain, because `resetAfterBake` hands that control back at
|
||||
unity. A render that summed voices alone would return every iteration shifted by 1/gain,
|
||||
and a gain dialed to silence would come back at full level.
|
||||
- **A degenerate or unholdable window is refused, not rendered.** `planBake` returns nullopt
|
||||
for a collapsed window, a non-positive rate, a window that rounds to no frames, and one
|
||||
past `kMaxBakeFrames` — an unbounded window is a `bad_alloc` inside a UI tick, and the
|
||||
seconds→frames narrowing is undefined long before the allocation would fail.
|
||||
- **The reset's survive list is written out; everything else defaults.** `resetAfterBake`
|
||||
starts from a default-constructed parameter set and copies back only the mapping facts.
|
||||
A parameter added later therefore resets by default — the safe direction, since
|
||||
under-resetting applies the same processing twice while over-resetting costs a re-dial.
|
||||
A new mapping fact must be added to the copy list explicitly.
|
||||
- **Play mode resets to TRIGGER, not to the value struct's Gate default** — the one
|
||||
classification this track made against the ratified rule rather than reading off it. The
|
||||
bake's product is a finished one-shot, and Trigger is the mode that plays a finished
|
||||
one-shot verbatim; Gate would re-gate the printed release tail and each iteration would
|
||||
truncate the previous one's. "Neutral" here means "adds no processing", not "the struct's
|
||||
own default". `bake_reset.cpp` carries the argument at the assignment.
|
||||
|
||||
## Modules
|
||||
|
||||
- `bake_plan` — `defaultBakeProgram` (the program a bake uses until the capture-signal
|
||||
popup ships; its release tail exists so the bake is not truncated at note-off),
|
||||
`BakePlan` (the frame window plus its two event frames), and `planBake`, the one
|
||||
`ResolvedNote` + rate -> frames resolution.
|
||||
- `bake_plan` — `defaultBakeProgram` (the program a bake uses until the capture-signal popup
|
||||
ships; its end offset is DERIVED from the dialed sound, never constant), `BakePlan` (the
|
||||
render window, the captured slice of it, and the two event frames), `kMaxBakeFrames`, and
|
||||
`planBake`, the one `ResolvedNote` + rate -> frames resolution.
|
||||
- `bake_render` — `BakeAudio` and `renderBake`: the programmed note through the sample's
|
||||
own voice path, summed into an interleaved buffer at the source's own channel count.
|
||||
- `bake_reset` — `BakeReset` and `resetAfterBake`: the ratified reset scope, answered for
|
||||
@@ -45,7 +54,13 @@ decision about what the render made obsolete.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Frame 0 of the render is the start of the CAPTURED FILE, not note-on. A capture that
|
||||
opens before the note has `noteOnFrame > 0` and silence ahead of it.
|
||||
- **`BakePlan` speaks two frame domains** — the captured file's and the render's, which are
|
||||
offset from each other whenever the note and the capture window do not start together.
|
||||
`bake_plan.h` says which field is in which; do not read them as one clock.
|
||||
- **`defaultBakeProgram`'s Trigger window bounds the Varispeed read stretch, it does not
|
||||
model it.** A downward pitch offset makes the read head take longer to cross the play
|
||||
span, so the window is scaled by the deepest downward offset the voice can reach — an
|
||||
upper bound, so a shallower excursion leaves trailing silence in the file. The
|
||||
capture-signal popup is where a user sets the window exactly.
|
||||
- The render's channel count is the loaded `SampleData`'s, which is already the instance's
|
||||
channel-mode decision — a mono-mode instance bakes mono, and that is faithful, not a fold.
|
||||
|
||||
Reference in New Issue
Block a user