From 52ac9b5eeafbf3f257d18e3dc248e7d8b4f6f3a7 Mon Sep 17 00:00:00 2001 From: daniel-c-harvey Date: Sun, 26 Jul 2026 23:18:46 -0400 Subject: [PATCH] =?UTF-8?q?Revert=20"docs(product):=20spec=20S7=20drop-and?= =?UTF-8?q?-load=20=E2=80=94=20drag=20capture=20onto=20TCP=20FX=20button?= =?UTF-8?q?=20to=20instantiate=20ReaSampler=209000=20preloaded"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit b8e8d47af5f748f823a625ae012658f7079a24ca. --- CONTEXT.md | 133 ----------------------------------------------------- PLAN.md | 107 ------------------------------------------ 2 files changed, 240 deletions(-) diff --git a/CONTEXT.md b/CONTEXT.md index 6217116..303b1b4 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -1311,134 +1311,6 @@ and embed message/lifecycle against `vendor/reaper-sdk/sdk/reaper_plugin_fx_embe `IPlugView`↔LICE window/bitmap bridge at the spike (window creation, sizing, event routing) — the least-trodden edge of the phase. -## Drop-and-load — drag a capture onto a track's FX button (S7 spec) - -**The gesture.** While a capture is dragged out of the `bank_panel`, a track's TCP **FX -button** becomes a drop zone. Dropping the capture there **instantiates a ReaSampler 9000 -on that track with the dragged capture already loaded and selected for playback** — one -gesture from bank to playable instrument. This is the *third* integration gesture: capture -(extension), placement-into-arrange (extension), and now **placement-of-the-player** -(this wave). It is drop-and-load, not drop-to-arrange — no media item touches the timeline. - -**Why it needs a new drag mode (the CF_HDROP path can't carry it).** Today's drag-out -(M11) becomes an **OS file drag** (`CF_HDROP` via `drag_out` + `drag_out_win`) the moment -the pointer leaves the panel client rect. REAPER's TCP FX button is **not** a native drop -target that instantiates a plugin-with-a-file, so this feature cannot ride the OS-drag -path: an OS drop of a WAV onto the FX area does not create "an instrument preloaded with -that WAV." It requires an **internal drag** where the extension itself tracks the pointer -over REAPER's own UI, detects the FX-button hover, and on release **drives the insert -itself**. The extension is the actor for the whole gesture. - -**The two-part mechanism.** - -1. **Internal-drag hover detection (extension-side, pure + shell).** The `drag_out` pure - module gains a **third `DragGesture`** beyond `Internal` (bank-to-bank) and `OsDrag` - (M11) — `InstrumentDrop`. The gesture decision is refined: leaving the panel client - rect no longer *immediately* means OS-bound. Instead: - - Pointer **inside** the panel client rect → `Internal` (unchanged bank-to-bank drag). - - Pointer **outside the panel but still over REAPER's own window/UI** → - `InstrumentDrop` (new — the shell hover-tracks the TCP FX button and highlights it). - - Pointer **left REAPER entirely** (Explorer / another app) → `OsDrag` (unchanged M11). - - The pure module stays REAPER-free: it decides `InstrumentDrop` vs. `OsDrag` from - position **plus an "over-REAPER's-own-UI" predicate the shell supplies** (the shell owns - the REAPER window/hit query; the pure layer owns the set/boundary algebra). Mirror of how - M11 kept `decideGesture` pure over a rect the shell supplied. The shell then resolves the - pointer to a track + FX-button hotspot, highlights it, and on release drives the drop. - -2. **FX-button drop → add-VST + load-capture (extension-side shell, then instrument - seam).** On release over an FX button the shell: - - Adds a fresh instance: `TrackFX_AddByName(track, "VST3:ReaSampler 9000", /*recFX*/ - false, /*instantiate*/ )`. **Verified present** in - `reaper_plugin_functions.h`: - `int TrackFX_AddByName(MediaTrack* track, const char* fxname, bool recFX, int - instantiate)` — a **negative** `instantiate` always creates a new effect (per the - header comment); the `"VST3:"` prefix selects the format. Captures the returned FX - index (or `-1` on failure). - - **Loads the dragged capture into that instance via the load-capture seam** (below). - - Wraps the whole thing in one REAPER undo point (`Undo_BeginBlock2`/`EndBlock2`) so the - gesture is one Ctrl-Z — the same discipline the bank verbs use. - -**The ReaSampler 9000 load-capture seam (the hard coupling — MUST be added; does not yet -exist).** The Phase S spec today gives the instrument a **live-state *read* seam** (it -reads bank index + mapping from `"reasampler"` ext-state via the bridge — §The two seams) -but **no entry point for an external actor to say "this fresh instance should play *this -specific* capture."** Reading the bank is not the same as being *pointed at one sample*. -This wave is the reason to add that seam, and the seam lands **inside the instrument** -(the `phase-s` artifact), not the extension. Two candidate mechanisms — **the choice is a -Phase S open question:** -- **(A) Fresh-instance ext-state handshake.** The extension writes a small "pending load" - hint into `"reasampler"` ext-state keyed to the target track/FX (e.g. the capture id + - a target GUID); a freshly-instantiated ReaSampler 9000 reads it on init via the same - bridge it already uses, claims + clears the hint, and self-selects that capture. **Pro:** - reuses the existing bridge; no new VST3 surface. **Con:** a cross-process handshake with - a claim/clear race to get right; "which instance claims which hint" needs a stable key. -- **(B) VST3 `setState` / preset injection.** The extension builds the instance's - component state (the same blob `getState`/`setState` round-trips) with the capture - pre-selected and injects it right after `TrackFX_AddByName`. **Pro:** deterministic, no - shared-state race, uses the instrument's own persistence format. **Con:** the extension - must know and construct the instrument's state blob format — a tighter cross-artifact - coupling to a format that is itself still being built in Phase S; verify whether the - extension can set an added FX's state through the REAPER API (candidate: - `TrackFX_SetNamedConfigParm` / a state-set path — **not yet confirmed against - `reaper_plugin_functions.h`**). - - Lean: **(A)** keeps the artifacts loosely coupled through the one ext-state seam they - already share and avoids the extension hard-coding the instrument's state format — but - it inherits the claim/clear race. Daniel to decide (open question below). - -**Coexistence with the OS drag-out (disambiguation contract).** The two OS-vs-internal -modes are disambiguated **by pointer location, not a mode toggle** — the user never picks -"OS drag" vs. "instrument drop"; the extension infers it from where the pointer is when -released. The M11 boundary (left the client rect) is *refined*, not replaced: leaving the -rect now asks "over REAPER's UI → InstrumentDrop, else → OsDrag." Both M11 OS drag-out and -the internal bank-to-bank drag must remain **byte-for-byte unchanged** in their own -regions — this wave only inserts a new middle case. Multi-capture payloads are a -disambiguation input too (see open question — instrument drop is naturally single-capture; -a multi-capture drag over the FX button is either rejected or loads the first). - -**Precision / invariant implications (drop-and-load).** -- **Explicit user-driven placement — consistent with capture↔placement separation.** This - is a *deliberate placement gesture*: the user chooses to put a playing instrument on a - track, exactly as inserting an item into the arrange is a deliberate act. It does **not** - auto-capture (the file already exists in the bank) and does **not** insert a media item - into the timeline. It instantiates a *reader* of the bank on a track and points it at one - already-captured sample. Capture, placement, and playback stay three distinct acts; this - is placement-of-the-player, not a capture and not a timeline insert. -- **No private sample copy.** The instantiated instrument consumes the one authoritative - bank (it resolves the WAV via the shared M4 project-relative machinery like any - ReaSampler 9000 instance); the seam hands it a *reference* (a capture identity), never a - copied file. Any path that copies bytes into the instance is a bug. -- **The internal drag stays pure-decidable and testable.** The new `InstrumentDrop` - gesture is decided in the `drag_out` pure module (REAPER-free) over a shell-supplied - predicate; the M11 `drag_out` unit tests must not regress. - -**Open questions (Daniel / Phase S team to decide).** -- **Load-capture seam mechanism (A vs. B above).** The single load-bearing Phase S design - choice this wave forces. Lean is (A) for loose coupling; needs Daniel's call. -- **Multi-capture drag over an FX button** — reject (only single-capture drags arm - `InstrumentDrop`), or load the first / a keymap of all? Tier-0 leans reject-or-first; - a multi-capture keymap load is a Tier-1 stretch. -- **FX-button hotspot vs. whole TCP.** Does the drop zone have to be the FX button - specifically, or is dropping anywhere on the target track's TCP enough (simpler hit - resolution, arguably clearer target)? Depends on what the SDK exposes (see must-verify). -- **Numbering vs. the `phase-s` worktree.** Drop-and-load is a sibling of the worktree's - ingest-relay / drop-to-load work (not on dev). Reconcile the S7 label when `phase-s` - merges (see PLAN.md §S7 reconciliation note) — possibly fold into the ingest-relay family. - -**Must-verify before build (drop-and-load).** -- `TrackFX_AddByName` — **verified present** (`reaper_plugin_functions.h`): signature and - the `"VST3:"`-prefix + negative-`instantiate` semantics confirmed from the header. -- **Pointer→track / FX-button hit resolution during a drag** — **not yet confirmed.** - Candidates: `GetTrackFromPoint` / `GetThingFromPoint` (verify names + signatures against - `reaper_plugin_functions.h`); whether the FX button specifically is addressable vs. the - TCP as a whole is an open verification that also decides the "hotspot vs. whole TCP" - question. -- **Instance state injection (only if seam mechanism (B) is chosen)** — whether the - extension can set a just-added FX's state via the REAPER API - (`TrackFX_SetNamedConfigParm` or similar) — **not yet confirmed against - `reaper_plugin_functions.h`.** Moot if (A) is chosen. - ## Non-goals / guardrails - **The instrument never captures and never inserts into the arrange.** Playback is a @@ -1458,11 +1330,6 @@ a multi-capture drag over the FX button is either rejected or loads the first). M/D/B/R/V pillars. - **Do not spec Tier 2/3.** Tier 2 is held (noted, not specified); Tier 3 is optional-forever. Do not let their feature lists drive Tier 0–1's build shape. -- **Drop-and-load must not regress the two existing drags.** S7 inserts a new middle case - (`InstrumentDrop`) between the M11 OS drag-out and the internal bank-to-bank drag; both - existing gestures stay byte-for-byte unchanged in their own regions. Drop-and-load never - inserts a media item into the arrange and never copies sample bytes into the instance — - it hands the new instance a *reference* to an already-captured bank sample. - **Verify Steinberg SDK, bridge, embed, and LICE-view surfaces** against the vendored headers before use — several §1a claims are experienced estimates until the spike confirms them. diff --git a/PLAN.md b/PLAN.md index cadc240..4e6e323 100644 --- a/PLAN.md +++ b/PLAN.md @@ -248,103 +248,6 @@ build:** the `IReaperUIEmbedInterface` contract + embed message/lifecycle agains - [ ] Embed lifecycle (open/close/resize/hit-test inline) handled cleanly; reflects the live keymap/levels. -## S7 — drop-and-load: drag a capture onto a track's FX button → instantiate ReaSampler 9000 with the capture loaded -**Goal:** Turn a bank capture into a playable instrument in one gesture. Today a drag -out of the `bank_panel` becomes an OS file drag once it leaves the panel (M11 — -`drag_out` + `drag_out_win`, CF_HDROP). This wave adds a **second, internal drag mode**: -while a capture is dragged, a track's TCP **FX button** lights as a drop zone, and -dropping there instantiates a **ReaSampler 9000** (the Phase S VST3 sampler) on that -track with the dragged capture **already loaded and selected** for playback. The -extension drives the whole gesture itself — REAPER's FX button is not a native -plugin-with-file drop target, so this cannot ride the CF_HDROP path. CONTEXT.md §Phase S -(drop-and-load — internal-drag hover mode + the FX-button drop → add-VST + load-capture -seam). Product framing: `docs/product/midi-playback.md` (drop-and-load — the third -integration gesture). -**Consistent with the load-bearing principle (make the reasoning explicit):** this is an -**explicit, user-driven placement gesture** — the user is deliberately choosing to place -a playing instrument on a track, exactly as inserting an item into the arrange is a -deliberate placement act. It does **not** auto-capture (the file already exists in the -bank) and does **not** insert a media item into the timeline; it instantiates a *reader* -of the bank on a track and points it at one already-captured sample. Capture, placement, -and playback stay distinct acts; drop-and-load is a placement-of-the-player gesture, not -a capture and not a timeline insert. -**Two-part mechanism:** -- **(a) Internal-drag hover mode.** A drag armed with a *single* capture that stays - *inside* REAPER's own UI (does not cross to Explorer / another app) is tracked by the - extension: it detects the pointer hovering a track's TCP FX button, highlights it as a - drop target, and on release drives the insert. This is a *third* `DragGesture` beyond - the existing `Internal` (bank-to-bank) and `OsDrag` (M11) — call it `InstrumentDrop`. -- **(b) FX-button drop → add-VST + load-capture.** On drop, the extension adds a - ReaSampler 9000 instance to the target track via `TrackFX_AddByName` (verified present - in `reaper_plugin_functions.h`; signature - `int TrackFX_AddByName(MediaTrack*, const char* fxname, bool recFX, int instantiate)` — - use `"VST3:ReaSampler 9000"` and a negative `instantiate` to always create a new - instance), then pushes the dragged capture's identity into that instance so it plays - that sample — via the **load-capture seam** (below). -**The ReaSampler 9000 load-capture seam (the hard Phase S coupling — MUST be added):** -The current Phase S spec gives the instrument a *live-state read* seam (it reads the bank -index + mapping from `"reasampler"` ext-state via the bridge) but **no entry point for an -external actor to say "instantiate playing *this specific* capture."** This wave is the -reason to add that seam. It is a Phase S dependency, not extension-side, and must land in -the instrument before drop-and-load's drop half can work end-to-end. See CONTEXT.md -§Phase S for the two candidate seam mechanisms (fresh-instance ext-state handshake vs. -VST3 `setState` preset injection) and the open question on which is chosen. -**Coexistence with the M11 OS drag-out (disambiguation, load-bearing):** the two drag -modes are disambiguated by **where the pointer goes**, not by a mode toggle. Inside the -panel client rect → `Internal` (unchanged). Left the panel but still over REAPER's own -window/UI → `InstrumentDrop` (new — hover-tracks the FX button). Left REAPER entirely -(Explorer / another app) → `OsDrag` (unchanged M11). The M11 `decideGesture` boundary -(pointer left the client rect) is **refined**, not replaced: leaving the client rect no -longer immediately means OS-bound; it means "resolve which of InstrumentDrop / OsDrag by -whether the pointer is over REAPER's UI." Single-capture vs. multi-capture also -disambiguates — see open questions. -**Verify (in DAW):** dragging a single capture from the dock over a track's FX button -highlights it; dropping instantiates ReaSampler 9000 on that track with the dragged -capture loaded, selected, and MIDI-playable immediately (no manual pick step); the OS -drag-out to Explorer / another DAW still works unchanged; the internal bank-to-bank drag -still works unchanged; no media item is ever inserted into the arrange; the instrument -holds no private copy (it reads the one authoritative bank). -**Depends on:** M11 (`drag_out` gesture machinery — the mode it extends); **Phase S S4** -(a loadable, playing ReaSampler 9000 instance must exist) **AND the new load-capture seam -added inside ReaSampler 9000**. Gated on **Phase S landing on dev** — the instrument and -its seam are on the `phase-s` worktree, not dev; this wave cannot be built on dev until -they merge (same gate posture as L3). - -- [ ] Extend the `drag_out` pure module with the third gesture: `decideGesture` (or a - successor) returns `InstrumentDrop` when a drag armed with a single capture is over - REAPER's UI outside the panel client rect, `OsDrag` only when it has left REAPER - entirely, `Internal`/`OsDrag`/`None` otherwise unchanged. Pure over (drag state + - pointer + panel rect + an "over-own-UI" predicate the shell supplies). Unit-tested — - the existing `drag_out` invariants (M11) must not regress. -- [ ] Shell (extension): hover-track the pointer over REAPER's UI during the drag, - resolve the hovered track + its FX button (verify the TCP/FX-button hit surface against - the SDK — see must-verify), highlight it as a drop target, and on release drive the - drop. Extends the `bank_panel` drag hook alongside the M11 `drag_out_win` path. -- [ ] Shell (extension): on drop, `TrackFX_AddByName(track, "VST3:ReaSampler 9000", - false, /*instantiate*/ negative)` to always add a fresh instance; capture the returned - FX index; then invoke the load-capture seam to point the new instance at the dragged - capture. Batched into one REAPER undo point (`Undo_BeginBlock2`/`EndBlock2`) so the - whole gesture is one Ctrl-Z (mirrors the bank-verb undo discipline). -- [ ] **ReaSampler 9000 (Phase S artifact):** add the **load-capture seam** — the entry - point that lets the just-added instance be told which capture to play (mechanism chosen - per the CONTEXT.md open question). This is the cross-artifact half; it lands in the - instrument, not the extension. -- [ ] Tests: gesture disambiguation (inside-panel / over-REAPER-UI / left-REAPER) across - single- and multi-capture payloads; FX-button hit resolution (pure geometry where it - can be factored out); M11 OS drag-out and internal bank-to-bank drag both unchanged. - -> **Numbering reconciliation (load-bearing for doc-keeper).** On **dev**, Phase S runs -> S1–S6; the next free label is **S7**, assigned here. **However**, the `phase-s` -> worktree carries additional, not-yet-merged Phase S points (a stereo point, an -> **ingest-relay** point, and an S10–S13 UX overhaul — the "S10–S13" the L3 coordination -> contract already references but which are not on dev). Drop-and-load is a **close -> sibling of the worktree's ingest-relay / drop-to-load work** (both are cross-artifact -> "get a capture into an instance" gestures). When `phase-s` merges to dev, **reconcile -> this S7 against the worktree's S7+ numbering** — likely by renumbering this wave and/or -> folding it into the ingest-relay family rather than shipping two overlapping -> drop-into-instrument specs. This label is provisional-on-dev, not a claim that the -> worktree's S7+ do not exist. - ## Phase S — held and optional-forever (noted, not specified) - **Tier 2 — "expressive" (HELD).** Velocity layers, round-robin (anti-machine-gun), full ADSR, per-sample tuning/gain trim, sustain loops. The next depth increment once @@ -363,16 +266,6 @@ they merge (same gate posture as L3). `video_processor.h` / `reaper_plugin_functions.h`. - **`IReaperUIEmbedInterface`** — embed contract + message/lifecycle, against `reaper_plugin_fx_embed.h` (needed only at S6). -- **Drop-and-load (S7) — three surfaces.** (1) `TrackFX_AddByName` — **verified present** - in `reaper_plugin_functions.h` (signature confirmed; the `"VST3:"` name prefix and the - negative-`instantiate`-always-adds semantics are documented in the header comment). (2) - **TCP / FX-button hit resolution** — how the extension resolves the pointer-under-cursor - to a track and its FX-button hotspot during a drag: **not yet confirmed against the - SDK/SWELL** — `GetTrackFromPoint` / `GetThingFromPoint` are candidates to verify against - `reaper_plugin_functions.h`; whether the FX button specifically is addressable (vs. the - TCP as a whole) is an open verification. (3) The **ReaSampler 9000 load-capture seam** — - a *new* interface added inside the Phase S instrument; its mechanism is a Phase S design - choice (see CONTEXT.md §Phase S open question), not a pre-existing SDK surface. ---