docs: record post-S-VIEW DAW-fix pass + voice-system redesign (parameterized voices, mono, preview card, two-tier panic, v7)
This commit is contained in:
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
|
||||
## Repo identity and current state
|
||||
|
||||
**ReaSampler** is a per-project audio sample-bank capture tool that builds two artifacts: the REAPER extension (`reaper_reasampler`) and **ReaSampler 9000**, a Windows-only VST3 sampler instrument (`reasampler_9000.vst3`, `src/vst/`, second CMake target `reasampler_vst`, gated on the vendored `vendor/vst3sdk` submodule slice). The pure-testable-core / REAPER-facing-shell discipline is preserved throughout. CONTEXT.md is the authoritative spec — settled decisions, invariants, guardrails, and not-yet-built specs; it is large, so locate the relevant phase section by grepping its headings and read only that section with an offset rather than reading it whole. Build detail for landed phases lives in CONTEXT-ARCHIVE.md. Every REAPER API name cited there is correct-by-intent; verify argument order, types, and flag values against `vendor/reaper-sdk/sdk/reaper_plugin_functions.h` before use.
|
||||
**ReaSampler** is a per-project audio sample-bank capture tool that builds two artifacts: the REAPER extension (`reaper_reasampler`) and **ReaSampler 9000**, a Windows-only VST3 sampler instrument (`reasampler_9000.vst3`, `src/vst/`, second CMake target `reasampler_vst`, gated on the vendored `vendor/vst3sdk` submodule slice). The pure-testable-core / REAPER-facing-shell discipline is preserved throughout. CONTEXT.md is the authoritative spec — settled decisions, invariants, guardrails, and not-yet-built specs; it is large, so locate the relevant phase section by grepping its headings and read only that section with an offset rather than reading it whole. Build detail for landed phases lives in CONTEXT-ARCHIVE.md. Every REAPER API name cited there is correct-by-intent; verify argument order, types, and flag values against `vendor/reaper-sdk/sdk/reaper_plugin_functions.h` before use. A post-S-VIEW DAW-fix pass has landed (all 52 suite tests green): envelope nodes fully editable in both modes (every Gate stage A/H/D/S/R + Trigger zero-fade-out node, param-domain schematic scaling, 8 px min node separation, all nodes clamped in-canvas); gap-free per-column waveform render (`columnMinMax` homed in `peaks`, `waveformColumnCount` in `component_geometry`, shared via `drawWaveform`); `param_slider` `Knob` primitive (7→5 o'clock arc, needle, vertical-drag); zone-bleed fix 3a (`reconcileSingleCaptureZones` in `sample_map`). The voice-system redesign is also landed: `sampler_core` gains user-parameterized voice count (1–32, default 16), `VoiceMode` Poly/Mono (last-note held-note stack, `MonoTrigger` retrigger/legato toggle), an isolated `PreviewCard` (dedicated preview voice outside the MIDI pool — never steals from/into it; unity-Preserve zero-latency bypass scoped to it), and two-tier panic (CC 123 = release, CC 120 = immediate hard-stop incl. Trigger one-shots); processor sums the preview card alongside the engine + drain, `retireIdleDrain()` retires fully-idle drain snapshots, and voice-param edits rebuild from the already-decoded PCM (no bank re-read/WAV re-decode) via the drain-slot swap; `ComponentState` envelope bumped v6→v7 (voiceCount/voiceMode/monoTrigger bytes; pre-v7 blobs lift to 16/Poly/Retrigger).
|
||||
|
||||
## One-time submodule setup
|
||||
|
||||
@@ -98,7 +98,7 @@ There is no hot-reload. Copy the built binary into REAPER's `UserPlugins/` folde
|
||||
- `actions` — registers the capture/placement/slot, Design View, multi-bank, and prune action families; routes each via the `command_id`/`gaccel`/`hookcommand` contract. **Every bank index verb wraps its mutation in a batched REAPER undo point (`Undo_BeginBlock2`/`EndBlock2`, `UNDO_STATE_MISCCFG`) so one bank operation is one Ctrl-Z.** The prune action (`BANK_PRUNE_FOLDER`) is **the ONLY file-deletion authority in the system**; it opens no undo point (file deletion is not REAPER-undoable).
|
||||
|
||||
**VST3 instrument (`src/vst/`) — pure core:**
|
||||
- `sampler_core` — polyphonic voice engine with bounded stealing, per-zone `ZonePlayParams` (Gate/Trigger, AHDSR, pitch engine Varispeed/Preserve, AD pitch mod envelope), repitch/interpolation with loop-point-aware sustain.
|
||||
- `sampler_core` — polyphonic voice engine with bounded stealing, user-parameterized voice count (1–32, default 16), `VoiceMode` Poly/Mono (last-note held-note stack, `MonoTrigger` Retrigger/Legato toggle), isolated `PreviewCard` (dedicated preview voice outside the MIDI pool — never steals from/into it; unity-Preserve zero-latency bypass scoped to it), two-tier panic (CC 123 = all-notes-off release, CC 120 = immediate hard-stop including Trigger one-shots); per-zone `ZonePlayParams` (Gate/Trigger, AHDSR, pitch engine Varispeed/Preserve, AD pitch mod envelope), repitch/interpolation with loop-point-aware sustain.
|
||||
- `sample_map` — zone payload: zones keyed by note range. **Wall-clock times stored as rate-free SECONDS, resolved against the live project rate — NO hardcoded sample rates in `src/`** (Daniel's standing ruling, load-bearing). JSON round-trip.
|
||||
- `pitch_shift` — hand-rolled overlap-add pitch shifter for the Preserve playback mode; no third-party dependencies.
|
||||
- `bank_sync` — generation change-detection + assignment-request consume: owns the yes/no decision logic so the rules are provable without a host. The processor shell owns cadence and side effects.
|
||||
@@ -116,7 +116,7 @@ There is no hot-reload. Copy the built binary into REAPER's `UserPlugins/` folde
|
||||
|
||||
**VST3 instrument (`src/vst/`) — shells:**
|
||||
- `reaper_bridge` — READ-ONLY bank consumer: receives bank snapshots from the extension and exposes them as a read-only view. **Never writes to the extension's bank** — this is a load-bearing invariant; no mutation path exists in this module.
|
||||
- `reasampler_processor` — VST3 `SingleComponentEffect` shell: declares event-input bus + stereo output, marshals MIDI note-on/off into the VoiceEngine, renders audio; owns off-audio-thread `reloadFromBank` + atomic pointer swap so `process()` does no allocation, no file I/O, no bridge calls.
|
||||
- `reasampler_processor` — VST3 `SingleComponentEffect` shell: declares event-input bus + stereo output, marshals MIDI note-on/off into the VoiceEngine, renders audio; owns off-audio-thread `reloadFromBank` + atomic pointer swap so `process()` does no allocation, no file I/O, no bridge calls. Sums the `PreviewCard` alongside the engine + drain in `process()`; `retireIdleDrain()` retires fully-idle drain snapshots on the UI-timer cadence. Voice-param edits (`setVoiceCount`/`setVoiceMode`/`setMonoTrigger`) rebuild the engine from the already-decoded keymap via the drain-slot swap — no bank re-read, no WAV re-decode, no audible cut to ringing tails.
|
||||
- `reasampler_editor` — VST3 `IPlugView` LICE editor shell: hosts a LICE-drawn child window; default face is the capture browser, then single-capture setup, with opt-in zones panel. Drop-onto-editor ingest is NOT shipped (deferred).
|
||||
- `reasampler_embed` — implements `IReaperUIEmbedInterface` so the instrument draws inline in the TCP/MCP without a plugin-owned HWND; delegates layout/hit-test to `embed_strip`.
|
||||
- `vst_entry` — VST3 entry point: `GetPluginFactory` export, class registration, channel-forked class UIDs.
|
||||
|
||||
@@ -2615,3 +2615,60 @@ state persists via the index.
|
||||
|
||||
Slot model + slot↔sample assignment.
|
||||
"Capture to slot N" / "insert slot N" actions, MIDI-bindable.
|
||||
|
||||
---
|
||||
|
||||
## Post-S-VIEW DAW-fix pass + voice-system redesign (2026-07-27)
|
||||
|
||||
> **Merged to dev 2026-07-27. Integrated suite 52/52 green.** These items were found during
|
||||
> Daniel's post-S-VIEW DAW testing (fixes) and a subsequent Daniel directive (voice redesign) —
|
||||
> not tracked as PLAN points. PLAN.md has no corresponding entries to move.
|
||||
|
||||
**Envelope node editing (DAW-fix):** Every Gate stage (A/H/D/S/R incl. a visible in-bounds
|
||||
Release) and Trigger's zero-fade-out node are now fully grabbable in both modes. `envelope_edit`
|
||||
uses param-domain schematic scaling (`kGateNodeSepPx = 8` minimum node separation enforced by the
|
||||
forward map in `envelope_overlay`); all nodes clamped in-canvas. Previously only a subset of nodes
|
||||
was editable.
|
||||
|
||||
**Gap-free waveform render (DAW-fix):** `columnMinMax` moved to `peaks`; `waveformColumnCount`
|
||||
moved to `component_geometry`. The dock panel and VST editor now share one gap-free per-column
|
||||
min/max algorithm via `draw_kit::drawWaveform`.
|
||||
|
||||
**Radial Knob primitive (DAW-fix):** `param_slider` gained a `Knob` control kind (7→5 o'clock arc,
|
||||
needle, vertical-drag) as the foundation for the Wave B control deck. `ControlKind::Knob` added
|
||||
to the enum; `computeKnob`/`knobHitTest`/`knobValueAngleDeg` pure helpers added.
|
||||
|
||||
**Zone-bleed fix 3a (DAW-fix):** `reconcileSingleCaptureZones` added to `sample_map` — fixes
|
||||
stale full-range zone shadowing so the engine plays the zone the editor draws. Called on load
|
||||
(`setState`), on bank-assign, and on capture-confirm in the editor.
|
||||
|
||||
**Voice-system redesign (Daniel directive):**
|
||||
- `sampler_core` — user-parameterized voice count (1–32, default 16 via `kDefaultVoiceCount`);
|
||||
`VoiceMode` enum (Poly/Mono: last-note held-note stack, `MonoTrigger` Retrigger/Legato toggle);
|
||||
isolated `PreviewCard` class (dedicated preview voice outside the MIDI pool — never steals
|
||||
from/into it; unity-Preserve zero-latency bypass scoped to it); two-tier panic (`allNotesOff`
|
||||
= CC 123 release, `allSoundsOff` = CC 120 immediate hard-stop including Trigger one-shots).
|
||||
- Processor — `process()` sums `PreviewCard` alongside the engine + drain; `retireIdleDrain()`
|
||||
retires fully-idle drain snapshots on the UI-timer cadence (idle-drain retirement); voice-param
|
||||
setters (`setVoiceCount`/`setVoiceMode`/`setMonoTrigger`) rebuild the engine from the
|
||||
already-decoded keymap via the drain-slot swap — no bank re-read, no WAV re-decode, ringing
|
||||
tails not cut.
|
||||
- `ComponentState` envelope bumped **v6→v7**: three voice bytes added (voiceCount 1–32 / voiceMode
|
||||
Poly|Mono / monoTrigger Retrigger|Legato). Pre-v7 blobs lift to `{16, Poly, Retrigger}` —
|
||||
reproduces pre-Phase-S behavior exactly. Zones-payload axis untouched.
|
||||
|
||||
- [x] `envelope_edit` + `envelope_overlay`: all Gate and Trigger nodes draggable; `kGateNodeSepPx`
|
||||
separation enforced; param-domain schematic scaling; in-canvas clamp.
|
||||
- [x] `columnMinMax` homed in `peaks`; `waveformColumnCount` homed in `component_geometry`;
|
||||
`draw_kit::drawWaveform` shared by dock panel and VST editor — gap-free at any bins-to-pixels ratio.
|
||||
- [x] `param_slider` `Knob` control kind: `computeKnob`/`knobHitTest`/`knobValueAngleDeg` pure
|
||||
helpers; 7→5 o'clock arc; vertical-drag pixel mapping.
|
||||
- [x] `reconcileSingleCaptureZones` in `sample_map`: stale full-range zone shadowing fixed; called
|
||||
on `setState`, bank-assign, and editor capture-confirm.
|
||||
- [x] `VoiceMode` / `MonoTrigger` enums and `PreviewCard` class in `sampler_core`.
|
||||
- [x] `VoiceEngine` constructible with user voice count; `allNotesOff` (CC 123) / `allSoundsOff`
|
||||
(CC 120) two-tier panic.
|
||||
- [x] Processor: `PreviewCard` summed in `process()`; `retireIdleDrain()` on UI-timer cadence;
|
||||
voice-param rebuild via drain-slot swap (no disk I/O).
|
||||
- [x] `ComponentState` envelope v6→v7; `voiceCount`/`voiceMode`/`monoTrigger` on `ComponentState`;
|
||||
back-compat lift in `deserializeComponentState`.
|
||||
|
||||
Reference in New Issue
Block a user