3c2a7c45b2
Vendor Steinberg VST3 SDK (v3.7.9_build_61); add reasampler_vst.vst3 as a second, additive build artifact with pure editor-geometry + bridge-marshal helpers under CTest.
89 lines
4.1 KiB
C++
89 lines
4.1 KiB
C++
// reaper_bridge.cpp — see reaper_bridge.h. The DAW-facing edge; keep it thin.
|
|
|
|
#include "reaper_bridge.h"
|
|
|
|
#include <vector>
|
|
|
|
#include "bridge_marshal.h"
|
|
|
|
// The VST3 base types must be included before REAPER's VST3 interface header, which
|
|
// uses FUnknown / CStringA / uint32 / DECLARE_CLASS_IID / PLUGIN_API from
|
|
// pluginterfaces/base — all in namespace Steinberg.
|
|
#include "pluginterfaces/base/funknown.h"
|
|
#include "pluginterfaces/base/ftypes.h"
|
|
|
|
// REAPER's VST3-side bridge interface (vendored). IReaperHostApplication is what REAPER
|
|
// passes (as an IHostApplication) to IComponent::initialize; it exposes getReaperApi
|
|
// (resolve-by-name) and getReaperParent (host context). The header uses UNQUALIFIED
|
|
// Steinberg types (FUnknown, CStringA, uint32, FUID, DECLARE_CLASS_IID, PLUGIN_API), so
|
|
// it must be pulled into the Steinberg namespace — the same way REAPER's own VST3
|
|
// examples include it.
|
|
namespace Steinberg {
|
|
#include "reaper_vst3_interfaces.h"
|
|
} // namespace Steinberg
|
|
|
|
// DECLARE_CLASS_IID in the REAPER header only DECLARES IReaperHostApplication::iid; some
|
|
// TU must DEFINE it. We do it here — this is the only place that queries for the
|
|
// interface (FUnknownPtr uses the iid), so the definition lives with its sole use.
|
|
DEF_CLASS_IID(Steinberg::IReaperHostApplication)
|
|
|
|
// The "reasampler" ext-state namespace + bank key. Kept in sync with persist.h by
|
|
// value (the extension writes them); we only READ here, so we duplicate the two string
|
|
// constants rather than pull the whole REAPER-facing persist.h into the VST artifact.
|
|
// If persist.h's kProjExtNamespace / kProjExtBanksKey ever change, these must follow —
|
|
// they are the shared wire contract between the extension (writer) and instrument
|
|
// (reader). VERIFY against persist.h.
|
|
namespace {
|
|
constexpr const char* kReasamplerNamespace = "reasampler";
|
|
}
|
|
|
|
namespace reasampler::vst {
|
|
|
|
bool ReaperBridge::connect(Steinberg::FUnknown* context) {
|
|
getProjExtState_ = nullptr;
|
|
enumProjExtState_ = nullptr;
|
|
hostApp_ = nullptr;
|
|
if (!context) return false;
|
|
|
|
// Query the host context for REAPER's bridge interface. In a non-REAPER host this
|
|
// query fails and we stay unconnected — the instrument still loads.
|
|
Steinberg::FUnknownPtr<Steinberg::IReaperHostApplication> reaper(context);
|
|
if (!reaper) return false;
|
|
hostApp_ = reaper.get();
|
|
|
|
// Resolve the ext-state functions by name. getReaperApi returns the same function
|
|
// pointers the extension resolves via rec->GetFunc; a null return means the symbol
|
|
// is unavailable (very old REAPER) — degrade gracefully.
|
|
getProjExtState_ = reinterpret_cast<GetProjExtStateFn>(
|
|
reaper->getReaperApi("GetProjExtState"));
|
|
enumProjExtState_ = reinterpret_cast<EnumProjExtStateFn>(
|
|
reaper->getReaperApi("EnumProjExtState"));
|
|
|
|
return getProjExtState_ != nullptr;
|
|
}
|
|
|
|
std::optional<std::string> ReaperBridge::readReasamplerExtState(const std::string& key) {
|
|
if (!getProjExtState_ || !hostApp_) return std::nullopt;
|
|
|
|
// Fetch the host project (getReaperParent(3) — project). Reads that live "reasampler"
|
|
// ext-state against the ACTIVE project the instrument was instantiated in, so it
|
|
// follows project switches for free (D6).
|
|
auto* reaper = static_cast<Steinberg::IReaperHostApplication*>(hostApp_);
|
|
void* proj = reaper->getReaperParent(3);
|
|
// A null project is legitimate (e.g. instantiated before a project context exists);
|
|
// REAPER treats null as the current project for these calls, so we pass it through
|
|
// rather than bailing — but if the read yields nothing the caller sees nullopt.
|
|
|
|
// GetProjExtState writes into a caller buffer; size it generously for a JSON blob
|
|
// and let the pure decoder interpret the result. The buffer is NUL-terminated by
|
|
// REAPER on success.
|
|
std::vector<char> buf(64 * 1024, '\0');
|
|
const int rv = getProjExtState_(proj, kReasamplerNamespace, key.c_str(), buf.data(),
|
|
static_cast<int>(buf.size()));
|
|
|
|
// Marshal the raw result through the pure decoder (handles the absent-key case).
|
|
return decodeGetProjExtState(rv, std::string(buf.data()));
|
|
}
|
|
|
|
} // namespace reasampler::vst
|