X-Git-Url: https://scm.cri.ensmp.fr/git/Faustine.git/blobdiff_plain/1059e1cc0c2ecfa237406949aa26155b6a5b9154..66f23d4fabf89ad09adbd4dfc15ac6b5b2b7da83:/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 index 0000000..2f1f0a0 --- /dev/null +++ b/interpreter/preprocessor/faust-0.9.47mr3/architecture/supercollider.cpp @@ -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 +#include +#include +#include +#include +#include + +#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> n); } +inline int int2pow2 (int x) { int r=0; while ((1<> + +/****************************************************************************** +******************************************************************************* + + META DATA + +******************************************************************************* +*******************************************************************************/ + +struct Meta : std::map +{ + 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 +//---------------------------------------------------------------------------- + +<> + + +/****************************************************************************** +******************************************************************************* + + 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