Files
reasampler/src/shell/instrument/reaper_bridge.h
T

91 lines
4.8 KiB
C++

// reaper_bridge.h — the REAPER VST-host bridge. Thin shell: resolves REAPER API functions
// by name over the host context and reads the live "reasampler" project ext-state. The
// fiddly decode lives in bridge_marshal (pure).
//
// Bridge mechanism: REAPER passes an IHostApplication as `context` to
// IComponent::initialize; querying it for IReaperHostApplication yields getReaperApi
// (resolve a REAPER API function pointer by name) and getReaperParent(3) (the host
// ReaProject*; 1=track, 2=take, 3=project, 4=fxdsp, 5=trackchan) — not VST2 hostcb opcodes.
#pragma once
#include <optional>
#include <string>
#include "pluginterfaces/base/funknown.h"
namespace reasampler::vst {
// Wraps the REAPER host bridge for a single plugin instance. Constructed cheaply;
// connect() must be called with the initialize() context before any read. All reads
// degrade to nullopt (never crash) when the host is not REAPER or a symbol is absent —
// the instrument must load in non-REAPER hosts too, just without live state.
class ReaperBridge {
public:
ReaperBridge() = default;
// Binds to the host (`context` is the FUnknown* IComponent::initialize hands us).
// Returns true when the host is REAPER and the ext-state API resolved; safe to call
// with a null or non-REAPER context (returns false).
bool connect(Steinberg::FUnknown* context);
bool isConnected() const { return getProjExtState_ != nullptr; }
// Reads a "reasampler" ext-state value by key from the host's active project.
// Returns nullopt when unconnected, unresolvable, or the key is absent.
//
// NOT REAL-TIME SAFE (allocates + calls into REAPER): audio-thread callers MUST NOT
// invoke this. The instrument reads on the main/UI thread and hands a snapshot to
// the process path.
std::optional<std::string> readReasamplerExtState(const std::string& key);
// The active project's directory (forward-slashed, no trailing slash) — the same
// convention persist uses to place the bank alongside the .rpp. Empty for an unsaved
// project or when unconnected. Not RT-safe.
std::string activeProjectDir();
// Writes THIS INSTANCE's usage record: the ONE sanctioned instrument-side ext-state
// write. `usageKey` MUST carry the "rsusage_" prefix (ext_keys.h's usageKeyFor); any
// other key is refused, enforcing the read-only-bank invariant structurally (banks/
// view/tail/assign stay unwritable from the instrument). Returns true iff written
// (the SetProjExtState return is checked). NOT RT-safe — publish sites are the
// off-audio-thread reload path only. Deliberately does NOT mark the project dirty: a
// usage change always rides a component-state change that already does.
bool writeUsageExtState(const std::string& usageKey, const std::string& value);
// The canonical GUID string of the track hosting this FX instance (same rendering as
// the extension's track_guid::guidString, so usage records compare byte-equal
// against its live-FX enumeration). Empty when unconnected or no track context (the
// usage reader then falls back to any-instance liveness). Not RT-safe.
std::string currentTrackGuid();
private:
// Resolved REAPER API function pointers (by name via getReaperApi). Signatures
// verified against reaper_plugin_functions.h.
using GetProjExtStateFn = int (*)(void* proj, const char* extname, const char* key,
char* valOutNeedBig, int valOutNeedBig_sz);
using EnumProjExtStateFn = bool (*)(void* proj, const char* extname, int idx,
char* keyOut, int keyOut_sz, char* valOut,
int valOut_sz);
// EnumProjects(-1, projfnOut, sz) -> active project + its .rpp path. idx=-1 (current
// tab) follows the active project, same convention as the persist shell.
using EnumProjectsFn = void* (*)(int idx, char* projfnOut, int projfnOut_sz);
// Used ONLY by writeUsageExtState (prefix-guarded) — see the read-only-bank note there.
using SetProjExtStateFn = int (*)(void* proj, const char* extname, const char* key,
const char* value);
// Opaque-pointer signatures so the header stays SDK-type-free; the GUID* is passed
// straight through, never dereferenced here.
using GetTrackGuidFn = void* (*)(void* tr);
using GuidToStringFn = void (*)(const void* g, char* destNeed64);
void* hostApp_ = nullptr; // IReaperHostApplication* (opaque here; used in .cpp)
GetProjExtStateFn getProjExtState_ = nullptr;
EnumProjExtStateFn enumProjExtState_ = nullptr;
EnumProjectsFn enumProjects_ = nullptr;
SetProjExtStateFn setProjExtState_ = nullptr;
GetTrackGuidFn getTrackGuid_ = nullptr;
GuidToStringFn guidToString_ = nullptr;
};
} // namespace reasampler::vst