Logo Search packages:      
Sourcecode: faust version File versions  Download package

vsti-mono.cpp

/********************************************************************
 * 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 <remy.muller at ircam.fr>
 * (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 <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <math.h>
#include <errno.h>
#include <time.h>
//#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <string>
#include <vector>
#include <math.h>

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 <xmmintrin.h>
    #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)<?(y))

//abs(x) should be already predefined

#else

//-------------------------------------------------------------------
// Generic min and max using c++ inline
//-------------------------------------------------------------------

inline int  max (unsigned int a, unsigned int b) { return (a>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<b) ? a : b; }

inline long min (long a, long b)          { return (a<b) ? a : b; }
inline long min (int a, long b)           { return (a<b) ? a : b; }
inline long min (long a, int b)           { return (a<b) ? a : b; }

inline float      min (float a, float b)        { return (a<b) ? a : b; }
inline float      min (int a, float b)          { return (a<b) ? a : b; }
inline float      min (float a, int b)          { return (a<b) ? a : b; }
inline float      min (long a, float b)         { return (a<b) ? a : b; }
inline float      min (float a, long b)         { return (a<b) ? a : b; }

inline double     min (double a, double b)      { return (a<b) ? a : b; }
inline double     min (int a, double b)         { return (a<b) ? a : b; }
inline double     min (double a, int b)         { return (a<b) ? a : b; }
inline double     min (long a, double b)        { return (a<b) ? a : b; }
inline double     min (double a, long b)        { return (a<b) ? a : b; }
inline double     min (float a, double b)       { return (a<b) ? a : b; }
inline double     min (double a, float b)       { return (a<b) ? a : b; }
            
#endif

// abs is now predefined
//template<typename T> T abs (T a) { return (a<T(0)) ? -a : a; }

inline int lsr (int x, int n) { return int(((unsigned int)x) >> n); }

inline int int2pow2 (int x) { int r=0; while ((1<<r)<x) r++; return r; }

/******************************************************************************
*******************************************************************************
*
*                                                VECTOR INTRINSICS
*
*******************************************************************************
*******************************************************************************/

//inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((unsigned)(calloc((nmemb*size)+15,sizeof(char)))+15 & 0xfffffff0); }
//inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((size_t)(calloc((nmemb*size)+15,sizeof(char)))+15 & ~15); }

<<includeIntrinsic>>

/******************************************************************************
*******************************************************************************
*
*                                               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;
};

//----------------------------------------------------------------
//  Faust-generated dsp class 
//----------------------------------------------------------------
                  
<<includeclass>>

/******************************************************************************
 *
 * 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;i<fLabel.length();i++) acc += (fLabel.c_str())[i];
    return acc;
  }
};

/*--------------------------------------------------------------------------*/
class vstToggleButton : public vstUIObject {
      
public:     
      
  vstToggleButton(char* label, float* zone):vstUIObject(label,zone) {}
  virtual ~vstToggleButton() {}
  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 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<vstUIObject*> fUITable;

public:
                  
  int freqIndex;
  int gainIndex;
  int gateIndex;

  vstUI(){   
    freqIndex = gainIndex = gateIndex = -1;
  }
  virtual ~vstUI() 
  {
    for (vector<vstUIObject*>::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(index<fUITable.size()); fUITable[index]->SetValue(f);}
  float GetValue(VstInt32 index) {assert(index<fUITable.size()); return fUITable[index]->GetValue();}
  void  GetDisplay(VstInt32 index, char *text) {assert(index<fUITable.size()); fUITable[index]->GetDisplay(text);}
  void  GetName(VstInt32 index, char *text) {assert(index<fUITable.size()); fUITable[index]->GetName(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;i<fUITable.size();i++) id += fUITable[i]->GetID();
    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(index<numParams)
    dspUI->GetDisplay(index,text); // get displayed float value as text
  else
    vst_strncpy (text, "IndexOutOfRange", kVstMaxParamStrLen);
}

//-----------------------------------------------------------------------------
void Faust::getParameterName(VstInt32 index, char *label)
{
  if(index<numParams)
    dspUI->GetName(index,label); // parameter name, including units
  else
    vst_strncpy (label, "IndexOutOfRange", kVstMaxParamStrLen);
}

//-----------------------------------------------------------------------------
void Faust::setParameter(VstInt32 index, float value)
{
  if(index<numParams)
    dspUI->SetValue(index,value);
}

//-----------------------------------------------------------------------------
float Faust::getParameter(VstInt32 index)
{
  if(index<numParams)
    return dspUI->GetValue(index);
  else
    return 0.0f;
}

//-----------------------------------------------------------------------------
bool Faust::getInputProperties (VstInt32 index, VstPinProperties* properties)
{
  if(index>=0 && index<dsp->getNumInputs())
  {
    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 && index<dsp->getNumOutputs())
  {
    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; i<nouts; i++) { memset (outptr[i], 0, sampleFrames * sizeof (float)); }
        return;
      } else {
        // float* outptr[nouts];
        float** outptr = (float **)malloc(nouts * sizeof(float*));

#ifdef DEBUG
        fprintf(stderr,"*** Faust vsti: currentDelta = %d\n",currentDelta);
#endif

        for (i=0; i<nouts; i++) {
          outptr[i] = outputs[i]; // leaving caller's pointers alone
          // According to the VST programming sample, we DO clear the output buffers now
          // (since the start-time for the note is somewhere within the current chunk buf).
          memset (outptr[i], 0, currentDelta * sizeof (float));
          outptr[i] += currentDelta;
        }
        sampleFrames -= currentDelta;
        currentDelta = 0;
        dsp->compute(sampleFrames, inputs, outptr);
        free(outptr);
      }
      } else {
      dsp->compute(sampleFrames, inputs, outputs);
      }

    } else { // silence until NoteOn . . .
      for (i=0; i<nouts; i++) {     memset (outputs[i], 0, sampleFrames * sizeof (float)); }
    }
  }
}

//-----------------------------------------------------------------------------
VstInt32 Faust::processEvents (VstEvents* ev)
{
  if (ev->numEvents > 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
  }
}

Generated by  Doxygen 1.6.0   Back to index