I've been trying to write a simple VST plugin. It doesn't need any fancy interfaces, just a few controls. But I don't know where to start. Begin huge wall of text.
I've been researching religiously around the net for information and guides on this topic, but the best I've found so far is this and this page. While they're good, I can't seem to recreate a program using those sources.
For reference, I'm using VST SDK 3.5.2 and MSVC 2010.
I added the folder \public.sdk\source\vst2.x
to my project (which includes the source for audioeffect & vstplugmain). I really wish there was somewhere a simple bullet point list of what you need to do to get a working VST plugin effect working / exporting correctly etc.
The first two links I provided walk it through nicely, but it seems the method for creating a VST has changed since then. This is the skeleton of my program, which, while it compiles, won't get recognized by my VST host (error upon loading).
harmonicmodulator.h
#include "public.sdk\source\vst2.x\audioeffectx.h"
namespace Steinberg {
namespace VST {
class HarmonicModulator : public AudioEffectX {
public:
/* ?? what about createEffectInstance
static FUnknown* createInstance (void* context) {
return (IAudioProcessor*)new HarmonicModulator;
}
*/
HarmonicModulator(audioMasterCallback master);
virtual ~HarmonicModulator(); //can't hurt
/*
virtuals
*/
virtual void process (float **inputs, float **outputs, VstInt32 sampleFrames);
virtual void processReplacing (float **inputs, float **outputs, VstInt32 sampleFrames);
virtual void setProgramName (char *name);
virtual void getProgramName (char *name);
virtual void setParameter (VstInt32 index, float value);
virtual float getParameter (VstInt32 index);
virtual void getParameterLabel (VstInt32 index, char *label);
virtual void getParameterName (VstInt32 index, char *label);
virtual void getParameterDisplay (VstInt32 index, char *text);
virtual bool getEffectName (char * name);
virtual bool getVendorString (char * text);
virtual bool getProductString (char * text);
virtual VstInt32 getVendorVersion () { return 1000; }
virtual VstPlugCategory getPlugCategory () { return kPlugCategEffect; }
protected:
char progname[64];
float fparam;
};
}
}
harmonicmodulator.cpp
#include "HarmonicModulator.h"
namespace Steinberg {
namespace VST {
/*
Implementation for the constructor.
*/
HarmonicModulator::HarmonicModulator(audioMasterCallback cb) : AudioEffectX(cb, 1, 1), fparam(0.f) {
setNumInputs (2); // stereo in
setNumOutputs (2); // stereo out
setUniqueID ('HMXX'); // identify
canProcessReplacing (); // supports both accumulating and replacing output
strcpy_s(progname, "Default");
}
/*
Implementation for the destructor.
*/
HarmonicModulator::~HarmonicModulator() {}
/*
ProcessReplacing
*/
void HarmonicModulator::processReplacing (float **inputs, float **outputs, VstInt32 sampleFrames) {
float *in1 = inputs[0];
float *in2 = inputs[1];
float *out1 = outputs[0];
float *out2 = outputs[1];
while (--sampleFrames >= 0) {
(*out1++) += (*in1++);
(*out2++) += (*in2++);
}
}
/*
Process
*/
void HarmonicModulator::process (float **inputs, float **outputs, VstInt32 sampleFrames) {
float *in1 = inputs[0];
float *in2 = inputs[1];
float *out1 = outputs[0];
float *out2 = outputs[1];
while (--sampleFrames >= 0) {
(*out1++) += (*in1++);
(*out2++) += (*in2++);
}
}
/*
Below seems to be needed to work
*/
void HarmonicModulator::setProgramName (char *name){
strcpy_s(progname, name);
}
void HarmonicModulator::getProgramName (char *name){
strcpy_s(name, 32, progname);
}
void HarmonicModulator::setParameter (VstInt32 index, float value) {
fparam = value;
}
void HarmonicModulator::getParameterLabel (VstInt32 index, char *label) {
strcpy_s(label, 32, "dB");
}
void HarmonicModulator::getParameterName (VstInt32 index, char *label) {
strcpy_s(label, 32, "Volume");
}
void HarmonicModulator::getParameterDisplay (VstInt32 index, char *text) {
this->dB2string(fparam, text, 32);
}
//-----------------------------------------------------------------------------------------
float HarmonicModulator::getParameter (VstInt32 index) {
return fparam;
}
bool HarmonicModulator::getEffectName (char * name) {
strcpy_s(name, 32, "Harmonic Modulator");
return true;
}
bool HarmonicModulator::getVendorString (char * text) {
strcpy_s(text, 32, "LightBridge");
return true;
}
bool HarmonicModulator::getProductString (char * text) {
strcpy_s(text, 32, "Harmonic Modulator");
return true;
}
}
}
AudioEffect* createEffectInstance (audioMasterCallback audioMaster) {
return new Steinberg::VST::HarmonicModulator (audioMaster);
}
Okay, the "method" I'mm using is: According to both of the previous guides, to make a successful plugin, you at least need to derive your plugin from audio effectx and override process()
and processReplacing()
which do the actual processing.
The rest was added in hope that it would do something. Moreover, the exported function createEffectInstance()
returns a new instance of the plugin. vstplugmain.cpp
holds a dllmain and an exported function VstPlugMain
that receives an audiomastercallback and returns createEffectInstance(callback)
.
IMO, that seems like a working method and a re-creation (as far as I can see) of the two guides provided earlier. The plugin is defined and there's an interface between plug and host that allows to create instances of it. What am I missing? The guide says that's all you need.
Is this a difference between different versions of VST? 2/3?
So I couldn't get the VstPluginTestHost bundled to work, it couldn't locate my VST. I tried the validator, and stepping through that, I found that since my program doesn't export a function called GetPluginFactory
, it's discarded. Okay, understandable, but none of the guides tell anything about this.
Searching through endless amounts of source, it seems some VST sources add this cryptic passage at the bottom (code taken from AGainSimple.cpp):
BEGIN_FACTORY_DEF ("Steinberg Media Technologies",
"http://www.steinberg.net",
"mailto:info@steinberg.de")
//---First Plugin included in this factory-------
// its kVstAudioEffectClass component
DEF_CLASS2 (INLINE_UID (0xB9F9ADE1, 0xCD9C4B6D, 0xA57E61E3, 0x123535FD),
PClassInfo::kManyInstances, // cardinality
kVstAudioEffectClass, // the component category (don't change this)
"AGainSimple VST3", // here the Plug-in name (to be changed)
0, // single component effects can not be destributed so this is zero
"Fx", // Subcategory for this Plug-in (to be changed)
FULL_VERSION_STR, // Plug-in version (to be changed)
kVstVersionString, // the VST 3 SDK version (don't change this, use always this definition)
Steinberg::Vst::AGainSimple::createInstance)// function pointer called when this component should be instantiated
END_FACTORY
Which seems to export an interface that gives the host some basic information and an interface for creating the plugin. BUT. I thought createEffectInstance
did this. Now there's a new function called createInstance
. Is there a difference? The function signatures suggest createInstance
does NOT receive the audiomaster callback, and thus can't instantiate any derivation of AudioEffect (which takes this as an parameter in its constructor) - I provided the function, commented out, in harmonicmodulator.h.
Also, I noticed that many newer sources include another "main" cpp file (dllmain.cpp, in \public.sdk\source\main
, that defines exports for InitModule
and DeInitModule
, but no createEffectInstance
anymore. This is dizzying me. They also seem to derive from either AudioEffect
(no x) or SingleComponentEffect
(seems to be a lot more complicated? lol).
On top of this, I can't seem to get that begin_factory
stuff working because of a lot of missing constants and defines that reside in many different files. Are you supposed to add the whole SDL to your project? Thats 6,000 files.
TL;DR
Nothing really works and I can't seem to get a clue. The bundled source samples work, but they all approach the "method" of creating a VST differently. Seriously, any guidance or help will be so appreciated. I'm trying to create this as part of an application, and I got everything else pretty much worked out.
I've been trying to write a simple VST plugin. It doesn't need any fancy interfaces, just a few controls. But I don't know where to start. Begin huge wall of text.
Start by compiling the example plugins that come with the SDK. Then duplicate that with your own bare bones plugin. Continue building up from there.
Is this a difference between different versions of VST? 2/3?
VST 2 and VST 3 are different formats. I would recommend building a VST 2.4 plugin unless you have a specific reason for building a VST 3 plguin. VST 2.4 is widely supported by many hosts and will likely continue to be for some years yet. VST 3 is a newer format but not so widely supported.