docs: record Phase Gamma Wave 4's landed track and collapse the wave to it
This commit is contained in:
@@ -1248,3 +1248,75 @@ unlimited — and Daniel has ruled that a future track will change the bake to p
|
||||
limiter. Until that lands this is a recorded, known limitation, not an oversight.
|
||||
|
||||
**Neither track has been verified in a running DAW; both are asserted in CTest only.**
|
||||
|
||||
### Γ-W4-T1 — vst3-parameter-set
|
||||
|
||||
The instrument now reports its automatable parameters to the host: 44 of 44 issue, under a
|
||||
FOREVER-FROZEN `ParamID` table — blocks of 100 per deck group in signal-flow order, steps
|
||||
of 10 within a block, a curve dial at its outer knob's id + 1 — each with a real plain
|
||||
range, `units` string and display precision at the host boundary, not a raw normalized
|
||||
float. The exposed set is DERIVED from `deckParamCommit` / `liveCommitFor`, never
|
||||
hand-maintained: a control qualifies iff its class is `Live` or `NoteOnLatched`. Everything
|
||||
else — play mode, the pitch engine, filter enable, the three Staged↔Spline toggles, voice
|
||||
count, Poly|Mono, Retrigger|Legato, and the limiter enable — is OMITTED from the list
|
||||
entirely rather than exposed read-only, a named limitation rather than a silent one. A new
|
||||
pure module, `core/instrument/param` (`param_id`, `param_units`, `param_format`,
|
||||
`param_live`, `param_merge`), holds the id table, the plain-value layer, the one formatter
|
||||
per unit category (eight of them), and the audio thread's block-boundary merge decision;
|
||||
`shell/instrument/instrument_params` adapts it onto `Steinberg::Vst::Parameter` and decides
|
||||
nothing itself.
|
||||
|
||||
**Both VST3 delivery channels are serviced.** An earlier pass routed host automation
|
||||
through `IEditController::setParamNormalized` alone — the SDK documents that as the
|
||||
GUI-update channel only ("should update the according GUI element(s) only") — while
|
||||
`ProcessData::inputParameterChanges` is the audio-side one; the SDK's own
|
||||
`SingleComponentEffect` sample (`public.sdk/samples/vst/again/source/againsimple.cpp`)
|
||||
drains the queue in `process()` *and* implements `setParamNormalized`. Both are now
|
||||
serviced.
|
||||
|
||||
**A host automation point's authority is bounded, not permanent.** It outranks the model
|
||||
only between the point landing and the UI thread folding it into the model and
|
||||
republishing — at most one UI tick — never a later restore, bake reset, or knob move. An
|
||||
earlier pass made the hold permanent, which silently defeated `setState`, preset load,
|
||||
undo, and the bake's reset for any parameter that had ever carried an automation point.
|
||||
The model is now written down in full — `shell/instrument/CLAUDE.md`'s "THE AUTHORITY
|
||||
MODEL" section — and enforced by the pure `param_merge`; `test_param_merge` asserts both
|
||||
halves: that a held point outranks the model until the model catches up, and that a writer
|
||||
after the release reaches the audio again.
|
||||
|
||||
**Two rulings, both Daniel, 2026-08-02.** (1) Pitch key-track and Trigger length promote
|
||||
from `Reload` to `NoteOnLatched` — the promotion that takes the count to 44 of 44 and
|
||||
issues ids 1000 and 1450. It was **not** the predicate-only change the plan anticipated:
|
||||
key-track lives on `InstrumentParams`, not `PlaySeconds`, so the host's write path could
|
||||
not reach it without `LiveValues` and `foldLive`'s input widening and `Voice::start`
|
||||
taking the two latched values as arguments beside rate; the new `param::valueHomeFor`
|
||||
guard closes the class of bug this exposed (a promoted control with no home would have
|
||||
no-oped silently in both directions) by asserting every exposed control has a home and
|
||||
branching the shell's own read/write paths on it. (2) The curve-shape dials' ±0.01
|
||||
snap-to-centre band now applies on the mouse-drag path only, never on a host-facing map —
|
||||
*"our continuous ranges should be continuous."*
|
||||
|
||||
**Two adjacent SDK surfaces were assessed and left unimplemented, with dispositions
|
||||
recorded rather than re-surveyed later.** `IMidiMapping` — no CC vocabulary fits what's
|
||||
exposed, and REAPER's own per-parameter MIDI learn is expected to cover the case.
|
||||
`IParameterFunctionName` and `IAutomationState` are also not implemented; the latter
|
||||
reports the host's automation mode for the whole plug-in, not per parameter, so it cannot
|
||||
answer the bake's "is this parameter automated" question.
|
||||
|
||||
**The bake's reset now notifies the host, and its one remaining gap is named rather than
|
||||
hidden.** Every internal writer of an exposed parameter's value goes through the one
|
||||
`beginEdit`/`performEdit`/`endEdit` path, the bake's reset included. What it cannot do:
|
||||
clear a host automation lane. If a reset-class parameter carries one, the lane replays its
|
||||
curve onto audio the bake already baked that processing into — double processing — and
|
||||
`IAutomationState`'s whole-plugin (not per-parameter) granularity means there is no way to
|
||||
detect or refuse it. Documented as a boundary of the bake's fidelity claim, not discovered
|
||||
later as a bug against Phase Ξ.
|
||||
|
||||
**The per-sample voice path is byte-identical across the whole track.**
|
||||
|
||||
**Not verified in a running DAW — CTest-asserted only.** `docs/TODO.md` carries the
|
||||
residual DAW-verification items: whether REAPER renders `ParameterInfo::units` beside the
|
||||
formatted string, whether REAPER's MIDI learn actually covers the un-shipped `IMidiMapping`
|
||||
case, the three migration round trips (a pre-parameter project, a save/reopen in an older
|
||||
binary, automation drawn and replayed), whether an offline render replays automation, and
|
||||
whether REAPER restores instance state through `setState` rather than `setComponentState`.
|
||||
|
||||
Reference in New Issue
Block a user