Rename interpretor to interpreter.
[Faustine.git] / interpreter / preprocessor / faust-0.9.47mr3 / architecture / supercollider.cpp
diff --git a/interpreter/preprocessor/faust-0.9.47mr3/architecture/supercollider.cpp b/interpreter/preprocessor/faust-0.9.47mr3/architecture/supercollider.cpp
new file mode 100644 (file)
index 0000000..2f1f0a0
--- /dev/null
@@ -0,0 +1,640 @@
+// If other than 'faust2sc --prefix Faust' is used, sed this as well:
+#define SC_FAUST_PREFIX "Faust"
+
+//-------------------------------------------------------------------
+// FAUST architecture file for SuperCollider.
+// Copyright (C) 2005-2008 Stefan Kersten.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+// 02111-1307 USA
+//-------------------------------------------------------------------
+
+#include <ctype.h>
+#include <limits.h>
+#include <map>
+#include <string>
+#include <string.h>
+#include <SC_PlugIn.h>
+
+#if defined(__GNUC__) && __GNUC__ >= 4
+# define FAUST_EXPORT __attribute__((visibility("default")))
+#else
+# define FAUST_EXPORT /* NOP */
+#endif
+
+//-------------------------------------------------------------------
+// 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; }
+
+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>>
+
+/******************************************************************************
+*******************************************************************************
+
+                                META DATA
+
+*******************************************************************************
+*******************************************************************************/
+
+struct Meta : std::map<std::string, std::string>
+{
+    void declare(const char* key, const char* value)
+    {
+        (*this)[key] = value;
+    }
+};
+
+/******************************************************************************
+*******************************************************************************
+
+                                GRAPHIC USER INTERFACE
+
+*******************************************************************************
+*******************************************************************************/
+
+//----------------------------------------------------------------------------
+// Abstract user interface
+//----------------------------------------------------------------------------
+
+class UI
+{
+public:
+    virtual ~UI() { }
+
+    // active widgets
+    virtual void addButton(const char* label, float* zone) = 0;
+    virtual void addToggleButton(const char* label, float* zone) = 0;
+    virtual void addCheckButton(const char* label, float* zone) = 0;
+    virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
+    virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
+    virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step) = 0;
+
+    // passive widgets
+    virtual void addNumDisplay(const char* label, float* zone, int precision) = 0;
+    virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max) = 0;
+    virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) = 0;
+    virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) = 0;
+
+    // layout widgets
+    virtual void openFrameBox(const char* label) = 0;
+    virtual void openTabBox(const char* label) = 0;
+    virtual void openHorizontalBox(const char* label) = 0;
+    virtual void openVerticalBox(const char* label) = 0;
+    virtual void closeBox() = 0;
+
+    virtual void declare(float* zone, const char* key, const char* value) {}
+};
+
+//----------------------------------------------------------------------------
+// Control counter
+//----------------------------------------------------------------------------
+
+class ControlCounter : public UI
+{
+public:
+    ControlCounter()
+        : mNumControlInputs(0),
+          mNumControlOutputs(0)
+    { }
+
+    size_t getNumControls() const { return getNumControlInputs(); }
+    size_t getNumControlInputs() const { return mNumControlInputs; }
+    size_t getNumControlOutputs() const { return mNumControlOutputs; }
+
+    // active widgets
+    virtual void addButton(const char* label, float* zone)
+    { addControlInput(); }
+    virtual void addToggleButton(const char* label, float* zone)
+    { addControlInput(); }
+    virtual void addCheckButton(const char* label, float* zone)
+    { addControlInput(); }
+    virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step)
+    { addControlInput(); }
+    virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step)
+    { addControlInput(); }
+    virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step)
+    { addControlInput(); }
+
+    // passive widgets
+    virtual void addNumDisplay(const char* label, float* zone, int precision) { addControlOutput(); }
+    virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max) { addControlOutput(); }
+    virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) { addControlOutput(); }
+    virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) { addControlOutput(); }
+
+    // layout widgets
+    virtual void openFrameBox(const char* label) { }
+    virtual void openTabBox(const char* label) { }
+    virtual void openHorizontalBox(const char* label) { }
+    virtual void openVerticalBox(const char* label) { }
+    virtual void closeBox() { }
+
+protected:
+    void addControlInput() { mNumControlInputs++; }
+    void addControlOutput() { mNumControlOutputs++; }
+
+private:
+    size_t mNumControlInputs;
+    size_t mNumControlOutputs;
+};
+
+//----------------------------------------------------------------------------
+// UI control
+//----------------------------------------------------------------------------
+
+struct Control
+{
+    typedef void (*UpdateFunction)(Control* self, float value);
+
+    UpdateFunction updateFunction;
+    float min, max, step;
+    float* zone;
+
+    inline void update(float value)
+    {
+        (*updateFunction)(this, value);
+    }
+
+    static void simpleUpdate(Control* self, float value)
+    {
+        *self->zone = value;
+    }
+    static void boundedUpdate(Control* self, float value)
+    {
+        *self->zone = sc_clip(value, self->min, self->max);
+    }
+};
+
+//----------------------------------------------------------------------------
+// Control allocator
+//----------------------------------------------------------------------------
+
+class ControlAllocator : public UI
+{
+public:
+    ControlAllocator(Control* controls)
+        : mControls(controls)
+    { }
+
+    // active widgets
+    virtual void addButton(const char* label, float* zone)
+    { addSimpleControl(zone); }
+    virtual void addToggleButton(const char* label, float* zone)
+    { addSimpleControl(zone); }
+    virtual void addCheckButton(const char* label, float* zone)
+    { addSimpleControl(zone); }
+    virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step)
+    { addBoundedControl(zone, min, max, step); }
+    virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step)
+    { addBoundedControl(zone, min, max, step); }
+    virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step)
+    { addBoundedControl(zone, min, max, step); }
+
+    // passive widgets
+    virtual void addNumDisplay(const char* label, float* zone, int precision) { }
+    virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max) { }
+    virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) { }
+    virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) { }
+
+    // layout widgets
+    virtual void openFrameBox(const char* label) { }
+    virtual void openTabBox(const char* label) { }
+    virtual void openHorizontalBox(const char* label) { }
+    virtual void openVerticalBox(const char* label) { }
+    virtual void closeBox() { }
+
+private:
+    void addControl(Control::UpdateFunction updateFunction, float* zone, float min, float max, float step)
+    {
+        Control* ctrl        = mControls++;
+        ctrl->updateFunction = updateFunction;
+        ctrl->min            = min;
+        ctrl->max            = max;
+        ctrl->step           = step;
+        ctrl->zone           = zone;
+    }
+    void addSimpleControl(float* zone)
+    {
+        addControl(Control::simpleUpdate, zone, 0.f, 0.f, 0.f);
+    }
+    void addBoundedControl(float* zone, float min, float max, float step)
+    {
+        addControl(Control::boundedUpdate, zone, min, max, step);
+    }
+
+private:
+    Control* mControls;
+};
+
+
+/******************************************************************************
+*******************************************************************************
+
+                                FAUST DSP
+
+*******************************************************************************
+*******************************************************************************/
+
+//----------------------------------------------------------------------------
+// Abstract DSP interface
+//----------------------------------------------------------------------------
+
+class dsp
+{
+public:
+    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;
+
+protected:
+    int fSamplingFreq;
+};
+
+dsp::~dsp() { }
+
+//----------------------------------------------------------------------------
+// FAUST generated code
+//----------------------------------------------------------------------------
+
+<<includeclass>>
+
+
+/******************************************************************************
+*******************************************************************************
+
+                            SUPERCOLLIDER DSP INTERFACE
+
+*******************************************************************************
+*******************************************************************************/
+
+struct Faust : public Unit
+{
+    // Faust dsp instance
+    mydsp       mDSP;
+    // Buffers for control to audio rate conversion
+    float**     mInBufCopy;
+    float*      mInBufValue;
+    // Controls
+    size_t      mNumControls;
+    // NOTE: This needs to be the last field!
+    //
+    // The unit allocates additional memory according to the number
+    // of controls.
+    Control     mControls[0];
+
+    int getNumAudioInputs() { return mDSP.getNumInputs(); }
+};
+
+// Global state
+
+static size_t       g_numControls; // Number of controls
+static const char*  g_unitName;    // Unit name
+
+// Initialize the global state with unit name and sample rate.
+void initState(const std::string& name, int sampleRate);
+
+// Return the unit size in bytes, including static fields and controls.
+static size_t unitSize();
+
+// Convert a file name to a valid unit name.
+static std::string fileNameToUnitName(const std::string& fileName);
+
+// Convert the XML unit name to a valid class name.
+static std::string normalizeClassName(const std::string& name);
+
+void initState(const std::string& name, int sampleRate)
+{
+    g_unitName = strdup(name.c_str());
+
+    mydsp* dsp = new mydsp;
+    ControlCounter* cc = new ControlCounter;
+
+    dsp->classInit(sampleRate);
+    dsp->buildUserInterface(cc);
+    g_numControls = cc->getNumControls();
+
+    delete dsp;
+    delete cc;
+}
+
+size_t unitSize()
+{
+    return sizeof(Faust) + g_numControls * sizeof(Control);
+}
+
+std::string fileNameToUnitName(const std::string& fileName)
+{
+    // Extract basename
+    size_t lpos = fileName.rfind('/', fileName.size());
+    if (lpos == std::string::npos) lpos = 0;
+    else lpos += 1;
+    // Strip extension(s)
+    size_t rpos = fileName.find('.', lpos);
+    // Return substring
+    return fileName.substr(lpos, rpos > lpos ? rpos - lpos : 0);
+}
+
+// Globals
+
+static InterfaceTable *ft;
+
+// The SuperCollider UGen class name generated here must match
+// that generated by faust2sc:
+static std::string normalizeClassName(const std::string& name)
+{
+  std::string s;
+  char c;
+
+  unsigned int i=0;
+  bool upnext=true;
+  while (c=name[i++]) {
+    if (upnext) { c = toupper(c); upnext=false; }
+    if ( (c == '_') || (c == '-') || isspace(c)) { upnext=true; continue; }
+    s += c;
+    if (i > 31) { break; }
+  }
+  return s;
+}
+
+extern "C"
+{
+#ifdef SC_API_EXPORT
+    int api_version(void);
+#endif
+    void load(InterfaceTable*);
+    void Faust_next(Faust*, int);
+    void Faust_next_copy(Faust*, int);
+    void Faust_next_clear(Faust*, int);
+    void Faust_Ctor(Faust*);
+    void Faust_Dtor(Faust*);
+};
+
+inline static void fillBuffer(float* dst, int n, float v)
+{
+    Fill(n, dst, v);
+}
+
+inline static void fillBuffer(float* dst, int n, float v0, float v1)
+{
+    Fill(n, dst, v0, (v1 - v0) / n);
+}
+
+inline static void copyBuffer(float* dst, int n, float* src)
+{
+    Copy(n, dst, src);
+}
+
+inline static void Faust_updateControls(Faust* unit)
+{
+    Control* controls = unit->mControls;
+    int numControls   = unit->mNumControls;
+    int curControl    = unit->mDSP.getNumInputs();
+    for (int i=0; i < numControls; ++i) {
+        float value = IN0(curControl);
+        (controls++)->update(value);
+        curControl++;
+    }
+}
+
+void Faust_next(Faust* unit, int inNumSamples)
+{
+    // update controls
+    Faust_updateControls(unit);
+    // dsp computation
+    unit->mDSP.compute(inNumSamples, unit->mInBuf, unit->mOutBuf);
+}
+
+void Faust_next_copy(Faust* unit, int inNumSamples)
+{
+    // update controls
+    Faust_updateControls(unit);
+    // Copy buffers
+    for (int i = 0; i < unit->getNumAudioInputs(); ++i) {
+        float* b = unit->mInBufCopy[i];
+        if (INRATE(i) == calc_FullRate) {
+            // Audio rate: copy buffer
+            copyBuffer(b, inNumSamples, unit->mInBuf[i]);
+        } else {
+            // Control rate: linearly interpolate input
+            float v1 = IN0(i);
+            fillBuffer(b, inNumSamples, unit->mInBufValue[i], v1);
+            unit->mInBufValue[i] = v1;
+        }
+    }
+    // dsp computation
+    unit->mDSP.compute(inNumSamples, unit->mInBufCopy, unit->mOutBuf);
+}
+
+void Faust_next_clear(Faust* unit, int inNumSamples)
+{
+    ClearUnitOutputs(unit, inNumSamples);
+}
+
+void Faust_Ctor(Faust* unit)  // module constructor
+{
+    // init dsp
+    unit->mDSP.instanceInit((int)SAMPLERATE);
+
+    // allocate controls
+    unit->mNumControls = g_numControls;
+    ControlAllocator ca(unit->mControls);
+    unit->mDSP.buildUserInterface(&ca);
+    unit->mInBufCopy  = 0;
+    unit->mInBufValue = 0;
+
+    // check input/output channel configuration
+    const size_t numInputs  = unit->mDSP.getNumInputs() + unit->mNumControls;
+    const size_t numOutputs = unit->mDSP.getNumOutputs();
+
+    bool channelsValid =   (numInputs  == unit->mNumInputs)
+                        && (numOutputs == unit->mNumOutputs);
+
+    if (channelsValid) {
+        bool rateValid = true;
+        for (int i = 0; i < unit->getNumAudioInputs(); ++i) {
+            if (INRATE(i) != calc_FullRate) {
+                rateValid = false;
+                break;
+            }
+        }
+        if (rateValid) {
+            SETCALC(Faust_next);
+        } else {
+            unit->mInBufCopy = (float**)RTAlloc(unit->mWorld, unit->getNumAudioInputs()*sizeof(float*));
+            // Allocate memory for input buffer copies (numInputs * bufLength)
+            // and linear interpolation state (numInputs)
+            // = numInputs * (bufLength + 1)
+            unit->mInBufValue = (float*)RTAlloc(unit->mWorld, unit->getNumAudioInputs()*sizeof(float));
+            float* mem = (float*)RTAlloc(unit->mWorld, unit->getNumAudioInputs()*BUFLENGTH*sizeof(float));
+            // Aquire memory for interpolator state.
+            for (int i=0; i < unit->getNumAudioInputs(); ++i) {
+                // Initialize interpolator.
+                unit->mInBufValue[i] = IN0(i);
+                // Aquire buffer memory.
+                unit->mInBufCopy[i] = mem;
+                mem += BUFLENGTH;
+            }
+            SETCALC(Faust_next_copy);
+        }
+#if !defined(NDEBUG)
+        Print("Faust[%s]:\n", g_unitName);
+        Print("    Inputs:   %d\n"
+              "    Outputs:  %d\n"
+              "    Callback: %s\n",
+              numInputs, numOutputs,
+              unit->mCalcFunc == (UnitCalcFunc)Faust_next ? "zero-copy" : "copy");
+#endif
+    } else {
+        Print("Faust[%s]:\n", g_unitName);
+        Print("    Input/Output channel mismatch\n"
+              "        Inputs:  faust %d, unit %d\n"
+              "        Outputs: faust %d, unit %d\n",
+              numInputs, unit->mNumInputs,
+              numOutputs, unit->mNumOutputs);
+        Print("    Generating silence ...\n");
+        SETCALC(Faust_next_clear);
+    }
+}
+
+void Faust_Dtor(Faust* unit)  // module destructor
+{
+    if (unit->mInBufValue) {
+        RTFree(unit->mWorld, unit->mInBufValue);
+    }
+    if (unit->mInBufCopy) {
+        if (unit->mInBufCopy[0]) {
+            RTFree(unit->mWorld, unit->mInBufCopy[0]);
+        }
+        RTFree(unit->mWorld, unit->mInBufCopy);
+    }
+}
+
+#ifdef SC_API_EXPORT
+FAUST_EXPORT int api_version(void) { return sc_api_version; }
+#endif
+
+FAUST_EXPORT void load(InterfaceTable* inTable)
+{
+
+    ft = inTable;
+
+    Meta meta;
+    mydsp::metadata(&meta);
+
+    std::string name = meta["name"];
+
+    if (name.empty()) {
+        name = fileNameToUnitName(__FILE__);
+    }
+
+    name = normalizeClassName(name);
+
+#if !defined(NDEBUG) & defined(SC_API_EXPORT)
+    Print("*** Faust: supercollider.cpp: sc_api_version = %d\n",sc_api_version);
+#endif
+
+    if (name.empty()) {
+        // Catch empty name
+        Print("*** Faust: supercollider.cpp: "
+             "Could not create unit-generator module name from filename\n"
+              "       bailing out ...\n");
+        return;
+    }
+
+    if (strncmp(name.c_str(),SC_FAUST_PREFIX,strlen(SC_FAUST_PREFIX))!=0){
+      name = SC_FAUST_PREFIX + name;
+    }
+
+    // Initialize global data
+    // TODO: Use correct sample rate
+    initState(name, 48000);
+
+    // Register ugen
+    (*ft->fDefineUnit)(
+        (char*)name.c_str(),
+        unitSize(),
+        (UnitCtorFunc)&Faust_Ctor,
+        (UnitDtorFunc)&Faust_Dtor,
+        kUnitDef_CantAliasInputsToOutputs
+        );
+
+#if !defined(NDEBUG)
+    Print("Faust: %s numControls=%d\n", name.c_str(), g_numControls);
+#endif // NDEBUG
+}
+
+// EOF