Service both VST3 parameter channels, and promote pitch key-track and Trigger length so all 44 ids issue
The SDK's own single-component sample drains inputParameterChanges in process() and implements setParamNormalized; automation was reading the GUI channel alone. The audio thread now patches a block it solely owns.
This commit is contained in:
@@ -336,10 +336,18 @@ invariant Θ-W1-T1 was run to establish.
|
||||
> automation and is not a defect to design away — but it has one sharp consequence for the
|
||||
> resample bake, and that is §9.
|
||||
|
||||
**[verify] at the track, before wiring:** 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. Verify against the vendored SDK
|
||||
and in the DAW — do not build on the paragraph above without it.
|
||||
**SETTLED at the track, from the vendored SDK.** The delivery question the `[verify]` here
|
||||
bundled is answered by the headers rather than by the DAW: `setParamNormalized` is documented as
|
||||
the GUI-update channel (*"should update the according GUI element(s) only"*,
|
||||
`ivsteditcontroller.h`), and `ProcessData::inputParameterChanges` is the audio-side one — the
|
||||
SDK's own `SingleComponentEffect` sample services BOTH
|
||||
(`public.sdk/samples/vst/again/source/againsimple.cpp`), and so do we. The `setState` ordering
|
||||
half dissolves with it: an automation point held by the audio thread is re-applied over every
|
||||
merge, so a written lane outranks the restore whichever way round the two arrive, which is
|
||||
VST3's own authority rule rather than a race. **The audio thread cannot run the model path**
|
||||
(`resolvePlay` copies velocity curves and spline contours, so it allocates), so the drain patches
|
||||
the live block in place through one pure RT-safe function whose routing is pinned by an
|
||||
exhaustive equivalence test against the model path.
|
||||
|
||||
### 6.2 The ID space: hand-assigned constants in one frozen table
|
||||
|
||||
@@ -897,11 +905,16 @@ state fits them exactly:
|
||||
- **Trigger length** — *"resolves `playEnd_`, a fact about the note, not a setting of it."*
|
||||
Same shape.
|
||||
|
||||
**[propose at review, Γ-W4-T1]** promote both. The promotion aligns the routing with the
|
||||
predicate's own stated semantics — and it is what makes them automatable, since today they
|
||||
would re-decode a WAV per automation point. **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.
|
||||
**RULED (Daniel, 2026-08-02): promote both.** Ids 1000 and 1450 issue; the count is 44 of 44.
|
||||
The promotion aligns the routing with the predicate's own stated semantics — and it is what
|
||||
makes them automatable, since otherwise they would re-decode a WAV per automation point.
|
||||
|
||||
**It was not the predicate-only change this section implied.** Key-track lives on
|
||||
`InstrumentParams`, not `PlaySeconds`, so the host's write path could not reach it and id 1000
|
||||
would have no-oped in both directions with nothing failing to compile; both controls also had to
|
||||
reach the engine, which widened `LiveValues` and `foldLive`'s input and gave `Voice::start` the
|
||||
two latched values as arguments beside the rate. `param::valueHomeFor`, asserted over the
|
||||
exposed set, is what makes the next promotion of this shape a test failure instead of a silence.
|
||||
|
||||
**Not promoted, and not proposed for promotion: Rate to Live.** §3.5 records the cost;
|
||||
that paragraph is the first thing to read if it is ever proposed.
|
||||
|
||||
Reference in New Issue
Block a user