docs: schedule VST3 parameters into Phase Γ
Automation ships as Γ-W4; the stage ceiling goes to 10 s in W1-T1 ahead of the one-way door; a new Γ-W3-T2 corrects Ξ's bake reset list. Four waves, ten tracks. Opens Γ-F7 on parameter order.
This commit is contained in:
+656
-125
@@ -48,7 +48,15 @@ with a correction to the analysis, not merely a ruling**: dynamic reported laten
|
||||
for VST3 instruments and REAPER handles it as a matter of course; what makes the mandated
|
||||
restart expensive *here* is self-inflicted (`setActive(true)` calls `reloadInstrument`), so
|
||||
the cost is ours to reduce and the reduction is filed in `docs/TODO.md` rather than designed
|
||||
around. **No track in this plan carries an unanswered [Daniel]-class question.**
|
||||
around.
|
||||
|
||||
**Γ-F3 was subsequently REVERSED and a seventh fork opened, both by Daniel's later rulings
|
||||
of 2026-08-01.** Γ-F3 (*"the stage-time ceiling stays 2.0 s"*) is replaced by *"extend the
|
||||
stage lengths to 10s"* — the ceiling moves in Γ-W1-T1. And **Γ-F7 is OPEN**: the VST3
|
||||
parameter *order* (signal flow, or the editor's visual rows), a forever commitment that
|
||||
cannot be closed by proposal at review. It blocks nothing until **Γ-W4 dispatches**, which is
|
||||
the last track of the last wave of the phase. **Exactly one track in this plan carries an
|
||||
unanswered [Daniel]-class question: Γ-W4-T1, and it is Γ-F7.**
|
||||
|
||||
### Flagged for awareness — not blocking, but decision-grade
|
||||
|
||||
@@ -62,23 +70,39 @@ around. **No track in this plan carries an unanswered [Daniel]-class question.**
|
||||
verification, item 15's "one click from inside the VST" framing is what gives, not
|
||||
the read-only invariant — the fallback is a bindable extension-side action.
|
||||
|
||||
2. **Phase Γ must land before Ξ-W2, and this is a correctness point, not a preference.**
|
||||
Ξ-W2's settled reset scope enumerates parameters by name; Γ adds rate, pitch offset and
|
||||
the limiter flag, so shipping the bake first means its reset list is incomplete on the
|
||||
day it lands. Γ's product doc pre-classifies all three against the ratified rule (all
|
||||
**reset**), so this costs no Daniel decision — only ordering. Second, weaker reason: Γ
|
||||
owns params-payload v14 and v15, and Ξ-W3's programmed-signal persistence will want the
|
||||
next rung; two phases contending for the ladder is the fight Θ's organizing constraint
|
||||
exists to avoid.
|
||||
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
|
||||
correct phase xi inside gamma. wasn't a choice."* Ξ-W2-T1 (`resample-bake-chain`) ran
|
||||
ahead of this plan's sequencing claim, so the bake's settled reset scope — which
|
||||
enumerates parameters **by name** — ships incomplete: it cannot name rate, pitch offset or
|
||||
the limiter flag, none of which existed when it was written.
|
||||
|
||||
3. **The taper work inside Γ-W1-T1 is a one-way door with respect to automation.** Once
|
||||
VST3 parameters exist, the taper *is* the host-facing normalization, and re-tapering
|
||||
re-interprets every recorded automation point in project files we do not own and cannot
|
||||
migrate. Re-tapering is free today and permanently expensive afterwards. See
|
||||
`docs/product/parameter-automation.md` §4 — that doc is scoping only, nothing in it is
|
||||
scheduled here. **The same door applies to the stage-time ceiling**, which Γ-F3 left at
|
||||
2.0 s with a 10 s ambition recorded in `docs/TODO.md`: if that ceiling is ever raised, it
|
||||
wants to happen before the parameter system, not after.
|
||||
**This is no longer a scheduling constraint to honour. It is a correction obligation with
|
||||
a named owner: Γ-W3-T2 `bake-reset-amendment`.** The classification costs no Daniel
|
||||
decision — `docs/product/instrument-control-surface.md` §3.4 pre-classifies all three
|
||||
against Ξ-W2's own ratified rule (all **reset**) — but the amendment must be written
|
||||
**against what Ξ-W2-T1 actually shipped, not against what this plan predicted it would
|
||||
ship.** Ruling 1 adds a second correction of the same shape, homed on Γ-W4-T1 rather than
|
||||
here: see item 3.
|
||||
|
||||
3. **The one-way doors are now IN-PHASE, and the sweep for them is a delivered artifact.**
|
||||
Ruling 1 (Daniel, 2026-08-01) schedules VST3 parameter reporting **inside Phase Γ**, as
|
||||
Γ-W4-T1. Everything that participates in a parameter's normalization therefore freezes at
|
||||
the end of this phase rather than at the start of some later one, and anything that ought
|
||||
to move must move first.
|
||||
|
||||
- **The taper** (Γ-W1-T1) — known, and the reason this phase was ordered as it was.
|
||||
- **The stage-time ceiling 2.0 → 10.0 s** (Γ-W1-T1) — Γ-F3 **reversed** by Daniel's
|
||||
*"extend the stage lengths to 10s."* A range endpoint is normalization exactly as much
|
||||
as the curve between the endpoints is.
|
||||
- **Two further doors that need action, both new**, both landing on Γ-W1-T1: every
|
||||
default must have an **exact normalized preimage** (a host's reset-to-default has no
|
||||
`resetDeckParam` bypass to use), and the filter's four `*Norm` controls **must not be
|
||||
re-tapered** (their laws are already wire-frozen in payload v9).
|
||||
- **Six more constants freeze without needing to change**, and three are already frozen
|
||||
for unrelated reasons; the complete sweep, with dispositions and with what was checked,
|
||||
is `docs/product/parameter-automation.md` §8. **That doc is no longer scoping-only —
|
||||
§§6–10 are the specification Γ-W4-T1 is built from.**
|
||||
|
||||
## Phase-wide acceptance criteria
|
||||
|
||||
@@ -400,6 +424,12 @@ stays musical-division-only, and an offset stores the denomination it was entere
|
||||
computable (T1) and the programmed-note record the offline pass renders (T2). **Also
|
||||
depends on all of Phase Θ** — see the phase note above.
|
||||
|
||||
**This wave ran AHEAD of Phase Γ, and that was not a choice.** The plan asserted Γ must land
|
||||
first so the bake's reset list would be complete on the day it shipped; Ξ-W2-T1 was already
|
||||
live. The consequence is owned, not absorbed: **Γ-W3-T2 `bake-reset-amendment`** completes
|
||||
the list afterwards, and **Γ-W4-T1** adds the host-notification obligation once parameters
|
||||
exist. Neither is this wave's work, and neither is a defect report against it.
|
||||
|
||||
**One track.** The bake is one gesture and one chain; the architecture decision at its
|
||||
head governs every step after it.
|
||||
|
||||
@@ -567,6 +597,11 @@ DEGRADED, escalate rather than improvise — the fallback is (1c) + (2a).
|
||||
review. Not a new Daniel call. (Θ adds: curve exponents → reset; spline contours →
|
||||
reset, already named; the filter's velocity/key-tracking mod → reset with the filter;
|
||||
loop crossfade → reset with the loop points; the Staged/Spline mode flag → classify.)
|
||||
**Phase Γ's additions are NOT this track's** — this track ran ahead of Γ, so the values Γ
|
||||
introduces (rate, pitch offset, the limiter flag, the loop enable) are amended in by
|
||||
**Γ-W3-T2 `bake-reset-amendment`** afterwards, against what this track actually shipped.
|
||||
Γ-W4-T1 then adds the host-notification obligation over the completed list. Nothing here
|
||||
needs to anticipate either.
|
||||
- **Naming and lineage [propose, jointly with Ξ-W1-T1's lineage-record question].** When
|
||||
add-distinct fires, the new capture needs a display name (derived from the original?),
|
||||
and the bank some way to read iteration lineage across repeated bakes. One proposal,
|
||||
@@ -644,23 +679,31 @@ must be closed.
|
||||
**Ships:** the deck reflowed into two categorical rows with a double-height MASTER bus deck,
|
||||
a PITCH/RATE deck with playback-rate and baseline-pitch controls, a master limiter with
|
||||
dynamic reported latency and a real output meter, one consistent knob interaction/taper law
|
||||
across every variable control, a fix for staged contour traces drawing straight, and a
|
||||
re-approached loop/crossfade marker UX under an explicit chrome-row loop enable.
|
||||
across every variable control **over a stage-time range raised 2 s → 10 s**, a fix for staged
|
||||
contour traces drawing straight, a re-approached loop/crossfade marker UX under an explicit
|
||||
chrome-row loop enable, **the Phase Ξ bake's reset list corrected**, and — as the phase's last
|
||||
track — **the instrument's first VST3 automatable parameters, reported to the host under a
|
||||
frozen id contract.**
|
||||
|
||||
**Consolidates:** none of the seventeen. Phase Γ came from a direct interview with Daniel
|
||||
(2026-08-01); the product reasoning, the measured layout table, the invariant collisions and
|
||||
the fork rulings are in **`docs/product/instrument-control-surface.md`**. Read §1.2 (the
|
||||
layout 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.
|
||||
the fork rulings are in **`docs/product/instrument-control-surface.md`**, and the parameter
|
||||
system's is in **`docs/product/parameter-automation.md` §§6–10**. Read §1.2 (the layout
|
||||
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.
|
||||
|
||||
**Fork state — all six forks are ruled; nothing in this phase awaits Daniel.** Indexed at
|
||||
spec §8, folded into the tracks below:
|
||||
**Fork state — six ruled, ONE OF THEM LATER REVERSED, and one open.** Indexed at spec §8,
|
||||
folded into the tracks below:
|
||||
- **Γ-F1** — `kEditorMinHeight` stays **680**.
|
||||
- **Γ-F2** — the limiter has **lookahead with DYNAMIC reported latency** (zero when off,
|
||||
the lookahead when on, reported to host PDC). *This inverted the product recommendation;*
|
||||
W1-T2's scope grows accordingly — spec §3.1.1.
|
||||
- **Γ-F3** — the stage-time ceiling stays **2.0 s** in this phase. The 10 s ambition is
|
||||
carried in `docs/TODO.md` with its rationale and its prerequisites.
|
||||
- **Γ-F3 — RULED, THEN REVERSED THE SAME DAY.** First ruled *"the ceiling stays 2.0 s in this
|
||||
phase"*; then Daniel: ***"extend the stage lengths to 10s."*** `kEnvTimeMaxSeconds` /
|
||||
`kGateStageMaxSeconds` move **2.0 → 10.0 in Γ-W1-T1**, and the `docs/TODO.md` entry that
|
||||
carried the ambition is discharged rather than deferred. **The reversal's cause is Ruling 1**
|
||||
— parameters now ship in-phase, so the ceiling is a one-way door that must be walked through
|
||||
before them, not after. Spec §4.3.1.
|
||||
- **Γ-F4** — there **is** an explicit loop enable, and it lives on the **chrome row**, not
|
||||
in a deck. W2-T2's scope grows accordingly — spec §6.4.
|
||||
- **Γ-F5** — MASTER's reserved slot is **one** cell. The 90 px headroom argument behind
|
||||
@@ -669,6 +712,26 @@ spec §8, folded into the tracks below:
|
||||
deactivate/reactivate the SDK mandates is accepted: *"the limiter will either be on or off
|
||||
on its instance, toggling during playback is not a use case."* No constant-latency
|
||||
fallback, no measurement gate. *This ruling also corrected the analysis* — spec §3.1.1.
|
||||
- **Γ-F7 — OPEN, and it is the only unanswered [Daniel] question in this plan.** The VST3
|
||||
parameter **order**: signal-flow order (the deck's own documented rule, layout-independent)
|
||||
or the editor's visual row order after the reflow. Same membership, different sequence,
|
||||
frozen forever the day parameters ship. **Recommendation: signal flow**, because the visual
|
||||
layout has already moved twice and this phase moves it again. Reasoning and both arguments:
|
||||
`docs/product/parameter-automation.md` §6.4. **Blocks nothing until Γ-W4 dispatches**; it
|
||||
cannot be closed by proposal at review.
|
||||
|
||||
**Ruling 1 (Daniel, 2026-08-01) — VST3 parameter reporting ships in this phase.** Verbatim
|
||||
intent: *"correct the phase gamma plan to account for complying with the VST3 standard for
|
||||
parameter reporting… by the end of gamma we have the automatable params reported. Make the
|
||||
parameter order logical."* `docs/product/parameter-automation.md` was written as scoping and
|
||||
has been **promoted in place**: §§1–5 are the original analysis, **§§6–10 are the
|
||||
specification** Γ-W4-T1 is built from. Three things it decides that the scoping pass left
|
||||
open: the blob stays authoritative and parameters are a third surface onto the one model
|
||||
(§6.1); the id space is an independent, hand-assigned, FOREVER-FROZEN table (§6.2, §6.3); and
|
||||
the exposed list is **derived from the three-state commit predicate**, never hand-maintained
|
||||
(§7). Today the plugin has **zero** parameters — `ReaSamplerProcessor::initialize`
|
||||
(`reasampler_processor.cpp:56-73`) never populates `SingleComponentEffect::parameters`, so
|
||||
`getParameterCount()` returns the SDK default 0.
|
||||
|
||||
**What the Γ-F6 ruling changed in the analysis, not just in the plan.** Dynamic latency
|
||||
reporting is **routine** for VST3 instruments and REAPER handles it as a matter of course;
|
||||
@@ -682,27 +745,38 @@ ours to reduce if it ever matters, and the reduction is decoupling reload from a
|
||||
not abandoning dynamic latency.** That improvement is filed as a `docs/TODO.md` entry with its
|
||||
trigger condition; it is not scheduled in this phase.
|
||||
|
||||
**Sequencing against Phase Ξ — Γ runs BEFORE Ξ-W2.** Two reasons, both the same shape as
|
||||
Ξ's own stated gate:
|
||||
1. **The bake bakes the control surface.** Ξ-W2's settled reset scope enumerates parameters
|
||||
by name; Γ adds rate, pitch offset and the limiter flag. Shipping Ξ-W2 first means its
|
||||
reset list is incomplete on the day it lands. (Γ's doc §3.4 pre-classifies all three
|
||||
against the ratified rule — all **reset** — so this is a sequencing point, not a new
|
||||
Daniel question.)
|
||||
2. **One params-payload ladder.** Γ takes v14 and v15. Ξ-W2 does not currently bump the
|
||||
payload, but Ξ-W3's programmed-signal persistence will, and two phases contending for the
|
||||
ladder is exactly the fight Θ's organizing constraint calls out.
|
||||
**Sequencing against Phase Ξ — the ordering claim is RETIRED and replaced by an owned
|
||||
correction.** This plan previously asserted that Γ must run before Ξ-W2 and called it *"a
|
||||
correctness point, not a preference."* **Ξ-W2-T1 ran first.** That was not a decision anyone
|
||||
took — the track was live before this phase existed (Daniel: *"xi was started before I spun
|
||||
you up, we'll have to correct phase xi inside gamma. wasn't a choice."*). So:
|
||||
|
||||
**The organizing constraint.** Five surfaces are single-writer and dictate the wave shape:
|
||||
`ui/deck_values.cpp` (the taper law, then the two new controls), `editor_paint_waveform.cpp`
|
||||
(the contour trace, then the loop marks), `ui/deck_groups.cpp` (the row predicate, then the
|
||||
PITCH/RATE descriptor, then the reflow's row consumption — three tracks, three waves),
|
||||
`engine/voice.cpp` (the Preserve read path, then the rate compounding into it), and the
|
||||
params-payload ladder. **Every wave boundary below is one of those collisions**, not a
|
||||
preference. Where a wave has more than one track, the tracks are disjoint by surface.
|
||||
1. **The bake's reset list is incomplete as shipped, and Γ-W3-T2 amends it.** Rate, pitch
|
||||
offset and the limiter flag are all **reset** under Ξ-W2's own ratified rule (spec §3.4),
|
||||
so no Daniel decision is owed — only the edit, and it must be made **against what Ξ-W2-T1
|
||||
actually shipped rather than against what this plan predicted it would ship.**
|
||||
2. **Ruling 1 adds a second correction of the same shape, and it lands one wave later.**
|
||||
Exposing the reset-class values as VST3 parameters means the bake's reset must notify the
|
||||
host, and a host automation lane on a reset-class parameter re-imposes its curve onto
|
||||
already-baked audio. Both are Γ-W4-T1's acceptance criteria — that track creates the
|
||||
condition, so it carries it (`docs/product/parameter-automation.md` §9).
|
||||
3. **The payload-ladder half of the old claim needs re-checking, not restating** — see the
|
||||
ladder block below, which now states rungs **relatively** rather than by number.
|
||||
|
||||
**Resequenced 2026-08-01 (Daniel), two changes.** The prior four-wave shape put the reflow at
|
||||
W3 and the Preserve stretcher at W4; both moved.
|
||||
**The organizing constraint.** Six surfaces are single-writer and dictate the wave shape:
|
||||
`ui/deck_values.cpp` **and the taper module extracted from it** (the taper law and the new
|
||||
ceiling, then the two new controls, then the host normalization — three tracks, three waves),
|
||||
`editor_paint_waveform.cpp` (the contour trace, then the loop marks), `ui/deck_groups.cpp`
|
||||
(the row predicate, then the PITCH/RATE descriptor, then the reflow's row consumption — three
|
||||
tracks, three waves), `engine/voice.cpp` (the Preserve read path, then the rate compounding
|
||||
into it), `shell/instrument/reasampler_processor` (the limiter chain and latency, then the
|
||||
parameter surface), and the params-payload ladder. **Every wave boundary below is one of
|
||||
those collisions**, not a preference. Where a wave has more than one track, the tracks are
|
||||
disjoint by surface.
|
||||
|
||||
**Resequenced 2026-08-01 (Daniel), three changes.** The prior four-wave shape put the reflow
|
||||
at W3 and the Preserve stretcher at W4; both moved. **Ruling 1 then added a fourth wave** —
|
||||
see "The wave shape after Ruling 1" below.
|
||||
|
||||
1. **The reflow is split, canvas from arrangement.** The window floor and the width budget it
|
||||
is derived from land **early** (Γ-W1-T4), so every other UI track in the phase is drawn,
|
||||
@@ -718,13 +792,51 @@ W3 and the Preserve stretcher at W4; both moved.
|
||||
Net: four waves become three, and both of the phase's DSP unknowns (the limiter, the
|
||||
stretcher) are exposed in wave 1 rather than one of them landing last.
|
||||
|
||||
**The params-payload ladder is unchanged by the resequencing, and re-checked against the new
|
||||
membership.** Exactly one bump per wave, owned by exactly one track: **W1-T2 owns v14** (the
|
||||
limiter flag), **W2-T1 owns v15** (rate + pitch offset), and **every other track in the phase
|
||||
owns no rung** — W1-T4 changes no persisted field, W1-T5 adds no parameter, W2-T2's loop
|
||||
enable maps onto the already-persisted `SampleLoop::hasLoop`, and W3-T1 is layout only. The
|
||||
ordering still works because v14 lands a whole wave before v15, and neither of the two tracks
|
||||
that moved touches the codec.
|
||||
**The wave shape after Ruling 1 — three waves become four.** The parameter system cannot be
|
||||
a track inside any existing wave, and the reason is a chain of hard prerequisites, not
|
||||
caution:
|
||||
|
||||
- **after W1-T1**, because the taper and the 10 s ceiling *are* the host-facing
|
||||
normalization, and Γ-W1-T1 is also what extracts them into the one module the host will
|
||||
read through;
|
||||
- **after W1-T2 and W2-T1**, because every control that could be a parameter must exist
|
||||
before the list is declared — the list is derived from the control inventory, and an
|
||||
inventory that is still growing produces a list that has to be re-frozen;
|
||||
- **after W2-T1 specifically**, because `isLiveDeckParam` becoming three-valued is the
|
||||
*prerequisite* of the classification, not an incidental of it: the exposed set is exactly
|
||||
`Live ∪ NoteOnLatched`;
|
||||
- **after W3-T1**, because MASTER's inventory (the limiter toggle, the GR bubble, the
|
||||
reserved cell) is the last change to what controls exist at all;
|
||||
- **after W3-T2**, so the bake's reset list is already complete when Γ-W4-T1 adds the
|
||||
host-notification obligation over it — one amendment instead of an amendment to an
|
||||
amendment.
|
||||
|
||||
The result is a single-track **Γ-W4**, which is the right shape for it anyway: the storage
|
||||
decision governs every part of the work, exactly as Ξ-W2-T1's crossing decision governs its
|
||||
chain. **And it satisfies Daniel's own framing literally** — *"by the end of gamma we have
|
||||
the automatable params reported."*
|
||||
|
||||
**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
|
||||
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
|
||||
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
|
||||
> that number is READ, not assumed.** In order: **the first rung to W1-T2** (the limiter
|
||||
> enable flag), **the second to W2-T1** (rate + pitch offset), **the third RESERVED for
|
||||
> W4-T1** — spent only if the storage-architecture verification forces a persisted field,
|
||||
> 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.
|
||||
>
|
||||
> **On `dev` as of 2026-08-01 that resolves to v14 / v15 / v16-reserved.** If Ξ-W2-T1 landed
|
||||
> a bump, every number shifts 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
|
||||
stores raw engine doubles, so both the taper and the new ceiling are persistence-neutral),
|
||||
W1-T3, W1-T4 and W1-T5 add no field, W2-T2's loop enable maps onto the already-persisted
|
||||
`SampleLoop::hasLoop`, W3-T1 is layout only, and W3-T2 changes a reset list, not a format.
|
||||
|
||||
**The editor's deck is knowingly mis-composed between Γ-W1-T4 and Γ-W3-T1, and that is not a
|
||||
defect report.** Raising the floor without the reflow leaves the greedy whole-group wrap
|
||||
@@ -738,11 +850,37 @@ exact interim layout; do not "fix" it in a track that does not own it.
|
||||
`modAmount == 0` hold the at-rest path unchanged.
|
||||
- **No `ComponentState` sound change.** A project saved before this phase reopens sounding
|
||||
identical: absent rate lifts to 100 %, absent pitch offset to 0 st, absent limiter flag to
|
||||
bypassed. Re-tapering a knob (Γ-W1-T1) changes needle angles only — the payload stores raw
|
||||
engine doubles, so saved values reload bit-identical.
|
||||
bypassed. Re-tapering a knob **and raising the stage-time ceiling** (both Γ-W1-T1) change
|
||||
needle angles only — the payload stores raw engine doubles, so saved values reload
|
||||
bit-identical, and a 3 s stage saved at the old ceiling is simply unreachable-by-hand
|
||||
rather than altered.
|
||||
- **`kVelocityPitchRangeSemitones` / `kPitchDepthMaxSemis` (24.0) does not move.** It is
|
||||
load-bearing in the v12 wire format. The new Pitch knob **reads** it; it does not mint a
|
||||
second ±24 constant.
|
||||
second ±24 constant. **From Γ-W4-T1 it is also a frozen host normalization** — one more
|
||||
reason, not a new rule.
|
||||
- **The taper has exactly ONE home and three consumers.** Γ-W1-T1 extracts it into a pure
|
||||
module; the knob's needle (`deck_values`), the AHDSR overlay's schematic axis
|
||||
(`envelope_overlay` + `envelope_edit`), and the host's `normalizedParamToPlain` (Γ-W4-T1)
|
||||
all call the same function. **Three functions that agree today is a defect, not an
|
||||
implementation choice** — the failure it prevents is a host automation lane that means one
|
||||
value and a needle that draws another.
|
||||
- **Every default value has an EXACT normalized preimage under its own taper.** Binds
|
||||
Γ-W1-T1 (which designs the taper) and Γ-W4-T1 (which declares
|
||||
`ParameterInfo::defaultNormalizedValue`). `resetDeckParam` bypasses the taper; **a host's
|
||||
reset-to-default cannot**, so exactness in the map itself is the only thing that makes the
|
||||
editor's reset and the host's reset land on the same value.
|
||||
- **Nothing in this phase may re-map the filter's four normalized controls.** Cutoff, Q,
|
||||
morph and drive persist as `*Norm` doubles in payload v9 — their laws are already
|
||||
wire-frozen, and re-tapering them would re-tune every saved project independently of
|
||||
automation. The snap-unit table names them; that is display, not law.
|
||||
- **From Γ-W4-T1, the parameter-id table is FOREVER-FROZEN**, on the same footing as the
|
||||
extension's `"STABLE_FOREVER_STRING"` command ids, the two VST3 class UIDs, and the
|
||||
params-payload field order. No id is reassigned, reused or re-pointed; no exposed
|
||||
parameter's normalization ever changes; a retired control's id is retired with it.
|
||||
Full wording: `docs/product/parameter-automation.md` §6.3.
|
||||
- **The exposed parameter set is DERIVED, never hand-maintained.** A control is a parameter
|
||||
if and only if its commit class is `Live` or `NoteOnLatched`. There is no second table
|
||||
beside `isLiveDeckParam` / `liveCommitFor`, and no list that can drift from it.
|
||||
- **The window floor is 1190 × 680 and must not exceed 1280 × 720.** **Γ-W1-T4 sets it, in
|
||||
wave 1; no other track in the phase may move it**, and from that point every track is
|
||||
authored and judged at it. A track that pushes the floor past 1280 has failed, not overrun.
|
||||
@@ -766,23 +904,43 @@ against this membership rather than carried over from the four-wave shape:
|
||||
|
||||
| Track | Owns |
|
||||
|---|---|
|
||||
| **T1** `knob-interaction-law` | `ui/deck_values`, `ui/param_slider`, the three `shell/instrument/editor_input_*` drag paths, the shared modifier helper in `editor_internal.h` |
|
||||
| **T2** `master-bus-audio` | new pure `engine/limiter` + `engine/meter_ballistics`, `shell/instrument/reasampler_processor` + `processor_state`, `map/component_state_io` + `params_payload` (**v14**) |
|
||||
| **T3** `contour-trace-curves` | `shell/instrument/editor_paint_waveform.cpp`'s staged trace + a **pure** tessellation helper |
|
||||
| **T1** `knob-interaction-law` | a **new pure taper module** under `core/instrument/ui/`, `ui/deck_values`, `ui/envelope_overlay` + `ui/envelope_edit` (the AHDSR schematic axis and its drag inverse), `ui/param_slider`, the three `shell/instrument/editor_input_*` drag paths, `editor_controls.cpp`'s `envClampBounds` only, the shared modifier helper in `editor_internal.h` |
|
||||
| **T2** `master-bus-audio` | new pure `engine/limiter` + `engine/meter_ballistics`, `shell/instrument/reasampler_processor` + `processor_state`, `map/component_state_io` + `params_payload` (**the wave's payload rung**) |
|
||||
| **T3** `contour-trace-curves` | `shell/instrument/editor_paint_waveform.cpp`'s staged trace + a **new pure** tessellation module |
|
||||
| **T4** `editor-floor-and-row-law` | `ui/sample_bands.h` (the floor), `ui/knob_deck.h` (budget constants + two invalidated header notes), `ui/deck_groups` (the row predicate **only**), five test fixtures |
|
||||
| **T5** `preserve-time-stretch` | `engine/pitch_shift` + a new pure stretcher module, `engine/voice.{h,cpp}`'s Preserve read path |
|
||||
|
||||
**One shared file in the wave, named rather than discovered at merge:
|
||||
`src/core/instrument/engine/CMakeLists.txt`.** T2 declares two new pure libraries and their
|
||||
test targets there; T5 declares one. Both are append-only additions in separate blocks —
|
||||
**textual merge adjacency, not semantic contention.** Whichever lands second rebases.
|
||||
**Two shared files in the wave, named rather than discovered at merge.**
|
||||
`src/core/instrument/engine/CMakeLists.txt` — T2 declares two new pure libraries and their
|
||||
test targets there, T5 declares one. **And, newly, `src/core/instrument/ui/CMakeLists.txt`** —
|
||||
T1 declares the taper module and its test target, T3 declares the tessellation module and
|
||||
its. All four are append-only additions in separate blocks — **textual merge adjacency, not
|
||||
semantic contention.** Whichever lands second rebases.
|
||||
|
||||
**Two near-misses that are avoided by construction, and must stay avoided.** (a) T3's
|
||||
tessellation helper **lands pure** (`ui/envelope_overlay` or a new pure module), *not* in
|
||||
`editor_internal.h`, which T1 is editing — this also satisfies the phase's geometry-stays-pure
|
||||
criterion, so it costs nothing. (b) T4 touches `deck_groups` but adds **only** the new row
|
||||
predicate; it does not touch `sampleDeckGroups`, which W2-T1 and W3-T1 own in later waves, and
|
||||
it does not touch `deck_values`, which is T1's.
|
||||
**Three near-misses that are avoided by construction, and must stay avoided.**
|
||||
|
||||
(a) **T3's tessellation helper lands in a NEW pure module — explicitly NOT
|
||||
`ui/envelope_overlay`, which T1 now owns**, and not in `editor_internal.h`, which T1 is also
|
||||
editing. The prior wording offered `envelope_overlay` as an option; Ruling 2 removed it,
|
||||
because T1's schematic-axis work rewrites that module's whole time→x map. This still
|
||||
satisfies the phase's geometry-stays-pure criterion, so it costs nothing.
|
||||
|
||||
(b) **T1 and T3 are disjoint by file but coupled by data, and the coupling has a stated
|
||||
resolution.** T1 owns where an AHDSR's vertices *land*; T3 owns the stroke *between*
|
||||
vertices. T3's tessellation is over φ across a segment's pixel span, so the tapered axis
|
||||
changes nothing about the curve it draws — **but T3's tests must assert against the returned
|
||||
vertices, not against absolute pixel literals**, or they break when T1 lands. Whichever
|
||||
track lands second rebases; expressing T3's assertions relatively makes that rebase free.
|
||||
|
||||
(c) **T4 touches `deck_groups` but adds only the new row predicate**; it does not touch
|
||||
`sampleDeckGroups`, which W2-T1 and W3-T1 own in later waves, and it does not touch
|
||||
`deck_values`, which is T1's.
|
||||
|
||||
**Two consumption boundaries worth stating, because they look like collisions and are not.**
|
||||
T1 **consumes** `engine/master_gain`'s dB taper for its whole-dB snap and does not edit it;
|
||||
T2 does not touch it either. And T2's payload rung is the wave's only format change —
|
||||
T1's taper and ceiling changes are persistence-neutral by construction (the payload stores
|
||||
raw engine doubles).
|
||||
|
||||
**Both of the phase's DSP unknowns are in this wave** — T2's limiter and T5's stretcher. That
|
||||
is deliberate: they are the two tracks whose gate can fail, and failing in wave 1 is
|
||||
@@ -791,16 +949,38 @@ recoverable in a way that failing in the last wave is not.
|
||||
#### Γ-W1-T1 — `knob-interaction-law`
|
||||
|
||||
**Goal.** One consistent, unit-category-driven interaction and taper rule across every
|
||||
variable control, landed **before** any new control is added so the new ones are authored
|
||||
into it rather than retro-fitted.
|
||||
variable control, **over a stage-time range raised 2 s → 10 s**, landed **before** any new
|
||||
control is added so the new ones are authored into it rather than retro-fitted — and before
|
||||
any parameter is declared, so the law is what the host is handed rather than something the
|
||||
host has to be reconciled with later.
|
||||
|
||||
**Spec:** `docs/product/instrument-control-surface.md` §4.
|
||||
**Spec:** `docs/product/instrument-control-surface.md` §4, **§4.3.1 (the 10 s ceiling and the
|
||||
overlay-legibility design — new, read it before scoping this track)**, and
|
||||
`docs/product/parameter-automation.md` §8 (the one-way-door sweep this track discharges).
|
||||
|
||||
**Surface boundary — owns:** `core/instrument/ui/deck_values` (the taper maps, the
|
||||
snap-unit table, `resetDeckParam`), `core/instrument/ui/param_slider` (the drag law),
|
||||
`shell/instrument/editor_input_*` (modifier read + re-anchor), and the modifier-reading
|
||||
helper the three input paths share. **Does not own** any deck descriptor, any parameter, or
|
||||
the waveform painter.
|
||||
**Surface boundary — owns:** a **new pure taper module** under `core/instrument/ui/` (the
|
||||
ms/semitone/exponent maps, extracted so they have one home),
|
||||
`core/instrument/ui/deck_values` (the bindings, the snap-unit table, `resetDeckParam`),
|
||||
`core/instrument/ui/envelope_overlay` (the ceiling constant **and** the AHDSR schematic
|
||||
axis) and `core/instrument/ui/envelope_edit` (its drag inverse),
|
||||
`core/instrument/ui/param_slider` (the drag law), `shell/instrument/editor_input_*`
|
||||
(modifier read + re-anchor), `shell/instrument/editor_controls.cpp`'s `envClampBounds`
|
||||
**only** (it reads `kEnvTimeMaxSeconds`), and the modifier-reading helper the three input
|
||||
paths share. **Does not own** any deck descriptor, any parameter, the waveform painter, or
|
||||
`engine/master_gain` (consumed, not edited).
|
||||
|
||||
**Why this track does NOT split, asked and answered.** Ruling 2 makes it materially bigger —
|
||||
tapers, modifiers, re-anchor, reset bypass, the ceiling, and the overlay's schematic scale.
|
||||
Two splits were considered and both are **serial, not parallel**, so neither buys any
|
||||
concurrency: an *interaction* half (modifiers, snap, re-anchor) needs the *domain* half's
|
||||
taper and snap-unit table to exist first; and a standalone *overlay-axis* track needs the
|
||||
taper module and the final ceiling before it can define a stage's slot width. Splitting
|
||||
would therefore cost a wave and gain nothing, while putting the single most
|
||||
identity-critical function in the phase across a wave boundary — the same function the host
|
||||
will normalize against three waves later. **The seam that matters is internal and is a
|
||||
deliverable: the taper is extracted into its own pure module**, which is what makes "the
|
||||
taper IS the host-facing normalization" structurally true rather than a comment. The
|
||||
~600-line ceiling is a per-file bar, and the extraction is what keeps every file under it.
|
||||
|
||||
**Behavior.**
|
||||
- **Shift snaps to whole numbers in the control's displayed unit**; **Ctrl scales the drag by
|
||||
@@ -817,9 +997,47 @@ the waveform painter.
|
||||
`(1 − 0.05) ×` the accumulated delta.
|
||||
- **Millisecond knobs become log-scaled.** Exactly 0 s at norm 0 and exactly
|
||||
`kEnvTimeMaxSeconds` at norm 1, monotone throughout; **10 ms lands within 0.12–0.20 of
|
||||
travel and 100 ms within 0.42–0.52**. The ceiling stays **2.0 s** — it reads
|
||||
`kGateStageMaxSeconds`, which the AHDSR overlay's schematic scale is derived from, and the
|
||||
two must agree.
|
||||
travel and 100 ms within 0.42–0.52**.
|
||||
- **The stage-time ceiling moves 2.0 s → 10.0 s** (Daniel, reversing Γ-F3):
|
||||
`kGateStageMaxSeconds` (`envelope_overlay.h:85`) and, through it, `kEnvTimeMaxSeconds`
|
||||
(`deck_values.h:22`). **The two move together or not at all** — `deck_values.h` reads the
|
||||
overlay's constant rather than restating it precisely so they cannot drift
|
||||
(`deck_values.h:19-22`). The taper's landmarks above are fit against the **new** ceiling,
|
||||
which is why the ceiling cannot be a follow-up: fitting the taper twice is the only other
|
||||
way to get there.
|
||||
- **`resetDeckParam`'s bypass becomes MANDATORY rather than merely required-anyway.**
|
||||
`deck_values.h:42-46` records that exact default recovery depends on the ceiling being a
|
||||
power of two; **2.0 is, 10.0 is not**, and the log taper compounds it. Nothing here may be
|
||||
"simplified" back into a norm round-trip under any circumstance.
|
||||
- **NEW, and the sharpest requirement in the track: every default must have an EXACT
|
||||
normalized preimage under its taper.** `ParameterInfo::defaultNormalizedValue` (Γ-W4-T1)
|
||||
is normalized, so a host's reset-to-default arrives as `toPlain(defaultNorm)` — and **the
|
||||
host has no `resetDeckParam` bypass to use**. The bypass fixes the editor's reset and
|
||||
cannot fix the host's; only exactness in the map itself makes the two land on the same
|
||||
value. This binds the taper's *shape*, so it belongs here and cannot be handed forward.
|
||||
Master gain's unity (≈ 0.714 norm) is the case where a hair off is audible.
|
||||
- **The AHDSR overlay's schematic axis becomes the taper — the ceiling's real cost, and it
|
||||
is design work, not a constant change.** Each of the four timed stages gets an equal slot
|
||||
and today maps seconds across it linearly (`gatePxPerSecond`,
|
||||
`envelope_overlay.cpp:33-34`). At 2 s a 30 ms attack is 1.5 % of its stage's domain; **at
|
||||
10 s it is 0.3 %, under a pixel at the floor width.** The fix: a stage's slot width becomes
|
||||
`slotPx × taperNorm(seconds)` instead of `slotPx × seconds / ceiling`, so a node's position
|
||||
within its slot **is** its knob's needle position. Legibility becomes ceiling-independent by
|
||||
construction; the one-model invariant gets stronger rather than strained; and **the drawn
|
||||
curve is unaffected**, because the taper decides only where a stage's end node lands while φ
|
||||
still runs linearly across the stage's pixel span — so Γ-W1-T3's φ^p trace composes with it
|
||||
rather than fighting it. **The AHD policy is untouched**: an AHD maps 1:1 onto the
|
||||
waveform's own PCM-aligned time axis and stays linear in seconds. Two alternatives
|
||||
(content-fit auto-scale; a minimum drawn stage width) were considered and rejected — spec
|
||||
§4.3.1 names why, and neither is to be reintroduced as a "simplification."
|
||||
- **`envelope_edit`'s drag inverse must remain the EXACT inverse of the draw.** Both read the
|
||||
same taper module; a node dragged to a pixel and the knob's value at that pixel are one
|
||||
number, not two that agree.
|
||||
- **The taper is EXTRACTED into its own pure module**, with its own `<module>_tests` target,
|
||||
because it now has three consumers in two different dependency layers: `deck_values` (which
|
||||
sits above `envelope_overlay`), `envelope_overlay`/`envelope_edit` (which sit below it),
|
||||
and — from Γ-W4-T1 — the host. Leaving it inside `deck_values` would force an inverted
|
||||
include edge. **Do not solve that by copying the map.**
|
||||
- **Semitone knobs become log2/centre-expanded.** Symmetric, exactly 0 at centre, exactly
|
||||
±`kPitchDepthMaxSemis` at the ends, monotone; **±7 st reached at 50–58 % of each
|
||||
half-travel**.
|
||||
@@ -842,17 +1060,48 @@ the waveform painter.
|
||||
- Double-clicking any knob (outer ring and inner dial independently) lands **exactly** on its
|
||||
default at every taper, verified against a default-constructed `PlaySeconds` rather than a
|
||||
round trip.
|
||||
- The log/log2 landmark positions above are asserted in `deck_values`' own tests.
|
||||
- The log/log2 landmark positions above are asserted in the **taper module's** own tests, and
|
||||
hold at the **10 s** ceiling — the fit is against the new ceiling, not the old one.
|
||||
- **Every default round-trips exactly through `norm → value`**, asserted per unit category
|
||||
against a default-constructed `PlaySeconds` and against `master_gain`'s unity. This is the
|
||||
criterion Γ-W4-T1 will declare `defaultNormalizedValue` from; it fails here, not there.
|
||||
- **A stage time of several seconds is reachable by hand with no loss of resolution below
|
||||
100 ms**, and `kEnvTimeMaxSeconds == kGateStageMaxSeconds` is asserted, not assumed.
|
||||
- **A project saved at the 2 s ceiling reloads with identical stored seconds and identical
|
||||
audio** — the ceiling change is persistence-neutral for the same reason the taper is.
|
||||
- **The AHDSR overlay reads legibly at both ends of the new range**: a default 3 ms attack is
|
||||
a visible, grabbable node at the floor width, and a 10 s decay still lands its end node at
|
||||
its slot's edge. Assert the node separation, then judge the result by eye in the DAW.
|
||||
- **The overlay's drag inverse is the exact inverse of its draw** at the tapered axis —
|
||||
`nodeAtPoint` / `resolveNodeDrag` and `buildEnvelopePolyline` round-trip.
|
||||
- **The AHD 1:1 policy is unchanged**, asserted: a sustain-less envelope's x-axis stays
|
||||
wall-clock over the waveform.
|
||||
- **The taper module is pure, CTest-covered, and is the ONLY definition of each map** — a
|
||||
grep finds no second copy in `deck_values`, `envelope_overlay`, or the shell.
|
||||
- **The filter's four `*Norm` controls are untouched by the taper pass** — cutoff, Q, morph
|
||||
and drive are already wire-frozen in payload v9; a regression baseline proves their audio
|
||||
is unchanged.
|
||||
- One shared modifier-read helper serves all drag surfaces; no second modifier grammar exists.
|
||||
|
||||
**Open questions.** None **[Daniel]** — fork Γ-F3 is ruled: **the ceiling stays 2.0 s.** The
|
||||
10 s ambition Daniel described (*"a horrifically long decay with tight exp"*) is carried as a
|
||||
`docs/TODO.md` entry, and **this track lands both of its prerequisites**: the log taper (which
|
||||
is what makes a higher ceiling usable at the low end rather than unusable) and the reset
|
||||
bypass (which retires the power-of-two dependency — 2.0 is a power of two, 10.0 is not).
|
||||
**Neither is optional on that basis alone** — they are already required by this track — but
|
||||
the engineer should know the reset bypass is doing double duty, and should not "simplify" it
|
||||
back into a norm round-trip.
|
||||
**Open questions.**
|
||||
- **No [Daniel] questions.** Fork **Γ-F3 is REVERSED**: the ceiling moves to **10.0 s, in this
|
||||
track.** Daniel's *"a horrifically long decay with tight exp"* is the case it serves, and
|
||||
the `docs/TODO.md` entry that carried it is discharged rather than deferred again. **The
|
||||
reversal's cause is Ruling 1** — a range endpoint is host-facing normalization, free to
|
||||
move now and permanently expensive after Γ-W4-T1. Both of the prerequisites the deferred
|
||||
entry named are in this track anyway: the log taper (which is what makes a higher ceiling
|
||||
usable at the low end rather than unusable) and the reset bypass (which retires the
|
||||
power-of-two dependency — 2.0 is a power of two, 10.0 is not). The engineer should know the
|
||||
reset bypass is now doing triple duty and must not be "simplified" back into a norm
|
||||
round-trip under any circumstance.
|
||||
- **[propose at review]** the exact shape of the taper, subject to the landmark bounds **and**
|
||||
the exact-default-preimage requirement. Those two together are tighter than either alone,
|
||||
and the second is easy to satisfy by accident and easy to lose in a refactor — **assert it,
|
||||
do not observe it.**
|
||||
- **[propose at review]** whether the tapered schematic axis wants a visible tick or
|
||||
gradation cue, now that it is no longer linear in time. The plan's lean is **no** — the ms
|
||||
labels carry the number and the editor's no-decoration policy stands — but a reader who
|
||||
finds the axis illegible in the DAW should say so rather than silently adding one.
|
||||
|
||||
#### Γ-W1-T2 — `master-bus-audio`
|
||||
|
||||
@@ -867,9 +1116,12 @@ first; it was rewritten when Γ-F6 closed, so an older reading of it is wrong)**
|
||||
**Surface boundary — owns:** a new pure limiter module and a new pure meter-ballistics
|
||||
module under `core/instrument/engine/` (each with its own `<module>_tests` target),
|
||||
`shell/instrument/reasampler_processor` (the chain, the published block state, **and the
|
||||
`getLatencySamples` / `restartComponent(kLatencyChanged)` path**), and **params payload v14**
|
||||
(the limiter enable flag). **Does not own** MASTER's deck geometry or any drawing — that is
|
||||
Γ-W3-T1.
|
||||
`getLatencySamples` / `restartComponent(kLatencyChanged)` path**), and **the phase's FIRST
|
||||
params-payload rung** (the limiter enable flag). **Does not own** MASTER's deck geometry or
|
||||
any drawing — that is Γ-W3-T1. **Read `kParamsPayloadVersion` on `dev` and take the next rung
|
||||
above it rather than assuming the number** — Phase Ξ ran ahead of this plan's sequencing, so
|
||||
the plan is not the record of what the ladder currently carries. On `dev` as of 2026-08-01
|
||||
that resolves to **v14**.
|
||||
|
||||
**Behavior.**
|
||||
- **Chain:** `voice mixer → master gain (existing ramped multiply) → limiter (bypassable) →
|
||||
@@ -936,8 +1188,8 @@ module under `core/instrument/engine/` (each with its own `<module>_tests` targe
|
||||
- **Meter ballistics (pure, unit-tested):** instantaneous rise; **fall 20 dB/s**; peak-hold
|
||||
latched at the running max, **held 1.5 s**, then falling at the same rate; scale **linear in
|
||||
dB over −60…+6 dBFS**; clip latches at block peak ≥ 0 dBFS and is cleared on request.
|
||||
- **`ComponentState` payload v14** appends the limiter flag as a strict suffix on the existing
|
||||
discipline; a v13 blob is a strict prefix and lifts to bypassed.
|
||||
- **The `ComponentState` payload rung** appends the limiter flag as a strict suffix on the
|
||||
existing discipline; the preceding version's blob is a strict prefix and lifts to bypassed.
|
||||
|
||||
**Acceptance criteria.**
|
||||
- **With the limiter bypassed the rendered output is byte-identical to the pre-change build**,
|
||||
@@ -982,8 +1234,16 @@ mid-segment knot stops floating off its own trace.
|
||||
**Spec:** `docs/product/instrument-control-surface.md` §5.
|
||||
|
||||
**Surface boundary — owns:** `shell/instrument/editor_paint_waveform.cpp`'s staged-envelope
|
||||
trace and any pure tessellation helper it needs. **Does not own** the loop/crossfade marks
|
||||
(Γ-W2-T2), `envelope_overlay`'s vertex model, or the drawn-EG (spline) trace.
|
||||
trace and a **new pure tessellation module** for it. **Does not own** the loop/crossfade
|
||||
marks (Γ-W2-T2), `envelope_overlay`'s vertex model, or the drawn-EG (spline) trace.
|
||||
|
||||
**The helper's home is now constrained, not a choice.** `ui/envelope_overlay` was previously
|
||||
offered as a candidate home for the tessellation helper; **Γ-W1-T1 now owns that module**
|
||||
(the AHDSR schematic axis, per Ruling 2), so the helper lands in a **new** pure module under
|
||||
`core/instrument/ui/`. T1 also owns where an AHDSR's vertices land — this track owns only the
|
||||
stroke *between* vertices, and tessellates over φ across a segment's pixel span, so the
|
||||
tapered axis changes nothing about the curve drawn. **Express this track's assertions against
|
||||
the returned vertices, not against absolute pixel literals**, and the rebase onto T1 is free.
|
||||
|
||||
**Behavior.** The defect is verified: `editor_paint_waveform.cpp:218` drops knots
|
||||
(`if (v.knot) continue;`) and joins the remaining vertices with straight strokes, and
|
||||
@@ -1218,10 +1478,18 @@ are otherwise single-writer surfaces, so it is stated rather than discovered at
|
||||
track lands second rebases onto the first. No *new* in-wave adjacency was created by the
|
||||
resequencing: T2 touches neither `deck_values` nor `deck_groups` nor `voice`.
|
||||
|
||||
**One cross-wave hand-off, new with Ruling 2 and NOT a contention.** Rate's taper — linear in
|
||||
semitones over ±12, the stated exception to the centre-expansion law — belongs in the **taper
|
||||
module Γ-W1-T1 extracts**, since that module is the one home of every map. T1 therefore
|
||||
appends a law to a module a previous wave created. Serial across waves by construction, the
|
||||
same shape as its `engine/voice.{h,cpp}` hand-off from W1-T5. **What would be wrong is a
|
||||
second taper defined inside `deck_values`' binding** — one home, appended to, not forked.
|
||||
|
||||
**The format ladder stays clean.** The loop enable maps onto the existing
|
||||
`SampleLoop::hasLoop`, which is already persisted and whose `start`/`end` are already written
|
||||
unconditionally — **no new field, no version bump** — so T1 keeps sole ownership of payload v15
|
||||
exactly as specced.
|
||||
unconditionally — **no new field, no version bump** — so T1 keeps sole ownership of **the
|
||||
phase's second payload rung** exactly as specced (v15 on `dev` as of 2026-08-01; read the
|
||||
ladder rather than assuming the number).
|
||||
|
||||
#### Γ-W2-T1 — `pitch-rate-deck`
|
||||
|
||||
@@ -1232,7 +1500,8 @@ existing Varisp|Presrv toggle, with both new controls wired through the engine.
|
||||
|
||||
**Surface boundary — owns:** `core/instrument/engine/play_params.h` +
|
||||
`core/instrument/map/play_seconds.h` (the two new fields),
|
||||
`core/instrument/map/component_state_io` + `params_payload` (**payload v15**),
|
||||
`core/instrument/map/component_state_io` + `params_payload` (**the phase's SECOND payload
|
||||
rung** — v15 on `dev` as of 2026-08-01; read the ladder, do not assume the number),
|
||||
`core/instrument/engine/voice.{h,cpp}` (the compounding and the note-on latch),
|
||||
`core/instrument/ui/deck_groups` (the PITCH/RATE descriptor **and** the three-state live
|
||||
predicate), `core/instrument/ui/deck_values` (the two new bindings). **Does not own** the
|
||||
@@ -1273,8 +1542,12 @@ by the time this track runs).
|
||||
caption row overtakes the 180 px knob row and the group exceeds 192). If the text will not
|
||||
fit at 80, narrow the `Varisp|Presrv` segments 48 → 44 (ceiling becomes 88) — **do not widen
|
||||
the group**.
|
||||
- **Payload v15** appends both fields as a strict suffix; a v14 blob lifts to rate 100 % /
|
||||
pitch 0 st, bit-identical playback.
|
||||
- **The payload rung** appends both fields as a strict suffix; the preceding version's blob
|
||||
lifts to rate 100 % / pitch 0 st, bit-identical playback.
|
||||
- **Both new `DeckParam`s are classified in the three-state predicate, and that classification
|
||||
is what puts them in the VST3 parameter list three waves later** — Rate `NoteOnLatched`,
|
||||
Pitch `Live`. Γ-W4-T1 derives the exposed set from this predicate rather than from a list
|
||||
of its own, so a mis-classification here is a mis-declared parameter there.
|
||||
|
||||
**Acceptance criteria.**
|
||||
- Rate at 50 % plays an octave down and half speed under Varispeed; at 200 %, an octave up and
|
||||
@@ -1293,7 +1566,8 @@ by the time this track runs).
|
||||
waveform marker.
|
||||
- The PITCH/RATE group measures **exactly 192 px**; adding the two `DeckParam`s produces a
|
||||
compile error in `isLiveDeckParam`'s exhaustive switch until they are classified.
|
||||
- A v14 project reopens at rate 100 % / pitch 0 st and sounds identical.
|
||||
- A project saved at the preceding payload version reopens at rate 100 % / pitch 0 st and
|
||||
sounds identical.
|
||||
|
||||
**Open questions.**
|
||||
- **None [Daniel].**
|
||||
@@ -1449,21 +1723,40 @@ track changes drawing, hit-testing and one editor-state retention rule — no fo
|
||||
|
||||
---
|
||||
|
||||
### Γ-W3 — The reflow
|
||||
### Γ-W3 — The reflow, and the bake correction
|
||||
|
||||
**Depends on Γ-W2 for:** the PITCH/RATE descriptor (W2-T1) — the reflow measures the real
|
||||
three-cell group, and laying it out against a forecast of that group means re-measuring
|
||||
afterward. **This is the whole reason the arrangement is late**, and it is why the canvas was
|
||||
split out of it into W1-T4.
|
||||
split out of it into W1-T4. **T2 depends on the same wave for a different reason:** rate and
|
||||
pitch offset must exist before the bake's reset list can name them.
|
||||
|
||||
**Depends on Γ-W1 for:** W1-T2's published meter/GR/clip state, which MASTER's deck draws
|
||||
(drawing against a stub would mean building the meter twice), and W1-T4's floor, budget
|
||||
constants and row predicate, which this track **consumes rather than re-derives**.
|
||||
constants and row predicate, which T1 **consumes rather than re-derives**. **T2 depends on
|
||||
W1-T2 for the limiter enable flag**, the third of the three values it must add.
|
||||
|
||||
**One track.** The row law, the group inventory and the double-height deck are one geometry
|
||||
decision spread over `knob_deck`, `deck_groups` and the deck painter. Splitting it would put two
|
||||
tracks in the same pure modules. **The window floor is no longer part of it** — W1-T4 set it
|
||||
two waves ago, and this track must not move it.
|
||||
**Depends on Phase Ξ for T2 — the phase's only EXTERNAL gate.** `Ξ-W2-T1
|
||||
(resample-bake-chain)` must have landed on `dev` before T2 dispatches. T2 amends what that
|
||||
track shipped; it cannot amend a branch.
|
||||
|
||||
**Two tracks, disjoint by surface — but T2's disjointness is CONDITIONAL and must be
|
||||
confirmed, not assumed.** T1 owns `ui/knob_deck`, `ui/deck_groups` (row-predicate
|
||||
consumption, FILTER's caption move, MASTER's inventory) and `shell/instrument/editor_paint_deck`.
|
||||
T2 owns the bake's reset step wherever Ξ-W2-T1 put it. **T2's first act is to read what
|
||||
actually shipped and confirm its reset surface touches none of T1's three modules.** If the
|
||||
shipped reset enumerates controls through `deck_groups` or `deck_values`, the two are not
|
||||
disjoint and **T2 serializes behind T1 inside the wave** — a named contingency, taken openly,
|
||||
not discovered at merge. That risk is real precisely because this plan cannot predict the
|
||||
shipped shape; predicting it is what put the phase in this position.
|
||||
|
||||
**Why T1 is one track.** The row law, the group inventory and the double-height deck are one
|
||||
geometry decision spread over `knob_deck`, `deck_groups` and the deck painter. Splitting it
|
||||
would put two tracks in the same pure modules. **The window floor is no longer part of it** —
|
||||
W1-T4 set it two waves ago, and this track must not move it.
|
||||
|
||||
**Neither track takes a payload rung.** T1 is layout only; T2 changes a reset list, not a
|
||||
format.
|
||||
|
||||
#### Γ-W3-T1 — `deck-reflow`
|
||||
|
||||
@@ -1572,6 +1865,226 @@ waveform band.
|
||||
is on row 2 (AMP binds at 55). No change is required; the comment stating the old ceiling
|
||||
stops being true and must be corrected (spec §7.2).
|
||||
|
||||
#### Γ-W3-T2 — `bake-reset-amendment`
|
||||
|
||||
**Goal.** Complete the resample bake's reset list against the control surface that now
|
||||
exists — the correction Phase Γ owes Phase Ξ because Ξ-W2-T1 shipped ahead of the sequencing
|
||||
this plan asserted.
|
||||
|
||||
**Consolidates:** nothing from the seventeen. It is a **correction obligation**, not a
|
||||
feature (see "Flagged for awareness" item 2).
|
||||
|
||||
**Spec:** `docs/product/instrument-control-surface.md` §3.4, and Ξ-W2-T1's own "Reset scope"
|
||||
block above — **which is the ratified rule this track applies, not a rule it may reinterpret.**
|
||||
|
||||
**Surface boundary — owns:** the bake's parameter-reset step, wherever Ξ-W2-T1 landed it, and
|
||||
its tests. **Does not own** the bake chain, the crossing architecture, the replace-vs-add
|
||||
decision, the capture path, any deck module, any painter, any parameter, or any
|
||||
`ComponentState` version. **It changes what a shipped list contains — nothing else.**
|
||||
|
||||
**Behavior.**
|
||||
- **Three values join the reset list**, all classified against Ξ-W2's own ratified rule
|
||||
("reset what the bake baked in"), all **reset**, none of them a new Daniel decision:
|
||||
**rate**, **pitch offset**, and **limiter enabled**. The limiter's reasoning is worth
|
||||
carrying rather than re-deriving: master gain is already on the reset list, so the bake
|
||||
includes the master stage, so the limiter's effect is in the audio.
|
||||
- **Verified against what shipped, not against what was predicted.** This plan named three
|
||||
values before either the bake or the controls existed. **Read Ξ-W2-T1's landed reset list
|
||||
first** and reconcile: if it already anticipated any of the three, say so and drop it; if
|
||||
it classified something differently from `docs/product/instrument-control-surface.md` §3.4,
|
||||
**the landed code is the fact and this plan is the prediction** — escalate the difference,
|
||||
do not silently overwrite either.
|
||||
- **Re-run Ξ-W2-T1's own "genuinely new parameter" check over everything Phase Γ added**, not
|
||||
just the three named. Γ also ships the loop enable (W2-T2) and raises the stage-time
|
||||
ceiling (W1-T1). Classify each **against the rule**: the loop enable is a loop fact whose
|
||||
effect is in the rendered audio (**reset**, with the loop points it travels with); the
|
||||
ceiling is not a parameter at all. State each disposition; silence is not one.
|
||||
- **Root note still survives.** The bake's most load-bearing exception is untouched by this
|
||||
track — capturing at root is what makes root survivable, and resetting it would detune
|
||||
every subsequent iteration.
|
||||
|
||||
**Acceptance criteria.**
|
||||
- After a bake, **rate reads 100 %, pitch offset 0 st, and the limiter reads bypassed** — and
|
||||
the root note, key-tracking and the VOICE group are still untouched.
|
||||
- **The bake stays audible and faithful with the new controls dialled in**: dial rate, pitch
|
||||
offset and the limiter, bake, and the neutral instrument playing the programmed note sounds
|
||||
as the dialled one did — the criterion Ξ-W2-T1 already carries, now actually exercised over
|
||||
Γ's controls.
|
||||
- **A reconciliation note in the track's review** stating, per value, whether the landed code
|
||||
already covered it, and recording any difference between what shipped and what §3.4
|
||||
predicted.
|
||||
- **No format change, no new field, no version bump, no change to the crossing architecture
|
||||
or the replace-vs-add decision.** A regression baseline proves the bake's audio is
|
||||
otherwise unchanged.
|
||||
|
||||
**Open questions.**
|
||||
- **No [Daniel] questions.** The rule is ratified and §3.4's classification is derived from
|
||||
it.
|
||||
- **[verify, FIRST]** the disjointness contingency in the wave header: read the shipped reset
|
||||
step and confirm it touches none of Γ-W3-T1's modules. If it does, serialize behind T1 and
|
||||
say so.
|
||||
- **Explicitly NOT this track's:** the two consequences automation adds to the bake — the
|
||||
reset having to notify the host, and a host lane re-imposing its curve onto baked audio.
|
||||
Both are **Γ-W4-T1's**, because that track creates them. Doing this correction once, before
|
||||
automation, and letting Γ-W4-T1 add its own obligation on top is deliberate: the
|
||||
alternative is an amendment to an amendment.
|
||||
|
||||
---
|
||||
|
||||
### Γ-W4 — VST3 parameters
|
||||
|
||||
**Depends on every earlier wave, and each dependency is a hard prerequisite rather than a
|
||||
courtesy:**
|
||||
|
||||
1. **← W1-T1.** The taper and the 10 s ceiling **are** the host-facing normalization, and
|
||||
W1-T1 is also what extracts them into the one pure module the host reads through. Declaring
|
||||
parameters against a taper that is still moving is the one-way door this whole phase is
|
||||
ordered around.
|
||||
2. **← W1-T2 and W2-T1.** Every control that could be a parameter must exist before the list
|
||||
is declared. The list is derived from the control inventory; an inventory still growing
|
||||
produces a list that has to be re-frozen, and it cannot be.
|
||||
3. **← W2-T1 specifically.** `isLiveDeckParam` becoming three-valued is the *prerequisite* of
|
||||
the classification, not an incidental: the exposed set is exactly `Live ∪ NoteOnLatched`.
|
||||
4. **← W3-T1.** MASTER's inventory (limiter toggle, GR bubble, reserved cell) is the last
|
||||
change to what controls exist at all.
|
||||
5. **← W3-T2.** The bake's reset list must already be complete, so this track adds the
|
||||
host-notification obligation once rather than amending an amendment.
|
||||
|
||||
**One track.** The storage decision governs every part of the work — the projection rule, the
|
||||
migration path, what `getParamNormalized` returns, and what the bake's reset must do — exactly
|
||||
as Ξ-W2-T1's crossing decision governs its chain. Every candidate split (a pure
|
||||
model/classification half and a host-wiring half) is **serial**, so it buys no concurrency and
|
||||
puts the decision on one side of a boundary and its consequences on the other.
|
||||
|
||||
#### Γ-W4-T1 — `vst3-parameter-set`
|
||||
|
||||
**Goal.** The instrument reports its automatable parameters to the host, under a frozen id
|
||||
contract and a logical order — which also hands it REAPER's whole per-parameter modulation
|
||||
block (LFO, envelope follower, MIDI link, parameter linking) for free.
|
||||
|
||||
**Consolidates:** nothing from the seventeen. **Ruling 1** (Daniel, 2026-08-01): *"correct the
|
||||
phase gamma plan to account for complying with the VST3 standard for parameter reporting… by
|
||||
the end of gamma we have the automatable params reported. Make the parameter order logical."*
|
||||
|
||||
**Spec:** `docs/product/parameter-automation.md` — **§§6–10 are the specification; §§1–5 are
|
||||
the analysis behind it.** Read §6.1 (storage), §6.3 (the freeze), §7 (the classification) and
|
||||
§8 (the one-way-door sweep) before scoping. **Today the plugin has zero parameters:**
|
||||
`ReaSamplerProcessor::initialize` (`reasampler_processor.cpp:56-73`) never populates
|
||||
`SingleComponentEffect::parameters`, so `getParameterCount()` returns the SDK default 0. This
|
||||
track introduces the whole surface.
|
||||
|
||||
**Surface boundary — owns:** a **new pure parameter-identity module** (the frozen id table,
|
||||
the `DeckParam` ↔ `ParamID` mapping, the derived exposed set, the unit assignment — with its
|
||||
own `<module>_tests` target), `shell/instrument/reasampler_processor` + `processor_state` (the
|
||||
`IEditController` parameter surface and the `IParameterChanges` read),
|
||||
`shell/instrument/editor_controls.cpp` and the editor's drag-commit sites (the
|
||||
`beginEdit`/`performEdit`/`endEdit` bracketing), and the bake's reset step **for the
|
||||
notification path only**. **Does not own** the taper (W1-T1's module, consumed), any control's
|
||||
value semantics, any deck geometry, or the bake's reset *membership* (W3-T2's).
|
||||
|
||||
**Behavior.**
|
||||
- **The blob stays authoritative; a parameter is a THIRD SURFACE onto the one model** —
|
||||
a peer of the deck knob and the overlay node, not a second copy of the value.
|
||||
`docs/product/parameter-automation.md` §6.1 states the load, host→plugin, plugin→host and
|
||||
save rules, and the two verified findings that closed the fork: this plugin is a
|
||||
`SingleComponentEffect`, where the SDK itself collapses `IComponent::setState` and
|
||||
`IEditController::setState` (`vstsinglecomponenteffect.h:41-47`), so there is one state and
|
||||
§3.3's drift hazard describes a split-component design we do not use; and the blob is a
|
||||
**cross-artifact contract** the extension's `instrument_drop` writes, which
|
||||
parameters-as-truth would silently make partial.
|
||||
- **`ParamID` is an independent, hand-assigned, FOREVER-FROZEN table** — blocks of 100 per
|
||||
deck group, steps of 10 within a block, a curve dial at its outer knob's id + 1, blocks
|
||||
starting at 1000. §6.2 for the layout and why hand-assignment beats derivation; **§6.3 for
|
||||
the freeze invariant, which is to be stated in the table's header with the same force as
|
||||
the command-id strings, the class UIDs and the payload field order.**
|
||||
- **The exposed set is DERIVED from `isLiveDeckParam` / `liveCommitFor`, never
|
||||
hand-maintained** — a control is a parameter iff its class is `Live` or `NoteOnLatched`.
|
||||
**44 parameters** at the end of Γ-W3, enumerated by group in §7.1.
|
||||
- **Everything else is OMITTED from the list entirely**, not exposed-and-flagged: the reload
|
||||
and rebuild tiers, all structural state, and the limiter enable (§3.8, settled). §7.2
|
||||
states why omission beats `kIsReadOnly`, and names the limitation plainly — the user cannot
|
||||
automate filter on/off, play mode, the pitch engine, Staged↔Spline or polyphony, and the
|
||||
unlock is to give the control a live path first.
|
||||
- **`normalizedParamToPlain` / `plainParamToNormalized` / `getParamStringByValue` /
|
||||
`getParamValueByString` route through W1-T1's taper module and the editor's own
|
||||
formatters.** Three functions that agree today is a defect; the host's normalization, the
|
||||
needle angle and the overlay node must be the same function.
|
||||
- **`IParameterChanges` is observed at BLOCK boundaries, stated in the header** — the last
|
||||
point in a block wins. Sample-accurate application would put a per-sample "did anything
|
||||
change" question on the per-voice-per-sample path, which the phase-wide guardrail forbids.
|
||||
- **A host parameter change takes the control's existing commit tier and no other.** Nothing
|
||||
on the automation path may reach `reloadInstrument` or `rebuildVoiceEngine` — which §7.2's
|
||||
omissions guarantee structurally rather than by care.
|
||||
- **`IUnitInfo`: one unit per deck group.** Order per **Γ-F7** (§6.4) — **recommendation
|
||||
signal flow; Daniel's call, and it must be closed before this track dispatches.**
|
||||
- **No `kIsBypass` on anything.** The plugin is an instrument and exposes no bypass
|
||||
parameter; the limiter is a safety device, not a bypass, and binding it there would hand
|
||||
the host a control that restarts the component.
|
||||
- **The bake's reset gains a notification obligation** (§9): every internal writer of a value
|
||||
that is an exposed parameter must go through the one `beginEdit`/`performEdit`/`endEdit`
|
||||
path, and the bake's reset is the codebase's first non-gesture writer. **Enumerating those
|
||||
sites is part of this track**, not a follow-up.
|
||||
- **Two adjacent SDK surfaces are assessed, with dispositions, so they are not re-surveyed:**
|
||||
`IMidiMapping` is **in scope and nearly free** (a CC → `ParamID` map, one function);
|
||||
`IParameterFunctionName` is **not implemented** (its vocabulary is compressor/panner
|
||||
semantics that name nothing here); `IAutomationState` is **not implemented** (it reports the
|
||||
host's automation mode for the whole plug-in, not per parameter, so it cannot answer the one
|
||||
question §9 would have wanted it for).
|
||||
|
||||
**Acceptance criteria.**
|
||||
- **The host lists exactly the derived set, in the ruled order, with no parameter the
|
||||
predicate does not classify `Live` or `NoteOnLatched`** — asserted against the predicate,
|
||||
not against a literal count.
|
||||
- **Every id in the table is asserted unique, in its group's block, and on its step** — and a
|
||||
test fails if any id changes value, which is what makes the freeze mechanical rather than
|
||||
cultural.
|
||||
- **Every parameter round-trips `plain → normalized → plain` exactly at its default**, so a
|
||||
host's reset-to-default and the editor's double-click land on the same value. If this fails,
|
||||
it is a W1-T1 defect surfacing here, not a defect of this track.
|
||||
- **`getParamStringByValue` prints what the editor prints**, unit for unit, at the same
|
||||
values.
|
||||
- **A host automation lane moving a Live parameter moves a sounding note; a lane moving a
|
||||
NoteOnLatched parameter takes effect on the next note and does NOT trigger a reload or an
|
||||
engine rebuild** — assert the tier, not just the sound.
|
||||
- **No automation path reaches `reloadInstrument` or `rebuildVoiceEngine`.**
|
||||
- **A project saved before this change opens with every parameter reading the blob's value
|
||||
and sounds identical**; a project saved by this build opens in an older binary with its
|
||||
sound intact; and a project with automation drawn, saved and reopened, replays against the
|
||||
same plain values.
|
||||
- **`process()` takes no new indirection and no new per-sample work** — the parameter read is
|
||||
a block-boundary act, on the existing live-publish path.
|
||||
- **The bake's reset notifies the host**, verified by the host's displayed value following it
|
||||
rather than snapping back on next touch.
|
||||
- **The double-processing limitation is documented, not discovered** — a bake whose
|
||||
reset-class parameter carries a host lane is a named boundary of the bake's fidelity claim
|
||||
(§9), stated in the product doc and in this track's review.
|
||||
|
||||
**Open questions.**
|
||||
- **[Daniel] — Γ-F7, the parameter order.** Signal flow (recommended) or the editor's visual
|
||||
rows. **This is the only unanswered [Daniel]-class question in this plan.** It blocks
|
||||
nothing until this track dispatches, and it cannot be closed by proposal at review: a
|
||||
forever commitment is Daniel's. §6.4.
|
||||
- **[verify, FIRST]** that REAPER calls `setState` (not `setComponentState`) on a
|
||||
single-component plug-in, and the ordering of `setState` against the first
|
||||
`IParameterChanges` block after a project load. §6.1 is built on the SDK's own
|
||||
name-collapse; **verify it in the DAW before wiring, and do not build on the paragraph
|
||||
alone.**
|
||||
- **[propose at review]** promoting **key-track** and **Trigger length** from `Reload` to
|
||||
`NoteOnLatched` (§7.4). Both are excluded from the live set *for the note-on-latch reason*
|
||||
in the predicate's own words, so the promotion aligns routing with documented semantics —
|
||||
and it is what makes them automatable at all. **If either promotion is refused, that
|
||||
control simply drops out of the parameter list.** The list follows the predicate; the
|
||||
predicate is never bent to fill the list.
|
||||
- **[propose at review]** whether to ship a default `IMidiMapping` CC table here or leave MIDI
|
||||
control to REAPER's host-side learn. Either is defensible; **skipping it silently is not.**
|
||||
- **[propose at review]** whether this track spends the reserved payload rung. §6.1 says
|
||||
nothing new is persisted and therefore it should not; if the `setState` verification says
|
||||
otherwise, it takes the reserved rung and says so.
|
||||
- **Closed, do not reopen:** Rate lifted from latched to live (§3.5 records the cost); the
|
||||
limiter enable made automatable (§3.8 — its one reopening condition is the `docs/TODO.md`
|
||||
reload/activation decoupling, and the answer is to do that first, not to re-litigate the
|
||||
classification).
|
||||
|
||||
---
|
||||
|
||||
## Traceability — all seventeen items
|
||||
@@ -1613,13 +2126,20 @@ proof it exists to give.
|
||||
from `TODO-1.0.md`, and not a track this plan originally scoped. The second such track
|
||||
in this plan today; if others appear, they belong on this list rather than in the
|
||||
table.
|
||||
- **All of Phase Γ** (`pg-*`). Eight tracks across three waves, from a direct interview with
|
||||
Daniel (2026-08-01), not from `TODO-1.0.md`. Listed here as a block rather than per track,
|
||||
because the whole phase is outside the source doc; the product reasoning lives in
|
||||
`docs/product/instrument-control-surface.md` and the automation scoping it defers in
|
||||
`docs/product/parameter-automation.md`. Γ-W3-T1 additionally **discharges** the
|
||||
`docs/TODO.md` deck-rework entry, whose original "one row of taller decks with
|
||||
within-deck stacking" shape Daniel explicitly superseded.
|
||||
- **All of Phase Γ** (`pg-*`). **Ten tracks across four waves**, from a direct interview with
|
||||
Daniel (2026-08-01) and his four later rulings the same day, not from `TODO-1.0.md`. Listed
|
||||
here as a block rather than per track, because the whole phase is outside the source doc;
|
||||
the product reasoning lives in `docs/product/instrument-control-surface.md` and the
|
||||
parameter system's in `docs/product/parameter-automation.md` §§6–10. **Two `docs/TODO.md`
|
||||
entries are discharged by this phase, not deferred again:** Γ-W3-T1 discharges the
|
||||
deck-rework entry (whose original "one row of taller decks with within-deck stacking" shape
|
||||
Daniel explicitly superseded), and **Γ-W1-T1 discharges "Raise the stage-time ceiling above
|
||||
2 s"** (Γ-F3 reversed).
|
||||
- **Γ-W3-T2 `bake-reset-amendment` is a CORRECTION, not a feature**, and belongs on this list
|
||||
for a different reason from the others: it exists only because Ξ-W2-T1 shipped ahead of this
|
||||
plan's sequencing claim. If more corrections of this shape appear, they belong here rather
|
||||
than in the table — the table is a completeness proof over `TODO-1.0.md`, and a correction
|
||||
has no source row to point at.
|
||||
|
||||
### Deliberate compressions
|
||||
|
||||
@@ -1681,26 +2201,37 @@ Phase Ξ — The resample loop (W1 concurrency-safe with Θ from Θ-W
|
||||
W1 Consolidated tracking, and the programmed-note model
|
||||
T1 tracking-consolidation .................. 17
|
||||
T2 note-program-model ...................... 15 (model)
|
||||
W2 The bake chain [requires all of Phase Θ, and Phase Γ before it]
|
||||
W2 The bake chain [ran AHEAD of Γ; its reset list is corrected by Γ-W3-T2]
|
||||
T1 resample-bake-chain ..................... 15 (chain)
|
||||
W3 The capture-signal popup
|
||||
T1 capture-signal-popup .................... 15 (popup)
|
||||
|
||||
Phase Γ — The instrument's control surface (none of the seventeen; runs before Ξ-W2)
|
||||
Phase Γ — The instrument's control surface (none of the seventeen; ends with VST3 params)
|
||||
W1 Foundations [5 tracks, disjoint by surface]
|
||||
T1 knob-interaction-law ....... modifiers + ms/semitone tapers + reset bypass
|
||||
T2 master-bus-audio ........... limiter + meter ballistics + dynamic PDC [payload v14]
|
||||
T1 knob-interaction-law ....... modifiers + ONE taper module + reset bypass
|
||||
+ 10 s ceiling + AHDSR schematic axis [Ruling 2]
|
||||
T2 master-bus-audio ........... limiter + meter ballistics + dynamic PDC [rung 1]
|
||||
T3 contour-trace-curves ....... staged traces draw curved, knot on its trace
|
||||
T4 editor-floor-and-row-law ... floor 1190x680 + budget constants + row predicate
|
||||
T5 preserve-time-stretch ...... real stretcher [measure-and-report gate]
|
||||
W2 New controls, and the overlay's marks [2 tracks]
|
||||
T1 pitch-rate-deck ............ Rate + Pitch, Varisp/Presrv compounding [payload v15]
|
||||
T1 pitch-rate-deck ............ Rate + Pitch, Varisp/Presrv compounding [rung 2]
|
||||
T2 loop-crossfade-ux .......... four-mark grammar; fade painted where it is heard
|
||||
W3 The reflow [1 track]
|
||||
W3 The reflow, and the bake correction [2 tracks]
|
||||
T1 deck-reflow ................ two rows + double-height MASTER, by construction
|
||||
T2 bake-reset-amendment ....... the Xi correction Gamma owns [needs Xi-W2-T1 on dev]
|
||||
W4 VST3 parameters [1 track]
|
||||
T1 vst3-parameter-set ......... 44 derived params, frozen id table [Ruling 1]
|
||||
[rung 3 RESERVED, spent only if verify says so]
|
||||
[OPEN: Gamma-F7, the parameter order — Daniel]
|
||||
|
||||
Resequenced 2026-08-01: the reflow split canvas (W1-T4) from arrangement (W3-T1), and
|
||||
preserve-time-stretch moved W4 -> W1-T5, which retires Rate's interim stand-in.
|
||||
Shared files, named: engine/CMakeLists.txt (W1-T2 | W1-T5) and editor_session.cpp
|
||||
(W2-T1 | W2-T2) — both textual adjacency, not semantic contention.
|
||||
Resequenced 2026-08-01, three times: the reflow split canvas (W1-T4) from arrangement
|
||||
(W3-T1); preserve-time-stretch moved W4 -> W1-T5, retiring Rate's interim stand-in; then
|
||||
Ruling 1 added W4 and Ruling 2 grew W1-T1.
|
||||
Payload rungs are RELATIVE, not absolute — read kParamsPayloadVersion on dev and take the
|
||||
next three above it. On dev at 2026-08-01 that is v14 / v15 / v16-reserved.
|
||||
Shared files, named: engine/CMakeLists.txt (W1-T2 | W1-T5), ui/CMakeLists.txt
|
||||
(W1-T1 | W1-T3), editor_session.cpp (W2-T1 | W2-T2) — all textual adjacency, not
|
||||
semantic contention. W3-T2's disjointness from W3-T1 is CONDITIONAL: confirm it against
|
||||
what Xi-W2-T1 shipped, and serialize behind T1 if it does not hold.
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user