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:
@@ -0,0 +1,99 @@
|
||||
// reasampler_embed.h — the S6 embedded TCP/MCP UI shell. Implements REAPER's
|
||||
// IReaperUIEmbedInterface (vendor/reaper-sdk/sdk/reaper_plugin_fx_embed.h +
|
||||
// reaper_vst3_interfaces.h) so the instrument draws a compact keymap/level strip INLINE in
|
||||
// the track/mixer control panel — the same Cockos surface REAPER's own embedded FX use.
|
||||
//
|
||||
// VERIFIED CONTRACT (against reaper_plugin_fx_embed.h + reaper_vst3_interfaces.h):
|
||||
// * VST3 exposes this by having the IEditController answer queryInterface for
|
||||
// IReaperUIEmbedInterface (iid {0x049bf9e7,0xbc74ead0,0xc4101e86,0x7f725981}). Our
|
||||
// SingleComponentEffect IS the edit controller, so the processor's queryInterface hands
|
||||
// REAPER a reference to this object.
|
||||
// * The single method is embed_message(int msg, TPtrInt parm2, TPtrInt parm3). msg is a
|
||||
// REAPER_FXEMBED_WM_* value (aliased to Win32 WM_*):
|
||||
// - WM_IS_SUPPORTED (0x0000): return 1 (supported+available), -1, or 0.
|
||||
// - WM_CREATE (0x0001) / WM_DESTROY (0x0002): embed begin/end; return ignored.
|
||||
// - WM_PAINT (0x000F): parm2 = REAPER_FXEMBED_IBitmap* (alias LICE_IBitmap) to draw
|
||||
// into; parm3 = REAPER_FXEMBED_DrawInfo* (context TCP=1/MCP=2, width/height, mouse,
|
||||
// flags). Return 1 if drawing occurred, 0 otherwise.
|
||||
// - WM_GETMINMAXINFO (0x0024): parm3 = SizeHints*; return 1 if filled.
|
||||
// - mouse WM_* (0x0200..0x020A): parm3 = DrawInfo*; return RETNOTIFY_INVALIDATE
|
||||
// (0x1000000) to force a redraw. Capture is auto-managed by the host.
|
||||
// * There is NO plugin-owned window/HWND here (unlike the IPlugView editor): REAPER hands
|
||||
// a LICE bitmap per paint; we only draw into it and read mouse coords from DrawInfo.
|
||||
//
|
||||
// RT DISCIPLINE (S6 constraint): all embed messages arrive on REAPER's UI thread; nothing
|
||||
// here runs in process(). It reads the same live state the editor reads (bank over the
|
||||
// bridge + the processor's performance map) with the same off-audio-thread accessors — no
|
||||
// new locks visible to process, read-only over the bank. Windows-only (D5), guarded so a
|
||||
// non-Windows build stays compilable.
|
||||
//
|
||||
// The strip's LAYOUT + HIT-TEST is pure (embed_strip.h, unit-tested); this shell marshals
|
||||
// REAPER's messages to/from it and draws with the same LICE idiom as reasampler_editor.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "pluginterfaces/base/funknown.h"
|
||||
|
||||
#include "sample_map.h" // SampleChoice, PerformanceMap (the state the strip reflects)
|
||||
|
||||
// REAPER's VST3-side embed interface (vendored). Uses UNQUALIFIED Steinberg types, so it is
|
||||
// pulled into the Steinberg namespace the same way reaper_bridge.cpp includes the host
|
||||
// interface header. Its iid is DEFINEd (DEF_CLASS_IID) in reasampler_embed.cpp.
|
||||
namespace Steinberg {
|
||||
#include "reaper_vst3_interfaces.h"
|
||||
} // namespace Steinberg
|
||||
|
||||
namespace reasampler::vst {
|
||||
|
||||
class ReaSamplerProcessor;
|
||||
|
||||
// Implements IReaperUIEmbedInterface. Lifetime is OWNED by the processor (the processor
|
||||
// holds the sole unique_ptr and hands out AddRef'd references from queryInterface); the
|
||||
// back-pointer to the processor is therefore always valid while this lives.
|
||||
class ReaSamplerEmbed : public Steinberg::IReaperUIEmbedInterface {
|
||||
public:
|
||||
explicit ReaSamplerEmbed(ReaSamplerProcessor* processor) : processor_(processor) {}
|
||||
|
||||
// The one embed entry point. Routes each REAPER_FXEMBED_WM_* message; see the header
|
||||
// note above for the per-message contract. UI thread only.
|
||||
Steinberg::TPtrInt embed_message(int msg, Steinberg::TPtrInt parm2,
|
||||
Steinberg::TPtrInt parm3) override;
|
||||
|
||||
// FUnknown: this object's lifetime is owned by the processor, not the host refcount, so
|
||||
// AddRef/release are no-ops (the processor's unique_ptr governs destruction) and
|
||||
// queryInterface answers only FUnknown + IReaperUIEmbedInterface. This mirrors how the
|
||||
// SDK's OBJ refcount would otherwise churn; here the owning processor guarantees the
|
||||
// object outlives every borrowed reference REAPER holds during embedding.
|
||||
Steinberg::tresult PLUGIN_API queryInterface(const Steinberg::TUID iid,
|
||||
void** obj) override;
|
||||
Steinberg::uint32 PLUGIN_API addRef() override { return 1000; }
|
||||
Steinberg::uint32 PLUGIN_API release() override { return 1000; }
|
||||
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
// Draw the current strip into REAPER's supplied LICE bitmap. Returns true if it drew.
|
||||
bool paint(Steinberg::TPtrInt bitmap, Steinberg::TPtrInt drawInfo);
|
||||
// Handle a mouse-down inside the strip: map to a zone and select it (S6: selection at
|
||||
// most — no new editing semantics). Returns true if the selection changed (the caller
|
||||
// then asks REAPER to invalidate).
|
||||
bool onMouseDown(Steinberg::TPtrInt drawInfo);
|
||||
#endif
|
||||
|
||||
// Snapshot the live bank + the instrument's performance map for the next paint, exactly
|
||||
// as the editor's refreshSampleList does (bridge read + processor accessors, UI thread).
|
||||
void refresh();
|
||||
|
||||
ReaSamplerProcessor* processor_ = nullptr;
|
||||
// Snapshotted for the current paint (refreshed each paint off the audio thread).
|
||||
std::vector<SampleChoice> samples_;
|
||||
PerformanceMap map_;
|
||||
std::string selectedId_;
|
||||
// The zone the last click selected (mirrored to the processor's editor-shared selection
|
||||
// where meaningful); -1 = none. Drives the strip's highlight.
|
||||
int selectedZone_ = -1;
|
||||
};
|
||||
|
||||
} // namespace reasampler::vst
|
||||
Reference in New Issue
Block a user