docs(product): spec Phase S sampling modes (S15 Trigger/Gate) + pitch envelope (S16)

Gate: AHDSR + loops; Trigger: fade-in / %-length / fade-out, note-off-immune.
Start point joins the instrument-side overrides. Pitch env is a per-frame
ratio multiply on the existing core — no resampler rewrite. WDL swept:
sinc resampler held as optional upgrade; no elastique-class stretch in WDL.
This commit is contained in:
2026-07-26 20:09:15 -04:00
parent 991c190bb8
commit c64ab687bf
3 changed files with 396 additions and 8 deletions
+74 -6
View File
@@ -7,7 +7,12 @@ the **product framing behind a scoped phase**. Its build roadmap lives in **PLAN
*why* (the plugin-format reasoning, the bare-VST3-vs-JUCE assessment, the settled
decision record).
Status: framed by product-designer (2026-07-26), **revised 2026-07-26 (r6)**. r6 records the
Status: framed by product-designer (2026-07-26), **revised 2026-07-26 (r7)**. r7 records the
**sampling-modes engine directive** (Daniel, 2026-07-26): Trigger vs Gate play modes (Gate =
AHDSR, Trigger = one-shot with %-length + fades), a modifiable start point in both, and an
off-by-default AD pitch envelope — specced as **new Phase S points S15/S16**, with the WDL
pitch surface swept and reported (sinc `WDL_Resampler` held as an optional quality upgrade;
no formant-preserving/elastique in WDL). See the "sampling modes" Addendum in §4. r6 records the
**workflow-first reframe of S10** (Daniel, 2026-07-26): the editor's default face becomes a
**capture browser + guided single-capture setup**, a fresh instance is **silent with a "pick
a capture" empty state** (reversing the S4 first-sample auto-play), and multi-zone editing is
@@ -770,6 +775,60 @@ binding can be more nuanced than "UID only" (an FXID match is involved), so UID-
is **not** safe to assert from source. Verify by save-rename-reopen in the DAW; if REAPER keys
partly on filename, fall back to keeping the filename and record that as shipped.
### Addendum — sampling modes (Trigger/Gate) + pitch envelope (Daniel, 2026-07-26)
Daniel directed a set of engine features for the sampler, specced as **new Phase S points
S15 (Trigger vs Gate) and S16 (pitch envelope)**. **The feature set is settled** — recorded
here per the doc's settled-decisions convention; PLAN.md §S15/S16 and CONTEXT.md §Sampling
modes carry the spec. Two forks are flagged with leans (S15-F1 choke, S15-F2 param
granularity); the WDL question was resolved by inspection.
**Directive, verbatim (Daniel, 2026-07-26):** *"let's have product spec out some features
for the sampler: Sampling mode: Trigger vs Gate. Gate has an AHDSR envelope. Trigger has
fade in, % length, and fade out. Both modes have modifiable start point, Gate has modifiable
loop points too. In addition to amp env, there will be a pitch envelope/curve (AD?) which is
off by default. Explore using WDL pitch capabilities."*
**What was specced (the shape is product judgment; the feature set is Daniel's):**
1. **Play mode — Gate vs Trigger (S15), per-sample/per-zone, instrument-owned (D-B).**
- **Gate** = classic held note: the current ADSR grows a **Hold** stage → **AHDSR**
(hold=0 is exactly today's ADSR, back-compat); note-off → release; **sustain loop
applies** (S11's loop markers become Gate-mode UI).
- **Trigger** = one-shot drum-pad: note-on fires a **% of sample length** with a
**fade-in** and **fade-out**, **ignores note-off**, **no loop**. Fade default
**equal-power** (click-free); note-off is a no-op (choke held, fork S15-F1).
- **Both:** a **modifiable start point** (non-zero initial read position).
- **Confirmed from `sampler_core.cpp`:** the read loop already advances by an arbitrary
per-frame ratio with linear interp and applies a per-frame amp tick, so both envelopes
are per-frame amplitude functions and the start point is a non-zero initial `readPos_`
— no resampler or voice-lifecycle rewrite.
2. **Pitch envelope — AD, off by default (S16).** A per-voice AD curve biasing the read
increment (the classic pitch drop). **RT clean, confirmed:** the resampler is already an
arbitrary per-frame `readPos_ += ratio_`, so the envelope is a per-frame multiply of
`ratio_` by `2^(semitones/12)`**hand-rolled, no new resampler, no WDL dependency**.
Off by default → bit-identical to pre-S16.
3. **WDL pitch capabilities — verified, not lore (full surface swept).** The whole vendored
WDL pitch/resample surface is two headers: **`resample.h`** (`WDL_Resampler`, a real
sinc/linear RT-suitable resampler — its sinc mode *beats* the core's 2-point linear interp
for base-repitch quality at a CPU cost; **held as an optional quality upgrade**, not
needed for S15/S16) and **`simple_pitchshift.h`** (`WDL_SimplePitchShifter`, a time-domain
OLA *duration-preserving* pitch shifter — wrong tool for a sampler; `set_formant_shift` is
an **empty stub**). **No elastique / formant-preserving / time-stretch exists in WDL**
REAPER's elastique is licensed (zplane), not in the vendored tree. **Recommendation:** S16
modulation stays hand-rolled; `WDL_Resampler` (sinc) is the only WDL piece worth adopting
and only as a held base-repitch quality upgrade.
4. **Sequencing.** S15 before S16 (S16 reuses S15's param plumbing). Both are S3-core
extensions but **channel-count-agnostic by construction** (per-frame amplitude + read-rate,
pre-mix), so they **compose with S7 stereo** rather than conflicting. Core halves land in
CTest independently of the editor; the mode toggle / Trigger handles / AD control surface
through the S10/S11 waveform + setup work.
**Forks flagged (leans given):** *S15-F1 (choke on note-off)***held**, out of S15 scope
(Trigger ignores note-off; choke-groups are Tier-3-adjacent). *S15-F2 (param granularity)*
**lean per-zone only** (the single capture is already a one-zone map), flagged because it
touches S10's single-capture setup surface.
---
## Where this landed
@@ -819,15 +878,24 @@ Post-DAW-test directives (2026-07-26; see the "product name + UX overhaul" Adden
current drawing and adopt the L1 kit when it lands — not gated on Phase L.** Answers
Daniel's "the VST is dogshit / temple os / does Cockos have a toolkit" (2026-07-26,
post-S1S6 DAW test).
10. **Sampling modes + pitch envelope → engine features** (**S15** Trigger vs Gate,
**S16** pitch envelope; see the "sampling modes" Addendum in §4). Gate = AHDSR held note
(hold added to today's ADSR); Trigger = one-shot with %-length + fade-in/out, ignores
note-off; both carry a modifiable start point; Gate keeps loop points. Pitch envelope =
per-voice AD, off by default, hand-rolled over the existing per-frame ratio read (no WDL
needed). WDL swept: `WDL_Resampler` (sinc) is a held optional repitch-quality upgrade;
no formant-preserving/elastique in WDL. Forks S15-F1 (choke, held) / S15-F2 (param
granularity, lean per-zone) flagged. Feature set settled.
**Authoritative from here:** **PLAN.md §Phase S** is the roadmap (S1S6 the original
dependency chain: spike → `Sample` fields → pure sampler core → Tier 0 → Tier 1 → embedded
UI; then **S7** stereo, **S8** ingest, **S9** change-detection, **S10S13** the ReaSampler
9000 UX overhaul); **CONTEXT.md §Phase S** is the spec (seam-field semantics, scope
contracts, the channel-mode / ingest / bank-generation contracts, the UX-overhaul spec, the
product-name convention, the pure/shell split, the must-verify SDK/bridge surfaces). This
doc is the framing/decision record they point back to. The "no PLAN.md footprint" era is
over.
9000 UX overhaul, **S15/S16** the Trigger-vs-Gate + pitch-envelope engine features);
**CONTEXT.md §Phase S** is the spec (seam-field semantics, scope contracts, the channel-mode
/ ingest / bank-generation / sampling-mode / pitch-envelope contracts, the UX-overhaul spec,
the product-name convention, the pure/shell split, the WDL finding, the must-verify
SDK/bridge surfaces). This doc is the framing/decision record they point back to. The "no
PLAN.md footprint" era is over.
---