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:
@@ -0,0 +1,82 @@
|
||||
// reasampler_processor.cpp — see reasampler_processor.h.
|
||||
|
||||
#include "reasampler_processor.h"
|
||||
|
||||
#include "pluginterfaces/vst/ivstaudioprocessor.h"
|
||||
#include "pluginterfaces/vst/vstspeaker.h"
|
||||
|
||||
#include "reasampler_editor.h"
|
||||
|
||||
using namespace Steinberg;
|
||||
using namespace Steinberg::Vst;
|
||||
|
||||
namespace reasampler::vst {
|
||||
|
||||
FUnknown* ReaSamplerProcessor::createInstance(void* /*context*/) {
|
||||
// The host owns the returned reference. Cast up to the combined interface the SDK
|
||||
// exposes (IAudioProcessor) so the FUnknown refcount is correctly rooted.
|
||||
return static_cast<IAudioProcessor*>(new ReaSamplerProcessor());
|
||||
}
|
||||
|
||||
tresult PLUGIN_API ReaSamplerProcessor::initialize(FUnknown* context) {
|
||||
tresult result = SingleComponentEffect::initialize(context);
|
||||
if (result != kResultOk) return result;
|
||||
|
||||
// Connect the REAPER bridge. Non-fatal if it fails (non-REAPER host): the
|
||||
// instrument still loads, the editor just shows "no bridge".
|
||||
bridge_.connect(context);
|
||||
|
||||
// Instrument bus topology: one event input (MIDI in, 16 channels), one stereo audio
|
||||
// output, no audio input. This is the standard VSTi arrangement.
|
||||
addEventInput(STR16("MIDI In"), 16);
|
||||
addAudioOutput(STR16("Stereo Out"), SpeakerArr::kStereo);
|
||||
|
||||
return kResultOk;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API ReaSamplerProcessor::terminate() {
|
||||
return SingleComponentEffect::terminate();
|
||||
}
|
||||
|
||||
tresult PLUGIN_API ReaSamplerProcessor::setActive(TBool /*state*/) {
|
||||
// Nothing to allocate/free in the silent skeleton; S4 will size voice buffers here
|
||||
// against the setupProcessing block size.
|
||||
return kResultOk;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API ReaSamplerProcessor::setupProcessing(ProcessSetup& setup) {
|
||||
return SingleComponentEffect::setupProcessing(setup);
|
||||
}
|
||||
|
||||
tresult PLUGIN_API ReaSamplerProcessor::process(ProcessData& data) {
|
||||
// Silent skeleton: emit silence on the output bus so the instrument runs cleanly in
|
||||
// REAPER's render/record path without a null buffer. S4 marshals MIDI->core->audio.
|
||||
if (data.numOutputs > 0 && data.outputs && data.numSamples > 0) {
|
||||
AudioBusBuffers& out = data.outputs[0];
|
||||
for (int32 ch = 0; ch < out.numChannels; ++ch) {
|
||||
if (data.symbolicSampleSize == kSample32) {
|
||||
if (float* buf = out.channelBuffers32[ch]) {
|
||||
for (int32 i = 0; i < data.numSamples; ++i) buf[i] = 0.f;
|
||||
}
|
||||
} else if (data.symbolicSampleSize == kSample64) {
|
||||
if (double* buf = out.channelBuffers64[ch]) {
|
||||
for (int32 i = 0; i < data.numSamples; ++i) buf[i] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Flag output silence so the host can optimize (nothing plays yet).
|
||||
out.silenceFlags = (out.numChannels >= 64)
|
||||
? ~0ULL
|
||||
: ((1ULL << out.numChannels) - 1);
|
||||
}
|
||||
return kResultOk;
|
||||
}
|
||||
|
||||
IPlugView* PLUGIN_API ReaSamplerProcessor::createView(FIDString name) {
|
||||
if (name && FIDStringsEqual(name, ViewType::kEditor)) {
|
||||
return new ReaSamplerEditor(&bridge_);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace reasampler::vst
|
||||
Reference in New Issue
Block a user