3a95ce61fe
No track is created; no routing changes. No selected track -> bank import proceeds, instrument placement is refused with a console message explaining why. createTrackWithInstrument removed (was sole caller).
85 lines
4.1 KiB
C++
85 lines
4.1 KiB
C++
// instrument_drop_win — the REAPER shell for S17 drop-and-load. See instrument_drop_win.h.
|
|
//
|
|
// Compiled into the reaper_reasampler MODULE. Includes reaper_plugin_functions.h WITHOUT
|
|
// REAPERAPI_IMPLEMENT (main.cpp owns the pointers; here they are extern via the WANT list).
|
|
|
|
#include "instrument_drop_win.h"
|
|
|
|
#include <string>
|
|
|
|
#include "app_version.h" // vstPluginName() — the CHANNEL-correct FX name (stable/beta pairing)
|
|
#include "instrument_drop.h" // infoNamesFxHotspot — the PURE, unit-tested hotspot classifier
|
|
|
|
#include "reaper_plugin.h"
|
|
|
|
#define REAPERAPI_MINIMAL
|
|
#define REAPERAPI_WANT_GetThingFromPoint
|
|
#define REAPERAPI_WANT_TrackFX_AddByName
|
|
#define REAPERAPI_WANT_TrackFX_Delete
|
|
#define REAPERAPI_WANT_TrackFX_SetNamedConfigParm
|
|
#define REAPERAPI_WANT_Undo_BeginBlock2
|
|
#define REAPERAPI_WANT_Undo_EndBlock2
|
|
#include "reaper_plugin_functions.h"
|
|
|
|
namespace reasampler {
|
|
|
|
FxDropTarget resolveFxDropTarget(int screenX, int screenY) {
|
|
FxDropTarget out;
|
|
char info[256] = {0};
|
|
// GetThingFromPoint returns the track under the point (may be null for a non-track thing)
|
|
// and fills `info` with what was hit. A non-empty info OR a non-null track means the point
|
|
// is over REAPER's own UI; a null track with an empty info means the pointer has left
|
|
// REAPER entirely (over another app / the desktop) — the OsDrag boundary.
|
|
MediaTrack* track = GetThingFromPoint(screenX, screenY, info, sizeof(info));
|
|
out.track = track;
|
|
out.overReaperUi = (track != nullptr) || (info[0] != '\0');
|
|
// S-VIEW-BUG-1: the hotspot is either the FX chain/floating window ("fx_*") OR the track/
|
|
// mixer panel that hosts the FX button ("tcp*"/"mcp*"). The pure classifier owns the rule.
|
|
out.overFxHotspot = (track != nullptr) && infoNamesFxHotspot(info);
|
|
return out;
|
|
}
|
|
|
|
bool loadInstrumentOntoTrack(MediaTrack* track, const std::string& chunkBase64) {
|
|
if (!track || chunkBase64.empty()) return false;
|
|
|
|
// The CHANNEL-correct FX name: "VST3:ReaSampler 9000" on stable, "VST3:ReaSampler 9000
|
|
// beta" on beta. Sourcing it from app_version::vstPluginName() (the same accessor the VST
|
|
// factory display name derives from) keeps the pairing invariant intact — a beta extension
|
|
// drops the beta VST, a stable extension the stable VST — with no literal to drift.
|
|
const std::string fxName = "VST3:" + vstPluginName();
|
|
|
|
// Negative `instantiate` => always create a NEW instance (verified in the header). recFX
|
|
// = false: a normal track FX chain instance, not a record/monitoring FX.
|
|
const int fxIndex = TrackFX_AddByName(track, fxName.c_str(), /*recFX=*/false,
|
|
/*instantiate=*/-1);
|
|
if (fxIndex < 0) return false;
|
|
|
|
// Inject the instrument's OWN component-state blob (the dragged capture pre-selected)
|
|
// via the documented vst_chunk write-parm. The blob was built by the shared writer
|
|
// (instrument_drop::buildInstrumentDropChunk -> sample_map::serializeComponentState),
|
|
// so these bytes are exactly what ReaSampler 9000's setState accepts.
|
|
const bool ok =
|
|
TrackFX_SetNamedConfigParm(track, fxIndex, "vst_chunk", chunkBase64.c_str());
|
|
if (!ok) {
|
|
// All-or-nothing: if the chunk write fails, remove the empty FX instance we just
|
|
// added so the track is left exactly as it was. TrackFX_Delete signature (verified
|
|
// in reaper_plugin_functions.h:7236): bool TrackFX_Delete(MediaTrack*, int fx).
|
|
TrackFX_Delete(track, fxIndex);
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
bool performInstrumentDrop(MediaTrack* track, const std::string& chunkBase64) {
|
|
if (!track || chunkBase64.empty()) return false;
|
|
|
|
// One undo point for the whole gesture (mirrors the bank-verb undo discipline). Both the
|
|
// FX add and the state write are REAPER-undoable, so Ctrl-Z removes the instance cleanly.
|
|
Undo_BeginBlock2(nullptr);
|
|
const bool ok = loadInstrumentOntoTrack(track, chunkBase64);
|
|
// The undo label reflects the placement-of-the-player framing (not a capture, not an insert).
|
|
Undo_EndBlock2(nullptr, "ReaSampler: drop capture onto FX chain", -1);
|
|
return ok;
|
|
}
|
|
|
|
} // namespace reasampler
|