#pragma once // instrument_drop_win — the REAPER-facing shell half of S17 drop-and-load. The pure gesture // decision lives in drag_out (DragGesture::InstrumentDrop) and the pure payload construction // in instrument_drop; THIS is the platform shell that (a) resolves a screen point to a track // + its FX-surface hotspot via REAPER's hit-test API, and (b) on release adds a ReaSampler // 9000 instance to that track and applies the dragged capture as its component state via a // temp .vstpreset + TrackFX_SetPreset (S-GA-DropFX: the earlier "vst_chunk" named-config-parm // write was silently unappliable — see instrument_drop.h for the diagnosis). // // Compiled into the reaper_reasampler MODULE. REAPER-facing (GetThingFromPoint, TrackFX_*, // Undo_*), so DAW-verified, not unit-tested; the pure decision + preset it drives are CTest'd. // // LOAD-BEARING (CONTEXT.md §Drop-and-load): this is an EXPLICIT user placement-of-the-player // gesture — it adds a READER of the bank on a track and points it at one already-captured // sample. It NEVER captures, NEVER writes the bank, and NEVER inserts a timeline item. The // only writes are: a new FX instance on the target track + that instance's own component // state — both REAPER-undoable, wrapped in one undo block so the whole gesture is one Ctrl-Z // — plus a transient .vstpreset in the OS temp dir, deleted before returning. #include #include // Opaque REAPER track handle at the boundary so includers don't need the SDK. The SDK // declares it as a class (reaper_plugin.h) — match that spelling so the mangled name agrees. class MediaTrack; namespace reasampler { // The result of hit-testing a screen point during a live InstrumentDrop drag. struct FxDropTarget { MediaTrack* track = nullptr; // the track under the pointer (null if none / not a track) bool overReaperUi = false; // the point is over REAPER's own window/UI at all bool overFxHotspot = false; // specifically over this track's FX button/chain surface // A valid drop target: a resolved track whose FX hotspot is under the pointer. bool valid() const { return track != nullptr && overFxHotspot; } }; // Hit-test a screen point (REAPER screen coords) to an FX drop target. Wraps // GetThingFromPoint, whose info string tells us what was hit ("tcp.fx*"/"mcp.fx*" for the // TCP/MCP FX button family; "fx_chain"/"fx_N" for the FX-chain and floating-FX windows; bare // "tcp"/"mcp" or other sub-element tokens for non-FX track-panel regions). `overReaperUi` is // the shell-supplied predicate the pure drag_out::decideGesture consumes (true when the point // is over REAPER's own UI — i.e. GetThingFromPoint returned a track OR a recognizable // non-track thing, false when the pointer has left REAPER entirely). `overFxHotspot` is true // only when the info string names a genuine FX-bearing surface — decided by the pure // instrument_drop::infoNamesFxHotspot from the SDK's own hit-test string. FxDropTarget resolveFxDropTarget(int screenX, int screenY); // Perform the drop on `track`: add a fresh ReaSampler 9000 instance and apply `presetBytes` // (the instrument_drop::buildInstrumentDropPreset output — a .vstpreset image) as its // component state so it plays the dragged capture. Wraps the add + apply in one REAPER undo // block (mirrors the bank-verb undo discipline). Returns true on success (the FX was added // and the preset applied), false on any failure. All-or-nothing: if the preset apply fails // after a successful add, the freshly-added FX instance is removed via TrackFX_Delete before // returning false, leaving the track exactly as it was (no orphaned empty-state FX). // NEVER inserts a timeline item; the ONLY persistent mutations are the FX instance + its // state, both undoable. bool performInstrumentDrop(MediaTrack* track, const std::vector& presetBytes); // Add a fresh ReaSampler 9000 instance to `track` and apply `presetBytes` as its component // state. Same all-or-nothing add+apply contract as performInstrumentDrop (rolls the FX back // via TrackFX_Delete on apply failure), but does NOT open its own undo block — the caller owns // the undo grouping so the whole gesture (persist + FX-add + apply) collapses to // one Ctrl-Z. This is the shared inner half performInstrumentDrop wraps in its own block. // Returns true on success, false on any failure. NEVER inserts a timeline item. bool loadInstrumentOntoTrack(MediaTrack* track, const std::vector& presetBytes); } // namespace reasampler