Files
SonicForgeStudio/native_bridge/src/Vst2Instrument.h
T
admin 6a3b430da0 A14: MIDI-out từ plugin (VST2/VST3) → SHM → Rust emit → DAW track
- Vst2Instrument: audioMaster callback thu VstEvents, push SHM midiOutQueue
- Vst3Instrument: IEventList output bus (kAudioMasterWantMidi) — check
- SharedMemoryIPC.h: midiOutQueue[64] + midiOutCount (offset 27556/28324, sizeof 28328)
- shm.rs: MidiEventIPC Serialize, drain_midi_out() emit 'bridge-midi-out'
- lib.rs: pump emit midi-out events
- nativeBridgeService.js: onMidiOut API
- app.jsx: route MIDI-out về selected track qua SonicMidiRouter (feedback guard)
- TASKS.md: A14 ✅
2026-08-19 21:12:07 +07:00

77 lines
3.4 KiB
C++

// 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 <string>
#include <vector>
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<float> inL_;
std::vector<float> inR_;
std::vector<float> extraOut_;
};
#endif // VST2_INSTRUMENT_H