X-Git-Url: https://scm.cri.ensmp.fr/git/Faustine.git/blobdiff_plain/1059e1cc0c2ecfa237406949aa26155b6a5b9154..66f23d4fabf89ad09adbd4dfc15ac6b5b2b7da83:/interpreter/preprocessor/faust-0.9.47mr3/architecture/pure.cpp diff --git a/interpreter/preprocessor/faust-0.9.47mr3/architecture/pure.cpp b/interpreter/preprocessor/faust-0.9.47mr3/architecture/pure.cpp new file mode 100644 index 0000000..aca3555 --- /dev/null +++ b/interpreter/preprocessor/faust-0.9.47mr3/architecture/pure.cpp @@ -0,0 +1,518 @@ +/************************************************************************ + ************************************************************************ + FAUST Architecture File + Copyright (C) 2009-2011 Albert Graef + --------------------------------------------------------------------- + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. + ************************************************************************ + ************************************************************************/ + +/* Pure architecture for Faust. This is similar to the Q architecture, but + uses double precision for the audio buffers and control variables. See + http://pure-lang.googlecode.com for a Pure module which can load these + extensions. */ + +#include +#include +#include +#include + +using namespace std; + +typedef pair strpair; + +struct Meta +{ + list< strpair > data; + void declare (const char* key, const char* value) + { data.push_back(strpair(key, value)); } +}; + +//------------------------------------------------------------------- +// 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 T abs (T a) { return (a> n); } + +/****************************************************************************** +******************************************************************************* + + 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); } + +<> + +/****************************************************************************** +******************************************************************************* + + ABSTRACT USER INTERFACE + +******************************************************************************* +*******************************************************************************/ + +class UI +{ + bool fStopped; +public: + + UI() : fStopped(false) {} + virtual ~UI() {} + + virtual void addButton(const char* label, double* zone) = 0; + virtual void addToggleButton(const char* label, double* zone) = 0; + virtual void addCheckButton(const char* label, double* zone) = 0; + virtual void addVerticalSlider(const char* label, double* zone, float init, float min, float max, float step) = 0; + virtual void addHorizontalSlider(const char* label, double* zone, float init, float min, float max, float step) = 0; + virtual void addNumEntry(const char* label, double* zone, float init, float min, float max, float step) = 0; + + virtual void addNumDisplay(const char* label, double* zone, int precision) = 0; + virtual void addTextDisplay(const char* label, double* zone, char* names[], float min, float max) = 0; + virtual void addHorizontalBargraph(const char* label, double* zone, float min, float max) = 0; + virtual void addVerticalBargraph(const char* label, double* zone, float min, float max) = 0; + + 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 run() = 0; + + void stop() { fStopped = true; } + bool stopped() { return fStopped; } + + virtual void declare(double* zone, const char* key, const char* value) {} +}; + +/*************************************************************************** + Pure UI interface + ***************************************************************************/ + +enum ui_elem_type_t { + UI_BUTTON, UI_TOGGLE_BUTTON, UI_CHECK_BUTTON, + UI_V_SLIDER, UI_H_SLIDER, UI_NUM_ENTRY, + UI_V_BARGRAPH, UI_H_BARGRAPH, + UI_END_GROUP, UI_V_GROUP, UI_H_GROUP, UI_T_GROUP +}; + +struct ui_elem_t { + ui_elem_type_t type; + const char *label; + double *zone; + void *ref; + float init, min, max, step; +}; + +class PureUI : public UI +{ +public: + int nelems; + ui_elem_t *elems; + map< int, list > metadata; + + PureUI(); + virtual ~PureUI(); + +protected: + void add_elem(ui_elem_type_t type, const char *label = NULL); + void add_elem(ui_elem_type_t type, const char *label, double *zone); + void add_elem(ui_elem_type_t type, const char *label, double *zone, + float init, float min, float max, float step); + void add_elem(ui_elem_type_t type, const char *label, double *zone, + float min, float max); + +public: + virtual void addButton(const char* label, double* zone); + virtual void addToggleButton(const char* label, double* zone); + virtual void addCheckButton(const char* label, double* zone); + virtual void addVerticalSlider(const char* label, double* zone, float init, float min, float max, float step); + virtual void addHorizontalSlider(const char* label, double* zone, float init, float min, float max, float step); + virtual void addNumEntry(const char* label, double* zone, float init, float min, float max, float step); + + virtual void addNumDisplay(const char* label, double* zone, int precision); + virtual void addTextDisplay(const char* label, double* zone, char* names[], float min, float max); + virtual void addHorizontalBargraph(const char* label, double* zone, float min, float max); + virtual void addVerticalBargraph(const char* label, double* zone, float min, float max); + + 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(); + + virtual void run(); + + virtual void declare(double* zone, const char* key, const char* value); +}; + +PureUI::PureUI() +{ + nelems = 0; + elems = NULL; +} + +PureUI::~PureUI() +{ + if (elems) free(elems); +} + +void PureUI::declare(double* zone, const char* key, const char* value) +{ + map< int, list >::iterator it = metadata.find(nelems); + if (it != metadata.end()) + it->second.push_back(strpair(key, value)); + else + metadata[nelems] = list(1, strpair(key, value)); +} + +inline void PureUI::add_elem(ui_elem_type_t type, const char *label) +{ + ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t)); + if (elems1) + elems = elems1; + else + return; + elems[nelems].type = type; + elems[nelems].label = label; + elems[nelems].zone = NULL; + elems[nelems].ref = NULL; + elems[nelems].init = 0.0; + elems[nelems].min = 0.0; + elems[nelems].max = 0.0; + elems[nelems].step = 0.0; + nelems++; +} + +inline void PureUI::add_elem(ui_elem_type_t type, const char *label, double *zone) +{ + ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t)); + if (elems1) + elems = elems1; + else + return; + elems[nelems].type = type; + elems[nelems].label = label; + elems[nelems].zone = zone; + elems[nelems].ref = NULL; + elems[nelems].init = 0.0; + elems[nelems].min = 0.0; + elems[nelems].max = 0.0; + elems[nelems].step = 0.0; + nelems++; +} + +inline void PureUI::add_elem(ui_elem_type_t type, const char *label, double *zone, + float init, float min, float max, float step) +{ + ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t)); + if (elems1) + elems = elems1; + else + return; + elems[nelems].type = type; + elems[nelems].label = label; + elems[nelems].zone = zone; + elems[nelems].ref = NULL; + elems[nelems].init = init; + elems[nelems].min = min; + elems[nelems].max = max; + elems[nelems].step = step; + nelems++; +} + +inline void PureUI::add_elem(ui_elem_type_t type, const char *label, double *zone, + float min, float max) +{ + ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t)); + if (elems1) + elems = elems1; + else + return; + elems[nelems].type = type; + elems[nelems].label = label; + elems[nelems].zone = zone; + elems[nelems].ref = NULL; + elems[nelems].init = 0.0; + elems[nelems].min = min; + elems[nelems].max = max; + elems[nelems].step = 0.0; + nelems++; +} + +void PureUI::addButton(const char* label, double* zone) +{ add_elem(UI_BUTTON, label, zone); } +void PureUI::addToggleButton(const char* label, double* zone) +{ add_elem(UI_TOGGLE_BUTTON, label, zone); } +void PureUI::addCheckButton(const char* label, double* zone) +{ add_elem(UI_CHECK_BUTTON, label, zone); } +void PureUI::addVerticalSlider(const char* label, double* zone, float init, float min, float max, float step) +{ add_elem(UI_V_SLIDER, label, zone, init, min, max, step); } +void PureUI::addHorizontalSlider(const char* label, double* zone, float init, float min, float max, float step) +{ add_elem(UI_H_SLIDER, label, zone, init, min, max, step); } +void PureUI::addNumEntry(const char* label, double* zone, float init, float min, float max, float step) +{ add_elem(UI_NUM_ENTRY, label, zone, init, min, max, step); } + +// FIXME: addNumDisplay and addTextDisplay not implemented in Faust yet? +void PureUI::addNumDisplay(const char* label, double* zone, int precision) {} +void PureUI::addTextDisplay(const char* label, double* zone, char* names[], float min, float max) {} +void PureUI::addHorizontalBargraph(const char* label, double* zone, float min, float max) +{ add_elem(UI_H_BARGRAPH, label, zone, min, max); } +void PureUI::addVerticalBargraph(const char* label, double* zone, float min, float max) +{ add_elem(UI_V_BARGRAPH, label, zone, min, max); } + +void PureUI::openFrameBox(const char* label) {} +void PureUI::openTabBox(const char* label) +{ add_elem(UI_T_GROUP, label); } +void PureUI::openHorizontalBox(const char* label) +{ add_elem(UI_H_GROUP, label); } +void PureUI::openVerticalBox(const char* label) +{ add_elem(UI_V_GROUP, label); } +void PureUI::closeBox() +{ add_elem(UI_END_GROUP); } + +void PureUI::run() {} + +/****************************************************************************** +******************************************************************************* + + FAUST DSP + +******************************************************************************* +*******************************************************************************/ + +//---------------------------------------------------------------- +// abstract definition of a signal processor +//---------------------------------------------------------------- + +class dsp { + protected: + int fSamplingFreq; + public: + // internal freelist for custom voice allocation + dsp *prev, *next; + 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, double** inputs, double** outputs) = 0; +}; + +//---------------------------------------------------------------------------- +// FAUST generated signal processor +//---------------------------------------------------------------------------- + +/* Define FAUSTFLOAT so that audio buffers and control values are always + represented as double pointers. This probably requires a recent Faust + version (0.9.9.6 or later should be ok). */ + +#define FAUSTFLOAT double + +<> + +#include + +// Define this to get some debugging output. +//#define DEBUG +#ifdef DEBUG +#include +#define FAUST_CN "mydsp" +#endif + +/* Dynamic voice allocation. We go to some lengths here to make this as + realtime-friendly as possible. The idea is that we keep a pool of allocated + mydsp instances. When a dsp is freed with deldsp(), it's in fact never + deleted, but put at the end of a freelist from where it may eventually be + reused by a subsequent call to newdsp(). By these means, the number of + actual calls to malloc() can be kept to a minimum. In addition, a small + number of voices are preallocated in static memory (1 by default in the + present implementation, but you can set this at compile time by redefining + the NVOICES constant accordingly). If you choose a suitable NVOICES value, + chances are that your application may never need to allocate dsp instances + on the heap at all. Also, even if dsp instances have to be created + dynamically, they are allocated in chunks of NVOICES units, in order to + reduce the calls to malloc(). Thus we generally recommend to set NVOICES to + a value >1 which best suits your application. */ + +#ifndef NVOICES +#define NVOICES 1 +#endif + +// Make sure that NVOICES is at least 1. +#if NVOICES<1 +#undefine NVOICES +#define NVOICES 1 +#endif + +struct dspmem_t { + char x[sizeof(mydsp)]; +}; + +struct mem_t { + dspmem_t mem[NVOICES]; + mem_t *next; +}; + +// statically and dynamically allocated dsp instances +static mem_t mem0, *mem; +// beginning and end of the freelist +static mydsp *first, *last; + +/* This is supposed to be executed when the module gets unloaded. You'll need + a recent gcc version (or compatible) to make this work. */ + +void __attribute__ ((destructor)) mydsp_fini(void) +{ + if (!mem) return; + mem = mem->next; + while (mem) { + mem_t *mem1 = mem->next; + free(mem); mem = mem1; + } +} + +/* The class factory, used to create and destroy mydsp objects in the client. + This is implemented using C linkage to facilitate dlopen access. */ + +#include + +extern "C" mydsp *newdsp() +{ + if (!mem) { + mem = &mem0; mem->next = 0; + // initialize the freelist with the statically allocated voices + mydsp *prev = 0, *next = (mydsp*)&mem->mem[0]; + first = next; + for (int i = 0; i < NVOICES; i++) { + void *p = &mem->mem[i]; + mydsp *d = new(p) mydsp; + d->prev = prev; prev = d; + d->next = ++next; + } + last = prev; last->next = 0; +#ifdef DEBUG + fprintf(stderr, ">>> %s: preallocated %d voices\n", FAUST_CN, NVOICES); +#endif + } + assert(mem); + if (!first) { + // allocate a new chunk of voices and add them to the freelist + mem_t *block = (mem_t*)calloc(1, sizeof(mem_t)); + block->next = mem->next; mem->next = block; + mydsp *prev = 0, *next = (mydsp*)&block->mem[0]; + first = next; + for (int i = 0; i < NVOICES; i++) { + void *p = &block->mem[i];; + mydsp *d = new(p) mydsp; + d->prev = prev; prev = d; + d->next = ++next; + } + last = prev; last->next = 0; +#ifdef DEBUG + fprintf(stderr, ">>> %s: allocated %d voices\n", FAUST_CN, NVOICES); +#endif + } + assert(first && last); + mydsp *d = first; + if (first == last) { + // freelist is now empty + first = last = 0; + } else { + // remove d from the freelist + first = (mydsp*)first->next; + } + d->prev = d->next = 0; +#ifdef DEBUG + fprintf(stderr, ">>> %s: allocating instance %p\n", FAUST_CN, d); +#endif + return d; +} + +extern "C" void deldsp(mydsp* d) +{ +#ifdef DEBUG + fprintf(stderr, ">>> %s: freeing instance %p\n", FAUST_CN, d); +#endif + // add d to the freelist + assert(!d->prev && !d->next); + if (last) { + last->next = d; d->prev = last; last = d; + } else + first = last = d; +} + +extern "C" Meta *newmeta() +{ + Meta *m = new Meta; + mydsp::metadata(m); + return m; +} + +extern "C" void delmeta(Meta* m) +{ + delete m; +}