S6: embedded TCP/MCP UI via IReaperUIEmbedInterface
Inline keymap/level strip drawn into REAPER's embed bitmap, reusing the LICE idiom. Pure embed_strip layout/hit-test (tested); processor exposes the embed interface off queryInterface and publishes an RT-safe block peak for the level.
This commit is contained in:
@@ -33,6 +33,8 @@
|
||||
|
||||
namespace reasampler::vst {
|
||||
|
||||
class ReaSamplerEmbed; // S6 embedded TCP/MCP UI shell (owned below; see queryInterface)
|
||||
|
||||
// One fully-built, ready-to-play instrument snapshot: the decoded keymap and the voice
|
||||
// engine that plays it. The engine holds a reference into the keymap, so the two MUST
|
||||
// live and die together at a STABLE address — hence this is heap-allocated and neither
|
||||
@@ -59,6 +61,9 @@ struct LoadedInstrument {
|
||||
class ReaSamplerProcessor : public Steinberg::Vst::SingleComponentEffect {
|
||||
public:
|
||||
ReaSamplerProcessor() = default;
|
||||
// Out-of-line so the owned ReaSamplerEmbed (held by unique_ptr, forward-declared here)
|
||||
// is a complete type at the destruction point (defined in the .cpp).
|
||||
~ReaSamplerProcessor() override;
|
||||
|
||||
// The factory create function (registered in vst_entry.cpp).
|
||||
static Steinberg::FUnknown* createInstance(void* /*context*/);
|
||||
@@ -87,6 +92,19 @@ public:
|
||||
// Hands the host our LICE IPlugView editor.
|
||||
Steinberg::IPlugView* PLUGIN_API createView(Steinberg::FIDString name) override;
|
||||
|
||||
// Override queryInterface to additionally expose REAPER's IReaperUIEmbedInterface (S6):
|
||||
// REAPER queries the IEditController for it to drive the inline TCP/MCP embed surface.
|
||||
// All other iids delegate to SingleComponentEffect's implementation unchanged.
|
||||
Steinberg::tresult PLUGIN_API queryInterface(const Steinberg::TUID iid,
|
||||
void** obj) override;
|
||||
|
||||
// The embedded-strip activity level (0..1), read by the S6 embed shell on the UI thread.
|
||||
// Backed by embedPeak_, the per-block mono peak the audio thread stores relaxed — a
|
||||
// lock-free advisory readout, never touched with a lock the audio thread could contend.
|
||||
double embedActivityLevel() const {
|
||||
return static_cast<double>(embedPeak_.load(std::memory_order_relaxed));
|
||||
}
|
||||
|
||||
// Called by the editor (main/UI thread) when the user picks a sample, and internally
|
||||
// on load. Reads the live bank over the bridge, resolves+decodes the selected WAV
|
||||
// OFF the audio thread, and publishes the built instrument to process() via an
|
||||
@@ -163,6 +181,18 @@ private:
|
||||
// off-thread only.
|
||||
double sampleRate_ = 44100.0;
|
||||
Steinberg::int32 maxBlockSize_ = 4096;
|
||||
|
||||
// --- S6 embedded TCP/MCP UI ---------------------------------------------
|
||||
// The embed shell (IReaperUIEmbedInterface), created lazily on the first queryInterface
|
||||
// and owned here for the processor's lifetime. REAPER borrows AddRef'd references from
|
||||
// queryInterface; the shell's refcount is a no-op because THIS unique_ptr governs its
|
||||
// destruction (the processor always outlives the borrowed references).
|
||||
std::unique_ptr<ReaSamplerEmbed> embed_;
|
||||
|
||||
// The per-block mono peak (0..1+) the audio thread stores relaxed; the embed strip's
|
||||
// level indicator reads it via embedActivityLevel(). Advisory only — a plain atomic,
|
||||
// no ordering coupling, never guarded by a lock the audio thread touches.
|
||||
std::atomic<float> embedPeak_{0.f};
|
||||
};
|
||||
|
||||
} // namespace reasampler::vst
|
||||
|
||||
Reference in New Issue
Block a user