X-Git-Url: https://scm.cri.ensmp.fr/git/Faustine.git/blobdiff_plain/c7f552fd8888da2f0d8cfb228fe0f28d3df3a12c..b4b6f2ea75b9f0f3ca918f5b84016610bf7a4d4f:/interpretor/preprocessor/faust-0.9.47mr3/architecture/vsti-mono.cpp diff --git a/interpretor/preprocessor/faust-0.9.47mr3/architecture/vsti-mono.cpp b/interpretor/preprocessor/faust-0.9.47mr3/architecture/vsti-mono.cpp new file mode 100644 index 0000000..51fc0f9 --- /dev/null +++ b/interpretor/preprocessor/faust-0.9.47mr3/architecture/vsti-mono.cpp @@ -0,0 +1,1072 @@ +/************************************************************************ + + IMPORTANT NOTE : this file contains two clearly delimited sections : + the ARCHITECTURE section (in two parts) and the USER section. Each section + is governed by its own copyright and license. Please check individually + each section for license and copyright information. +*************************************************************************/ + +/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/ + +/************************************************************************ + ************************************************************************ + FAUST Architecture File + Copyright (C) 2007-2011 Julius Smith + All rights reserved. + ----------------------------BSD License------------------------------ + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Julius Smith nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. + + ----------------------------VST SDK---------------------------------- + In order to compile a VST (TM) plugin with this architecture file + you will need the proprietary VST SDK from Steinberg. Please check + the corresponding license. + + ************************************************************************ + ************************************************************************/ + +/******************************************************************** + * vsti-mono.cpp - Monaural VSTi-2.4 wrapper for the FAUST language. + * + * Usage: faust -a vsti-mono.cpp myfaustprog.dsp + * + * By Julius Smith (http://ccrma.stanford.edu/~jos/), based on vst.cpp + * by remy muller + * (http://www.smartelectronix.com/~mdsp/). Essentially, vst.cpp was + * first edited to look more like the "again" programming sample that + * comes with the VST-2.4 SDK from Steinberg. Next, features from the + * "vstxsynth" program sample were added to give simple MIDI synth + * support analogous to that of faust2pd, except that only one voice + * is supported. (If the Faust patch has any input signals, this + * architecture file should reduce to vst2p4.cpp --- i.e., basic VST + * plugin support.) As with faust2pd, to obtain MIDI control via + * NoteOn/Off, Velocity, and KeyNumber, there must be a button named + * "gate" and sliders (or numeric entries) named "gain" and "freq" in + * the Faust patch specified in myfaustprog.dsp. + * + * NOTES: + * Relies on automatically generated slider GUI for VST plugins. + * - Horizontal and vertical sliders mapped to "vstSlider" + * - Numeric Entries similarly converted to "vstSlider" + * - No support for bar graphs or additional numeric and text displays + * - Tested on the Muse Receptor Pro 1.0, System Version 1.6.20070717, + * using Visual C++ 2008 Express Edition + * (part of the Microsoft Visual Studio 2008, Beta 2) + * - Reference: + * http://ccrma.stanford.edu/realsimple/faust/Generating_VST_Plugin_Faust.html + * + * FAUST + * Copyright (C) 2003-2007 GRAME, Centre National de Creation Musicale + * http://www.grame.fr/ + * + ********************************************************************/ + +// Suggestion: Faust could replace all leading comments in this file +// by the following shorter comment: + +/******************************************************************** + * C++ source generated by the following command line: + * + * faust -a vsti.cpp name.dsp -o name-vsti.cpp + * + ********************************************************************/ + +// (where the filenames could be really right, and the path to vsti.cpp +// could be included as well.) + +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include + +using namespace std ; + +// There is a bug with powf() when cross compiling with mingw +// the following macro avoid the problem +#ifdef WIN32 +#define powf(x,y) pow(x,y) +#define expf(x) exp(x) +#endif + +// On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero) +// flags to avoid costly denormals +#ifdef __SSE__ + #include + #ifdef __SSE2__ + #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040) + #else + #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000) + #endif +#else + #define AVOIDDENORMALS +#endif + +struct Meta +{ + void declare (const char* key, const char* value) { } +}; + + +#ifdef __GNUC__ + +//------------------------------------------------------------------- +// Generic min and max using gcc extensions +//------------------------------------------------------------------- + +#define max(x,y) ((x)>?(y)) +#define min(x,y) ((x)b) ? a : b; } +inline int max (int a, int b) { return (a>b) ? a : b; } + +inline long max (long a, long b) { return (a>b) ? a : b; } +inline long max (int a, long b) { return (a>b) ? a : b; } +inline long max (long a, int b) { return (a>b) ? a : b; } + +inline float max (float a, float b) { return (a>b) ? a : b; } +inline float max (int a, float b) { return (a>b) ? a : b; } +inline float max (float a, int b) { return (a>b) ? a : b; } +inline float max (long a, float b) { return (a>b) ? a : b; } +inline float max (float a, long b) { return (a>b) ? a : b; } + +inline double max (double a, double b) { return (a>b) ? a : b; } +inline double max (int a, double b) { return (a>b) ? a : b; } +inline double max (double a, int b) { return (a>b) ? a : b; } +inline double max (long a, double b) { return (a>b) ? a : b; } +inline double max (double a, long b) { return (a>b) ? a : b; } +inline double max (float a, double b) { return (a>b) ? a : b; } +inline double max (double a, float b) { return (a>b) ? a : b; } + +inline int min (int a, int b) { return (a T abs (T a) { return (a> n); } + +inline int int2pow2 (int x) { int r=0; while ((1<> + +/****************************************************************************** +******************************************************************************* +* +* USER INTERFACE +* +******************************************************************************* +*******************************************************************************/ + +class UI +{ + bool fStopped; + +public: + + UI() : fStopped(false) {} + virtual ~UI() {} + + virtual void addButton(char* label, float* zone) = 0; + virtual void addToggleButton(char* label, float* zone) = 0; + virtual void addCheckButton(char* label, float* zone) = 0; + virtual void addVerticalSlider(char* label, float* zone, float init, float min, float max, float step) = 0; + virtual void addHorizontalSlider(char* label, float* zone, float init, float min, float max, float step) = 0; + virtual void addNumEntry(char* label, float* zone, float init, float min, float max, float step) = 0; + + virtual void addNumDisplay(char* label, float* zone, int precision) = 0; + virtual void addTextDisplay(char* label, float* zone, char* names[], float min, float max) = 0; + virtual void addHorizontalBargraph(char* label, float* zone, float min, float max) = 0; + virtual void addVerticalBargraph(char* label, float* zone, float min, float max) = 0; + + virtual void openFrameBox(char* label) = 0; + virtual void openTabBox(char* label) = 0; + virtual void openHorizontalBox(char* label) = 0; + virtual void openVerticalBox(char* label) = 0; + virtual void closeBox() = 0; + + virtual void run() {}; + + void stop() { fStopped = true; } + bool stopped() { return fStopped; } + + virtual void declare(float* zone, const char* key, const char* value) {} +}; + + +/****************************************************************************** +******************************************************************************* +* +* FAUST DSP +* +******************************************************************************* +*******************************************************************************/ + + + +//---------------------------------------------------------------- +// Base dsp class for this architecture +//---------------------------------------------------------------- + +class dsp { + +protected: + + int fSamplingFreq; + +public: + + dsp() {} + virtual ~dsp() {} + virtual int getNumInputs() = 0; + virtual int getNumOutputs() = 0; + virtual void buildUserInterface(UI* interface) = 0; + virtual void init(int samplingRate) = 0; + virtual void compute(int len, float** inputs, float** outputs) = 0; +}; + +/********************END ARCHITECTURE SECTION (part 1/2)****************/ + +/**************************BEGIN USER SECTION **************************/ + +<> + +/***************************END USER SECTION ***************************/ + +/*******************BEGIN ARCHITECTURE SECTION (part 2/2)***************/ + +/****************************************************************************** + * + * VST wrapper + * + ******************************************************************************/ + +#include "audioeffectx.h" + +class vstUI; + +//------------------------------------------------------------------------------ +// Faust class prototype +//------------------------------------------------------------------------------ +class Faust : public AudioEffectX +{ +public: + Faust(audioMasterCallback audioMaster, mydsp* dspi, vstUI* dspUIi); + virtual ~Faust(); + + virtual void processReplacing (float **inputs, float **outputs, VstInt32 sampleFrames); + virtual VstInt32 processEvents (VstEvents* events); + + virtual void setProgram (VstInt32 program); + virtual void setProgramName (char *name); + virtual void getProgramName (char *name); + virtual bool getProgramNameIndexed (VstInt32 category, VstInt32 index, char *text); + + virtual void setParameter (VstInt32 index, float value); + virtual float getParameter (VstInt32 index); + virtual void getParameterLabel (VstInt32 index, char *label); + virtual void getParameterDisplay (VstInt32 index, char *text); + virtual void getParameterName (VstInt32 index, char *text); + + virtual void setSampleRate (float sampleRate); + + virtual bool getInputProperties (VstInt32 index, VstPinProperties *properties); + virtual bool getOutputProperties (VstInt32 index, VstPinProperties *properties); + + virtual bool getEffectName (char *name); + virtual bool getVendorString (char *text); + virtual bool getProductString (char *text); + virtual VstInt32 getVendorVersion (); + virtual VstInt32 canDo (char *text); + + virtual VstInt32 getNumMidiInputChannels (); + virtual VstInt32 getNumMidiOutputChannels (); + + virtual VstInt32 getMidiProgramName (VstInt32 channel, MidiProgramName *midiProgramName); + virtual VstInt32 getCurrentMidiProgram (VstInt32 channel, MidiProgramName *currentProgram); + virtual VstInt32 getMidiProgramCategory (VstInt32 channel, MidiProgramCategory *category); + +private: + mydsp* dsp; + vstUI* dspUI; + + // For synths: + bool noteIsOn; + VstInt32 currentNote; + VstInt32 currentVelocity; + VstInt32 currentDelta; + + void initProcess (); + void noteOn (VstInt32 note, VstInt32 velocity, VstInt32 delta); + void noteOff (); + void fillProgram (VstInt32 channel, VstInt32 prg, MidiProgramName* mpn); + + char programName[kVstMaxProgNameLen + 1]; +}; + +/*--------------------------------------------------------------------------*/ +class vstUIObject { /* superclass of all VST UI widgets */ +protected: + string fLabel; + float* fZone; + + inline float clip(float min, float max, float val) + { + return (val < min) ? min : (val > max) ? max : val; + } + + inline float normalize(float min, float max, float val) + { // VST parameters are normalized to the range [0;1] on the host + val = min + val * (max - min); + return (val < min) ? min : (val > max) ? max : val; + } + +public: + vstUIObject(char* label, float* zone):fLabel(label),fZone(zone) {} + virtual ~vstUIObject() {} + + virtual void GetName(char *text){std::strcpy(text,fLabel.c_str());} + virtual void SetValue(double f) {*fZone = normalize(0.0f,1.0f,(float)f);} + virtual void SetValueNoNormalization(double f) {*fZone = clip(0.0f,1.0f,(float)f);} + virtual float GetValue() {return *fZone;} + virtual void GetDisplay(char *text){std::sprintf(text,"%f",*fZone);} + virtual long GetID() + { /* returns the sum of all the ASCII characters contained in the parameter's label */ + unsigned int i; + long acc; + for(i=0,acc = 0;i0.5f)?1.0f:0.0f;} + virtual void GetDisplay(char *text){(*fZone>0.5f)? std::strcpy(text,"ON"): std::strcpy(text,"OFF");} +}; + +/*--------------------------------------------------------------------------*/ +class vstCheckButton : public vstUIObject { + +public: + + vstCheckButton(char* label, float* zone):vstUIObject(label,zone) {} + virtual ~vstCheckButton() {} + virtual float GetValue() {return *fZone;} + virtual void SetValue(double f) {*fZone = (f>0.5f)?1.0f:0.0f;} + virtual void GetDisplay(char *text){(*fZone>0.5f)? std::strcpy(text,"ON"): std::strcpy(text,"OFF");} +}; + +/*--------------------------------------------------------------------------*/ +class vstButton : public vstUIObject { + +public: + + vstButton(char* label, float* zone):vstUIObject(label,zone) {} + virtual ~vstButton() {} + virtual float GetValue() {return *fZone;} + virtual void SetValue(double f) {*fZone = (f>0.5f)?1.0f:0.0f;} + virtual void GetDisplay(char *text){(*fZone>0.5f)? std::strcpy(text,"ON"): std::strcpy(text,"OFF");} +}; + +/*--------------------------------------------------------------------------*/ +class vstSlider : public vstUIObject{ + +private: + + float fInit; + float fMin; + float fMax; + float fStep; + +public: + + vstSlider(char* label, float* zone, float init, float min, float max, float step) + :vstUIObject(label,zone), fInit(init), fMin(min), fMax(max),fStep(step) {} + virtual ~vstSlider() {} + + // The VST host calls GetValue() and expects a result in [0,1]. + // The VST host calls SetValue(f) with f in [0,1]. We convert to real units. + // When we process MIDI controls, we call SetValueNoNormalization(f) with f in real units. + virtual float GetValue() {return (*fZone-fMin)/(fMax-fMin);} // normalize + virtual void SetValue(double f) {*fZone = normalize(fMin,fMax,(float)f);} // denormalize + virtual void SetValueNoNormalization(double f) {*fZone = clip(fMin,fMax,(float)f);} // raw +}; + +/*--------------------------------------------------------------------------*/ +class vstUI : public UI +{ +private: + + vector fUITable; + +public: + + int freqIndex; + int gainIndex; + int gateIndex; + + vstUI(){ + freqIndex = gainIndex = gateIndex = -1; + } + virtual ~vstUI() + { + for (vector::iterator iter = fUITable.begin(); iter != fUITable.end(); iter++) delete *iter; + } + + void setAny(int anyIndex, float val, char *str) { + if (anyIndex<0) { +#ifdef DEBUG + // On the Receptor, and perhaps other hosts, output to stderr is logged in a file. + fprintf(stderr,"*** Faust vsti: %sIndex = %d never set!\n",str,anyIndex); +#endif + return; + } + if (anyIndex >= fUITable.size()) { +#ifdef DEBUG + fprintf(stderr,"*** Faust vsti: %sIndex = %d too large!\n",str,anyIndex); +#endif + return; + } +#ifdef DEBUG + fprintf(stderr,"*** Faust vsti: Setting %sIndex = %d to %f\n",str,anyIndex,val); +#endif + fUITable[anyIndex]->SetValueNoNormalization(val); + } + + void setFreq(float val) { + setAny(freqIndex, val, "freq"); + } + + void setGate(float val) { + setAny(gateIndex, val, "gate"); + } + + void setGain(float val) { + setAny(gainIndex, val, "gain"); + } + + bool ckAnyMatch(char* label, char* indexName, int *index) { + if (_stricmp(label,indexName)==0) { +#ifdef DEBUG + fprintf(stderr,"=== Faust vsti: label '%s' matches '%s'\n",label,indexName); +#endif + *index = fUITable.size() - 1; + return true; + } + return false; + } + + void ckAllMatches(char* label) { + ckAnyMatch(label,"gain",&gainIndex); + ckAnyMatch(label,"gate",&gateIndex); + ckAnyMatch(label,"freq",&freqIndex); + } + + void addButton(char* label, float* zone) { + vstButton* theButton = new vstButton(label, zone); + fUITable.push_back(theButton); +#ifdef DEBUG + fprintf(stderr,"=== Faust vsti: Adding Button with label '%s'\n",label); +#endif + ckAnyMatch(label,"gate",&gateIndex); + } + + void addToggleButton(char* label, float* zone) {fUITable.push_back(new vstToggleButton(label, zone));} + + void addCheckButton(char* label, float* zone) {fUITable.push_back(new vstCheckButton(label, zone));} + + void addVerticalSlider(char* label, float* zone, float init, float min, float max, float step) + { + vstSlider* theSlider = new vstSlider(label, zone, init, min, max, step); + fUITable.push_back(theSlider); +#ifdef DEBUG + fprintf(stderr,"=== Faust vsti: Adding VSlider (HSlider) with label '%s'\n",label); +#endif + ckAllMatches(label); + } + + void addHorizontalSlider(char* label, float* zone, float init, float min, float max, float step) + { + vstSlider* theSlider = new vstSlider(label, zone, init, min, max, step); + fUITable.push_back(theSlider); +#ifdef DEBUG + fprintf(stderr,"=== Faust vsti: Adding HSlider with label '%s'\n",label); +#endif + ckAllMatches(label); + } + + void addNumEntry(char* label, float* zone, float init, float min, float max, float step) + { /* Number entries converted to horizontal sliders */ + vstSlider* theSlider = new vstSlider(label, zone, init, min, max, step); + fUITable.push_back(theSlider); +#ifdef DEBUG + fprintf(stderr,"=== Faust vsti: Adding NumEntry (HSlider) with label '%s'\n",label); +#endif + ckAllMatches(label); + } + + void openFrameBox(char* label) {} + void openTabBox(char* label) {} + void openHorizontalBox(char* label) {} + void openVerticalBox(char* label) {} + void closeBox() {} + + void SetValue(VstInt32 index, double f) {assert(indexSetValue(f);} + float GetValue(VstInt32 index) {assert(indexGetValue();} + void GetDisplay(VstInt32 index, char *text) {assert(indexGetDisplay(text);} + void GetName(VstInt32 index, char *text) {assert(indexGetName(text);} + long GetNumParams() {return fUITable.size();} + + long makeID() + /* Creates a (unique?)id by summing all the parameter's labels, + * then wrapping it in the range [0;maxNumberOfId] and adding + * this number to the offset made by the Four Character ID: 'FAUS' + */ + { + const long maxNumberOfId = 128; + long baseid = 'FAUS'; + long id=0; + for(int i=0;iGetID(); + return baseid + id % maxNumberOfId; + } + + // To be implemented + void addNumDisplay(char* label, float* zone, int precision){} + void addTextDisplay(char* label, float* zone, char* names[], float min, float max){} + void addHorizontalBargraph(char* label, float* zone, float min, float max){} + void addVerticalBargraph(char* label, float* zone, float min, float max){} +}; + +//----------------------------------------------------------------------------- +// Class Implementations +//----------------------------------------------------------------------------- + +#define kNumPrograms 1 + +AudioEffect* createEffectInstance (audioMasterCallback audioMaster) +{ + // The dsp and its UI need to be allocated now because + // AudioEffectX wants the no. parameters available as an instance argument: + mydsp* dspi = new mydsp(); + vstUI* dspUIi = new vstUI(); + dspi->buildUserInterface(dspUIi); +#ifdef DEBUG + fprintf(stderr,"=== Faust vsti: created\n"); // look for this in the system log +#endif + return new Faust(audioMaster,dspi,dspUIi); +} + +//----------------------------------------------------------------------------- +// Faust +//----------------------------------------------------------------------------- +Faust::Faust(audioMasterCallback audioMaster, mydsp* dspi, vstUI* dspUIi) + :AudioEffectX(audioMaster, kNumPrograms,dspUIi->GetNumParams()) +{ + // Copy the pointers to dsp and dspUI instances and take them over + // (we'll also deallocate): + dsp = dspi; + dspUI = dspUIi; + +#ifdef DEBUG + fprintf(stderr,"=== Faust vsti: classInit:\n"); +#endif + + dsp->classInit((int)getSampleRate()); // Ask AudioEffect for sample-rate + + setProgram(0); + setProgramName("Default"); + + if (audioMaster) { + setNumInputs(dsp->getNumInputs()); + setNumOutputs(dsp->getNumOutputs()); + canProcessReplacing(); + if (dsp->getNumInputs() == 0) { + isSynth(); // at least let's hope so! + if (dsp->getNumOutputs() < 1) { + fprintf(stderr,"*** faust: vsti: No signal inputs or outputs, and Faust has no MIDI outputs!\n"); + } + } + setUniqueID(dspUI->makeID()); + } + initProcess(); + if (dsp->getNumInputs() == 0) { + suspend(); // Synths start out quiet + } +} + +//---------------------------------------------------------------------------- +Faust::~Faust() +{ + if (dsp) delete dsp; + if (dspUI) delete dspUI; +} + +//----------------------------------------------------------------------------- +void Faust::setProgram (VstInt32 program) +// Override this method of AudioEffect in order to set +// local instance variables corresponding to the current MIDI program. +// Here there is only one program. +{ + if (program < 0 || program >= kNumPrograms) { + fprintf(stderr,"*** Faust vsti: setting program to %d is OUT OF RANGE\n",program); + return; + } +#ifdef DEBUG + fprintf(stderr,"=== Faust vsti: setting program to %d\n",program); +#endif + curProgram = program; // curProgram defined in audioeffect.h +} + +//------------------------------------------------------------------------------ +void Faust::setProgramName (char* name) +{ + vst_strncpy (programName, name, kVstMaxProgNameLen); +} + +//----------------------------------------------------------------------------- +void Faust::getProgramName(char *name) +{ + vst_strncpy (name, programName, kVstMaxProgNameLen); +} + +//----------------------------------------------------------------------------- +void Faust::getParameterLabel(VstInt32 index, char *label) +{ + // We are not using parameter "units" display: + vst_strncpy (label, "", kVstMaxParamStrLen); // parameter units in Name +} + +//----------------------------------------------------------------------------- +void Faust::getParameterDisplay(VstInt32 index, char *text) +{ + if(indexGetDisplay(index,text); // get displayed float value as text + else + vst_strncpy (text, "IndexOutOfRange", kVstMaxParamStrLen); +} + +//----------------------------------------------------------------------------- +void Faust::getParameterName(VstInt32 index, char *label) +{ + if(indexGetName(index,label); // parameter name, including units + else + vst_strncpy (label, "IndexOutOfRange", kVstMaxParamStrLen); +} + +//----------------------------------------------------------------------------- +void Faust::setParameter(VstInt32 index, float value) +{ + if(indexSetValue(index,value); +} + +//----------------------------------------------------------------------------- +float Faust::getParameter(VstInt32 index) +{ + if(indexGetValue(index); + else + return 0.0f; +} + +//----------------------------------------------------------------------------- +bool Faust::getInputProperties (VstInt32 index, VstPinProperties* properties) +{ + if(index>=0 && indexgetNumInputs()) + { + sprintf (properties->label, "Grame Faust DSP input: %d",index); + sprintf (properties->shortLabel, "In %d",index); + properties->flags = kVstPinIsActive; + if (dsp->getNumInputs() == 2) { + properties->flags |= kVstPinIsStereo; + } + return true; + } + else + return false; +} + +//----------------------------------------------------------------------------- +bool Faust::getOutputProperties (VstInt32 index, VstPinProperties* properties) +{ + if(index>=0 && indexgetNumOutputs()) + { + sprintf (properties->label, "Grame Faust DSP output: %d",index); + sprintf (properties->shortLabel, "Out %d",index); + properties->flags = kVstPinIsActive; + if (dsp->getNumOutputs() == 2) { + properties->flags |= kVstPinIsStereo; + } + return true; + } + else + return false; +} + +//----------------------------------------------------------------------------- +bool Faust::getProgramNameIndexed (VstInt32 category, VstInt32 index, char* text) +{ + if (index < kNumPrograms) { + vst_strncpy (text, programName, kVstMaxProgNameLen); + return true; + } + return false; +} + +//----------------------------------------------------------------------------- +bool Faust::getEffectName (char* name) +{ + // Get from Faust-supplied metadata? + vst_strncpy (name, "Effect Name goes here", kVstMaxEffectNameLen); + return true; +} + +//----------------------------------------------------------------------------- +bool Faust::getVendorString (char* text) +{ + vst_strncpy (text, "Vendor String goes here", kVstMaxVendorStrLen); + return true; +} + +//----------------------------------------------------------------------------- +bool Faust::getProductString (char* text) +{ + vst_strncpy (text, "Product String goes here", kVstMaxProductStrLen); + return true; +} + +//----------------------------------------------------------------------------- +VstInt32 Faust::getVendorVersion () +{ + return 1000; +} + +//----------------------------------------------------------------------------- +VstInt32 Faust::canDo (char* text) +{ + if (!strcmp (text, "receiveVstEvents")) + return 1; + if (!strcmp (text, "receiveVstMidiEvent")) + return 1; + if (!strcmp (text, "midiProgramNames")) + return 1; + return -1; // explicitly can't do; 0 => don't know +} + +//----------------------------------------------------------------------------- +VstInt32 Faust::getNumMidiInputChannels () +{ + return 1; // one MIDI-in channel +} + +//----------------------------------------------------------------------------- +VstInt32 Faust::getNumMidiOutputChannels () +{ + return 0; // no MIDI-outs +} + +//----------------------------------------------------------------------------- +VstInt32 Faust::getMidiProgramName (VstInt32 channel, MidiProgramName* mpn) +{ + VstInt32 prg = mpn->thisProgramIndex; + if (prg < 0 || prg > 0) return 0; + fillProgram (channel, prg, mpn); + return 1; // we have only 1 "MIDI program" +} + +//------------------------------------------------------------------------ +VstInt32 Faust::getCurrentMidiProgram (VstInt32 channel, MidiProgramName* mpn) +{ + // There is only one MIDI program here, so return it regardless of MIDI channel: + if (channel < 0 || channel >= 16 || !mpn) return -1; + VstInt32 prg = 0; + mpn->thisProgramIndex = prg; + fillProgram (channel, prg, mpn); + return prg; +} + +//------------------------------------------------------------------------ +void Faust::fillProgram (VstInt32 channel, VstInt32 prg, MidiProgramName* mpn) +// Fill mpn struct for given channel. Here there should be only one. +{ + mpn->midiBankMsb = mpn->midiBankLsb = -1; + mpn->reserved = 0; + mpn->flags = 0; + vst_strncpy (mpn->name, programName, kVstMaxProgNameLen); + mpn->midiProgram = (char)prg; // prg should only be 0 + mpn->parentCategoryIndex = -1; +} + +//------------------------------------------------------------------------ +VstInt32 Faust::getMidiProgramCategory (VstInt32 channel, MidiProgramCategory* cat) +// VST host wants to fill cat struct for given channel. We have only one category. +{ + cat->parentCategoryIndex = -1; // -1:no parent category + cat->flags = 0; // reserved, none defined yet, zero. + VstInt32 category = cat->thisCategoryIndex; + vst_strncpy (cat->name, "Faust Patch", kVstMaxProgNameLen); + return 1; // one category +} + +//*********************************************************************** + +//----------------------------------------------------------------------------- +void Faust::setSampleRate(float sampleRate) +{ + AudioEffect::setSampleRate(sampleRate); + dsp->instanceInit((int)getSampleRate()); // in case AudioEffect altered it +} + +//----------------------------------------------------------------------------- +void Faust::initProcess () +{ + noteIsOn = false; + currentDelta = currentNote = currentDelta = 0; + dsp->instanceInit((int)getSampleRate()); +} + +//----------------------------------------------------------------------------- +void Faust::processReplacing(float **inputs, float **outputs, VstInt32 sampleFrames) +{ + AVOIDDENORMALS; +#ifdef DEBUG + fprintf(stderr,"=== Faust vsti: processReplacing . . .\n"); +#endif + + if (dsp->getNumInputs() > 0) { // We're an effect . . . keep going: + + dsp->compute(sampleFrames, inputs, outputs); + + } else { // We're a synth . . . + int i, nouts = dsp->getNumOutputs(); + + if (noteIsOn) { // we're synthesizing . . . + + if (currentDelta > 0) { // but waiting out a timestamp delay . . . + if (currentDelta >= sampleFrames) { // start time is after this chunk + currentDelta -= sampleFrames; + // According to the VST programming sample, we DON'T clear the output buffers yet. + // Could this be a bug in the sample program? I would like to add the following: + // for (i=0; icompute(sampleFrames, inputs, outptr); + free(outptr); + } + } else { + dsp->compute(sampleFrames, inputs, outputs); + } + + } else { // silence until NoteOn . . . + for (i=0; inumEvents > 0) { +#ifdef DEBUG + fprintf(stderr,"=== Faust vsti: processEvents processing %d events\n", + ev->numEvents); +#endif + } + + for (VstInt32 i = 0; i < ev->numEvents; i++) + { +#ifdef DEBUG + fprintf(stderr,"=== Faust vsti: event type = %d\n", + (ev->events[i])->type); +#endif + if ((ev->events[i])->type != kVstMidiType) { +#ifdef DEBUG + fprintf(stderr,"=== Faust vsti: EVENT IGNORED!\n"); +#endif + continue; + } + VstMidiEvent* event = (VstMidiEvent*)ev->events[i]; + char* midiData = event->midiData; + VstInt32 chan = midiData[0] & 0xf; + VstInt32 status = midiData[0] & 0xf0; +#ifdef DEBUG + fprintf(stderr,"\n=== Faust vsti: event->midiData[0] = 0x%x\n", + event->midiData[0]); + fprintf(stderr,"=== Faust vsti: midi channel = 0x%x\n", chan); + fprintf(stderr,"=== Faust vsti: midi status = 0x%x\n", status); + fprintf(stderr,"=== Faust vsti: event->midiData[1] = 0x%x\n", + event->midiData[1]); + fprintf(stderr,"=== Faust vsti: event->midiData[2] = 0x%x\n", + event->midiData[2]); +#endif + + if (status == 0x90) { // note on + VstInt32 note = midiData[1] & 0x7f; + VstInt32 velocity = midiData[2] & 0x7f; +#ifdef DEBUG + fprintf(stderr, + "=== Faust vsti: note = %d, velocity = %d, delay = %d\n", + note,velocity,event->deltaFrames); +#endif + if (velocity>0) { + noteOn(note, velocity, event->deltaFrames); + } else { + noteOff(); + } + } else if (status == 0x80) { // note off + noteOff(); + // } else if (status == 0xA0) { // poly aftertouch + } else if (status == 0xB0) { // control change + /* DO SOMETHING WITH THE CONTROLLER DATA */ + fprintf(stderr,"=== Faust vsti: CONTROL CHANGE (status 0xB0)!\n"); + if (midiData[1] == 0x7e || midiData[1] == 0x7b) { // all notes off + fprintf(stderr,"=== Faust vsti: ALL NOTES OFF!\n"); + noteOff (); // why is all-notes-off inside a "control change" event? + } + // } else if (status == 0xC0) { // program change + // } else if (status == 0xD0) { // mono aftertouch + // } else if (status == 0xE0) { // pitch change + // } else if (status == 0xF0) { // SYSX ... + } + // For a list, see + // http://www.alfred-j-faust.de/rft/midi%20status%20types.html + +#ifdef DEBUG + fprintf(stderr,"=== Faust vsti: Going to next event\n", event->midiData[2]); +#endif + + event++; + } + return 1; +} + +//----------------------------------------------------------------------------- +void Faust::noteOn (VstInt32 note, VstInt32 velocity, VstInt32 delta) +{ +#ifdef DEBUG + fprintf(stderr,"=== Faust vsti: noteOn: note = %d, vel = %d, del = %d\n",note,velocity,delta); +#endif + currentNote = note; + currentVelocity = velocity; + currentDelta = delta; + noteIsOn = true; + float freq = 440.0f * powf(2.0f,(((float)note)-69.0f)/12.0f); + float gain = velocity/127.0f; + dspUI->setFreq(freq); // Hz - requires Faust control-signal "freq" + dspUI->setGain(gain); // 0-1 - requires Faust control-signal "gain" + dspUI->setGate(1.0f); // 0 or 1 - requires Faust button-signal "gate" +} + +//----------------------------------------------------------------------------- +void Faust::noteOff () +{ + if (noteIsOn) { +#ifdef DEBUG + fprintf(stderr,"=== Faust vsti: noteOff\n"); +#endif + dspUI->setGate(0); + } else { +#ifdef DEBUG + fprintf(stderr,"=== Faust vsti: noteOff IGNORED (note was not on)\n"); +#endif + } +} + + +/********************END ARCHITECTURE SECTION (part 2/2)****************/ +