Files
SonicForgeStudio/native_bridge/include/Vst3Instrument.h
T
admin f7f20e3a0a fix(bridge): stop leaves sound looping — EventList maxSize=50 drops STOP sweep note-offs
Root cause: Steinberg EventList defaults to maxSize=50 events. The STOP
all-notes-off sweep queues 128 note-offs per channel (16ch x 128 pitch),
so addEvent beyond 50 fails silently and the plugin never receives the
remaining note-offs — voices keep sustaining and the transport loops
forever until the bridge process is killed.

Fix: raise eventList.setMaxSize(4096) in loadPlugin. Also assign unique
noteIds per overlapping note-on (stack per pitch) so note-off releases
every voice at that pitch, and log addEvent result + channel in debug
output for verification.
2026-08-14 09:45:50 +07:00

51 lines
2.0 KiB
C++

// native_bridge/include/Vst3Instrument.h
// VST3 host instrument (A7). Compiled ALWAYS; the real vst3sdk wiring is
// inside #ifdef HAVE_VST3SDK (set by CMake when the vst3sdk submodule is
// present). Without the SDK the class degrades to a no-op stub so the bridge
// still builds for SF2/SF3/SFZ.
#ifndef VST3_INSTRUMENT_H
#define VST3_INSTRUMENT_H
#include "INativeInstrument.h"
#include <string>
class Vst3Instrument : public INativeInstrument {
public:
Vst3Instrument();
~Vst3Instrument() override;
bool loadPlugin(const std::string& path, double sampleRate);
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 reloadForGUI() override;
bool attachView(void* parentWindowHandle) override;
void closeGUI() override;
void setChannel(uint32_t ch) { channel_ = ch; }
bool needsReload() const override { return hasAttachedOnce_ && !guiAttached_; }
void setReloading(bool on) override { reloading_ = on; }
void processAudioBlock(float* outputL, float* outputR, uint32_t numSamples) override;
private:
// pimpl: all Steinberg SDK types live in Vst3Instrument.cpp (Vst3HostState).
void* state_;
std::string path_;
double sampleRate_;
uint32_t maxBlockSize_;
bool loaded_;
bool guiAttached_;
bool hasAttachedOnce_;
bool reloading_; // guarded by InstrumentEngineManager::mu_ (set via setReloading)
uint32_t channel_ = 0;
bool reload();
};
#endif // VST3_INSTRUMENT_H