Merge ME-import → new RS9k instrument
Repurpose INGEST_IMPORT_MEDIA_EXPLORER to stand up a fresh instrument on a new track pre-loaded with the imported sound, instead of force-selecting on the active instance.
This commit is contained in:
+68
-19
@@ -6,6 +6,7 @@
|
||||
#include "instrument_drop_win.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "app_version.h" // vstPluginName() — the CHANNEL-correct FX name (stable/beta pairing)
|
||||
#include "instrument_drop.h" // infoNamesFxHotspot — the PURE, unit-tested hotspot classifier
|
||||
@@ -19,6 +20,12 @@
|
||||
#define REAPERAPI_WANT_TrackFX_SetNamedConfigParm
|
||||
#define REAPERAPI_WANT_Undo_BeginBlock2
|
||||
#define REAPERAPI_WANT_Undo_EndBlock2
|
||||
#define REAPERAPI_WANT_CountTracks
|
||||
#define REAPERAPI_WANT_InsertTrackInProject
|
||||
#define REAPERAPI_WANT_GetTrack
|
||||
#define REAPERAPI_WANT_DeleteTrack
|
||||
#define REAPERAPI_WANT_GetSetMediaTrackInfo_String
|
||||
#define REAPERAPI_WANT_TrackList_AdjustWindows
|
||||
#include "reaper_plugin_functions.h"
|
||||
|
||||
namespace reasampler {
|
||||
@@ -39,7 +46,7 @@ FxDropTarget resolveFxDropTarget(int screenX, int screenY) {
|
||||
return out;
|
||||
}
|
||||
|
||||
bool performInstrumentDrop(MediaTrack* track, const std::string& chunkBase64) {
|
||||
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
|
||||
@@ -48,32 +55,74 @@ bool performInstrumentDrop(MediaTrack* track, const std::string& chunkBase64) {
|
||||
// drops the beta VST, a stable extension the stable VST — with no literal to drift.
|
||||
const std::string fxName = "VST3:" + vstPluginName();
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
bool ok = false;
|
||||
if (fxIndex >= 0) {
|
||||
// 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.
|
||||
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);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
MediaTrack* createTrackWithInstrument(const std::string& trackName,
|
||||
const std::string& chunkBase64) {
|
||||
if (chunkBase64.empty()) return nullptr;
|
||||
|
||||
// Append a new track at the end of the active project (proj=0). flags=0: no default FX/
|
||||
// envelopes — we add exactly the one instrument ourselves. InsertTrackInProject returns
|
||||
// void, so re-fetch the appended track by its (now-last) zero-based index. The index BEFORE
|
||||
// insertion equals the new track's index AFTER insertion (append at the tail).
|
||||
const int newIndex = CountTracks(nullptr);
|
||||
InsertTrackInProject(nullptr, newIndex, /*flags=*/0);
|
||||
MediaTrack* track = GetTrack(nullptr, newIndex);
|
||||
if (!track) return nullptr; // insertion did not yield a fetchable track — nothing to clean up
|
||||
|
||||
// Name the track after the imported sound (RS5k parity). P_NAME writes are propagated to
|
||||
// the panels by TrackList_AdjustWindows below. GetSetMediaTrackInfo_String takes a non-const
|
||||
// buffer even when setting, so copy into a mutable vector.
|
||||
if (!trackName.empty()) {
|
||||
std::vector<char> nameBuf(trackName.begin(), trackName.end());
|
||||
nameBuf.push_back('\0');
|
||||
GetSetMediaTrackInfo_String(track, "P_NAME", nameBuf.data(), /*setNewValue=*/true);
|
||||
}
|
||||
|
||||
// Add + inject the pre-loaded instrument. No inner undo block — the caller owns the grouping
|
||||
// so track-create + persist + FX collapse to one Ctrl-Z. All-or-nothing on failure.
|
||||
if (!loadInstrumentOntoTrack(track, chunkBase64)) {
|
||||
// Roll back the track we just created so the project is left exactly as it was (no
|
||||
// orphaned empty track). DeleteTrack removes the track and everything on it.
|
||||
DeleteTrack(track);
|
||||
TrackList_AdjustWindows(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Repaint the TCP/MCP so the new named track + its FX appear immediately.
|
||||
TrackList_AdjustWindows(false);
|
||||
return track;
|
||||
}
|
||||
|
||||
} // namespace reasampler
|
||||
|
||||
Reference in New Issue
Block a user