// native_bridge/src/Vst2Instrument.h // VST2 (VST 2.4, 64-bit) instrument host. Clean-room ABI header // (native_bridge/vestige/aeffect.h) — no Steinberg SDK, no LMMS code. // GUI editor: supported for plugins with kEffectFlagsHasEditor (effEditOpen/ // effEditClose/effEditIdle); preset state is kept via effGetChunk/effSetChunk // (fxp-style chunks). #ifndef VST2_INSTRUMENT_H #define VST2_INSTRUMENT_H #include "INativeInstrument.h" #include #include class Vst2Instrument : public INativeInstrument { public: Vst2Instrument(); ~Vst2Instrument() override; bool loadPlugin(const std::string& path, double sampleRate); void setChannel(uint32_t channel) { channel_ = channel; } bool init(double sampleRate, uint32_t maxBlockSize) override; void selectProgram(uint32_t channel, uint32_t bank, uint32_t program) override; void noteOn(uint32_t channel, uint32_t pitch, float velocity, uint32_t sampleOffset) override; void noteOff(uint32_t channel, uint32_t pitch, uint32_t sampleOffset) override; void controlChange(uint32_t channel, uint32_t cc, uint32_t value) override; void programChange(uint32_t channel, uint32_t program) override; void pitchBend(uint32_t channel, uint32_t bend14) override; bool openGUI(void* parentWindowHandle) override; bool canOpenGUI() const override; bool attachView(void* parentWindowHandle) override; void closeGUI() override; bool hasAttachedView() const override; void guiIdle() override; void captureState() override; void restoreState() override; std::string serializeState() const override; void loadSerializedState(const std::string& base64) override; void processAudioBlock(float* outputL, float* outputR, uint32_t numSamples) override; // Accessors used by the audioMaster callback (same translation unit's // friend-ish helpers) without exposing AEffect* in the header. double sampleRate() const { return sampleRate_; } const std::string& pluginDir() const { return pluginDir_; } uint32_t maxBlockSize() const { return maxBlockSize_; } const void* effect() const; // AEffect*; null until loaded // Host window the editor is attached to (attachView sets, closeGUI // clears). The audioMaster SizeWindow handler moves it via the hook. void* editorParent() const { return editorParent_; } // Register the SizeWindow hook (main.cpp posts the resize to the UI // worker). Probe builds never set it -> no-op. static void setResizeHook(void (*fn)(void* hwnd, int w, int h)); // A14: register the plugin-MIDI-out sink (main.cpp writes SHM // midiOutQueue). Probe builds never set it -> no-op. static void setMidiOutHook(void (*fn)(uint8_t cmd, uint8_t ch, uint8_t d1, uint8_t d2, uint32_t deltaFrames)); private: void* state_; // Vst2HostState* (pimpl — aeffect.h stays out of the header) std::string path_; std::string pluginDir_; double sampleRate_; uint32_t maxBlockSize_; bool loaded_; bool guiAttached_ = false; // effEditOpen done, not yet effEditClose'd void* editorParent_ = nullptr; // host window the editor is a child of uint32_t channel_ = 0; // scratch buffers for silent plugin inputs and extra output channels // (plugins with numOutputs > 2 need full pointer arrays) std::vector inL_; std::vector inR_; std::vector extraOut_; }; #endif // VST2_INSTRUMENT_H