Code: Select all
00001 #ifndef __AEffect__
00002 #define __AEffect__
00003
00004 /*
00005 to create an Audio Effect for power pc's, create a
00006 code resource
00007 file type: 'aPcs'
00008 resource type: 'aEff'
00009 ppc header: none (raw pef)
00010
00011 for windows, it's a .dll
00012
00013 the only symbol searched for is:
00014 AEffect *main(float (*audioMaster)(AEffect *effect, long opcode, long index,
00015 long value, void *ptr, float opt));
00016 */
00017
00018 #if 0
00019
00020 /* dmazzoni: PRAGMA_ALIGN_SUPPORTED is obsolete in mwerks */
00021 #ifdef __MWERKS__
00022 #undef PRAGMA_ALIGN_SUPPORTED
00023 #endif
00024
00025 #if PRAGMA_ALIGN_SUPPORTED || __MWERKS__
00026 #pragma options align=mac68k
00027 #elif defined CBUILDER
00028 #pragma -a8
00029 #elif defined(WIN32) || defined(__FLAT__)
00030 #pragma pack(push)
00031 #pragma pack(8)
00032 #endif
00033
00034 #endif
00035
00036 #if defined(WIN32) || defined(__FLAT__) || defined CBUILDER
00037 #define VSTCALLBACK __cdecl
00038 #else
00039 #define VSTCALLBACK
00040 #endif
00041
00042 //---------------------------------------------------------------------------------------------
00043 // misc def's
00044 //---------------------------------------------------------------------------------------------
00045
00046 typedef struct AEffect AEffect;
00047 typedef long (VSTCALLBACK * audioMasterCallback) (AEffect * effect,
00048 long opcode, long index,
00049 long value, void *ptr,
00050 float opt);
00051
00052 // prototype for plug-in main
00053 // AEffect *main(audioMasterCallback audioMaster);
00054
00055 #ifdef CBUILDER
00056 #define kEffectMagic 'PtsV'
00057 #else
00058 #define kEffectMagic 'VstP'
00059 #endif
00060
00061 //---------------------------------------------------------------------------------------------
00062 //---------------------------------------------------------------------------------------------
00063
00064 struct AEffect {
00065 long magic; // must be kEffectMagic ('VstP')
00066 long (VSTCALLBACK * dispatcher) (AEffect * effect, long opCode,
00067 long index, long value, void *ptr,
00068 float opt);
00069 void (VSTCALLBACK * process) (AEffect * effect, float **inputs,
00070 float **outputs, long sampleframes);
00071 void (VSTCALLBACK * setParameter) (AEffect * effect, long index,
00072 float parameter);
00073 float (VSTCALLBACK * getParameter) (AEffect * effect, long index);
00074
00075 long numPrograms;
00076 long numParams; // all programs are assumed to have numParams parameters
00077 long numInputs; //
00078 long numOutputs; //
00079 long flags; // see constants
00080 long resvd1; // reserved, must be 0
00081 long resvd2; // reserved, must be 0
00082 long initialDelay; // for algorithms which need input in the first place
00083 long realQualities; // number of realtime qualities (0: realtime)
00084 long offQualities; // number of offline qualities (0: realtime only)
00085 float ioRatio; // input samplerate to output samplerate ratio, not used yet
00086 void *object; // for class access (see AudioEffect.hpp), MUST be 0 else!
00087 void *user; // user access
00088 long uniqueID; // pls choose 4 character as unique as possible.
00089 // this is used to identify an effect for save+load
00090 long version; //
00091 void (VSTCALLBACK * processReplacing) (AEffect * effect, float **inputs,
00092 float **outputs,
00093 long sampleframes);
00094 char future[60]; // pls zero
00095 };
00096
00097
00098 //---------------------------------------------------------------------------------------------
00099 // flags bits
00100 //---------------------------------------------------------------------------------------------
00101
00102 #define effFlagsHasEditor 1 // if set, is expected to react to editor messages
00103 #define effFlagsHasClip 2 // return > 1. in getVu() if clipped
00104 #define effFlagsHasVu 4 // return vu value in getVu(); > 1. means clipped
00105 #define effFlagsCanMono 8 // if numInputs == 2, makes sense to be used for mono in
00106 #define effFlagsCanReplacing 16 // supports in place output (processReplacing() exsists)
00107 #define effFlagsProgramChunks 32 // program data are handled in formatless chunks
00108
00109 //---------------------------------------------------------------------------------------------
00110 // dispatcher opCodes
00111 //---------------------------------------------------------------------------------------------
00112
00113 enum {
00114 effOpen = 0, // initialise
00115 effClose, // exit, release all memory and other resources!
00116
00117 effSetProgram, // program no in <value>
00118 effGetProgram, // return current program no.
00119 effSetProgramName, // user changed program name (max 24 char + 0) to as passed in string
00120 effGetProgramName, // stuff program name (max 24 char + 0) into string
00121
00122 effGetParamLabel, // stuff parameter <index> label (max 8 char + 0) into string
00123 // (examples: sec, dB, type)
00124 effGetParamDisplay, // stuff parameter <index> textual representation into string
00125 // (examples: 0.5, -3, PLATE)
00126 effGetParamName, // stuff parameter <index> label (max 8 char + 0) into string
00127 // (examples: Time, Gain, RoomType)
00128 effGetVu, // called if (flags & (effFlagsHasClip | effFlagsHasVu))
00129
00130 // system
00131
00132 effSetSampleRate, // in opt (float)
00133 effSetBlockSize, // in value
00134 effMainsChanged, // the user has switched the 'power on' button to
00135 // value (0 off, else on). This only switches audio
00136 // processing; you should flush delay buffers etc.
00137 // editor
00138
00139 effEditGetRect, // stuff rect (top, left, bottom, right) into ptr
00140 effEditOpen, // system dependant Window pointer in ptr
00141 effEditClose, // no arguments
00142 effEditDraw, // draw method, ptr points to rect
00143 effEditMouse, // index: x, value: y
00144 effEditKey, // system keycode in value
00145 effEditIdle, // no arguments. Be gentle!
00146 effEditTop, // window has topped, no arguments
00147 effEditSleep, // window goes to background
00148
00149 // new
00150
00151 effIdentify, // returns 'NvEf'
00152 effGetChunk, // host requests pointer to chunk into (void**)ptr, byteSize returned
00153 effSetChunk, // plug-in receives saved chunk, byteSize passed
00154
00155 effNumOpcodes
00156 };
00157
00158 //---------------------------------------------------------------------------------------------
00159 // audioMaster opCodes
00160 //---------------------------------------------------------------------------------------------
00161
00162 enum {
00163 audioMasterAutomate = 0, // index, value, returns 0
00164 audioMasterVersion, // vst version, currently 2 (0 for older)
00165 audioMasterCurrentId, // returns the unique id of a plug that's currently
00166 // loading
00167 audioMasterIdle, // call application idle routine (this will
00168 // call effEditIdle for all open editors too)
00169 audioMasterPinConnected // inquire if an input or output is beeing connected;
00170 // index enumerates input or output counting from zero,
00171 // value is 0 for input and != 0 otherwise. note: the
00172 // return value is 0 for <true> such that older versions
00173 // will always return true.
00174 };
00175
00176 #if 0
00177
00178 #if PRAGMA_ALIGN_SUPPORTED || __MWERKS__
00179 #pragma options align=reset
00180 #elif defined(WIN32) || defined(__FLAT__)
00181 #pragma pack(pop)
00182 #elif defined CBUILDER
00183 #pragma -a-
00184 #endif
00185
00186 #endif
00187
00188 #endif // __AEffect__
AND
Code: Select all
//host.cpp
//attempts to load and make use of a VST plugin
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream.h>
#include <fstream.h>
#include <string.h>
#include "aeffectx.h"
const int blocksize=512;
const float samplerate=44100.0f;
long VSTCALLBACK host(AEffect *effect, long opcode, long index, long value, void *ptr, float opt);
void main()
{
////////////////////////////////////////////////////////////////////////////
//
// Loading a plugin
//
////////////////////////////////////////////////////////////////////////////
//create a pointer for the plugin we're going to load
AEffect* ptrPlug=NULL;
bool editor;
//find and load the DLL and get a pointer to its main function
//this has a protoype like this: AEffect *main (audioMasterCallback audioMaster)
HINSTANCE libhandle=LoadLibrary("c:\\program files\\steinberg\\vstplugins\\muon\\cm101.dll");
if (libhandle!=NULL)
{
//DLL was loaded OK
AEffect* (__cdecl* getNewPlugInstance)(audioMasterCallback);
getNewPlugInstance=(AEffect*(__cdecl*)(audioMasterCallback))GetProcAddress(libhandle, "main");
if (getNewPlugInstance!=NULL)
{
//main function located OK
ptrPlug=getNewPlugInstance(host);
if (ptrPlug!=NULL)
{
//plugin instantiated OK
cout << "Plugin was loaded OK" << endl;
if (ptrPlug->magic==kEffectMagic)
{
cout << "It's a valid VST plugin" << endl;
}
else
{
cout << "Not a VST plugin" << endl;
FreeLibrary(libhandle);
Sleep(5000);
return;
}
}
else
{
cout << "Plugin could not be instantiated" << endl;
FreeLibrary(libhandle);
Sleep(5000);
return;
}
}
else
{
cout << "Plugin main function could not be located" << endl;
FreeLibrary(libhandle);
Sleep(5000);
return;
}
}
else
{
cout << "Plugin DLL could not be loaded" << endl;
Sleep(5000);
return;
};
////////////////////////////////////////////////////////////////////////////
//
// Examining the plugin
//
////////////////////////////////////////////////////////////////////////////
if (ptrPlug->dispatcher(ptrPlug,effGetVstVersion,0,0,NULL,0.0f)==2)
{
cout << "This is a VST 2 plugin" << endl;
}
else
{
cout << "This is a VST 1 plugin" << endl;
}
//Member variables:
cout << "numPrograms " << ptrPlug->numPrograms << endl;
cout << "numParams " << ptrPlug->numParams << endl;
cout << "numInputs " << ptrPlug->numInputs << endl;
cout << "numOutputs " << ptrPlug->numOutputs << endl;
cout << "resvd1 " << ptrPlug->resvd1 << endl;
cout << "resvd2 " << ptrPlug->resvd2 << endl;
cout << "initialDelay " << ptrPlug->initialDelay << endl;
cout << "realQualities " << ptrPlug->realQualities << endl;
cout << "offQualities " << ptrPlug->offQualities << endl;
cout << "ioRatio (float)" << ptrPlug->ioRatio << endl;
cout << "object (ptr)" << ptrPlug->object << endl;
cout << "user (ptr)" << ptrPlug->user << endl;
cout << "uniqueID " << ptrPlug->uniqueID << endl;
cout << "version " << ptrPlug->version << endl;
//VST 1.0 flags
if (ptrPlug->flags & effFlagsHasEditor)
{
//Meaning: plugin has its own GUI editor
cout << "plug has the effFlagsHasEditor flag" << endl;
editor=true;
}
if (ptrPlug->flags & effFlagsHasClip)
{
//Meaning: plugin can provide information to drive a clipping display
cout << "plug has the effFlagsHasClip flag" << endl;
}
if (ptrPlug->flags & effFlagsHasVu)
{
//Meaning: plugin can provide information to drive a VU display
cout << "plug has the effFlagsHasVu flag" << endl;
}
if (ptrPlug->flags & effFlagsCanMono)
{
//Meaning: plugin can accept mono input
//NB - if the plugin has two input buffers they can both be the same
cout << "plug has the effFlagsCanMono flag" << endl;
}
if (ptrPlug->flags & effFlagsCanReplacing)
{
//Meaning: plugin supports a replacing process
//The values in any output buffer given to the plug will be overwritten
//however, due to glitches in a few VST instruments it's advisable to
//zero these buffers anyway before handing them over.
cout << "plug has the effFlagsCanReplacing flag" << endl;
}
if (ptrPlug->flags & effFlagsProgramChunks)
{
//Meaning: plugin receives program and bank information via chunk method
cout << "plug has the effFlagsProgramChunks flag" << endl;
}
if (ptrPlug->dispatcher(ptrPlug,effGetVstVersion,0,0,NULL,0.0f)==2)
{
//VST 2.0 flags
if (ptrPlug->flags & effFlagsIsSynth)
{
//Meaning: plugin will require MIDI events, and processEvents must be
//called before process or processReplacing. Also, plugin cannot be
//used as an insert or send effect and will declare its own number of
//outputs, which should be assigned by the host as mixer channels
cout << "plug has the effFlagsIsSynth flag" << endl;
}
if (ptrPlug->flags & effFlagsNoSoundInStop)
{
//Meaning: if the transport is stopped the host need not call process
//or processReplacing - or if no input available?
cout << "plug has the effFlagsNoSoundInStop flag" << endl;
}
//also effFlagsExtIsAsync and effFlagsExtHasBuffer - refers to plugin that
//supports external DSP
//VST 2.0 Plugin Can Do's
if (ptrPlug->dispatcher(ptrPlug,effCanDo,0,0,"sendVstEvents",0.0f)>0)
{
cout << "plug can sendVstEvents" << endl;
}
if (ptrPlug->dispatcher(ptrPlug,effCanDo,0,0,"sendVstMidiEvent",0.0f)>0)
{
cout << "plug can sendVstMidiEvent" << endl;
}
if (ptrPlug->dispatcher(ptrPlug,effCanDo,0,0,"sendVstTimeInfo",0.0f)>0)
{
cout << "plug can sendVstTimeInfo" << endl;
}
if (ptrPlug->dispatcher(ptrPlug,effCanDo,0,0,"receiveVstEvents",0.0f)>0)
{
cout << "plug can receiveVstEvents" << endl;
}
if (ptrPlug->dispatcher(ptrPlug,effCanDo,0,0,"receiveVstMidiEvent",0.0f)>0)
{
cout << "plug can receiveVstMidiEvent" << endl;
}
if (ptrPlug->dispatcher(ptrPlug,effCanDo,0,0,"receiveVstTimeInfo",0.0f)>0)
{
cout << "plug can receiveVstTimeInfo" << endl;
}
if (ptrPlug->dispatcher(ptrPlug,effCanDo,0,0,"offline",0.0f)>0)
{
cout << "plug can offline" << endl;
}
if (ptrPlug->dispatcher(ptrPlug,effCanDo,0,0,"plugAsChannelInsert",0.0f)>0)
{
cout << "plug can plugAsChannelInsert" << endl;
}
if (ptrPlug->dispatcher(ptrPlug,effCanDo,0,0,"plugAsSend",0.0f)>0)
{
cout << "plug can plugAsSend" << endl;
}
if (ptrPlug->dispatcher(ptrPlug,effCanDo,0,0,"mixDryWet",0.0f)>0)
{
cout << "plug can mixDryWet" << endl;
}
} //end VST2 specific
////////////////////////////////////////////////////////////////////////////
//
// Using the plugin's C Interface - an example
//
////////////////////////////////////////////////////////////////////////////
long rc=0;
//try some dispatcher functions...
ptrPlug->dispatcher(ptrPlug,effOpen,0,0,NULL,0.0f);
//switch the plugin off (calls Suspend)
ptrPlug->dispatcher(ptrPlug,effMainsChanged,0,0,NULL,0.0f);
//set sample rate and block size
ptrPlug->dispatcher(ptrPlug,effSetSampleRate,0,0,NULL,samplerate);
ptrPlug->dispatcher(ptrPlug,effSetBlockSize,0,blocksize,NULL,0.0f);
if ((ptrPlug->dispatcher(ptrPlug,effGetVstVersion,0,0,NULL,0.0f)==2) &&
(ptrPlug->flags & effFlagsIsSynth))
{
//get I/O configuration for synth plugins - they will declare their
//own output and input channels
for (int i=0; i<ptrPlug->numInputs+ptrPlug->numOutputs;i++)
{
if (i<ptrPlug->numInputs)
{
//input pin
VstPinProperties temp;
if (ptrPlug->dispatcher(ptrPlug,effGetInputProperties,i,0,&temp,0.0f)==1)
{
cout << "Input pin " << (i+1) << " label " << temp.label << endl;
//cout << "Input pin " << (i+1) << " shortLabel " << temp.shortLabel << endl;
if (temp.flags & kVstPinIsActive)
{
cout << "Input pin " << (i+1) << " is active" << endl;
}
if (temp.flags & kVstPinIsStereo)
{
// is index even or zero?
if (i%2==0 || i==0)
{
cout << "Input pin " << (i+1) << " is left channel of a stereo pair" << endl;
}
else
{
cout << "Input pin " << (i+1) << " is right channel of a stereo pair" << endl;
}
}
}
}
else
{
//output pin
VstPinProperties temp;
if (ptrPlug->dispatcher(ptrPlug,effGetOutputProperties,i,0,&temp,0.0f)==1)
{
cout << "Output pin " << (i-ptrPlug->numInputs+1) << " label " << temp.label << endl;
//cout << "Output pin " << (i-ptrPlug->numInputs+1) << " shortLabel " << temp.shortLabel << endl;
if (temp.flags & kVstPinIsActive)
{
cout << "Output pin " << (i-ptrPlug->numInputs+1) << " is active" << endl;
}
else
{
cout << "Output pin " << (i-ptrPlug->numInputs+1) << " is inactive" << endl;
}
if (temp.flags & kVstPinIsStereo)
{
// is index even or zero?
if ((i-ptrPlug->numInputs)%2==0 || (i-ptrPlug->numInputs)==0)
{
cout << "Output pin " << (i+1) << " is left channel of a stereo pair" << endl;
}
else
{
cout << "Output pin " << (i+1) << " is right channel of a stereo pair" << endl;
}
}
else
{
cout << "Output pin " << (i+1) << " is mono" << endl;
}
}
}
}
} //end VST2 specific
//switch the plugin back on (calls Resume)
ptrPlug->dispatcher(ptrPlug,effMainsChanged,0,1,NULL,0.0f);
////////////////////////////////////////////////////////////////////////////
//set to program zero and fetch back the name
ptrPlug->dispatcher(ptrPlug,effSetProgram,0,0,NULL,0.0f);
char strProgramName[24+2];
ptrPlug->dispatcher(ptrPlug,effGetProgramName,0,0,strProgramName,0.0f);
cout << "Set plug to program zero, name is " << strProgramName << endl;
//get the parameter strings
char strName[24];
char strDisplay[24];
char strLabel[24];
ptrPlug->dispatcher(ptrPlug,effGetParamName,0,0,strName,0.0f);
cout << "Parameter name is " << strName << endl;
ptrPlug->dispatcher(ptrPlug,effGetParamLabel,0,0,strLabel,0.0f);
cout << "Parameter label is " << strLabel << endl;
ptrPlug->dispatcher(ptrPlug,effGetParamDisplay,0,0,strDisplay,0.0f);
cout << "Parameter display is " << strDisplay << endl;
//call the set and get parameter functions
ptrPlug->setParameter(ptrPlug,0,0.7071f);
float newval=ptrPlug->getParameter(ptrPlug,0);
cout << "Parameter 0 was changed to " << newval << endl;
ptrPlug->dispatcher(ptrPlug,effGetParamDisplay,0,0,strDisplay,0.0f);
cout << "Parameter display is now " << strDisplay << endl;
////////////////////////////////////////////////////////////////////////////
VstEvent* ptrEvents=NULL;
char* ptrEventBuffer=NULL;
int nEvents=4;
if ((ptrPlug->dispatcher(ptrPlug,effGetVstVersion,0,0,NULL,0.0f)==2) &&
((ptrPlug->flags & effFlagsIsSynth) ||
(ptrPlug->dispatcher(ptrPlug,effCanDo,0,0,"receiveVstEvents",0.0f)>0)))
{
//create some MIDI messages to send to the plug if it is a synth or can
//receive MIDI messages
//create a block of appropriate size
int pointersize=sizeof(VstEvent*);
int bufferSize=sizeof(VstEvents)-(pointersize*2);
bufferSize+=pointersize*(nEvents);
//create the buffer
ptrEventBuffer=new char[bufferSize+1];
//now, create some memory for the events themselves
VstMidiEvent* ptrEvents=new VstMidiEvent[nEvents];
VstMidiEvent* ptrWrite=ptrEvents;
//Create first event
ptrWrite->type=kVstMidiType;
ptrWrite->byteSize=24L;
ptrWrite->deltaFrames=0L;
ptrWrite->flags=0L;
ptrWrite->noteLength=0L;
ptrWrite->noteOffset=0L;
ptrWrite->midiData[0]=(char)0x90; //status & channel
ptrWrite->midiData[1]=(char)0x3C; //MIDI byte #2
ptrWrite->midiData[2]=(char)0xFF; //MIDI byte #3
ptrWrite->midiData[3]=(char)0x00; //MIDI byte #4 - blank
ptrWrite->detune=0x00;
ptrWrite->noteOffVelocity=0x00;
ptrWrite->reserved1=0x00;
ptrWrite->reserved2=0x00;
//Create second event
ptrWrite++;
ptrWrite->type=kVstMidiType;
ptrWrite->byteSize=24L;
ptrWrite->deltaFrames=128L;
ptrWrite->flags=0L;
ptrWrite->noteLength=0L;
ptrWrite->noteOffset=0L;
ptrWrite->midiData[0]=(char)0x90; //status & channel
ptrWrite->midiData[1]=(char)0x3C; //MIDI byte #2
ptrWrite->midiData[2]=(char)0x00; //MIDI byte #3
ptrWrite->midiData[3]=(char)0x00; //MIDI byte #4 - blank
ptrWrite->detune=0x00;
ptrWrite->noteOffVelocity=0x00;
ptrWrite->reserved1=0x00;
ptrWrite->reserved2=0x00;
//Create third event
ptrWrite++;
ptrWrite->type=kVstMidiType;
ptrWrite->byteSize=24L;
ptrWrite->deltaFrames=256L;
ptrWrite->flags=0L;
ptrWrite->noteLength=0L;
ptrWrite->noteOffset=0L;
ptrWrite->midiData[0]=(char)0x90; //status & channel
ptrWrite->midiData[1]=(char)0x3C; //MIDI byte #2
ptrWrite->midiData[2]=(char)0xFF; //MIDI byte #3
ptrWrite->midiData[3]=(char)0x00; //MIDI byte #4 - blank
ptrWrite->detune=0x00;
ptrWrite->noteOffVelocity=0x00;
ptrWrite->reserved1=0x00;
ptrWrite->reserved2=0x00;
//Create fourth event
ptrWrite++;
ptrWrite->type=kVstMidiType;
ptrWrite->byteSize=24L;
ptrWrite->deltaFrames=384L;
ptrWrite->flags=0L;
ptrWrite->noteLength=0L;
ptrWrite->noteOffset=0L;
ptrWrite->midiData[0]=(char)0x90; //status & channel
ptrWrite->midiData[1]=(char)0x3C; //MIDI byte #2
ptrWrite->midiData[2]=(char)0x00; //MIDI byte #3
ptrWrite->midiData[3]=(char)0x00; //MIDI byte #4 - blank
ptrWrite->detune=0x00;
ptrWrite->noteOffVelocity=0x00;
ptrWrite->reserved1=0x00;
ptrWrite->reserved2=0x00;
//copy the addresses of our events into the eventlist structure
VstEvents* ev=(VstEvents*)ptrEventBuffer;
for (int i=0;i<nEvents;i++)
{
ev->events[i]=(VstEvent*)(ptrEvents+i);
}
//do the block header
ev->numEvents=nEvents;
ev->reserved=0L;
}
////////////////////////////////////////////////////////////////////////////
float** ptrInputBuffers=NULL;
float** ptrOutputBuffers=NULL;
if (ptrPlug->numInputs)
{
if (ptrPlug->flags & effFlagsCanMono)
{
//only one input buffer required, others are just copies?
//This could be an incorrect interpretation
ptrInputBuffers=new float*[ptrPlug->numInputs];
//create the input buffers
for (int i=0;i<ptrPlug->numInputs;i++)
{
if (i==0)
{
cout << "Input buffer " << (i+1) << " created" << endl;
ptrInputBuffers[i]=new float[blocksize];
}
else
{
cout << "Input buffer " << (i+1) << " is a copy of input buffer 1" << endl;
ptrInputBuffers[i]=ptrInputBuffers[0];
}
}
}
else
{
//Plug requires independent input signals
ptrInputBuffers=new float*[ptrPlug->numInputs];
//create the input buffers
for (int i=0;i<ptrPlug->numInputs;i++)
{
cout << "Input buffer " << (i+1) << " created" << endl;
ptrInputBuffers[i]=new float[blocksize];
}
}
}
if (ptrPlug->numOutputs)
{
ptrOutputBuffers=new float*[ptrPlug->numOutputs];
//create the output buffers
for (int i=0;i<ptrPlug->numOutputs;i++)
{
cout << "Output buffer " << (i+1) << " created" << endl;
ptrOutputBuffers[i]=new float[blocksize];
}
}
if (ptrPlug->numInputs>0)
{
//fill the input buffers with ones to simulate some input having been
//received
//We don't have to do this for synths, obviously
for (int i=0;i<ptrPlug->numInputs;i++)
{
for (int j=0;j<blocksize;j++)
{
*(ptrInputBuffers[i]+j)=1.0f;
}
}
}
if (ptrPlug->numOutputs>0)
{
//fill the output buffers with ones to simulate some prior output to be
//accumulated on
for (int i=0;i<ptrPlug->numOutputs;i++)
{
for (int j=0;j<blocksize;j++)
{
//*(ptrOutputBuffers[i]+j)=-1.0f;
//note that VSTXsynth, when replacing, requires the host
//to clear the buffer first!
*(ptrOutputBuffers[i]+j)=0.0f;
}
}
}
////////////////////////////////////////////////////////////////////////////
ofstream outfile;
outfile.open("hello.txt");
//ProcessEvents
if ((ptrPlug->dispatcher(ptrPlug,effGetVstVersion,0,0,NULL,0.0f)==2) &&
((ptrPlug->flags & effFlagsIsSynth) ||
(ptrPlug->dispatcher(ptrPlug,effCanDo,0,0,"receiveVstEvents",0.0f)>0)))
{
if (ptrPlug->dispatcher(ptrPlug,effProcessEvents,0,0,(VstEvents*)ptrEventBuffer,0.0f)==1)
{
cout << "plug processed events OK and wants more" << endl;
}
else
{
cout << "plug does not want any more events" << endl;
}
}
//process (replacing)
if (ptrPlug->flags & effFlagsCanReplacing)
{
cout << "Process (replacing)" << endl;
ptrPlug->processReplacing(ptrPlug,ptrInputBuffers,ptrOutputBuffers,blocksize);
}
/*
//process (accumulating)
cout << "Process (accumulating)" << endl;
ptrPlug->process(ptrPlug,ptrInputBuffers,ptrOutputBuffers,sampleframes);
*/
//Dump output to disk
for (int i=0;i<ptrPlug->numOutputs;i++)
{
for (int j=0;j<blocksize;j++)
{
outfile << i << "," << j << "," << *(ptrOutputBuffers[i]+j) << endl;
}
}
outfile.close();
////////////////////////////////////////////////////////////////////////////
ptrPlug->dispatcher(ptrPlug,effMainsChanged,0,0,NULL,0.0f); //calls suspend
////////////////////////////////////////////////////////////////////////////
//delete the MIDI data
if (ptrEventBuffer!=NULL)
{
delete[] ptrEventBuffer;
}
if (ptrEvents!=NULL)
{
delete[] ptrEvents;
}
//delete the input buffers
if (ptrPlug->numInputs>0)
{
if (!(ptrPlug->flags & effFlagsCanMono))
{
//independent buffers have been assigned, delete them
for (i=0;i<ptrPlug->numInputs;i++)
{
delete[] ptrInputBuffers[i];
}
}
else
{
//there's only one buffer, delete it
delete[] ptrInputBuffers[0];
}
//remove the pointers to the buffers
delete[] ptrInputBuffers;
}
//delete the output buffers
if (ptrPlug->numOutputs>0)
{
for (i=0;i<ptrPlug->numOutputs;i++)
{
delete[] ptrOutputBuffers[i];
}
//remove the pointers to the buffers
delete[] ptrOutputBuffers;
}
//Shut the plugin down and free the library (this deletes the C++ class
//memory and calls the appropriate destructors...)
ptrPlug->dispatcher(ptrPlug,effClose,0,0,NULL,0.0f);
FreeLibrary(libhandle);
////////////////////////////////////////////////////////////////////////////
cout << "Done!" << endl;
Sleep(10000);
}
//host callback function
//this is called directly by the plug-in!!
//
long VSTCALLBACK host(AEffect *effect, long opcode, long index, long value, void *ptr, float opt)
{
long retval=0;
switch (opcode)
{
//VST 1.0 opcodes
case audioMasterVersion:
//Input values:
//none
//Return Value:
//0 or 1 for old version
//2 or higher for VST2.0 host?
cout << "plug called audioMasterVersion" << endl;
retval=2;
break;
case audioMasterAutomate:
//Input values:
//<index> parameter that has changed
//<opt> new value
//Return value:
//not tested, always return 0
//NB - this is called when the plug calls
//setParameterAutomated
cout << "plug called audioMasterAutomate" << endl;
break;
case audioMasterCurrentId:
//Input values:
//none
//Return Value
//the unique id of a plug that's currently loading
//zero is a default value and can be safely returned if not known
cout << "plug called audioMasterCurrentId" << endl;
break;
case audioMasterIdle:
//Input values:
//none
//Return Value
//not tested, always return 0
//NB - idle routine should also call effEditIdle for all open editors
Sleep(1);
cout << "plug called audioMasterIdle" << endl;
break;
case audioMasterPinConnected:
//Input values:
//<index> pin to be checked
//<value> 0=input pin, non-zero value=output pin
//Return values:
//0=true, non-zero=false
cout << "plug called audioMasterPinConnected" << endl;
break;
//VST 2.0 opcodes
case audioMasterWantMidi:
//Input Values:
//<value> filter flags (which is currently ignored, no defined flags?)
//Return Value:
//not tested, always return 0
cout << "plug called audioMasterWantMidi" << endl;
break;
case audioMasterGetTime:
//Input Values:
//<value> should contain a mask indicating which fields are required
//...from the following list?
//kVstNanosValid
//kVstPpqPosValid
//kVstTempoValid
//kVstBarsValid
//kVstCyclePosValid
//kVstTimeSigValid
//kVstSmpteValid
//kVstClockValid
//Return Value:
//ptr to populated const VstTimeInfo structure (or 0 if not supported)
//NB - this structure will have to be held in memory for long enough
//for the plug to safely make use of it
cout << "plug called audioMasterGetTime" << endl;
break;
case audioMasterProcessEvents:
//Input Values:
//<ptr> Pointer to a populated VstEvents structure
//Return value:
//0 if error
//1 if OK
cout << "plug called audioMasterProcessEvents" << endl;
break;
case audioMasterSetTime:
//IGNORE!
break;
case audioMasterTempoAt:
//Input Values:
//<value> sample frame location to be checked
//Return Value:
//tempo (in bpm * 10000)
cout << "plug called audioMasterTempoAt" << endl;
break;
case audioMasterGetNumAutomatableParameters:
//Input Values:
//None
//Return Value:
//number of automatable parameters
//zero is a default value and can be safely returned if not known
//NB - what exactly does this mean? can the host set a limit to the
//number of parameters that can be automated?
cout << "plug called audioMasterGetNumAutomatableParameters" << endl;
break;
case audioMasterGetParameterQuantization:
//Input Values:
//None
//Return Value:
//integer value for +1.0 representation,
//or 1 if full single float precision is maintained
//in automation.
//NB - ***possibly bugged***
//Steinberg notes say "parameter index in <value> (-1: all, any)"
//but in aeffectx.cpp no parameters are taken or passed
cout << "plug called audioMasterGetParameterQuantization" << endl;
break;
case audioMasterIOChanged:
//Input Values:
//None
//Return Value:
//0 if error
//non-zero value if OK
cout << "plug called audioMasterIOChanged" << endl;
break;
case audioMasterNeedIdle:
//Input Values:
//None
//Return Value:
//0 if error
//non-zero value if OK
//NB plug needs idle calls (outside its editor window)
//this means that effIdle must be dispatched to the plug
//during host idle process and not effEditIdle calls only when its
//editor is open
//Check despatcher notes for any return codes from effIdle
cout << "plug called audioMasterNeedIdle" << endl;
break;
case audioMasterSizeWindow:
//Input Values:
//<index> width
//<value> height
//Return Value:
//0 if error
//non-zero value if OK
cout << "plug called audioMasterSizeWindow" << endl;
break;
case audioMasterGetSampleRate:
//Input Values:
//None
//Return Value:
//not tested, always return 0
//NB - Host must despatch effSetSampleRate to the plug in response
//to this call
//Check despatcher notes for any return codes from effSetSampleRate
cout << "plug called audioMasterGetSampleRate" << endl;
effect->dispatcher(effect,effSetSampleRate,0,0,NULL,samplerate);
break;
case audioMasterGetBlockSize:
//Input Values:
//None
//Return Value:
//not tested, always return 0
//NB - Host must despatch effSetBlockSize to the plug in response
//to this call
//Check despatcher notes for any return codes from effSetBlockSize
cout << "plug called audioMasterGetBlockSize" << endl;
effect->dispatcher(effect,effSetBlockSize,0,blocksize,NULL,0.0f);
break;
case audioMasterGetInputLatency:
//Input Values:
//None
//Return Value:
//input latency (in sampleframes?)
cout << "plug called audioMasterGetInputLatency" << endl;
break;
case audioMasterGetOutputLatency:
//Input Values:
//None
//Return Value:
//output latency (in sampleframes?)
cout << "plug called audioMasterGetOutputLatency" << endl;
break;
case audioMasterGetPreviousPlug:
//Input Values:
//None
//Return Value:
//pointer to AEffect structure or NULL if not known?
//NB - ***possibly bugged***
//Steinberg notes say "input pin in <value> (-1: first to come)"
//but in aeffectx.cpp no parameters are taken or passed
cout << "plug called audioMasterGetPreviousPlug" << endl;
break;
case audioMasterGetNextPlug:
//Input Values:
//None
//Return Value:
//pointer to AEffect structure or NULL if not known?
//NB - ***possibly bugged***
//Steinberg notes say "output pin in <value> (-1: first to come)"
//but in aeffectx.cpp no parameters are taken or passed
cout << "plug called audioMasterGetNextPlug" << endl;
break;
case audioMasterWillReplaceOrAccumulate:
//Input Values:
//None
//Return Value:
//0: not supported
//1: replace
//2: accumulate
cout << "plug called audioMasterWillReplaceOrAccumulate" << endl;
break;
case audioMasterGetCurrentProcessLevel:
//Input Values:
//None
//Return Value:
//0: not supported,
//1: currently in user thread (gui)
//2: currently in audio thread (where process is called)
//3: currently in 'sequencer' thread (midi, timer etc)
//4: currently offline processing and thus in user thread
//other: not defined, but probably pre-empting user thread.
cout << "plug called audioMasterGetCurrentProcessLevel" << endl;
break;
case audioMasterGetAutomationState:
//Input Values:
//None
//Return Value:
//0: not supported
//1: off
//2:read
//3:write
//4:read/write
cout << "plug called audioMasterGetAutomationState" << endl;
break;
case audioMasterGetVendorString:
//Input Values:
//<ptr> string (max 64 chars) to be populated
//Return Value:
//0 if error
//non-zero value if OK
cout << "plug called audioMasterGetVendorString" << endl;
break;
case audioMasterGetProductString:
//Input Values:
//<ptr> string (max 64 chars) to be populated
//Return Value:
//0 if error
//non-zero value if OK
cout << "plug called audioMasterGetProductString" << endl;
break;
case audioMasterGetVendorVersion:
//Input Values:
//None
//Return Value:
//Vendor specific host version as integer
cout << "plug called audioMasterGetVendorVersion" << endl;
break;
case audioMasterVendorSpecific:
//Input Values:
//<index> lArg1
//<value> lArg2
//<ptr> ptrArg
//<opt> floatArg
//Return Values:
//Vendor specific response as integer
cout << "plug called audioMasterVendorSpecific" << endl;
break;
case audioMasterSetIcon:
//IGNORE
break;
case audioMasterCanDo:
//Input Values:
//<ptr> predefined "canDo" string
//Return Value:
//0 = Not Supported
//non-zero value if host supports that feature
//NB - Possible Can Do strings are:
//"sendVstEvents",
//"sendVstMidiEvent",
//"sendVstTimeInfo",
//"receiveVstEvents",
//"receiveVstMidiEvent",
//"receiveVstTimeInfo",
//"reportConnectionChanges",
//"acceptIOChanges",
//"sizeWindow",
//"asyncProcessing",
//"offline",
//"supplyIdle",
//"supportShell"
cout << "plug called audioMasterCanDo" << endl;
if (strcmp((char*)ptr,"sendVstEvents")==0 ||
strcmp((char*)ptr,"sendVstMidiEvent")==0 ||
strcmp((char*)ptr,"supplyIdle")==0)
{
retval=1;
}
else
{
retval=0;
}
break;
case audioMasterGetLanguage:
//Input Values:
//None
//Return Value:
//kVstLangEnglish
//kVstLangGerman
//kVstLangFrench
//kVstLangItalian
//kVstLangSpanish
//kVstLangJapanese
cout << "plug called audioMasterGetLanguage" << endl;
retval=1;
break;
/*
MAC SPECIFIC?
case audioMasterOpenWindow:
//Input Values:
//<ptr> pointer to a VstWindow structure
//Return Value:
//0 if error
//else platform specific ptr
cout << "plug called audioMasterOpenWindow" << endl;
break;
case audioMasterCloseWindow:
//Input Values:
//<ptr> pointer to a VstWindow structure
//Return Value:
//0 if error
//Non-zero value if OK
cout << "plug called audioMasterCloseWindow" << endl;
break;
*/
case audioMasterGetDirectory:
//Input Values:
//None
//Return Value:
//0 if error
//FSSpec on MAC, else char* as integer
//NB Refers to which directory, exactly?
cout << "plug called audioMasterGetDirectory" << endl;
break;
case audioMasterUpdateDisplay:
//Input Values:
//None
//Return Value:
//Unknown
cout << "plug called audioMasterUpdateDisplay" << endl;
break;
}
return retval;
};
I began to do this :
Code: Select all
Structure AEffect
magic.l; must be kEffectMagic ('VstP')
dispatcher.l; long (VSTCALLBACK * dispatcher) (AEffect * effect, long opCode,long index, long value, void *ptr,float opt)
process.l; void (VSTCALLBACK * process) (AEffect * effect, float **inputs,float **outputs, long sampleframes);
setParameter.l; void (VSTCALLBACK * setParameter) (AEffect * effect, long index, float parameter);
getParameter.l; float (VSTCALLBACK * getParameter) (AEffect * effect, long index);
numPrograms.l
numParams.l; // all programs are assumed to have numParams parameters
numInputs.l; //
numOutputs.l; //
flags.l; // see constants
resvd1.l; // reserved, must be 0
resvd2.l; // reserved, must be 0
initialDelay.l; // for algorithms which need input in the first place
realQualities.l; // number of realtime qualities (0: realtime)
offQualities.l; // number of offline qualities (0: realtime only)
ioRatio.f; // input samplerate to output samplerate ratio, not used yet
*object.l; // for class access (see AudioEffect.hpp), MUST be 0 else!
*user.l; // user access
uniqueID.l; // pls choose 4 character as unique as possible.
;// this is used To identify an effect For save+load
version.l; //
processReplacing.l; void (VSTCALLBACK * processReplacing) (AEffect * effect, float **inputs,
*outputs.f
sampleframes.l
future.b[60] ; // pls zero
EndStructure
;
Procedure host(*effect.AEffect, opcode.l, index.l, value.l, *ptr.l, opt.f)
Debug "Opcode : "+Str(opcode)
ProcedureReturn 0
EndProcedure
LibName$ = OpenFileRequester("Choose a VST (.dll file)", "", ".DLL|*.dll",0)
If LibName$
If OpenLibrary(0, LibName$)
If ExamineLibraryFunctions(0)
Result = IsFunction(0, "main")
If Result
*ptrPlug.AEffect = CallFunctionFast(Result,@host,0)
Else
MessageRequester("Error","This library is not a VST",0)
EndIf
Else
MessageRequester("Error","Can't examine this library.",0)
EndIf
CloseLibrary(0)
Else
MessageRequester("Error","Can't open this library.",0)
EndIf
EndIf