New directory tree, with preprocessor/ inside interpretor/.
[Faustine.git] / interpretor / preprocessor / faust-0.9.47mr3 / architecture / puredata.cpp
diff --git a/interpretor/preprocessor/faust-0.9.47mr3/architecture/puredata.cpp b/interpretor/preprocessor/faust-0.9.47mr3/architecture/puredata.cpp
new file mode 100644 (file)
index 0000000..a41324a
--- /dev/null
@@ -0,0 +1,760 @@
+/************************************************************************
+ ************************************************************************
+    FAUST Architecture File
+       Copyright (C) 2006-2011 Albert Graef <Dr.Graef@t-online.de>
+    ---------------------------------------------------------------------
+    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. 
+ ************************************************************************
+ ************************************************************************/
+
+/* Pd architecture file, written by Albert Graef <Dr.Graef@t-online.de>.
+   This was derived from minimal.cpp included in the Faust distribution.
+   Please note that this is to be compiled as a shared library, which is
+   then loaded dynamically by Pd as an external. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <string>
+
+using namespace std;
+
+// 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
+  #warning *** puredata.cpp: NO SSE FLAG (denormals may slow things down) ***
+  #define AVOIDDENORMALS
+#endif
+
+struct Meta 
+{
+    void declare (const char* key, const char* 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<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; }
+
+// 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); }
+
+/******************************************************************************
+*******************************************************************************
+
+                                                              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>>
+
+/******************************************************************************
+*******************************************************************************
+
+                       ABSTRACT USER INTERFACE
+
+*******************************************************************************
+*******************************************************************************/
+
+class UI
+{
+  bool fStopped;
+public:
+               
+  UI() : fStopped(false) {}
+  virtual ~UI() {}
+       
+  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;
+
+  virtual void addNumDisplay(const char* label, float* zone, int precision) = 0;
+  virtual void addTextDisplay(const char* label, float* zone, const 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;
+       
+  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(float* zone, const char* key, const char* value) {}
+};
+
+/***************************************************************************
+   Pd 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;
+  char *label;
+  float *zone;
+  float init, min, max, step;
+};
+
+class PdUI : public UI
+{
+public:
+  int nelems;
+  ui_elem_t *elems;
+               
+  PdUI();
+  PdUI(const char *s);
+  virtual ~PdUI();
+
+protected:
+  string path;
+  void add_elem(ui_elem_type_t type, const char *label = NULL);
+  void add_elem(ui_elem_type_t type, const char *label, float *zone);
+  void add_elem(ui_elem_type_t type, const char *label, float *zone,
+               float init, float min, float max, float step);
+  void add_elem(ui_elem_type_t type, const char *label, float *zone,
+               float min, float max);
+
+public:
+  virtual void addButton(const char* label, float* zone);
+  virtual void addToggleButton(const char* label, float* zone);
+  virtual void addCheckButton(const char* label, float* zone);
+  virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step);
+  virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step);
+  virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step);
+
+  virtual void addNumDisplay(const char* label, float* zone, int precision);
+  virtual void addTextDisplay(const char* label, float* zone, const 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);
+  
+  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();
+};
+
+static string mangle(const char *s)
+{
+  const char *s0 = s;
+  string t = "";
+  if (!s) return t;
+  while (*s)
+    if (isalnum(*s))
+      t += *(s++);
+    else {
+      const char *s1 = s;
+      while (*s && !isalnum(*s)) ++s;
+      if (s1 != s0 && *s) t += "-";
+    }
+  return t;
+}
+
+static string normpath(string path)
+{
+  path = string("/")+path;
+  int pos = path.find("//");
+  while (pos >= 0) {
+    path.erase(pos, 1);
+    pos = path.find("//");
+  }
+  return path;
+}
+
+static string pathcat(string path, string label)
+{
+  if (path.empty())
+    return normpath(label);
+  else if (label.empty())
+    return normpath(path);
+  else
+    return normpath(path+"/"+label);
+}
+
+PdUI::PdUI()
+{
+  nelems = 0;
+  elems = NULL;
+  path = "";
+}
+
+PdUI::PdUI(const char *s)
+{
+  nelems = 0;
+  elems = NULL;
+  path = s?s:"";
+}
+
+PdUI::~PdUI()
+{
+  if (elems) {
+    for (int i = 0; i < nelems; i++)
+      if (elems[i].label)
+       free(elems[i].label);
+    free(elems);
+  }
+}
+
+inline void PdUI::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;
+  string s = pathcat(path, mangle(label));
+  elems[nelems].type = type;
+  elems[nelems].label = strdup(s.c_str());
+  elems[nelems].zone = NULL;
+  elems[nelems].init = 0.0;
+  elems[nelems].min = 0.0;
+  elems[nelems].max = 0.0;
+  elems[nelems].step = 0.0;
+  nelems++;
+}
+
+inline void PdUI::add_elem(ui_elem_type_t type, const char *label, float *zone)
+{
+  ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t));
+  if (elems1)
+    elems = elems1;
+  else
+    return;
+  string s = pathcat(path, mangle(label));
+  elems[nelems].type = type;
+  elems[nelems].label = strdup(s.c_str());
+  elems[nelems].zone = zone;
+  elems[nelems].init = 0.0;
+  elems[nelems].min = 0.0;
+  elems[nelems].max = 1.0;
+  elems[nelems].step = 1.0;
+  nelems++;
+}
+
+inline void PdUI::add_elem(ui_elem_type_t type, const char *label, float *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;
+  string s = pathcat(path, mangle(label));
+  elems[nelems].type = type;
+  elems[nelems].label = strdup(s.c_str());
+  elems[nelems].zone = zone;
+  elems[nelems].init = init;
+  elems[nelems].min = min;
+  elems[nelems].max = max;
+  elems[nelems].step = step;
+  nelems++;
+}
+
+inline void PdUI::add_elem(ui_elem_type_t type, const char *label, float *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;
+  string s = pathcat(path, mangle(label));
+  elems[nelems].type = type;
+  elems[nelems].label = strdup(s.c_str());
+  elems[nelems].zone = zone;
+  elems[nelems].init = 0.0;
+  elems[nelems].min = min;
+  elems[nelems].max = max;
+  elems[nelems].step = 0.0;
+  nelems++;
+}
+
+void PdUI::addButton(const char* label, float* zone)
+{ add_elem(UI_BUTTON, label, zone); }
+void PdUI::addToggleButton(const char* label, float* zone)
+{ add_elem(UI_TOGGLE_BUTTON, label, zone); }
+void PdUI::addCheckButton(const char* label, float* zone)
+{ add_elem(UI_CHECK_BUTTON, label, zone); }
+void PdUI::addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step)
+{ add_elem(UI_V_SLIDER, label, zone, init, min, max, step); }
+void PdUI::addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step)
+{ add_elem(UI_H_SLIDER, label, zone, init, min, max, step); }
+void PdUI::addNumEntry(const char* label, float* 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 PdUI::addNumDisplay(const char* label, float* zone, int precision) {}
+void PdUI::addTextDisplay(const char* label, float* zone, const char* names[], float min, float max) {}
+void PdUI::addHorizontalBargraph(const char* label, float* zone, float min, float max)
+{ add_elem(UI_H_BARGRAPH, label, zone, min, max); }
+void PdUI::addVerticalBargraph(const char* label, float* zone, float min, float max)
+{ add_elem(UI_V_BARGRAPH, label, zone, min, max); }
+
+void PdUI::openFrameBox(const char* label)
+{
+  if (!path.empty()) path += "/";
+  path += mangle(label);
+}
+void PdUI::openTabBox(const char* label)
+{
+  if (!path.empty()) path += "/";
+  path += mangle(label);
+}
+void PdUI::openHorizontalBox(const char* label)
+{
+  if (!path.empty()) path += "/";
+  path += mangle(label);
+}
+void PdUI::openVerticalBox(const char* label)
+{
+  if (!path.empty()) path += "/";
+  path += mangle(label);
+}
+void PdUI::closeBox()
+{
+  int pos = path.rfind("/");
+  if (pos < 0) pos = 0;
+  path.erase(pos);
+}
+
+void PdUI::run() {}
+
+/******************************************************************************
+*******************************************************************************
+
+                           FAUST DSP
+
+*******************************************************************************
+*******************************************************************************/
+
+
+
+//----------------------------------------------------------------
+//  abstract definition of a signal processor
+//----------------------------------------------------------------
+                       
+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 signal processor
+//----------------------------------------------------------------------------
+               
+
+<<includeclass>>
+
+#include <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+
+#define faust_setup(name) xfaust_setup(name)
+#define xfaust_setup(name) name ## _tilde_setup(void)
+#define sym(name) xsym(name)
+#define xsym(name) #name
+
+// time for "active" toggle xfades in secs
+#define XFADE_TIME 0.1f
+
+static t_class *faust_class;
+
+struct t_faust {
+  t_object x_obj;
+#ifdef __MINGW32__
+  /* This seems to be necessary as some as yet undetermined Pd routine seems
+     to write past the end of x_obj on Windows. */
+  int fence; /* dummy field (not used) */
+#endif
+  mydsp *dsp;
+  PdUI *ui;
+  string *label;
+  int active, xfade, n_xfade, rate, n_in, n_out;
+  t_sample **inputs, **outputs, **buf;
+  t_outlet *out;
+  t_sample f;
+};
+
+static t_symbol *s_button, *s_checkbox, *s_vslider, *s_hslider, *s_nentry,
+  *s_vbargraph, *s_hbargraph;
+
+static inline void zero_samples(int k, int n, t_sample **out)
+{
+  for (int i = 0; i < k; i++)
+#ifdef __STDC_IEC_559__
+    /* IEC 559 a.k.a. IEEE 754 floats can be initialized faster like this */
+    memset(out[i], 0, n*sizeof(t_sample));
+#else
+    for (int j = 0; j < n; j++)
+      out[i][j] = 0.0f;
+#endif
+}
+
+static inline void copy_samples(int k, int n, t_sample **out, t_sample **in)
+{
+  for (int i = 0; i < k; i++)
+    memcpy(out[i], in[i], n*sizeof(t_sample));
+}
+
+static t_int *faust_perform(t_int *w)
+{
+  t_faust *x = (t_faust *)(w[1]);
+  int n = (int)(w[2]);
+  if (!x->dsp || !x->buf) return (w+3);
+  AVOIDDENORMALS;
+  if (x->xfade > 0) {
+    float d = 1.0f/x->n_xfade, f = (x->xfade--)*d;
+    d = d/n;
+    x->dsp->compute(n, x->inputs, x->buf);
+    if (x->active)
+      if (x->n_in == x->n_out)
+       /* xfade inputs -> buf */
+       for (int j = 0; j < n; j++, f -= d)
+         for (int i = 0; i < x->n_out; i++)
+           x->outputs[i][j] = f*x->inputs[i][j]+(1.0f-f)*x->buf[i][j];
+      else
+       /* xfade 0 -> buf */
+       for (int j = 0; j < n; j++, f -= d)
+         for (int i = 0; i < x->n_out; i++)
+           x->outputs[i][j] = (1.0f-f)*x->buf[i][j];
+    else
+      if (x->n_in == x->n_out)
+       /* xfade buf -> inputs */
+       for (int j = 0; j < n; j++, f -= d)
+         for (int i = 0; i < x->n_out; i++)
+           x->outputs[i][j] = f*x->buf[i][j]+(1.0f-f)*x->inputs[i][j];
+      else
+       /* xfade buf -> 0 */
+       for (int j = 0; j < n; j++, f -= d)
+         for (int i = 0; i < x->n_out; i++)
+           x->outputs[i][j] = f*x->buf[i][j];
+  } else if (x->active) {
+    x->dsp->compute(n, x->inputs, x->buf);
+    copy_samples(x->n_out, n, x->outputs, x->buf);
+  } else if (x->n_in == x->n_out) {
+    copy_samples(x->n_out, n, x->buf, x->inputs);
+    copy_samples(x->n_out, n, x->outputs, x->buf);
+  } else
+    zero_samples(x->n_out, n, x->outputs);
+  return (w+3);
+}
+
+static void faust_dsp(t_faust *x, t_signal **sp)
+{
+  int n = sp[0]->s_n, sr = (int)sp[0]->s_sr;
+  if (x->rate <= 0) {
+    /* default sample rate is whatever Pd tells us */
+    PdUI *ui = x->ui;
+    float *z = NULL;
+    if (ui->nelems > 0 &&
+       (z = (float*)malloc(ui->nelems*sizeof(float)))) {
+      /* save the current control values */
+      for (int i = 0; i < ui->nelems; i++)
+       if (ui->elems[i].zone)
+         z[i] = *ui->elems[i].zone;
+    }
+    /* set the proper sample rate; this requires reinitializing the dsp */
+    x->rate = sr;
+    x->dsp->init(sr);
+    if (z) {
+      /* restore previous control values */
+      for (int i = 0; i < ui->nelems; i++)
+       if (ui->elems[i].zone)
+         *ui->elems[i].zone = z[i];
+      free(z);
+    }
+  }
+  if (n > 0)
+    x->n_xfade = (int)(x->rate*XFADE_TIME/n);
+  dsp_add(faust_perform, 2, x, n);
+  for (int i = 0; i < x->n_in; i++)
+    x->inputs[i] = sp[i+1]->s_vec;
+  for (int i = 0; i < x->n_out; i++)
+    x->outputs[i] = sp[x->n_in+i+1]->s_vec;
+  if (x->buf != NULL)
+    for (int i = 0; i < x->n_out; i++) {
+      x->buf[i] = (t_sample*)malloc(n*sizeof(t_sample));
+      if (x->buf[i] == NULL) {
+       for (int j = 0; j < i; j++)
+         free(x->buf[j]);
+       free(x->buf);
+       x->buf = NULL;
+       break;
+      }
+    }
+}
+
+static int pathcmp(const char *s, const char *t)
+{
+  int n = strlen(s), m = strlen(t);
+  if (n == 0 || m == 0)
+    return 0;
+  else if (t[0] == '/')
+    return strcmp(s, t);
+  else if (n <= m || s[n-m-1] != '/')
+    return strcmp(s+1, t);
+  else
+    return strcmp(s+n-m, t);
+}
+
+static void faust_any(t_faust *x, t_symbol *s, int argc, t_atom *argv)
+{
+  if (!x->dsp) return;
+  PdUI *ui = x->ui;
+  if (s == &s_bang) {
+    for (int i = 0; i < ui->nelems; i++)
+      if (ui->elems[i].label && ui->elems[i].zone) {
+       t_atom args[6];
+       t_symbol *_s;
+       switch (ui->elems[i].type) {
+       case UI_BUTTON:
+         _s = s_button;
+         break;
+       case UI_TOGGLE_BUTTON:
+       case UI_CHECK_BUTTON:
+         _s = s_checkbox;
+         break;
+       case UI_V_SLIDER:
+         _s = s_vslider;
+         break;
+       case UI_H_SLIDER:
+         _s = s_hslider;
+         break;
+       case UI_NUM_ENTRY:
+         _s = s_nentry;
+         break;
+       case UI_V_BARGRAPH:
+         _s = s_vbargraph;
+         break;
+       case UI_H_BARGRAPH:
+         _s = s_hbargraph;
+         break;
+       default:
+         continue;
+       }
+       SETSYMBOL(&args[0], gensym(ui->elems[i].label));
+       SETFLOAT(&args[1], *ui->elems[i].zone);
+       SETFLOAT(&args[2], ui->elems[i].init);
+       SETFLOAT(&args[3], ui->elems[i].min);
+       SETFLOAT(&args[4], ui->elems[i].max);
+       SETFLOAT(&args[5], ui->elems[i].step);
+       outlet_anything(x->out, _s, 6, args);
+      }
+  } else {
+    const char *label = s->s_name;
+    int count = 0;
+    for (int i = 0; i < ui->nelems; i++)
+      if (ui->elems[i].label &&
+         pathcmp(ui->elems[i].label, label) == 0) {
+       if (argc == 0) {
+         if (ui->elems[i].zone) {
+           t_atom arg;
+           SETFLOAT(&arg, *ui->elems[i].zone);
+           outlet_anything(x->out, gensym(ui->elems[i].label), 1, &arg);
+         }
+         ++count;
+       } else if (argc == 1 &&
+                  (argv[0].a_type == A_FLOAT ||
+                   argv[0].a_type == A_DEFFLOAT) &&
+                  ui->elems[i].zone) {
+         float f = atom_getfloat(argv);
+         *ui->elems[i].zone = f;
+         ++count;
+       } else
+         pd_error(x, "[faust] %s: bad control argument: %s",
+                  x->label->c_str(), label);
+      }
+    if (count == 0 && strcmp(label, "active") == 0) {
+      if (argc == 0) {
+       t_atom arg;
+       SETFLOAT(&arg, (float)x->active);
+       outlet_anything(x->out, gensym((char*)"active"), 1, &arg);
+      } else if (argc == 1 &&
+                (argv[0].a_type == A_FLOAT ||
+                 argv[0].a_type == A_DEFFLOAT)) {
+       float f = atom_getfloat(argv);
+       x->active = (int)f;
+       x->xfade = x->n_xfade;
+      }
+    }
+  }
+}
+
+static void faust_free(t_faust *x)
+{
+  if (x->label) delete x->label;
+  if (x->dsp) delete x->dsp;
+  if (x->ui) delete x->ui;
+  if (x->inputs) free(x->inputs);
+  if (x->outputs) free(x->outputs);
+  if (x->buf) {
+    for (int i = 0; i < x->n_out; i++)
+      if (x->buf[i]) free(x->buf[i]);
+    free(x->buf);
+  }
+}
+
+static void *faust_new(t_symbol *s, int argc, t_atom *argv)
+{
+  t_faust *x = (t_faust*)pd_new(faust_class);
+  int sr = -1;
+  t_symbol *id = NULL;
+  x->active = 1;
+  for (int i = 0; i < argc; i++)
+    if (argv[i].a_type == A_FLOAT || argv[i].a_type == A_DEFFLOAT)
+      sr = (int)argv[i].a_w.w_float;
+    else if (argv[i].a_type == A_SYMBOL || argv[i].a_type == A_DEFSYMBOL)
+      id = argv[i].a_w.w_symbol;
+  x->rate = sr;
+  if (sr <= 0) sr = 44100;
+  x->xfade = 0; x->n_xfade = (int)(sr*XFADE_TIME/64);
+  x->inputs = x->outputs = x->buf = NULL;
+  x->label = new string(sym(mydsp) "~");
+  x->dsp = new mydsp();
+  x->ui = new PdUI(id?id->s_name:NULL);
+  if (!x->dsp || !x->ui || !x->label) goto error;
+  if (id) {
+    *x->label += " ";
+    *x->label += id->s_name;
+  }
+  x->n_in = x->dsp->getNumInputs();
+  x->n_out = x->dsp->getNumOutputs();
+  if (x->n_in > 0)
+    x->inputs = (t_sample**)malloc(x->n_in*sizeof(t_sample*));
+  if (x->n_out > 0) {
+    x->outputs = (t_sample**)malloc(x->n_out*sizeof(t_sample*));
+    x->buf = (t_sample**)malloc(x->n_out*sizeof(t_sample*));
+  }
+  if ((x->n_in > 0 && x->inputs == NULL) ||
+      (x->n_out > 0 && (x->outputs == NULL || x->buf == NULL)))
+    goto error;
+  for (int i = 0; i < x->n_out; i++)
+    x->buf[i] = NULL;
+  x->dsp->init(sr);
+  x->dsp->buildUserInterface(x->ui);
+  for (int i = 0; i < x->n_in; i++)
+    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+  x->out = outlet_new(&x->x_obj, 0);
+  for (int i = 0; i < x->n_out; i++)
+    outlet_new(&x->x_obj, &s_signal);
+  return (void *)x;
+ error:
+  faust_free(x);
+  x->dsp = NULL; x->ui = NULL;
+  x->inputs = x->outputs = x->buf = NULL;
+  return (void *)x;
+}
+
+extern "C" void faust_setup(mydsp)
+{
+  t_symbol *s = gensym(sym(mydsp) "~");
+  faust_class =
+    class_new(s, (t_newmethod)faust_new, (t_method)faust_free,
+             sizeof(t_faust), CLASS_DEFAULT,
+             A_GIMME, A_NULL);
+  class_addmethod(faust_class, (t_method)faust_dsp, gensym((char*)"dsp"), A_NULL);
+  class_addanything(faust_class, faust_any);
+  class_addmethod(faust_class, nullfn, &s_signal, A_NULL);
+  s_button = gensym((char*)"button");
+  s_checkbox = gensym((char*)"checkbox");
+  s_vslider = gensym((char*)"vslider");
+  s_hslider = gensym((char*)"hslider");
+  s_nentry = gensym((char*)"nentry");
+  s_vbargraph = gensym((char*)"vbargraph");
+  s_hbargraph = gensym((char*)"hbargrap");
+  /* give some indication that we're loaded and ready to go */
+  mydsp dsp = mydsp();
+  post("[faust] %s: %d inputs, %d outputs", sym(mydsp) "~",
+       dsp.getNumInputs(), dsp.getNumOutputs());
+}