diff --git a/CLAUDE.md b/CLAUDE.md index 73b9e8a..c172c61 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,9 +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). Phase S S-VIEW Wave 1 + Wave 2 + Wave 3 fully landed (2026-07-27, `Merge pS-w2-t1-shell` + `Merge pS-w2-t2-velcurve` + `Merge pS-w3-velcurve-ui`): three-view editor (Sample home face — hero waveform + envelope overlay + draggable nodes + fenced root + preview-trigger + velocity knob + Modes-and-down control strip; Browse full-window modal picker with confirm/cancel; Zone view retained + wired with piano-key pattern + key-track control); `envelope_overlay` (params→polyline) + `envelope_edit` (node hit-test + clamped/monotonic inverse map) wired in `reasampler_editor.cpp`; `trigger_seam` pure module (Trigger frames↔fraction converter, startFrame-aware, unit-tested); preview button + velocity knob UI wired (RT-safe off-thread preview-note mailbox); key-track UI control on Zone + Sample; two-tone piano-key overlay drawn; `velocity_curve` pure module (Fritsch–Carlson monotone cubic Hermite spline eval + control-point editing + hit-test/inverse-map + `pixelFromPoint`/`pointFromPixel` coordinate helpers; `velocity_curve_tests`); zones payload bumped to v7 (`velocityCurve` on `PerformanceZone`, pre-v7 blobs lift to flat y=1); `Voice::start()` now applies `curve.eval(velocity)` — default is flat y=1 (replaces prior linear `velocity/127`, deliberate non-back-compat change, Daniel-approved); S-VIEW-10 velocity-curve editor UI landed (Wave 3) — draggable spline-point editor drawn through the L1 kit in both the Sample view and Zone per-zone param panel, coordinate math via `pixelFromPoint`/`pointFromPixel`, snapshot-at-grab → off-audio-thread commit, no schema change. **Phase S S-VIEW complete (S-VIEW-1 through S-VIEW-10 all landed).** 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. +**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 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. ## One-time submodule setup @@ -28,67 +26,18 @@ Vendors three submodules (see `.gitmodules`): cmake --build build ctest --test-dir build -Key targets (see CMakeLists.txt for the full list): +Every pure module has a corresponding `_tests` executable target that runs without REAPER or a DAW. `CMakeLists.txt` is the authoritative target list. The two loadable-module targets are `reaper_reasampler` (the REAPER extension `.dll`/`.dylib`/`.so`) and `reasampler_vst` (the VST3 instrument; Windows-only, omitted if the `vendor/vst3sdk` slice is absent). -| Target | Kind | Purpose | -|---|---|---| -| `bank_model_tests` | executable | Pure unit tests for `bank_model` — no REAPER, no DAW. | -| `peaks_tests` | executable | Pure unit tests for `peaks` — no REAPER, no DAW. | -| `capture_paths_tests` | executable | Pure unit tests for `capture_paths` — no REAPER, no DAW. | -| `view_mode_model_tests` | executable | Pure unit tests for `view_mode_model` — no REAPER, no DAW. | -| `view_tree_tests` | executable | Pure unit tests for `view_tree` — no REAPER, no DAW. | -| `mode_switch_tests` | executable | Pure unit tests for `mode_switch` — no REAPER, no DAW. | -| `bank_grid_tests` | executable | Pure unit tests for `bank_grid` — no REAPER, no DAW. | -| `tab_strip_tests` | executable | Pure unit tests for `tab_strip` — no REAPER, no DAW. | -| `bank_book_tests` | executable | Pure unit tests for `bank_book` — no REAPER, no DAW. | -| `wav_trim_tests` | executable | Pure unit tests for `wav_trim` — no REAPER, no DAW. | -| `owned_manifest_tests` | executable | Pure unit tests for `owned_manifest` — no REAPER, no DAW. | -| `app_version_tests` | executable | Pure unit tests for `app_version` — no REAPER, no DAW. | -| `provenance_tests` | executable | Pure unit tests for `provenance` — no REAPER, no DAW. | -| `prune_reconcile_tests` | executable | Pure unit tests for `prune_reconcile` — no REAPER, no DAW. | -| `prune_button_tests` | executable | Pure unit tests for `prune_button` — no REAPER, no DAW. | -| `batch_capture_tests` | executable | Pure unit tests for `batch_capture` — no REAPER, no DAW. | -| `action_buttons_tests` | executable | Pure unit tests for `action_buttons` — no REAPER, no DAW. | -| `drag_out_tests` | executable | Pure unit tests for `drag_out` — no REAPER, no DAW. | -| `theme_tests` | executable | Pure unit tests for `theme` — no REAPER, no DAW. | -| `component_geometry_tests` | executable | Pure unit tests for `component_geometry` — no REAPER, no DAW. | -| `action_bar_tests` | executable | Pure unit tests for `action_bar` — no REAPER, no DAW. | -| `footer_bar_tests` | executable | Pure unit tests for `footer_bar` — no REAPER, no DAW. | -| `overflow_menu_tests` | executable | Pure unit tests for `overflow_menu` — no REAPER, no DAW. | -| `mode_enable_tests` | executable | Pure unit tests for `mode_enable` — no REAPER, no DAW. | -| `tooltip_tests` | executable | Pure unit tests for `tooltip` — no REAPER, no DAW. | -| `card_drag_tests` | executable | Pure unit tests for `card_drag` — no REAPER, no DAW. | -| `card_meta_tests` | executable | Pure unit tests for `card_meta` — no REAPER, no DAW. | -| `pitch_shift_tests` | executable | Pure unit tests for `pitch_shift` (S16 Preserve engine) — no REAPER, no DAW. | -| `instrument_drop_tests` | executable | Pure unit tests for `instrument_drop` (S17 FX-button blob) — no REAPER, no DAW. | -| `assignment_request_tests` | executable | Pure unit tests for `assignment_request` (S8 ingest-assign wire) — no REAPER, no DAW. | -| `sampler_core_tests` | executable | Pure unit tests for `sampler_core` (VST3 voice engine) — no REAPER, no DAW. | -| `editor_geometry_tests` | executable | Pure unit tests for `editor_geometry` (VST3 editor layout) — no REAPER, no DAW. | -| `bridge_marshal_tests` | executable | Pure unit tests for `bridge_marshal` (bridge read-decode) — no REAPER, no DAW. | -| `embed_strip_tests` | executable | Pure unit tests for `embed_strip` (VST3 embed layout, S6) — no REAPER, no DAW. | -| `sample_map_tests` | executable | Pure unit tests for `sample_map` (VST3 zone payload v5) — no REAPER, no DAW. | -| `capture_browser_tests` | executable | Pure unit tests for `capture_browser` (VST3 capture browser, S10) — no REAPER, no DAW. | -| `keyboard_strip_tests` | executable | Pure unit tests for `keyboard_strip` (VST3 keyboard strip) — no REAPER, no DAW. | -| `waveform_view_tests` | executable | Pure unit tests for `waveform_view` (VST3 waveform view) — no REAPER, no DAW. | -| `bank_sync_tests` | executable | Pure unit tests for `bank_sync` (VST3 generation change-detection, S9) — no REAPER, no DAW. | -| `browser_scroll_tests` | executable | Pure unit tests for `browser_scroll` (VST3 browser scroll, S12) — no REAPER, no DAW. | -| `note_entry_tests` | executable | Pure unit tests for `note_entry` (VST3 note entry, S12) — no REAPER, no DAW. | -| `param_slider_tests` | executable | Pure unit tests for `param_slider` (VST3 param slider, S12) — no REAPER, no DAW. | -| `trigger_seam_tests` | executable | Pure unit tests for `trigger_seam` (VST3 Trigger frames↔fraction converter, S-VIEW-3) — no REAPER, no DAW. | -| `velocity_curve_tests` | executable | Pure unit tests for `velocity_curve` (VST3 velocity→amp monotone-spline transfer curve, S-VIEW-9) — no REAPER, no DAW. | -| `reaper_reasampler` | loadable module | The REAPER extension binary (`.dll` / `.dylib` / `.so`). | -| `reasampler_vst` | loadable module | The VST3 sampler instrument (`reasampler_9000.vst3`); Windows-only, omitted if `vendor/vst3sdk` slice is absent. | - -### Beta channel build (Phase V, V4) +### Beta channel build To build the fully isolated beta binary (`reaper_reasampler_beta`), pass the channel flag at configure time: cmake -B build-beta -S . -DREASAMPLER_CHANNEL=beta cmake --build build-beta -The flag threads through `configure_file` → `version_generated.h` and fans out via `app_version` into the binary name, ext-state namespace (`"reasampler_beta"`), command-id prefix (`CEREBELLUM_REASAMPLER_BETA_`), action-name prefix (`"ReaSampler beta: "`), dock ident, and version display (`"0.9.01-beta"`). The default build (no flag) is byte-identical to the pre-V4 stable identity. +The flag threads through `configure_file` → `version_generated.h` and fans out via `app_version` into the binary name, ext-state namespace (`"reasampler_beta"`), command-id prefix (`CEREBELLUM_REASAMPLER_BETA_`), action-name prefix (`"ReaSampler beta: "`), dock ident, and version display (`"0.9.01-beta"`). The default build (no flag) is byte-identical to the stable identity. -The VST3 target forks identically (S18 channel isolation): `REASAMPLER_CHANNEL=beta` produces `reasampler_9000_beta.vst3`; the default produces `reasampler_9000.vst3`. The beta VST pairs **only** with the beta extension — each channel carries its own per-channel VST3 class UID, preventing a saved instance from rebinding across channels. +The VST3 target forks identically: `REASAMPLER_CHANNEL=beta` produces `reasampler_9000_beta.vst3`; the default produces `reasampler_9000.vst3`. The beta VST pairs **only** with the beta extension — each channel carries its own per-channel VST3 class UID, preventing a saved instance from rebinding across channels. ### macOS / Linux: SWELL dialog resources @@ -105,72 +54,72 @@ There is no hot-reload. Copy the built binary into REAPER's `UserPlugins/` folde ## Architecture: the load-bearing split **Pure core (no REAPER types, unit-testable outside the DAW):** -- `bank_model` — `Sample` metadata struct + `BankIndex` (add/remove/query/tier/dedup-by-hash + JSON round-trip). Test it hard — it is the heart. `Sample` carries `captureTimeSigNum`/`captureTimeSigDenom` (L7: stamped at capture via `TimeMap_GetTimeSigAtTime`, refreshed on re-capture). -- `peaks` — waveform min/max bin computation from raw PCM. Fed a known signal, asserts envelope. Does not depend on REAPER's peak API. -- `view_mode_model` — Design View mode system: mode registry, GUID-keyed membership, folder-tree-aware visibility derivation, snapshot-based park/restore planner, JSON round-trip. Mirror of `bank_model` for the Design View phase. -- `view_tree` — pure `I_FOLDERDEPTH`→FolderTree helper for the Design View shell; no REAPER types at the boundary. -- `bank_grid` — REAPER-free grid layout, selection, keyboard-nav, and thumbnail-cache-key logic for the docked bank panel: `computeCellRects` (N cells tiled left-to-right/top-to-bottom), `hitTestCell`, `Selection` mutators (`applyClick`, `navigate`), `ThumbnailKey`/`thumbnailKeyString`, and `compressAmplitudeForDisplay`. The originating geometry module that later pure modules mirror. -- `tab_strip` — REAPER-free scrollable tab-strip layout + hit-test for the named-banks strip (Phase B): `computeTabStripLayout` (overflow + chevron geometry), `computeTabRects` (clipped, scroll-offset-shifted tab rects), `hitTestTabStrip` (Tab / ScrollLeft / ScrollRight / None). Mirror of `bank_grid`. -- `mode_switch` — REAPER-free segment layout + hit-test math for the bank_panel's Design View mode switch; divides a header rectangle into N equal segments and hit-tests a point to a segment. Mirror of `bank_grid`. -- `bank_book` — multi-bank registry (Phase B): an ordered set of banks (pool seeded as bank-zero + named banks), each wrapping a `BankIndex`. Owns create/rename/reorder/delete of named banks, pool privileges (un-deletable/un-renamable/un-evacuable, never zero banks) enforced in-model, active-bank id, index-only move/copy/remove of a sample between or from banks, `hashReferencedElsewhere` cross-bank reference query, JSON round-trip + legacy-`bank_index`→pool migration. Wraps `BankIndex` (bank_model untouched; no `bankId` on `Sample`). L7 adds: per-`Bank` gap-preserving **`SlotMap`** (id→slot) for deterministic display order — persisted inside the existing `"banks"` blob; `reorderSample` (insert-before-shift; same-slot = no-op), `replaceSample` (occupant index-removal via standard remove path + pool-guard inheritance; no-op on reject), `orderedSampleIds`, `reconcileSlots` (pre-L7 migration seeds dense insertion order on load). -- `owned_manifest` — owned-file manifest seam (Phase B B-cap): the set of project-relative files the capture path itself created, persisted under the `"owned_files"` ext-state key, so Phase R prune can distinguish the bank system's own orphans from hand-dropped files. Deliberately decoupled from `bank_book` — tracks files created, not index membership. Phase R (R1/R2) consumes it; no prune logic here. -- `app_version` — REAPER-free version/channel identity (Phase V, V1+V4): CMake-sourced semver constant (`appVersion()`), ext-state stamp value (`stampVersion()` — numeric triple only, no channel suffix), `parseVersion`/`versionLess`/`classifyWritingVersion`, and the full set of channel-derived identity accessors (`extStateNamespace()`, `commandIdPrefix()`, `actionDisplayPrefix()`, `binaryName()`, `dockTitle()`, `dockIdent()`, `channelCommandId()`, `channelActionName()`). All channel strings derive from the one `REASAMPLER_CHANNEL_IS_BETA` bit threaded in via `configure_file` → `version_generated.h`; no scattered `#ifdef`s in the shells. -- `wav_trim` — 32-bit-float WAV parse + header-aware truncate plan (RIFF/data size rewrite) for the realtime tail's PCM decay-scan trim (T2). Rejects WAVE_FORMAT_EXTENSIBLE with non-float SubFormat GUID. Depends on `peaks` for the `AudioSample` float alias. -- `provenance` — capture-recipe fingerprint (M10): build/encode/compare a `rsprov1` length-prefixed fingerprint of scope, exact range, tail, rate/channels, track GUIDs, and order-sensitive FX-chain identity; parse/compare for drift detection on re-capture. A thin reproducibility fingerprint — NOT a serialized chain to restore. Drives `BankIndex::updateInPlace` / `BankBook::updateSampleInPlace` (order-preserving, id-stable) on re-capture. -- `prune_reconcile` — Phase R pure prune core: `pruneOrphans(present, referenced, owned)` computes `(owned ∩ present) − referenced` (exact-string path match); `buildPruneReport` tallies count/bytes/display-capped file list; `pruneDeletePlan` produces the confirm-time staleness intersection (`confirmed ∩ freshOrphans`). REAPER-free, filesystem-free. The safety-critical "which files are orphans" decision — hard-tested here before any I/O exists. Also: `BankBook::referencedPaths()` additive const union query (all banks incl. pool, de-duped) added to `bank_book`. -- `prune_button` — Phase R pure layout/hit-test for the `bank_panel` footer Prune button: `computePruneButton` (right-anchored, suppressed gracefully when footer is too narrow) + `hitTestPruneButton`. Mirror of `mode_switch` / `tab_strip`. -- `batch_capture` — M11 pure batch-capture planner: maps a list of source ranges to ordinal capture units, drives per-unit capture via a shared `captureAndIndexOne` helper, and aggregates mixed results. No REAPER types at the boundary. -- `action_buttons` — M11 pure action-button strip layout/hit-test: divides a strip rect into N action buttons, min-width overflow-hiding, label formatting with "(unbound)" fallback, `ActionButtonRect` struct. Mirror of `mode_switch` / `bank_grid`. -- `drag_out` — M11 pure OS drag-out module: gesture-boundary decision (internal drag becomes OS-bound when the pointer leaves the panel client rect), path-list assembly with dedupe and missing-file skip. S17 adds a third gesture `InstrumentDrop`: pointer is outside the panel but still over the REAPER UI, and exactly one sample is selected — signals that the shell should execute an instrument-drop rather than a file-copy drag. No REAPER types at the boundary. -- `theme` — Phase L pure palette module (L1): role→color mapping via one constants block (DS-2 revised — REAPER-grey neutral ladder: `bg/base #2b2b2b` / `bg/panel #333333` / `bg/cell #3a3a3a` / `line/hairline #4a4a4a` / `text/primary #dcdcdc` / `text/dim #a8a8a8`; three-accent pastel system: `accent/primary` pastel lime `#B0E098` = live/active/selected, `accent/secondary` pastel teal `#84D6D0` + `accent/tertiary` pastel purple `#C2AAE8` = categorical distinctions, `accent/hot` lighter lime = hover/drag feedback); `Role` enum carries the three accent roles; `roleColor`/`roleColorState` updated (Active/Dragging/Focus → primary accent); `spectralColor` is a pastel three-stop sweep anchored on the three accents (lime → teal → purple); WCAG contrast-floor helpers; full interaction-state color model. No LICE or REAPER types. -- `component_geometry` — Phase L pure component geometry/hit-test helpers (L1): button/slider/list-row geometry + hover hit-test. No LICE or REAPER types. Mirror of `mode_switch`/`bank_grid`. -- `action_bar` — Phase L pure task-grouped action-bar layout/hit-test (L2 + L4): clusters (Capture / Placement / Maintenance / Tagging / Switching), per-button label rects, whole-trailing-button overflow, point→index hit-test. `ActionCluster::Tagging` and `ActionCluster::Switching` added in L4 for the bottom Design-View toolbar. No LICE or REAPER types. Mirror of `mode_switch`/`bank_grid`/`action_buttons`. -- `footer_bar` — Phase L pure footer layout/hit-test (L4): narrow `[Arrange|Design]` mode-toggle geometry + per-mode count label, Tail button, and Prune placement in the panel footer strip. No LICE or REAPER types. Mirror of `mode_switch` / `prune_button`. -- `overflow_menu` — Phase L pure overflow-menu-button geometry/reserve/hit-test (L5): right-anchored More (⋯) button rect computation and hit-test for the top-toolbar overflow. No LICE or REAPER types. Mirror of `prune_button`. -- `mode_enable` — Phase L pure opposite-mode enablement predicate (L5): given the active mode, computes per-button live/disabled state for the four Item/Track × Arrange/Design tag buttons on the bottom toolbar. No LICE or REAPER types. -- `tooltip` — Phase L pure tooltip placement + prefix-strip (L5): custom LICE-kit hover-delay tooltip geometry and text derivation — strips the `ReaSampler:` display prefix from the registered action phrase; tooltip box width clamped to the client rect. No LICE or REAPER types. -- `card_drag` — Phase L pure drag-gesture precedence + slot hit-test (L7): leave-client → OS drag-out; other-bank → move/copy; same-bank → reorder / Alt-over-occupied → replace. Returns the resolved gesture so the shell can map it to a SWELL stock cursor cue. Sparse `computeSlotRects` / `hitTestSlot`. No LICE or REAPER types. Mirror of `drag_out` / `prune_button`. -- `card_meta` — Phase L pure card-metadata formatters (L7): bars.beats.subdivisions from `lengthSeconds` + `captureTempo` + capture-time-signature stamp; seconds.milliseconds rounded. Both blank when the sample is unstamped. No LICE or REAPER types. -- `instrument_drop` — Phase S pure FX-button drop blob builder (S17): constructs the base64-encoded vst_chunk blob needed to inject a pre-configured `reasampler_9000` instrument via `TrackFX_AddByName` + chunk inject; reuses the VST3 serializer. All-or-nothing contract — caller rolls back via `TrackFX_Delete` on any failure. No REAPER types at the boundary. -- `assignment_request` — Phase S pure ingest-assign wire (S8): typed request record carrying the drop payload (file path, zone assignment hint) from the `ingest` shell through to the VST3 bridge. No REAPER types at the boundary. +- `bank_model` — `Sample` metadata struct + `BankIndex` (add/remove/query/tier/dedup-by-hash + JSON round-trip). Test it hard — it is the heart. +- `peaks` — waveform min/max bin computation from raw PCM; does not depend on REAPER's peak API. +- `view_mode_model` — Design View mode system: mode registry, GUID-keyed membership, folder-tree-aware visibility derivation, snapshot-based park/restore planner, JSON round-trip. +- `view_tree` — pure `I_FOLDERDEPTH`→FolderTree helper for the Design View shell. +- `bank_grid` — REAPER-free grid layout, selection, keyboard-nav, and thumbnail-cache-key logic for the docked bank panel. +- `tab_strip` — REAPER-free scrollable tab-strip layout + hit-test for the named-banks strip. +- `mode_switch` — REAPER-free segment layout + hit-test for the bank_panel's Design View mode switch. +- `bank_book` — multi-bank registry: an ordered set of banks each wrapping a `BankIndex`. **Pool privileges (un-deletable/un-renamable/un-evacuable, never zero banks) enforced in-model.** Owns create/rename/reorder/delete of named banks, active-bank id, index-only move/copy/remove of a sample between banks, and JSON round-trip. +- `owned_manifest` — the set of project-relative files the capture path itself created, persisted under the `"owned_files"` ext-state key, so the prune path can distinguish the bank system's own orphans from hand-dropped files. +- `app_version` — REAPER-free version/channel identity: CMake-sourced semver constant, ext-state stamp value, and the full set of channel-derived identity accessors. All channel strings derive from one `REASAMPLER_CHANNEL_IS_BETA` bit; no scattered `#ifdef`s in the shells. +- `wav_trim` — 32-bit-float WAV parse + header-aware truncate plan for the realtime tail's PCM decay-scan trim. +- `provenance` — capture-recipe fingerprint: build/encode/compare a `rsprov1` fingerprint of scope, range, tail, rate/channels, track GUIDs, and FX-chain identity. **A thin reproducibility fingerprint — NOT a serialized chain to restore.** +- `prune_reconcile` — pure prune core: `pruneOrphans(present, referenced, owned)` computes `(owned ∩ present) − referenced`; the safety-critical "which files are orphans" decision, filesystem-free and hard-tested before any I/O exists. +- `prune_button` — pure layout/hit-test for the `bank_panel` footer Prune button. +- `batch_capture` — pure batch-capture planner: maps source ranges to capture units and aggregates results. +- `action_buttons` — pure action-button strip layout/hit-test. +- `drag_out` — pure OS drag-out module: gesture-boundary decision and path-list assembly. The `InstrumentDrop` gesture signals that the shell should execute an instrument-drop rather than a file-copy drag. +- `theme` — pure palette module: role→color mapping, REAPER-grey neutral ladder + three-accent pastel system, WCAG contrast-floor helpers. +- `component_geometry` — pure button/slider/list-row geometry + hover hit-test helpers. +- `action_bar` — pure task-grouped action-bar layout/hit-test: clusters (Capture / Placement / Maintenance / Tagging / Switching). +- `footer_bar` — pure footer layout/hit-test: `[Arrange|Design]` mode-toggle geometry, Tail button, and Prune placement. +- `overflow_menu` — pure overflow-menu-button geometry/reserve/hit-test for the top-toolbar More (⋯) button. +- `mode_enable` — pure opposite-mode enablement predicate: given the active mode, computes per-button live/disabled state for the four Item/Track × Arrange/Design tag buttons. +- `tooltip` — pure tooltip placement + prefix-strip: strips the `ReaSampler:` display prefix from the registered action phrase; width clamped to the client rect. +- `card_drag` — pure drag-gesture precedence + slot hit-test: leave-client → OS drag-out; other-bank → move/copy; same-bank → reorder / Alt-over-occupied → replace. +- `card_meta` — pure card-metadata formatters: bars.beats.subdivisions and seconds.milliseconds; blank when the sample is unstamped. +- `instrument_drop` — pure FX-button drop blob builder: constructs the base64-encoded vst_chunk blob needed to inject a pre-configured `reasampler_9000` instrument. All-or-nothing contract — caller rolls back via `TrackFX_Delete` on any failure. +- `assignment_request` — pure ingest-assign wire: typed request record carrying the drop payload from the `ingest` shell through to the VST3 bridge. **REAPER-facing shells:** - `capture` — `ICaptureBackend` interface; `OfflineRenderBackend` (deterministic default) and `RealtimeRecordBackend`. Input: `CaptureRequest`. Output: finished file + populated `Sample` handed to `bank_model`. -- `insert` — placement via `InsertMedia`; conform-to-project-tempo is an explicit opt-in flag, never silent stretching. -- `bank_panel` — docked LICE-drawn grid: thumbnails, audition, multi-select, keyboard navigation; three-zone layout (L4/L5/L6): **top toolbar** = visible bar in cluster order Capture (Capture Item, Capture Track) → Maintenance (Re-capture) → Placement (Insert, Insert Conform) via `action_bar`, each button showing a single-row short label, firing via `NamedCommandLookup` + `Main_OnCommand`; a right-anchored **More (⋯) overflow menu button** (`overflow_menu`) opens a `TrackPopupMenu` listing Batch Items / Batch Razor / Capture RT / Cancel RT; **hover tooltips** (`tooltip`) show the full action name with the `ReaSampler:` prefix stripped plus the live keybinding ("`phrase — binding`" when bound, bare phrase when unbound), sourced from the registered action phrase + `kbd_getTextFromCmd`; toolbar height 28 px; **bottom toolbar** = four opposite-mode tag buttons (Item: Arrange / Item: Design / Track: Arrange / Track: Design — live only for the opposite of the active mode, `Disabled` otherwise via `mode_enable`) + set-apart Show Both (`VIEW_SHOW_BOTH`); Toggle and Activate-Arrange/Activate-Design buttons removed (actions stay registered); grouping `clusterGap` 24 / `buttonGap` 4; **footer** = narrow `[Arrange|Design]` toggle · per-mode count · Tail button (cycles tail on click, proper kit button states) · set-apart `warn` Prune (rightmost) via `footer_bar`; entire panel draws through the L1 kit by palette role with hover on interactive elements, single `KitColor→LICE_pixel` boundary via `draw_kit`; OS drag-out hook (M11) initiating an OS-level copy drag when the pointer leaves the panel client rect, via `drag_out` + `drag_out_win`. L7 adds: **grid renders in sparse slot order** (decorative empty-gap cells for unoccupied slots; every cell↔sample consumer remapped to id-based occupied-ordinal space — selection, keyboard nav with gap-skip arrows, audition, multi-select, delete/re-capture resolution, drags); **drop dispatch** (reorder / Alt-replace / move-copy) with one-Ctrl-Z undo, per-slot drop highlight (`accent/hot`, doubled outline for replace), SWELL stock cursor cues via `SetCursor` per the `card_drag` resolved gesture; **metadata overlay** (bars.beats bottom-left Micro, s.ms bottom-right ValueMono, `TextDim`, decorative); **selection = normal cell + `accent/tertiary` purple border**, inversion removed, focus ring distinct. -- `persist` — project ext state (`SetProjExtState` / `GetProjExtState`, namespace `"reasampler"`) ↔ `BankBook` JSON (`"banks"` key — L7: per-`Bank` `SlotMap` rides inside this blob; a pre-L7 blob with no slot data migrates via `reconcileSlots()` to dense insertion order on load) + `ViewModeModel` JSON (`"view_state"` key) + `TailSetting` JSON (`"tail_setting"` key) + `OwnedManifest` JSON (`"owned_files"` key) + writing-version stamp (`"version"` key, written via `stampVersion()` on every `saveToActiveProject()`); project-relative path resolution. A `projectconfig` hook (`BeginLoadProjectState(isUndo)`) triggers a deferred session reload on undo/redo so Ctrl-Z/redo visibly restores book/view/tail/manifest in-session. Hosts `ReaSamplerSession::pruneDryRun()` (read-only orphan enumeration via M4 project-relative resolution) and `pruneOrphanSet()` (full-set query for the R3 delete path); supplies `referencedPaths()` + `owned().paths()` to the `prune_reconcile` pure core. -- `view` — Design View shell: reads the folder tree via `view_tree`, snapshots flag values before parking, drives hide + CPU-park on inactive-mode leaves (`B_SHOWINTCP`/`B_SHOWINMIXER`/`B_MAINSEND`/`I_FXEN` + per-FX offline) and derived visibility on parents; restores from snapshot. Never touches master or `B_MUTE`/`I_SOLO`. -- `track_guid` — shared `MediaTrack*` → canonical GUID-string formatter; single source of truth for membership keys used by both the view shell and the actions layer. -- `provenance_shell` — FX-chain identity queries via `TrackFX_*` / `TakeFX_*` APIs; collects source-item paths and parent-detection inputs to feed the pure `provenance` fingerprint builder. Stamps `Sample.provenance` on capture when every resolving source item maps by exact normalized path (case-folded on Windows) to exactly one bank sample; ambiguous/mixed cases record nothing conservatively. -- `drag_out_win` — M11 OS drag-out shell: Windows OLE `DoDragDrop` / `CF_HDROP`, copy-only structurally (`DROPEFFECT_MOVE` not offered, no source-deletion path); macOS/Linux via `SWELL_InitiateDragDropOfFileList` (copy-semantics caveat documented — SWELL does not expose a drop-effect query). Driven by the `drag_out` pure module. -- `ingest` — Phase S ingest-through-the-bank shell (S8) on the EXTENSION side: three surfaces — (1) arrange capture→bank→assign (bindable action), (2) Media-Explorer import→bank→instrument on the SELECTED TRACK (bindable action, single-file via `MediaExplorerGetLastPlayedFileInfo`; adds RS9k to the user's currently selected track via `loadInstrumentOntoTrack` — no new track created, no routing changed; if no track is selected the sound still lands in the bank but no instrument is placed, with a console message; no `assignment_request` written), (3) file drop onto the bank panel→bank only (multi-file, bank-fill; no `assignment_request` written, no effect on any live instance's selection — the bank-generation bump is retained so open instances' browsers refresh). Only surface (1) writes the `assignment_request` ext-state wire via `ingestAssignActiveInstance`. ingest NEVER inserts a timeline item. -- `instrument_drop_win` — Phase S FX-button drop shell (S17): (a) resolves a screen point to a track + its TCP FX-button hotspot via REAPER's hit-test API (`GetThingFromPoint`, `TrackFX_*`), and (b) on release adds a ReaSampler 9000 instance to that track and injects the dragged capture as its component state via `TrackFX_SetNamedConfigParm` "vst_chunk". Exposes two entry points: `loadInstrumentOntoTrack` (FX add+inject, no own undo block — the shared inner half used by callers that own the undo grouping; also the ME-import placement path), `performInstrumentDrop` (wraps `loadInstrumentOntoTrack` in its own undo block — the S17 drag-drop gesture path). Never captures, never writes the bank, never inserts a timeline item. -- `draw_kit` — Phase L shared LICE draw shell (L1): `fillSurface` (micro-gradient + inner highlight/shadow), `drawButton`/`drawSlider`/`drawListRow`/`drawWaveform`, cached-font `text()` over four `LICE_CachedFont`s (kit-owned lifecycle), full interaction-state model, double-buffer preserved. Consumes `theme` + `component_geometry`. First consumer: `bank_panel` (GDI `DrawText` path retired in L1). -- `actions` — registers the capture/placement/slot action family, the Design View action family (toggle active mode, activate Arrange/Design, tag/untag selected tracks, show-both), the multi-bank action family (create/rename/reorder/delete bank, evacuate, activate, move/copy/remove selected samples), and the Phase R prune action (`BANK_PRUNE_FOLDER` — dry-run-first, confirm-with-manifest, then `pruneDeletePlan`-guarded deletion; **the ONLY file-deletion authority in the system**); routes each to the modules above 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 writes no ext state and opens no undo point (file deletion is not REAPER-undoable). +- `insert` — placement via `InsertMedia`. **Conform-to-project-tempo is an explicit opt-in flag, never silent stretching.** +- `bank_panel` — docked LICE-drawn grid with three-zone layout: top toolbar (Capture → Maintenance → Placement via `action_bar`, short labels, More (⋯) overflow menu via `overflow_menu`), bottom toolbar (four opposite-mode tag buttons + Show Both), and footer (`[Arrange|Design]` toggle, Tail button, Prune via `footer_bar`). Grid renders in sparse slot order with gap cells, drop dispatch, metadata overlay, and selection via `accent/tertiary` purple border. Draws through the L1 kit by palette role; OS drag-out via `drag_out` + `drag_out_win`. +- `persist` — project ext state (`SetProjExtState`/`GetProjExtState`, namespace `"reasampler"`) ↔ `BankBook` JSON, `ViewModeModel` JSON, `TailSetting` JSON, `OwnedManifest` JSON, and writing-version stamp. A `projectconfig` hook triggers a deferred session reload on undo/redo. Hosts the prune dry-run and full-set orphan queries; supplies `referencedPaths()` + `owned().paths()` to the `prune_reconcile` pure core. +- `view` — Design View shell: snapshots flag values before parking, drives hide + CPU-park on inactive-mode leaves (`B_SHOWINTCP`/`B_SHOWINMIXER`/`B_MAINSEND`/`I_FXEN` + per-FX offline), restores from snapshot. **Never touches master or `B_MUTE`/`I_SOLO`.** +- `track_guid` — shared `MediaTrack*` → canonical GUID-string formatter; single source of truth for membership keys. +- `provenance_shell` — FX-chain identity queries via `TrackFX_*`/`TakeFX_*` APIs; feeds the pure `provenance` fingerprint builder. Stamps `Sample.provenance` on capture; ambiguous/mixed cases record nothing conservatively. +- `drag_out_win` — OS drag-out shell: Windows OLE `DoDragDrop`/`CF_HDROP`, copy-only (`DROPEFFECT_MOVE` not offered); macOS/Linux via `SWELL_InitiateDragDropOfFileList`. +- `ingest` — ingest-through-the-bank shell on the EXTENSION side: three surfaces — (1) arrange capture→bank→assign (bindable action), (2) Media-Explorer import→bank→instrument on the selected track, (3) file drop onto the bank panel→bank only. Only surface (1) writes the `assignment_request` ext-state wire. **ingest NEVER inserts a timeline item.** +- `instrument_drop_win` — FX-button drop shell: resolves a screen point to a track + TCP FX-button hotspot, then adds a ReaSampler 9000 instance and injects state via `TrackFX_SetNamedConfigParm` "vst_chunk". Exposes `loadInstrumentOntoTrack` (inner half, no own undo block) and `performInstrumentDrop` (wraps in its own undo block). **Never captures, never writes the bank, never inserts a timeline item.** +- `draw_kit` — shared LICE draw shell: `fillSurface`, `drawButton`/`drawSlider`/`drawListRow`/`drawWaveform`, cached-font `text()`, full interaction-state model, double-buffer preserved. Consumes `theme` + `component_geometry`. +- `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` — Phase S voice engine (S1–S16): polyphonic voice allocation with bounded stealing; per-zone `ZonePlayParams` (PlayMode Gate/Trigger, AHDSR envelope times in frames, Trigger %-length + fades, pitch engine Varispeed/Preserve, AD pitch modulation envelope); repitch/interpolation from a root note with loop-point-aware sustain; no file I/O. No REAPER types at the boundary. -- `sample_map` — Phase S zone payload v5 (S3): 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` — Phase S OLA pitch-preserve engine (S16): hand-rolled overlap-add pitch shifter for the Preserve playback mode; no third-party dependencies. No REAPER types at the boundary. -- `bank_sync` — Phase S generation change-detection + assignment-request consume (S9/S8): owns the yes/no decision logic — parses the generation stamp, decides whether it differs from what was last seen, decides whether a decoded assignment request is new-and-resolvable-and-worth-applying. The processor shell owns the cadence and side effects (reloadFromBank, setSelectedSampleId); this module owns only the maths so the rules are provable without a host. No REAPER types at the boundary. -- `bridge_marshal` — Phase S pure marshalling helper for the REAPER VST-host bridge read (S7): interprets the `GetProjExtState` int return against its filled buffer — the read-decode arithmetic split out of the `reaper_bridge` shell. The S1 string-scan JSON reader was retired in S4 when the instrument moved to the shared bank_book/bank_model JSON path. No IPC, no shared memory. No REAPER types at the boundary. -- `editor_geometry` — Phase S VST3 editor layout pure module (S1): defines the shared `Rect` type + `contains()` hit-test used across all editor geometry modules; provides the spike editor's `EditorLayout` (titleBar / button / canvas) and `layoutEditor(w,h)`. No REAPER or VST3 types at the boundary. -- `keyboard_strip` — Phase S piano-keyboard strip pure module: MIDI-note→key rect mapping, black/white key layout, hit-test, zone highlight overlay geometry. No REAPER or VST3 types at the boundary. -- `waveform_view` — Phase S waveform/marker geometry pure module (S11): maps a sample's full frame span [0, frameCount] linearly across a horizontal rect; generic named draggable markers (start, loop start, loop end) with drag-delta resolver, clamp, and zero-crossing snap. No REAPER or VST3 types at the boundary. -- `capture_browser` — Phase S capture browser pure module (S10): card-grid layout + bank-filter tab strip geometry and hit-test; knows only counts and rects — holds no sample data, draws nothing. Scroll is NOT here (S12 layers it over this module via `browser_scroll`). No REAPER or VST3 types at the boundary. -- `browser_scroll` — Phase S scroll + type-to-filter pure module (S12) layered over `capture_browser`: vertical scroll offset, max-offset clamp, visible-row window, scrollbar thumb rect, thumb-drag↔offset mapping; AND name-substring search (case-insensitive, composing with the bank filter). No REAPER or VST3 types at the boundary. -- `note_entry` — Phase S note-entry pure module (S12): parses a raw string into a clamped MIDI note [0,127] for zone low/high/root note editing; accepts plain decimal integers or note names (C4==60, DAW convention); out-of-range clamps, unparseable returns nullopt. No REAPER or VST3 types at the boundary. -- `param_slider` — Phase S parameter control-panel pure module (S12): lays out a vertical stack of fixed-height control rows in two shapes — TOGGLE (two-segment selector) and SLIDER (horizontal track with draggable 0..1 handle); maps normalized value to/from handle pixel; the shell owns domain-value conversion and control-id→engine-param binding. No REAPER or VST3 types at the boundary. -- `trigger_seam` — Phase S S-VIEW-3 pure Trigger frames↔fraction converter: owns the shared formula for converting between the engine's source-frame fade counts and the overlay's fractional representation (fraction of the played span, itself derived from `lengthFraction × (frameCount − startFrame)`); `startFrame` is threaded correctly through both the pack (frames→fraction, draw path) and unpack (fraction→frames, commit path) directions. Unit-tested independently of the shell. No REAPER or VST3 types at the boundary. -- `velocity_curve` — Phase S S-VIEW-9 pure velocity→amp transfer curve: `VelocityCurve` — an x-ordered list of `VelocityPoint` knots evaluated by a Fritsch–Carlson monotone cubic Hermite spline (no overshoot outside [0,1]; collinear knots reduce to the exact linear ramp); `eval(velocity)` called once per note-on in `Voice::start()`; control-point editing (`addPoint`/`movePoint`/`deletePoint`) with box-clamp and x-order invariant; hit-test (`pointAtPixel`) + drag inverse-map (`resolvePointDrag`); `flat()` default (y=1, every velocity→unity — zones-payload v7 default) and `linear()` (y=velocity/127, retained for tests). Replaces the prior fixed `velocity/127` engine path; default flat y=1 is a deliberate non-back-compat behavior change (Daniel-approved). No REAPER or VST3 types at the boundary. -- `embed_strip` — Phase S embed-mode strip layout pure module (S6): compact single-row control layout for when the editor is embedded in the track FX chain. No REAPER or VST3 types at the boundary. +- `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. +- `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. +- `bridge_marshal` — pure marshalling helper for the REAPER VST-host bridge read: interprets the `GetProjExtState` int return against its filled buffer. +- `editor_geometry` — VST3 editor layout: defines the shared `Rect` type + `contains()` hit-test; provides `EditorLayout` and `layoutEditor(w,h)`. +- `keyboard_strip` — piano-keyboard strip: MIDI-note→key rect mapping, black/white key layout, hit-test, zone highlight overlay geometry. +- `waveform_view` — waveform/marker geometry: maps frame span linearly across a rect; generic named draggable markers with drag-delta resolver, clamp, and zero-crossing snap. +- `capture_browser` — capture browser: card-grid layout + bank-filter tab strip geometry and hit-test; knows only counts and rects, draws nothing. +- `browser_scroll` — scroll + type-to-filter layered over `capture_browser`: vertical scroll offset, scrollbar thumb, thumb-drag mapping, and name-substring search. +- `note_entry` — parses a raw string into a clamped MIDI note [0,127]; accepts plain decimal integers or note names (C4==60, DAW convention). +- `param_slider` — parameter control-panel: vertical stack of TOGGLE (two-segment selector) and SLIDER (horizontal track) rows; maps normalized value to/from handle pixel. +- `trigger_seam` — pure Trigger frames↔fraction converter: owns the shared formula for converting between engine source-frame fade counts and the overlay's fractional representation, threading `startFrame` correctly through pack and unpack directions. +- `velocity_curve` — pure velocity→amp transfer curve: `VelocityCurve` evaluated by a Fritsch–Carlson monotone cubic Hermite spline (no overshoot outside [0,1]). `eval(velocity)` called once per note-on. `flat()` default (y=1, every velocity→unity) replaces the prior fixed `velocity/127` path — a deliberate non-back-compat behavior change (Daniel-approved). +- `embed_strip` — compact single-row control layout for embed mode in the track FX chain. **VST3 instrument (`src/vst/`) — shells:** -- `reaper_bridge` — Phase S READ-ONLY bank consumer (S7): receives bank snapshots from the extension over the IPC bridge and exposes them to the VST3 processor/editor 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` — Phase S VST3 `SingleComponentEffect` shell: declares an event-input bus + stereo audio output bus, marshals host MIDI note-on/off into the VoiceEngine, renders audio via the loaded `sample_map` zones; owns the off-audio-thread `reloadFromBank` + atomic pointer swap so process() does no allocation, no file I/O, no bridge calls. -- `reasampler_editor` — Phase S VST3 `IPlugView` LICE editor shell (S10): subclasses `CPluginView`, hosts a LICE-drawn child window inside the host's IPlugView seat; default face is the capture browser (bank-filter tabs + card grid), then single-capture setup (keyboard strip + root marker), with opt-in zones panel (S10-Z). Accepts file drops and shows a drop affordance (S13 relay to the extension's ingest path is deferred — drop-onto-editor ingest is NOT shipped). -- `reasampler_embed` — Phase S embed shell (S6): implements `IReaperUIEmbedInterface` so the instrument draws a compact keymap/level strip INLINE in the track/mixer control panel (TCP/MCP), without a plugin-owned HWND — REAPER hands a LICE bitmap per paint; delegates layout/hit-test to `embed_strip`. -- `vst_entry` — Phase S VST3 entry point: `GetPluginFactory` export, class registration, channel-forked class UIDs (S18). +- `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_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. ## REAPER extension contract (src/main.cpp)