docs(product): spec S18 — VST3 channel isolation (beta ReaSampler 9000 pairs with beta extension only)
This commit is contained in:
@@ -1027,6 +1027,104 @@ artifact, not extension-only.
|
||||
single- and multi-capture payloads; FX-button hit resolution (pure geometry where it
|
||||
can be factored out); M11 OS drag-out and internal bank-to-bank drag both unchanged.
|
||||
|
||||
## S18 — VST3 channel isolation: a beta ReaSampler 9000 that pairs with the beta extension only
|
||||
**Goal:** Extend Phase V's beta/stable channel split (V4 — the *extension* is fully
|
||||
isolated per channel) to the **ReaSampler 9000 VST3 instrument**, so a beta-built VST is a
|
||||
distinct plugin that pairs only with the beta extension, and a stable VST pairs only with
|
||||
stable — installable side-by-side in one REAPER with no collision. **What already works
|
||||
(established from the tree, not re-derived): data pairing is done.** `ext_keys.h`'s
|
||||
namespace is channel-derived (`kProjExtNamespace()` → `app_version::extStateNamespace()`),
|
||||
so a beta-compiled VST already *reads* `"reasampler_beta"`; every wire key (`banks`,
|
||||
`assign_request`, S9's future generation key, any future key) is a plain constant *under*
|
||||
that namespace, so channel data-isolation is **structural, not per-key** — new keys inherit
|
||||
it automatically. **What is missing is the VST's *plugin identity*:** its class UID, binary
|
||||
filename, and display strings are single-valued today (same for both channels → a
|
||||
UID/filename collision if both are installed). This wave closes that. Mirrors V4's
|
||||
philosophy: **one channel per binary; all identity derives from the ONE
|
||||
`REASAMPLER_CHANNEL_IS_BETA` bit via `app_version`, no scattered `#ifdef`s.** CONTEXT.md
|
||||
§Phase S (VST3 channel identity — the UID-pair invariant + the pairing surface). Product
|
||||
framing: `docs/product/midi-playback.md` §Addendum — VST channel isolation.
|
||||
**Consistent with V4 (make the invariant explicit):** V4 already committed the extension to
|
||||
*two* forever-stable command-id families and *two* forever-stable ext-state namespaces. This
|
||||
wave commits the *instrument* to the parallel permanent cost: **two forever-stable VST3 class
|
||||
UIDs** — the existing stable UID (S-NAME-1, locked) and a second beta UID (minted once,
|
||||
locked forever the same way). Both are frozen forever; the channel bit selects which is
|
||||
*compiled into this binary*. **One class per binary, not both in one binary** — this mirrors
|
||||
V4's fully-isolated-binary philosophy (a channel build carries only its own identity), keeps
|
||||
the factory registration a single `DEF_CLASS2`, and means a beta-installed VST cannot present
|
||||
the stable identity.
|
||||
**Verify (in DAW):** the stable VST3 (`reasampler_9000.vst3`, existing UID) and a beta VST3
|
||||
(`reasampler_9000_beta.vst3`, the new UID) install side-by-side in one REAPER and both appear
|
||||
in the FX browser as distinct plugins ("ReaSampler 9000" and "ReaSampler 9000 beta"); a beta
|
||||
instance reads only the beta extension's banks (its browser shows the beta banks, never
|
||||
stable's) and a stable instance only stable's; a project saved with a **beta** instance
|
||||
reopens rebinding to the beta VST (not the stable one) and restores its state; a project
|
||||
saved with a **stable** instance opened where only the beta extension has banks shows a clean
|
||||
empty "pick a capture" state (S10 policy), **not** an error; the S-NAME-1 save-rename-reopen
|
||||
compat test extends to the beta UID (a beta instance rebinds by its own UID). **Nothing plays
|
||||
differently** — this is an identity/pairing wave, no engine change.
|
||||
**Depends on:** V4 (the `app_version` channel-identity single-source this extends), S1 (the
|
||||
VST3 factory + `reasampler_vst.h` identity constants + the CMake second target it edits).
|
||||
Consumes the S4 live-state seam only to *demonstrate* pairing; adds no new seam. **Disjoint
|
||||
from the in-flight waves:** touches `vst_entry.cpp`, `reasampler_vst.h`, and the CMake VST3
|
||||
block — S9 (ext_keys additions) and S15/S16 (processor/editor) are elsewhere. **ext_keys
|
||||
coordination note:** S9's new generation key is a plain constant under the channel-derived
|
||||
namespace, so it inherits this isolation with no S18 change; no coordination edit is needed —
|
||||
only the shared awareness that all wire keys must live under `kProjExtNamespace()` (already
|
||||
the rule). Dispatchable in parallel with, or immediately after, the in-flight waves.
|
||||
|
||||
- [ ] **Beta VST3 class UID (the permanent commitment).** Mint a second FOREVER-STABLE
|
||||
class UID in `reasampler_vst.h` alongside the existing `kReaSamplerProcessorUID`
|
||||
(`REASAMPLER_PROC_UID_1..4`) — a distinct forever-frozen constant (e.g.
|
||||
`REASAMPLER_PROC_UID_BETA_1..4` + `kReaSamplerProcessorUIDBeta`). The channel bit selects
|
||||
which UID the factory registers (`DEF_CLASS2`'s `INLINE_UID` + the runtime `FUID`) —
|
||||
compile-time, one class per binary. **Both UIDs are frozen forever once shipped** — the
|
||||
same lock the stable UID carries (a saved project records the UID and rebinds by it; a
|
||||
changed UID orphans every saved beta instance). Record the invariant in the header's
|
||||
UID-lock comment. **Fork S18-F1 (flagged — Daniel's call):** whether the beta UID is
|
||||
minted *now* (locked from this wave) or deferred to *first beta release* of the VST
|
||||
(leaving a compile-time placeholder that must be replaced-once-and-locked before any beta
|
||||
VST ships). Lean: **mint now** — mirrors how the stable UID was minted at the S1 spike
|
||||
(locked long before ship), removes a "remember to mint before shipping" landmine, and the
|
||||
cost of an unused-until-beta constant is zero. Flagged because it is a forever commitment.
|
||||
- [ ] **Channel-derived binary + display identity (no scattered `#ifdef`s — the V4
|
||||
invariant).** Route all VST identity through `app_version` accessors, mirroring how the
|
||||
extension's `OUTPUT_NAME` already derives from `REASAMPLER_OUTPUT_NAME`. (a) **Binary
|
||||
name:** the CMake VST3 target's `OUTPUT_NAME` forks by channel — `reasampler_9000`
|
||||
(stable) / `reasampler_9000_beta` (beta) — driven by the same `REASAMPLER_CHANNEL` config
|
||||
the extension target reads (add a `REASAMPLER_VST_OUTPUT_NAME` beside
|
||||
`REASAMPLER_OUTPUT_NAME`, or reuse the one channel bit; **check what the extension does and
|
||||
mirror it exactly**). (b) **Display name:** the factory `DEF_CLASS2` plug-in display string
|
||||
is "ReaSampler 9000" / "ReaSampler 9000 beta" — sourced from an `app_version` VST-name
|
||||
accessor (a new channel-derived accessor beside `binaryName()`/`dockTitle()`, e.g.
|
||||
`vstPluginName()`), not a literal in `reasampler_vst.h`/`vst_entry.cpp`. (c) **Editor title
|
||||
band + S6 embed-strip label** are channel-aware from the same accessor. All fan out from the
|
||||
ONE channel bit — no per-file `#ifdef`.
|
||||
- [ ] **Factory vendor/version strings channel-aware where V4 does the equivalent.** The
|
||||
`BEGIN_FACTORY` vendor/url/email and the `PClassInfo2` version string
|
||||
(`REASAMPLER_VST_VERSION`, currently a fixed `"0.1.0.0"`) align with the channel where the
|
||||
extension's V4 equivalents do — the version display carries the `-beta` render
|
||||
(`appVersion()` already yields `"0.9.01-beta"` on beta); the vendor strings stay shared
|
||||
unless V4 qualified them (**check V4's treatment and match it** — V4 kept the lane-name
|
||||
prefix shared, so shared-where-V4-shares is the default). No new forever-stable string
|
||||
beyond the UID and the id-family V4 already owns.
|
||||
- [ ] **Pairing-surface invariant recorded (no new code — a documented guarantee).** Write
|
||||
the complete pairing surface as an invariant in CONTEXT.md: a channel's VST talks to that
|
||||
channel's extension **only**, because (1) plugin identity (UID + filename + display) is
|
||||
channel-forked here, and (2) **all** wire keys — `banks`, `assign_request`, S9's
|
||||
generation key, and any future key — live under the channel-derived `kProjExtNamespace()`,
|
||||
so the beta VST's bridge reads only `"reasampler_beta"`. The invariant to write: **channel
|
||||
isolation is structural — no per-key opt-in — so a future wire key that forgets to isolate
|
||||
is impossible by construction** (it keys under the namespace accessor, not a raw literal).
|
||||
This is the guard that S9/S8/S17's cross-artifact keys inherit isolation for free.
|
||||
- [ ] **DAW-verify contract (the acceptance gate, no unit test — identity is a shell fact).**
|
||||
Both channels installed side-by-side: each browser sees only its channel's banks; a
|
||||
stable-project + beta-VST opens clean-empty (not error); the S-NAME-1 rename/rebind compat
|
||||
test extended to the beta UID (save a beta instance, confirm it rebinds by the beta UID on
|
||||
reopen). The pure `app_version` accessors (binary/display name per channel) are CTest-green
|
||||
in `app_version_tests` (extend the existing V4 channel-string assertions to the new VST
|
||||
accessors); the UID selection + factory wiring are DAW-verified (no host-free test path).
|
||||
|
||||
## Phase S — held and optional-forever (noted, not specified)
|
||||
- **Tier 2 — "expressive" (HELD).** Velocity layers, round-robin (anti-machine-gun),
|
||||
full ADSR, per-sample tuning/gain trim, sustain loops. The next depth increment once
|
||||
|
||||
Reference in New Issue
Block a user