docs: close Phase Ξ — the popup abandoned by ruling, the bake window derives itself, and Γ's rung ladder shifts to v15
This commit is contained in:
@@ -754,3 +754,62 @@ bank-format change under the current deserializer, which fails the whole bank bl
|
|||||||
an out-of-range value — it wants its own decision); and `instrument_bake` copies the
|
an out-of-range value — it wants its own decision); and `instrument_bake` copies the
|
||||||
interleaved render buffer into a `std::vector<double>` for the WAV build, roughly
|
interleaved render buffer into a `std::vector<double>` for the WAV build, roughly
|
||||||
doubling peak memory for a large bake.
|
doubling peak memory for a large bake.
|
||||||
|
|
||||||
|
### Ξ-W3-T1 — capture-signal-popup (spec abandoned by ruling; shipped as derived bake window)
|
||||||
|
|
||||||
|
Phase Ξ's final track, and Phase Ξ is now complete. What `docs/PLAN.md` specified was a
|
||||||
|
popup menu letting the user hand-program the capture signal: note length as a
|
||||||
|
musical-division picker (1/64 to 64/1, dotted and triplet), start/end offsets editable in
|
||||||
|
both ms and beats, velocity, and a preview trigger auditioning the programmed note, under
|
||||||
|
the acceptance criterion "preview and bake cannot diverge."
|
||||||
|
|
||||||
|
**What shipped instead, and why — the spec and the landed code diverge substantially and
|
||||||
|
deliberately, by Daniel's ruling, not by shortfall.** The popup was built (~1500 lines)
|
||||||
|
and then abandoned unmerged. Daniel, verbatim: *"I didn't realize you had already derived
|
||||||
|
a usable window. The manual stuff for baking a specific midi length was just an idea, if
|
||||||
|
we have a smarter, fewer-clicks way of doing it, that is ideal. I just don't want to lose
|
||||||
|
anything when we bake. We can abandon the whole parameterized bake window if we can safely
|
||||||
|
derive the window in gate and trigger modes."* An audit then established, with executable
|
||||||
|
tests (`tests/test_bake_window.cpp`), that the window derives losslessly everywhere except
|
||||||
|
one irreducible case. What actually shipped, in `src/core/instrument/bake/`:
|
||||||
|
|
||||||
|
- **The bake window derives itself.** Trigger derives from the play span; Gate *without*
|
||||||
|
an active sustain loop derives from source exhaustion + release; Gate *with* an active
|
||||||
|
loop takes one user value, because a loop sounds for as long as it is held and no
|
||||||
|
derivation can supply a duration.
|
||||||
|
- **One control: "Hold,"** a musical-division picker in the chrome row, visible and
|
||||||
|
settable only when Gate + an active sustain loop. `bakeWindowNeedsHold` is the predicate
|
||||||
|
and it reads the ENGINE's loop fold (`resolveLoop`) rather than the loop fields.
|
||||||
|
- **Velocity comes from the instance's persisted preview velocity**, not a hard-coded 100
|
||||||
|
— three velocity curves are live, so the velocity is a property of the sound being
|
||||||
|
printed.
|
||||||
|
- **No preview trigger, and no popup at all.** The chrome-row play button stays a pure
|
||||||
|
MIDI trigger; bake parameters are their own thing. Daniel's ruling: *"play button is
|
||||||
|
pure MIDI trigger, Bake parameters are their own thing."* So the plan's acceptance
|
||||||
|
criterion 2 ("preview and bake cannot diverge") and its preview-trigger behavior bullet
|
||||||
|
are **retired by ruling.**
|
||||||
|
- **Three truncation bugs that pre-existed on `dev` were found and fixed:** a drawn EG
|
||||||
|
plus a stale stored `%`-length lost up to the whole take; the Preserve pitch engine's
|
||||||
|
window closed on the exact frame the terminal declick ramp began, ending files on a
|
||||||
|
full-scale hard cut; and the Gate hold length quantized onto a musical ladder that
|
||||||
|
**saturated at 384 beats**, cutting any source past it mid-sound (at 120 BPM, anything
|
||||||
|
from 192 s up — a full-mix bounce).
|
||||||
|
- **An invariant was deliberately amended:** `note/CLAUDE.md`'s "note length stays
|
||||||
|
musical-division-only" is superseded — a note length now carries EITHER an exact
|
||||||
|
duration (every derived path) or a musical division (the Hold picker only).
|
||||||
|
Quantizing a derived length is what caused the saturation truncation.
|
||||||
|
- Two undefined-behaviour paths closed as fallout: a NaN `keyTrack` from a corrupt payload
|
||||||
|
reached a narrowing cast on the per-sample audio path, and a misaligned payload tail
|
||||||
|
could fabricate a value rather than degrade to absent.
|
||||||
|
- Payload rung **v14** consumed (the Hold division).
|
||||||
|
|
||||||
|
**Not verified in a live REAPER session** — worth carrying forward as owed: the "Bake
|
||||||
|
Hold" label fitting its 56 px cell, the Hold knob's duration-ordered travel, and the
|
||||||
|
control's appearance/disappearance on the 500 ms sync tick.
|
||||||
|
|
||||||
|
**Deferred, not done — logged to `docs/TODO.md`:** the loop intrinsic is folded twice
|
||||||
|
(the editor's `pickedMarkers` resolves it from the live bank blob first, the processor's
|
||||||
|
`reloadInstrument` resolves it from the instance ref via `resolveCapture`), so the two can
|
||||||
|
disagree whenever a bank blob's loop for a capture differs from the copy in the instance's
|
||||||
|
own refs table. Pre-existing — `bakeWindowNeedsHold` is only a new *consumer* of
|
||||||
|
`pickedMarkers`, not the origin of the divergence.
|
||||||
|
|||||||
+52
-72
@@ -71,15 +71,15 @@ in Γ-W4-T1 and changes no wave boundary.
|
|||||||
|
|
||||||
### Flagged for awareness — not blocking, but decision-grade
|
### Flagged for awareness — not blocking, but decision-grade
|
||||||
|
|
||||||
1. **Item 15 has an unresolved cross-artifact seam, and it is the phase's largest
|
1. **Item 15's cross-artifact seam is RESOLVED — this is no longer an unknown.** The
|
||||||
unknown.** The instrument is a read-only bank consumer by invariant
|
instrument is a read-only bank consumer by invariant (`src/shell/instrument/CLAUDE.md`),
|
||||||
(`src/shell/instrument/CLAUDE.md`), and the one previous attempt at an
|
and the one previous attempt at an instrument→extension relay (S13) closed with a
|
||||||
instrument→extension relay (S13) closed with a **DEGRADED** spike verdict and was
|
**DEGRADED** spike verdict and was deferred (`docs/TODO.md`). Resample required that
|
||||||
deferred (`docs/TODO.md`). Resample requires that crossing. Ξ-W2-T1 opens with the
|
crossing. Ξ-W2-T1 ratified Decision 1 = (1b): the editor invokes the extension's bake
|
||||||
architecture decision and this plan names the candidates rather than assuming the
|
action directly over the VST-host bridge (`NamedCommandLookup`/`Main_OnCommandEx`), no
|
||||||
deferred relay shape; see that track. Consequence to hold: if every candidate fails
|
poller, no nonce — dissolving the S13 DEGRADED verdict rather than re-litigating it. The
|
||||||
verification, item 15's "one click from inside the VST" framing is what gives, not
|
read-only bank invariant held: the crossing is a bridge call, not a shell-side bank
|
||||||
the read-only invariant — the fallback is a bindable extension-side action.
|
write. See `docs/COMPLETED.md` for the full narrative.
|
||||||
|
|
||||||
2. **The "Γ before Ξ-W2" ordering is VIOLATED, it was never Daniel's choice, and Γ now owns
|
2. **The "Γ before Ξ-W2" ordering is VIOLATED, it was never Daniel's choice, and Γ now owns
|
||||||
the correction.** Daniel, 2026-08-01: *"xi was started before I spun you up, we'll have to
|
the correction.** Daniel, 2026-08-01: *"xi was started before I spun you up, we'll have to
|
||||||
@@ -396,6 +396,9 @@ and the loop points by name. Baking a processing chain that does not exist yet i
|
|||||||
schedule preference; the feature is not expressible. Phase Θ landed as of Θ-W7-T1 (see
|
schedule preference; the feature is not expressible. Phase Θ landed as of Θ-W7-T1 (see
|
||||||
`docs/COMPLETED.md`); this gate is satisfied.
|
`docs/COMPLETED.md`); this gate is satisfied.
|
||||||
|
|
||||||
|
**All three waves have landed — Phase Ξ is complete.** W1 through W3 each carry their own
|
||||||
|
landed note below; see `docs/COMPLETED.md` for every track's full narrative.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Ξ-W1 — Consolidated tracking, and the programmed-note model
|
### Ξ-W1 — Consolidated tracking, and the programmed-note model
|
||||||
@@ -427,8 +430,12 @@ peer of `engine/`/`map/`/`ui/` under `core/instrument/` — holding `musical_div
|
|||||||
`StartOffset`/`EndOffset`, `NoteProgram`, `resolveNote`). **Both open questions below
|
`StartOffset`/`EndOffset`, `NoteProgram`, `resolveNote`). **Both open questions below
|
||||||
are answered, for Ξ-W3-T1:** negative offsets are legal in both directions (sign
|
are answered, for Ξ-W3-T1:** negative offsets are legal in both directions (sign
|
||||||
uniform, positive is later in time; only an inverted window is refused, reported via
|
uniform, positive is later in time; only an inverted window is refused, reported via
|
||||||
`ResolvedNote::windowCollapsed`), and the denomination seam is confirmed — note length
|
`ResolvedNote::windowCollapsed`), and the denomination seam is confirmed as of this
|
||||||
stays musical-division-only, and an offset stores the denomination it was entered in.
|
landing — note length stays musical-division-only, and an offset stores the denomination
|
||||||
|
it was entered in. **Superseded by Ξ-W3-T1's landed work** (see `docs/COMPLETED.md`):
|
||||||
|
`note/CLAUDE.md`'s musical-division-only rule is amended — a note length now carries
|
||||||
|
EITHER an exact derived duration or a musical division, not division-only. The offset
|
||||||
|
denomination rule is unaffected.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -470,63 +477,35 @@ Daniel's manual verification is still owed.
|
|||||||
|
|
||||||
### Ξ-W3 — The capture-signal popup
|
### Ξ-W3 — The capture-signal popup
|
||||||
|
|
||||||
**Depends on Ξ-W2 for:** the bake chain that the popup programs and its preview must not
|
**Depends on Ξ-W2 for:** the bake chain this track was originally scoped to build a
|
||||||
diverge from. The acceptance criterion "preview and bake cannot diverge" requires one
|
preview against, under the acceptance criterion "preview and bake cannot diverge." **That
|
||||||
render path, which W2 owns — building the preview against a second path is exactly the
|
motivation is retired, not satisfied** — see below.
|
||||||
defect the criterion exists to catch.
|
|
||||||
|
|
||||||
**One track.**
|
**One track.**
|
||||||
|
|
||||||
#### Ξ-W3-T1 — `capture-signal-popup`
|
**Ξ-W3-T1 has landed** — `capture-signal-popup` — see `docs/COMPLETED.md` for the full
|
||||||
|
narrative, and it diverges substantially and deliberately from this section's spec. The
|
||||||
**Goal.** Let the user program the capture signal — note length, offsets, velocity — and
|
popup this track was scoped to build (a musical-division note-length picker, ms/beat-
|
||||||
hear it before committing the bake.
|
editable offsets, velocity, and a preview trigger) was built (~1500 lines) and then
|
||||||
|
**abandoned unmerged** on Daniel's ruling: *"I didn't realize you had already derived a
|
||||||
**Consolidates item 15 (the popup sub-feature).**
|
usable window. The manual stuff for baking a specific midi length was just an idea, if we
|
||||||
|
have a smarter, fewer-clicks way of doing it, that is ideal. I just don't want to lose
|
||||||
**Surface boundary — owns:** `core/instrument/ui/curve_popup`'s sibling — a new pure popup
|
anything when we bake. We can abandon the whole parameterized bake window if we can
|
||||||
geometry module for the capture-signal sheet (mirror the `curve_popup` precedent: centered
|
safely derive the window in gate and trigger modes."* An audit, backed by executable
|
||||||
sheet, width/height clamps, title row, Close button rect, outside-sheet dismissal test) —
|
tests, established the window derives losslessly everywhere except Gate over an active
|
||||||
plus the editor's popup paint/input wiring in the deck or chrome band, and the preview
|
sustain loop, which has no intrinsic duration to derive. What shipped instead: the bake
|
||||||
trigger's call into W2's render path. Reads Ξ-W1-T2's note-program record; does not
|
window derives itself in Trigger and loop-less Gate; one control, a musical-division
|
||||||
re-own it.
|
**Hold** picker, covers the one irreducible case and is shown only for Gate-with-active-
|
||||||
|
loop (`bakeWindowNeedsHold`, reading the engine's own loop fold); bake velocity now reads
|
||||||
**Behavior.**
|
the instance's persisted preview velocity rather than a hard-coded value; and the
|
||||||
- **A popup menu programs the capture signal:** **note length**, **start and end offsets —
|
chrome-row play button stays a pure MIDI trigger — Daniel's ruling: *"play button is pure
|
||||||
in ms AND in beats** — and **velocity**.
|
MIDI trigger, Bake parameters are their own thing."* **This retires this section's
|
||||||
- **A preview trigger button** auditions the capture note exactly as currently programmed
|
acceptance criterion 2 ("preview and bake cannot diverge") and its preview-trigger
|
||||||
— the user hears the bake before committing it — and the offline pass renders that same
|
behavior bullet by ruling, not by shortfall** — there is no popup and no preview trigger.
|
||||||
programmed performance.
|
Three pre-existing truncation bugs were found and fixed along the way, and
|
||||||
- **Note length is a musical-division picker** spanning 1/64th to 64/1 with dotted and
|
`note/CLAUDE.md`'s musical-division-only invariant is amended (see Ξ-W1-T2 above): a note
|
||||||
triplet multipliers.
|
length now carries either an exact derived duration or a musical division, not
|
||||||
- **Offsets are anchored** — start to note-on, end to note-off — and each is readable and
|
division-only.
|
||||||
editable in **both** ms and beats, the two views of one stored value.
|
|
||||||
- **Beat-denominated values resolve against the project tempo under the cursor.** The
|
|
||||||
shell reads the tempo; the arithmetic is Ξ-W1-T2's.
|
|
||||||
- **The programmed velocity is the render velocity** — material because the velocity
|
|
||||||
transfer curves modulate amp, pitch, and filter at that velocity.
|
|
||||||
- House-consistent: drawn through the shared kit by palette role, geometry pure and
|
|
||||||
CTest-covered, no decorative animation.
|
|
||||||
|
|
||||||
**Acceptance criteria.**
|
|
||||||
- The popup exposes: note length as a musical-division picker spanning **1/64th to 64/1
|
|
||||||
with dotted and triplet multipliers**; start and end offsets, **each readable and
|
|
||||||
editable in both ms and beats**, anchored to note-on and note-off respectively; and
|
|
||||||
velocity.
|
|
||||||
- **Its preview trigger auditions the capture note exactly as programmed, and the bake
|
|
||||||
renders that same programmed performance — preview and bake cannot diverge.** Verify
|
|
||||||
structurally (one render path), not just by ear.
|
|
||||||
- **Beat-denominated values resolve against the project tempo under the cursor:** the same
|
|
||||||
programmed division yields a correspondingly different rendered duration when the tempo
|
|
||||||
at the cursor differs.
|
|
||||||
- The programmed signal persists with the instance and round-trips save/reload.
|
|
||||||
- The popup's geometry and dismissal test are pure and unit-tested; no hit-test math lands
|
|
||||||
in shell code.
|
|
||||||
|
|
||||||
**Open questions.** Both of Ξ-W1-T2's residuals (negative offsets; the note-length
|
|
||||||
denomination seam) surface here as UI consequences — if T2 answered them, this track
|
|
||||||
implements the answer; if T2 deferred either, this track is where it becomes visible and
|
|
||||||
must be closed.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -682,7 +661,7 @@ the automatable params reported."*
|
|||||||
**The params-payload ladder — re-checked, and now stated RELATIVELY.** The old block named
|
**The params-payload ladder — re-checked, and now stated RELATIVELY.** The old block named
|
||||||
v14 and v15 as absolutes. **That is no longer safe to assume**, because Ξ ran ahead of its
|
v14 and v15 as absolutes. **That is no longer safe to assume**, because Ξ ran ahead of its
|
||||||
sequencing and this plan is not the record of what Ξ-W2-T1 actually took. On `dev` today
|
sequencing and this plan is not the record of what Ξ-W2-T1 actually took. On `dev` today
|
||||||
`kParamsPayloadVersion` is **13** (`map/component_state_io.h:154`) and Ξ-W2-T1 was specced to
|
`kParamsPayloadVersion` is **14** (`map/component_state_io.h:163`) and Ξ-W2-T1 was specced to
|
||||||
take no rung — but the plan's prediction is not evidence. So:
|
take no rung — but the plan's prediction is not evidence. So:
|
||||||
|
|
||||||
> **Γ owns the next three rungs above whatever `dev` carries when Γ-W1-T2 dispatches, and
|
> **Γ owns the next three rungs above whatever `dev` carries when Γ-W1-T2 dispatches, and
|
||||||
@@ -692,9 +671,10 @@ take no rung — but the plan's prediction is not evidence. So:
|
|||||||
> which the specification says it will not (`docs/product/parameter-automation.md` §6.1,
|
> which the specification says it will not (`docs/product/parameter-automation.md` §6.1,
|
||||||
> §10). If unspent, that rung falls through to the next phase unclaimed.
|
> §10). If unspent, that rung falls through to the next phase unclaimed.
|
||||||
>
|
>
|
||||||
> **On `dev` as of 2026-08-01 that resolves to v14 / v15 / v16-reserved.** If Ξ-W2-T1 landed
|
> **On `dev` as of 2026-08-01 that resolves to v15 / v16 / v17-reserved.** Ξ-W3-T1 landed and
|
||||||
> a bump, every number shifts by one and **nothing else about the ownership changes** — which
|
> consumed a rung (v14, the bake Hold division) — not Ξ-W2-T1, which took none as specced — so
|
||||||
> is the whole point of stating it relatively.
|
> every number shifted by one and **nothing else about the ownership changes** — which is the
|
||||||
|
> whole point of stating it relatively.
|
||||||
|
|
||||||
**Every other track in the phase owns no rung**: W1-T1 changes no persisted field (the payload
|
**Every other track in the phase owns no rung**: W1-T1 changes no persisted field (the payload
|
||||||
stores raw engine doubles, so both the taper and the new ceiling are persistence-neutral),
|
stores raw engine doubles, so both the taper and the new ceiling are persistence-neutral),
|
||||||
@@ -2769,7 +2749,7 @@ The check that nothing was dropped. Every row points at a track that exists abov
|
|||||||
| 12 | Toolbar cleanup; full-width piano strip; tooltips | Θ-W2-T3 | `pth-w2-t3-toolbar-and-piano-strip` |
|
| 12 | Toolbar cleanup; full-width piano strip; tooltips | Θ-W2-T3 | `pth-w2-t3-toolbar-and-piano-strip` |
|
||||||
| 13 | Antialiased rendering audit for high-DPI | Θ-W6-T1 | `pth-w6-t1-legibility-and-antialiasing` |
|
| 13 | Antialiased rendering audit for high-DPI | Θ-W6-T1 | `pth-w6-t1-legibility-and-antialiasing` |
|
||||||
| 14 | Trigger amp/filter fade → AHD consolidation | Θ-W3-T2 | `pth-w3-t2-staged-envelope-curves` |
|
| 14 | Trigger amp/filter fade → AHD consolidation | Θ-W3-T2 | `pth-w3-t2-staged-envelope-curves` |
|
||||||
| 15 | One-click in-sampler resample | Ξ-W1-T2 (note model) **+** Ξ-W2-T1 (bake chain) **+** Ξ-W3-T1 (popup) | `pxi-w1-t2-note-program-model`, `pxi-w2-t1-resample-bake-chain`, `pxi-w3-t1-capture-signal-popup` |
|
| 15 | One-click in-sampler resample | Ξ-W1-T2 (note model) **+** Ξ-W2-T1 (bake chain) **+** Ξ-W3-T1 (popup abandoned by ruling; window derives itself) | `pxi-w1-t2-note-program-model`, `pxi-w2-t1-resample-bake-chain`, `pxi-w3-t1-capture-signal-popup` |
|
||||||
| 16 | Retire the zone mapping system | Θ-W1-T1 | `pth-w1-t1-zone-retirement` |
|
| 16 | Retire the zone mapping system | Θ-W1-T1 | `pth-w1-t1-zone-retirement` |
|
||||||
| 17 | Consolidate provenance/usage tracking | Ξ-W1-T1 | `pxi-w1-t1-tracking-consolidation` |
|
| 17 | Consolidate provenance/usage tracking | Ξ-W1-T1 | `pxi-w1-t1-tracking-consolidation` |
|
||||||
|
|
||||||
@@ -2870,8 +2850,8 @@ Phase Ξ — The resample loop (W1 concurrency-safe with Θ from Θ-W
|
|||||||
T2 note-program-model ...................... 15 (model)
|
T2 note-program-model ...................... 15 (model)
|
||||||
W2 The bake chain [ran AHEAD of Γ; its reset list is corrected by Γ-W3-T2]
|
W2 The bake chain [ran AHEAD of Γ; its reset list is corrected by Γ-W3-T2]
|
||||||
T1 resample-bake-chain ..................... 15 (chain)
|
T1 resample-bake-chain ..................... 15 (chain)
|
||||||
W3 The capture-signal popup
|
W3 The capture-signal popup [popup abandoned by ruling; bake window derives itself]
|
||||||
T1 capture-signal-popup .................... 15 (popup)
|
T1 capture-signal-popup .................... 15 (popup abandoned; window derives)
|
||||||
|
|
||||||
Phase Γ — The instrument's control surface (none of the seventeen; ends with VST3 params)
|
Phase Γ — The instrument's control surface (none of the seventeen; ends with VST3 params)
|
||||||
W1 Foundations [5 tracks, disjoint by surface]
|
W1 Foundations [5 tracks, disjoint by surface]
|
||||||
|
|||||||
Reference in New Issue
Block a user