feat(vst): stand up VST3 instrument spike (S1) — skeleton, IPlugView↔LICE editor, REAPER bridge read

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.
This commit is contained in:
2026-07-26 15:29:54 -04:00
parent 5595ba42f9
commit 3c2a7c45b2
17 changed files with 1256 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
// reasampler_editor.h — the VST3 IPlugView LICE editor (Phase S1 bridge spike). THIN
// shell: hosts a LICE-drawn child window inside the host's IPlugView seat and routes
// host paint/click into the pure editor_geometry hit-test. Windows-only (D5).
//
// This is the phase's ONE genuine unknown (per CONTEXT.md §Phase S / S1): wiring LICE
// into an IPlugView. It reuses the bank_panel LICE/SWELL competence — a LICE_SysBitmap
// blitted in WM_PAINT, GET_X/Y_LPARAM hit-testing in WM_LBUTTONDOWN — but hangs it off a
// child HWND created in IPlugView::attached() rather than a docked SWELL dialog.
//
// Subclasses CPluginView (public.sdk/source/common/pluginview.h) for the IPlugView
// refcount + attached/removed/getSize/onSize boilerplate; we override the attach/remove
// hooks to create/destroy the child window and onSize to resize it.
#pragma once
#include "public.sdk/source/common/pluginview.h"
#ifdef _WIN32
#include <windows.h>
#endif
namespace reasampler::vst {
class ReaperBridge;
class ReaSamplerEditor : public Steinberg::CPluginView {
public:
// `bridge` is owned by the processor and outlives the editor; the editor reads
// (never mutates) it to show a live-state readout. May be null (non-REAPER host).
explicit ReaSamplerEditor(ReaperBridge* bridge);
~ReaSamplerEditor() override;
// Accept only the Windows HWND platform type (D5: Windows-only).
Steinberg::tresult PLUGIN_API isPlatformTypeSupported(
Steinberg::FIDString type) override;
// The view is user-resizable in the spike so we exercise the onSize path.
Steinberg::tresult PLUGIN_API canResize() override;
protected:
// CPluginView hooks: systemWindow is set by the time attachedToParent() fires.
void attachedToParent() override;
void removedFromParent() override;
Steinberg::tresult PLUGIN_API onSize(Steinberg::ViewRect* newSize) override;
private:
#ifdef _WIN32
// Draw the current surface into the child window's DC via a LICE bitmap.
void paint(HDC hdc);
// Route a client-space click through editor_geometry::hitTest.
void onClick(int x, int y);
static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
HWND childHwnd_ = nullptr;
#endif
ReaperBridge* bridge_ = nullptr;
// Latched on click so the paint reflects the last hit-test result — the spike's
// proof that host->click->draw routing round-trips.
bool buttonHit_ = false;
};
} // namespace reasampler::vst