Added VST SDK support.
This commit is contained in:
parent
a1482ec110
commit
8e09f58944
25 changed files with 850 additions and 23 deletions
132
examples/steinberg/sdk_plugins.cpp
Normal file
132
examples/steinberg/sdk_plugins.cpp
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
// Original MIT-licensed xtc examples using an external official Steinberg SDK.
|
||||
// C++ is confined to this optional SDK example, never linked into libxtc.
|
||||
#include "public.sdk/source/vst/vstaudioeffect.h"
|
||||
#include "public.sdk/source/vst/vsteditcontroller.h"
|
||||
#include "public.sdk/source/main/pluginfactory.h"
|
||||
#include "pluginterfaces/base/ibstream.h"
|
||||
#include "pluginterfaces/vst/ivstevents.h"
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
|
||||
namespace {
|
||||
using namespace Steinberg;
|
||||
using namespace Steinberg::Vst;
|
||||
|
||||
const FUID controllerID(0x58544343,0x4F4E5431,0x98561234,0xABCD0003);
|
||||
class Controller final : public EditController {
|
||||
public:
|
||||
static FUnknown* create(void*) { return static_cast<IEditController*>(new Controller); }
|
||||
tresult PLUGIN_API setComponentState(IBStream* stream) override { return stream ? kResultOk : kInvalidArgument; }
|
||||
};
|
||||
|
||||
class Gain final : public AudioEffect {
|
||||
public:
|
||||
Gain() { setControllerClass(controllerID); }
|
||||
static FUnknown* create(void*) { return static_cast<IAudioProcessor*>(new Gain); }
|
||||
tresult PLUGIN_API initialize(FUnknown* host) override {
|
||||
const auto result = AudioEffect::initialize(host);
|
||||
if (result != kResultOk) return result;
|
||||
addAudioInput(STR16("Input"), SpeakerArr::kMono);
|
||||
addAudioOutput(STR16("Output"), SpeakerArr::kMono);
|
||||
return kResultOk;
|
||||
}
|
||||
tresult PLUGIN_API setBusArrangements(SpeakerArrangement* in, int32 ni,
|
||||
SpeakerArrangement* out, int32 no) override {
|
||||
if (ni != 1 || no != 1 || !in || !out || in[0] != SpeakerArr::kMono || out[0] != SpeakerArr::kMono)
|
||||
return kResultFalse;
|
||||
return AudioEffect::setBusArrangements(in, ni, out, no);
|
||||
}
|
||||
tresult PLUGIN_API canProcessSampleSize(int32 size) override {
|
||||
return size == kSample32 ? kResultOk : kResultFalse;
|
||||
}
|
||||
tresult PLUGIN_API setProcessing(TBool) override { return kResultOk; }
|
||||
tresult PLUGIN_API process(ProcessData& data) override {
|
||||
if (data.symbolicSampleSize != kSample32 || data.numSamples < 0) return kInvalidArgument;
|
||||
if (!data.numSamples) return kResultOk;
|
||||
if (data.numInputs != 1 || data.numOutputs != 1 || !data.inputs || !data.outputs ||
|
||||
data.inputs[0].numChannels != 1 || data.outputs[0].numChannels != 1 ||
|
||||
!data.inputs[0].channelBuffers32 || !data.outputs[0].channelBuffers32 ||
|
||||
!data.inputs[0].channelBuffers32[0] || !data.outputs[0].channelBuffers32[0]) return kInvalidArgument;
|
||||
for (int32 i = 0; i < data.numSamples; ++i)
|
||||
data.outputs[0].channelBuffers32[0][i] = data.inputs[0].channelBuffers32[0][i] * .5f;
|
||||
data.outputs[0].silenceFlags = data.inputs[0].silenceFlags;
|
||||
return kResultOk;
|
||||
}
|
||||
// Stateless examples still implement the SDK's stream contract.
|
||||
tresult PLUGIN_API setState(IBStream* stream) override { return stream ? kResultOk : kInvalidArgument; }
|
||||
tresult PLUGIN_API getState(IBStream* stream) override { return stream ? kResultOk : kInvalidArgument; }
|
||||
};
|
||||
|
||||
class Sine final : public AudioEffect {
|
||||
struct Voice { double phase = 0; float velocity = 0; };
|
||||
std::array<std::array<Voice, 128>, 16> voices{};
|
||||
void event(const Event& e) {
|
||||
if (e.type == Event::kNoteOnEvent && e.noteOn.channel >= 0 && e.noteOn.channel < 16 &&
|
||||
e.noteOn.pitch >= 0 && e.noteOn.pitch < 128) {
|
||||
auto& v = voices[e.noteOn.channel][e.noteOn.pitch];
|
||||
v.phase = 0; v.velocity = e.noteOn.velocity;
|
||||
} else if (e.type == Event::kNoteOffEvent && e.noteOff.channel >= 0 && e.noteOff.channel < 16 &&
|
||||
e.noteOff.pitch >= 0 && e.noteOff.pitch < 128)
|
||||
voices[e.noteOff.channel][e.noteOff.pitch].velocity = 0;
|
||||
}
|
||||
public:
|
||||
Sine() { setControllerClass(controllerID); }
|
||||
static FUnknown* create(void*) { return static_cast<IAudioProcessor*>(new Sine); }
|
||||
tresult PLUGIN_API initialize(FUnknown* host) override {
|
||||
const auto result = AudioEffect::initialize(host);
|
||||
if (result != kResultOk) return result;
|
||||
addEventInput(STR16("Notes"), 16);
|
||||
addAudioOutput(STR16("Output"), SpeakerArr::kMono);
|
||||
return kResultOk;
|
||||
}
|
||||
tresult PLUGIN_API setBusArrangements(SpeakerArrangement*, int32 ni,
|
||||
SpeakerArrangement* out, int32 no) override {
|
||||
if (ni != 0 || no != 1 || !out || out[0] != SpeakerArr::kMono) return kResultFalse;
|
||||
return kResultOk;
|
||||
}
|
||||
tresult PLUGIN_API canProcessSampleSize(int32 size) override { return size == kSample32 ? kResultOk : kResultFalse; }
|
||||
tresult PLUGIN_API setProcessing(TBool) override { voices = {}; return kResultOk; }
|
||||
tresult PLUGIN_API process(ProcessData& data) override {
|
||||
if (data.symbolicSampleSize != kSample32 || data.numSamples < 0) return kInvalidArgument;
|
||||
if (!data.numSamples) return kResultOk;
|
||||
if (data.numOutputs != 1 || !data.outputs || data.outputs[0].numChannels != 1 ||
|
||||
!data.outputs[0].channelBuffers32 || !data.outputs[0].channelBuffers32[0]) return kInvalidArgument;
|
||||
int32 index = 0;
|
||||
const int32 count = data.inputEvents ? data.inputEvents->getEventCount() : 0;
|
||||
Event next{};
|
||||
bool pending = index < count && data.inputEvents->getEvent(index, next) == kResultOk;
|
||||
bool silent = true;
|
||||
for (int32 i = 0; i < data.numSamples; ++i) {
|
||||
while (pending && next.sampleOffset <= i) {
|
||||
event(next); ++index;
|
||||
pending = index < count && data.inputEvents->getEvent(index, next) == kResultOk;
|
||||
}
|
||||
double value = 0;
|
||||
for (auto& channel : voices) for (size_t key = 0; key < channel.size(); ++key) {
|
||||
auto& v = channel[key];
|
||||
if (v.velocity == 0) continue;
|
||||
value += std::sin(v.phase) * v.velocity * .1;
|
||||
v.phase += 6.283185307179586 * 440.0 * std::pow(2.0, (static_cast<double>(key)-69.0)/12.0) / processSetup.sampleRate;
|
||||
v.phase = std::fmod(v.phase, 6.283185307179586);
|
||||
}
|
||||
data.outputs[0].channelBuffers32[0][i] = static_cast<float>(std::tanh(value));
|
||||
if (value != 0) silent = false;
|
||||
}
|
||||
data.outputs[0].silenceFlags = silent ? 1 : 0;
|
||||
return kResultOk;
|
||||
}
|
||||
tresult PLUGIN_API setState(IBStream* stream) override { return stream ? kResultOk : kInvalidArgument; }
|
||||
tresult PLUGIN_API getState(IBStream* stream) override { return stream ? kResultOk : kInvalidArgument; }
|
||||
};
|
||||
}
|
||||
BEGIN_FACTORY("xtc", "", "", 0)
|
||||
DEF_CLASS2(INLINE_UID(0x58544347,0x41494E31,0x98561234,0xABCD0001),
|
||||
PClassInfo::kManyInstances, kVstAudioEffectClass, "xtc SDK Half Gain", 0,
|
||||
"Fx", "1.0.0", kVstVersionString, Gain::create)
|
||||
DEF_CLASS2(INLINE_UID(0x58544353,0x494E4531,0x98561234,0xABCD0002),
|
||||
PClassInfo::kManyInstances, kVstAudioEffectClass, "xtc SDK Sine", 0,
|
||||
"Instrument|Synth", "1.0.0", kVstVersionString, Sine::create)
|
||||
DEF_CLASS2(INLINE_UID(0x58544343,0x4F4E5431,0x98561234,0xABCD0003),
|
||||
PClassInfo::kManyInstances, kVstComponentControllerClass, "xtc SDK Controller", 0,
|
||||
"", "1.0.0", kVstVersionString, Controller::create)
|
||||
END_FACTORY
|
||||
Loading…
Add table
Add a link
Reference in a new issue