From 203005e6cfe9a39e82f2f1900f4cb04ec7700d4e Mon Sep 17 00:00:00 2001 From: daniel-c-harvey Date: Mon, 27 Jul 2026 13:49:45 -0400 Subject: [PATCH] docs(phase-s): reconcile PLAN/COMPLETED/CLAUDE for S-VIEW Wave 1 Move S-VIEW-BUG-1 + S-VIEW-SIZE-1 to COMPLETED; annotate S-VIEW-3/4/6/7 as Wave 1 core landed / Wave 2 shell pending; record R10-F1 SETTLED (Option A, flat y=1) into S-VIEW-9. --- CLAUDE.md | 2 +- COMPLETED.md | 36 ++++++++++++++++++++++++++++++++++++ PLAN.md | 44 +++++++++++++++++++++----------------------- 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 5477f8d..4efd9bc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Repo identity and current state -The CMake project and binary are now named `reaper_reasampler`. This is **ReaSampler** — a per-project audio sample-bank capture tool that now 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 MPE modules (`mpe_model`, `mpe_view`) have been removed. M0–M8 are complete (bank_model, peaks, capture offline+realtime, persist, bank_panel, insert, capture action family, RealtimeRecordBackend, tail T1+T2+T1-followons). Phase B multi-bank (B1–B5, B-cap), Phase D1/D2 Design View (D1–D5, D2-W1–W3-B), Phase V versioning/beta-channel (V1/V3, V4), M10 provenance + re-capture from source, Phase R Reclaim (R1–R3: prune-reconcile core, dry-run shell, guarded deletion + action + panel button), M11 in full (batch capture, action-button strip + keybinding labels, conform-on-insert verified-extant, native OS drag-out), Phase L L1 (shared LICE drawing kit: `theme`/palette module, `component_geometry` geometry helpers, `draw_kit` shell, GDI DrawText retired in `bank_panel`), Phase L L2 (dock-panel layout redesign: `action_bar` pure task-grouped layout module, full M11-aware button inventory placed by task cluster, `bank_panel` redesigned through the L1 kit), Phase L L4 (dock-panel button layout enhancement: three-zone layout — top capture/placement/maintenance toolbar, bottom Design-View tagging/switching toolbar, footer narrow-toggle + Tail-button + Prune; `footer_bar` pure module + `footer_bar_tests`; `ActionCluster::Tagging`/`Switching` in `action_bar`), Phase L L5 (dock-panel button refinements: top-bar overflow menu for Batch Items/Batch Razor/Capture RT via `overflow_menu` pure module; custom LICE-kit hover-delay tooltips via `tooltip` pure module; four opposite-mode Item/Track tag buttons + Show Both on the bottom toolbar; Toggle + Activate-Arrange/Design buttons removed; grouping spacing widened — `mode_enable` pure opposite-mode enablement predicate), Phase L L6 (toolbar polish: single-row short-label button faces — keybinding micro sub-row removed from `ActionBarSlot`, keybinding now shown in hover tooltip as "`phrase — binding`"; Cancel RT moved from visible bar into the overflow menu — More (⋯) now lists Batch Items / Batch Razor / Capture RT / Cancel RT; visible top-bar cluster order Capture → Maintenance → Placement; toolbar height 40→28 px), Phase L L7 (capture ordering, card metadata, and selection styling: per-bank `SlotMap` (id→slot) in `bank_book` — gap-preserving persisted display order, `reorderSample`/`replaceSample`/`orderedSampleIds`/`reconcileSlots` mutators; `captureTimeSigNum`/`captureTimeSigDenom` stamped on `Sample` at capture via `TimeMap_GetTimeSigAtTime`; `card_drag` pure module — gesture precedence + SWELL stock cursor cues; `card_meta` pure module — bars.beats.subdivisions + s.ms formatters; `bank_panel` sparse-grid rendering with gap cells, drop dispatch + cursor cues, metadata overlay, tertiary-border selection), Phase L L3 (VST editor + embed-strip restyle: `reasampler_editor.cpp` + `reasampler_embed.cpp` restyled through the L1 kit — REAPER-grey neutrals + three pastel accents, pastel spectral keyboard strip + zone bars as the signature surface with active zone lifting to `accent/primary` + static glow, hover/pressed/drag states throughout; local `kCol*` forest-green palette retired; GDI `DrawTextA` path retired in both VST shells; VST3 class UID unchanged; Phase L now complete), and Phase S (S1–S18 complete; S13 cross-artifact relay deferred): VST3 sampler instrument `reasampler_9000.vst3` — voice engine (`sampler_core`), zone payload (`sample_map`), pitch-preserve OLA (`pitch_shift`), bank change-detection (`bank_sync`), IPC bridge (`bridge_marshal`), editor UI modules (`editor_geometry`, `keyboard_strip`, `waveform_view`, `capture_browser`, `browser_scroll`, `note_entry`, `param_slider`, `embed_strip`), VST3 shells (`reasampler_processor`, `reasampler_editor`, `reasampler_embed`, `reaper_bridge` READ-ONLY bank consumer, `vst_entry`); extension additions: `instrument_drop` pure FX-button blob builder (S17), `assignment_request` pure ingest-assign wire (S8), `ingest` shell (S8: docked-panel drop → capture/import + assign), `instrument_drop_win` shell (S17: `TrackFX_AddByName` + vst_chunk inject, rollback on fail); `drag_out` extended with `InstrumentDrop` third gesture; S18 channel isolation forks VST3 binary to `reasampler_9000_beta.vst3` alongside the beta extension have all landed. M9 slots abandoned (Daniel, 2026-07-27). The *discipline* — pure REAPER-free testable core split from REAPER-facing shells — is **preserved** throughout. +The CMake project and binary are now named `reaper_reasampler`. This is **ReaSampler** — a per-project audio sample-bank capture tool that now 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 MPE modules (`mpe_model`, `mpe_view`) have been removed. M0–M8 are complete (bank_model, peaks, capture offline+realtime, persist, bank_panel, insert, capture action family, RealtimeRecordBackend, tail T1+T2+T1-followons). Phase B multi-bank (B1–B5, B-cap), Phase D1/D2 Design View (D1–D5, D2-W1–W3-B), Phase V versioning/beta-channel (V1/V3, V4), M10 provenance + re-capture from source, Phase R Reclaim (R1–R3: prune-reconcile core, dry-run shell, guarded deletion + action + panel button), M11 in full (batch capture, action-button strip + keybinding labels, conform-on-insert verified-extant, native OS drag-out), Phase L L1 (shared LICE drawing kit: `theme`/palette module, `component_geometry` geometry helpers, `draw_kit` shell, GDI DrawText retired in `bank_panel`), Phase L L2 (dock-panel layout redesign: `action_bar` pure task-grouped layout module, full M11-aware button inventory placed by task cluster, `bank_panel` redesigned through the L1 kit), Phase L L4 (dock-panel button layout enhancement: three-zone layout — top capture/placement/maintenance toolbar, bottom Design-View tagging/switching toolbar, footer narrow-toggle + Tail-button + Prune; `footer_bar` pure module + `footer_bar_tests`; `ActionCluster::Tagging`/`Switching` in `action_bar`), Phase L L5 (dock-panel button refinements: top-bar overflow menu for Batch Items/Batch Razor/Capture RT via `overflow_menu` pure module; custom LICE-kit hover-delay tooltips via `tooltip` pure module; four opposite-mode Item/Track tag buttons + Show Both on the bottom toolbar; Toggle + Activate-Arrange/Design buttons removed; grouping spacing widened — `mode_enable` pure opposite-mode enablement predicate), Phase L L6 (toolbar polish: single-row short-label button faces — keybinding micro sub-row removed from `ActionBarSlot`, keybinding now shown in hover tooltip as "`phrase — binding`"; Cancel RT moved from visible bar into the overflow menu — More (⋯) now lists Batch Items / Batch Razor / Capture RT / Cancel RT; visible top-bar cluster order Capture → Maintenance → Placement; toolbar height 40→28 px), Phase L L7 (capture ordering, card metadata, and selection styling: per-bank `SlotMap` (id→slot) in `bank_book` — gap-preserving persisted display order, `reorderSample`/`replaceSample`/`orderedSampleIds`/`reconcileSlots` mutators; `captureTimeSigNum`/`captureTimeSigDenom` stamped on `Sample` at capture via `TimeMap_GetTimeSigAtTime`; `card_drag` pure module — gesture precedence + SWELL stock cursor cues; `card_meta` pure module — bars.beats.subdivisions + s.ms formatters; `bank_panel` sparse-grid rendering with gap cells, drop dispatch + cursor cues, metadata overlay, tertiary-border selection), Phase L L3 (VST editor + embed-strip restyle: `reasampler_editor.cpp` + `reasampler_embed.cpp` restyled through the L1 kit — REAPER-grey neutrals + three pastel accents, pastel spectral keyboard strip + zone bars as the signature surface with active zone lifting to `accent/primary` + static glow, hover/pressed/drag states throughout; local `kCol*` forest-green palette retired; GDI `DrawTextA` path retired in both VST shells; VST3 class UID unchanged; Phase L now complete), and Phase S (S1–S18 complete; S13 cross-artifact relay deferred): VST3 sampler instrument `reasampler_9000.vst3` — voice engine (`sampler_core`), zone payload (`sample_map`), pitch-preserve OLA (`pitch_shift`), bank change-detection (`bank_sync`), IPC bridge (`bridge_marshal`), editor UI modules (`editor_geometry`, `keyboard_strip`, `waveform_view`, `capture_browser`, `browser_scroll`, `note_entry`, `param_slider`, `embed_strip`), VST3 shells (`reasampler_processor`, `reasampler_editor`, `reasampler_embed`, `reaper_bridge` READ-ONLY bank consumer, `vst_entry`); extension additions: `instrument_drop` pure FX-button blob builder (S17), `assignment_request` pure ingest-assign wire (S8), `ingest` shell (S8: docked-panel drop → capture/import + assign), `instrument_drop_win` shell (S17: `TrackFX_AddByName` + vst_chunk inject, rollback on fail); `drag_out` extended with `InstrumentDrop` third gesture; S18 channel isolation forks VST3 binary to `reasampler_9000_beta.vst3` alongside the beta extension have all landed. M9 slots abandoned (Daniel, 2026-07-27). Phase S Wave 1 S-VIEW pure cores landed (2026-07-27): `envelope_overlay` (params→polyline) + `envelope_edit` (node hit-test + clamped/monotonic inverse map), `previewVelocity` on `ComponentState` v6 (envelope bump v5→v6, processor round-trip), per-`PerformanceZone` `keyTrack` field (zones payload v6, pure ratio math applied in both engines), `keyboard_strip::isNaturalKey` predicate; S-VIEW-BUG-1 (drop-to-FX predicate fix in `instrument_drop`: `fx_*`/`tcp.fx`/`mcp.fx`) and S-VIEW-SIZE-1 (default `ViewRect` 840×560 + `checkSizeConstraint` floor) also landed; Wave 2 shell integration pending. The *discipline* — pure REAPER-free testable core split from REAPER-facing shells — is **preserved** throughout. CONTEXT.md is the authoritative spec and build roadmap. Read it first for any non-trivial task. 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. diff --git a/COMPLETED.md b/COMPLETED.md index d671594..bf5e0c5 100644 --- a/COMPLETED.md +++ b/COMPLETED.md @@ -2235,3 +2235,39 @@ save/reopen rebinds by the correct UID; nothing plays differently (identity/pair - [x] **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 project saved with a beta instance reopens rebinding to the beta VST and restores its state. + +--- + +## S-VIEW-BUG-1 — drop-to-FX bug fix (Wave 1) +**Goal:** Dropping a capture onto a track's FX chain (TCP FX button or FX-chain window) must +instantiate + init ReaSampler 9000, not fall through to arrange-as-audio. +**Root cause (diagnosed and fixed in Wave 1):** the FX-hotspot classifier in the pure +`instrument_drop` module only matched FX-chain and floating-window hotspot strings (`fx_*`); +a drop on the TCP FX button (`tcp.fx`) or MCP FX button (`mcp.fx`) was not matched and fell +through to `OsDrag` (arrange-as-audio). +**Fix:** widened then narrowed the predicate in `instrument_drop` to match `fx_*` / `tcp.fx` / +`mcp.fx`; unit-tested in `instrument_drop_tests` at the boundary. The shell (`instrument_drop_win`) +calls the updated pure predicate unchanged. +**Verify (in DAW):** DAW-confirmation pending Daniel's post-merge smoke test — drop → a playing +instance on the track, one Ctrl-Z removes it. + +- [x] Pure `instrument_drop` predicate widened: `infoNamesFxHotspot` now matches `fx_*` / `tcp.fx` / + `mcp.fx`; unit-tested at each matched and unmatched hotspot string. +- [x] Shell unchanged — calls the updated pure predicate. + +--- + +## S-VIEW-SIZE-1 — 1080p default window size (Wave 1, interim) +**Goal:** The editor opens too small (`ViewRect(0,0,560,400)`); set a larger default sized for +the three-band Sample face on 1080p. +**What landed (interim):** default `ViewRect` bumped to **840×560** and a `checkSizeConstraint` +minimum floor added. The mechanism (`getSize`/`setRect`/`checkSizeConstraint`/`onSize`/`canResize` +in `vendor/vst3sdk/public.sdk/source/common/pluginview.h`) was verified correct at this point. +**NOTE:** Wave 2 (T-SHELL) will re-tune the final numbers to the three concrete Sample-face band +heights once the Sample view layout is built; 840×560 is the correct starting point, not the +final tuned value. +**Verify (in DAW):** opens at 840×560 showing more of the editor surface than before; cannot +shrink below the floor. Final tuning deferred to T-SHELL. + +- [x] Default `ViewRect` bumped to 840×560. +- [x] `checkSizeConstraint` minimum floor enforced. diff --git a/PLAN.md b/PLAN.md index 91f6156..85c12fb 100644 --- a/PLAN.md +++ b/PLAN.md @@ -229,6 +229,10 @@ piano-key pattern work; drop-a-capture-onto-FX instantiates a playing instance. envelope fields** — one source of truth, kept in sync by re-reading params each paint (no listener chain). Node-drag commits via the same off-audio-thread path a slider edit uses (no new RT surface). + > **Wave 1 (S-VIEW cores) ✓:** `envelope_overlay` + `envelope_edit` pure modules landed + > and unit-tested. **Wave 2 shell PENDING:** `reasampler_editor.cpp` must trace the overlay + > and wire draggable node handles; a Trigger frames↔fraction converter is owed at the module + > seam (documented there). - [ ] **S-VIEW-4 — preview-trigger + velocity knob (new, Sample view).** A button firing the sampler at the loaded capture's root note through the live voice engine (off the audio-thread commit path — no MIDI controller needed) + an adjacent velocity knob. **Preview velocity PERSISTS** @@ -237,6 +241,9 @@ piano-key pattern work; drop-a-capture-onto-FX instantiates a playing instance. `getState`/`setState` over `IBStream` — **not** the extension's project-scoped `persist` ext-state (wrong owner + wrong scope; see CONTEXT.md §S-VIEW). Zones payload untouched (independent version axes); older blobs lift to a mid default. RT discipline: no `process`-thread work. + > **Wave 1 (S-VIEW cores) ✓:** `previewVelocity` field on `ComponentState`, envelope v5→v6 + > bump, processor `getState`/`setState` round-trip, clamped 1..127 — all landed. **Wave 2 + > shell PENDING:** the preview button + velocity knob UI in `reasampler_editor.cpp`. - [ ] **S-VIEW-5 — Browse reduced to *choosing* (modal over Sample).** Keep search + bank tabs + captures grid + scroll + selection; add **confirm/cancel** (double-click loads). **Remove** the large waveform preview, Mono/Stereo toggle, root keyboard-strip (all moved to Sample), and the @@ -248,11 +255,18 @@ piano-key pattern work; drop-a-capture-onto-FX instantiates a playing instance. math lives in the pure sampler core** (unit-tested note/root/keyTrack → ratio), applied in both Varispeed and Preserve repitch. Surfaces as a control on the Zone param panel + Sample control strip. + > **Wave 1 (S-VIEW cores) ✓:** per-`PerformanceZone` `keyTrack` field (zones payload v6, + > default 100% bit-identical), pure ratio math, applied in both Varispeed and Preserve + > engines — landed. **Wave 2 shell PENDING:** the UI control in the Zone param panel + + > Sample control strip. - [ ] **S-VIEW-7 — real piano-key pattern on the keyboard strip (new visual).** Overlay the actual alternating white/black (bright/dark per palette) key pattern over the pastel spectral fill so the strip reads as a keyboard. Pure `keyboard_strip` gains a natural/accidental predicate (12- tone, unit-tested); shell draws the two-tone overlay. Shared by the Zone strip + Sample root affordance. + > **Wave 1 (S-VIEW cores) ✓:** pure `isNaturalKey` predicate on `keyboard_strip`, unit-tested + > — landed. **Wave 2 shell PENDING:** `reasampler_editor.cpp` must draw the two-tone overlay + > over the spectral fill. - [ ] **S-VIEW-8 — Zone view retained + wired.** Keep +Add Zone / Delete, the per-zone keyboard strip (now with the piano pattern), the Low/High/Root numeric-entry legend, and the per-zone param panel; add the key-tracking control. Nothing from today's Zones view dropped. @@ -261,7 +275,10 @@ piano-key pattern work; drop-a-capture-onto-FX instantiates a playing instance. to the 0–127×0–1 box; control-point add/move/delete x-ordered + box-clamped; hit-test + pixel- delta→clamped-point inverse map; mirror of `envelope_edit`; unit-tested at eval + clamp/order boundaries). Additive `velocityCurve` field on `PerformanceZone` (instrument-owned, D-B), on the - **zones-payload version axis**, default = the R10-F1 curve; older blobs lift to that default. + **zones-payload version axis**, default = **flat y=1** (R10-F1 SETTLED — Option A, Daniel + 2026-07-27: "any velocity plays at full level"); older blobs lift to that default. **Back-compat + caveat: this is a deliberate non-back-compat behavior change** — the current engine does linear + `velocity/127`, so existing zones' soft hits will be louder after upgrade. Flagged and accepted. Apply at **`Voice::start()`** — replace `velocityGain_ = velocity / 127.0` (`sampler_core.cpp:261`) with `velocityGain_ = curve.eval(velocity)`, off the per-frame path (no new RT work). **BLOCKED BY Wave 1 T-KEYTRK** (`PerformanceZone` schema + payload bump) — this is a LATER additive payload bump @@ -281,34 +298,15 @@ piano-key pattern work; drop-a-capture-onto-FX instantiates a playing instance. > Framed in CONTEXT.md §S-VIEW; both are functional prerequisites with the SDK swept and no > platform ceiling — a diagnosis and a one-line default, not product decisions. - -- [ ] **S-VIEW-BUG-1 — drop-to-FX diagnosis (staff-engineer).** Dropping a capture onto a track's - FX chain does not instantiate + init ReaSampler 9000 (drops as audio to arrange instead). The - S17 machinery is **SDK-correct and present** (`TrackFX_AddByName` + `vst_chunk` injection, all - verified); this is a **runtime bug**. Investigate in order: (1) FX-name match (`"VST3:" + - vstPluginName()` vs REAPER's scanned name); (2) gesture routing (`decideGesture` → - `InstrumentDrop` vs falling to `OsDrag` — the observed symptom); (3) `vst_chunk` write result + - blob-format match with `setState`. **Verify in DAW:** drop → a playing instance on the track, - one Ctrl-Z removes it. -- [ ] **S-VIEW-SIZE-1 — 1080p default window size (staff-engineer).** The editor opens too small - (`ViewRect(0,0,560,400)`). Mechanism **verified** (`getSize`/`setRect`/`checkSizeConstraint`/ - `onSize`/`canResize` in `vendor/vst3sdk/public.sdk/source/common/pluginview.h`): set a larger - default `ViewRect` sized for the new three-band Sample face on 1080p (~840×560+ starting point, - tuned to the band heights) + a `checkSizeConstraint` minimum floor. **Verify in DAW:** opens at - the new default showing the full Sample face without scroll; cannot shrink below the floor. +> **S-VIEW-BUG-1 and S-VIEW-SIZE-1 have both landed (Wave 1) — see `COMPLETED.md`.** ### Phase S editor redesign — forks (Daniel's to call) *(S-VIEW-F1 and S-VIEW-F2 SETTLED 2026-07-27 — folded into S-VIEW-4 / S-VIEW-3 above. F1: preview velocity persists via envelope-v6 `ComponentState`. F2: envelope nodes are draggable via the pure -`envelope_edit` module. Only F3 remains open.)* +`envelope_edit` module. R10-F1 SETTLED 2026-07-27 — Option A flat y=1, folded into S-VIEW-9 above. +Only F3 remains open.)* - **S-VIEW-F3 — Browse modal presentation:** full-window overlay (**lean**) vs. a centered sheet over a dimmed Sample. Presentation detail. -- **R10-F1 — velocity-curve default (r10):** **Option A flat y=1** (**lean** — Daniel's verbatim - "any velocity plays at full level"; NOT back-compat with today's linear `velocity/127`, so - existing zones' dynamics change — flagged as a deliberate shipped-behavior change) vs. **Option B - linear y = x/127** (bit-identical to the shipped engine; contradicts the verbatim "full level" - default). The only non-back-compat surface the velocity-curve feature introduces. **Daniel's - call.** ---