User Manual first draft.
[Faustine.git] / interpreter / preprocessor / faust-0.9.47mr3 / architecture / puredata.cpp
1 /************************************************************************
2 ************************************************************************
3 FAUST Architecture File
4 Copyright (C) 2006-2011 Albert Graef <Dr.Graef@t-online.de>
5 ---------------------------------------------------------------------
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20 ************************************************************************
21 ************************************************************************/
22
23 /* Pd architecture file, written by Albert Graef <Dr.Graef@t-online.de>.
24 This was derived from minimal.cpp included in the Faust distribution.
25 Please note that this is to be compiled as a shared library, which is
26 then loaded dynamically by Pd as an external. */
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <math.h>
31 #include <string>
32
33 using namespace std;
34
35 // On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero)
36 // flags to avoid costly denormals
37 #ifdef __SSE__
38 #include <xmmintrin.h>
39 #ifdef __SSE2__
40 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
41 #else
42 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
43 #endif
44 #else
45 #warning *** puredata.cpp: NO SSE FLAG (denormals may slow things down) ***
46 #define AVOIDDENORMALS
47 #endif
48
49 struct Meta
50 {
51 void declare (const char* key, const char* value) {}
52 };
53
54 //-------------------------------------------------------------------
55 // Generic min and max using c++ inline
56 //-------------------------------------------------------------------
57
58 inline int max (unsigned int a, unsigned int b) { return (a>b) ? a : b; }
59 inline int max (int a, int b) { return (a>b) ? a : b; }
60
61 inline long max (long a, long b) { return (a>b) ? a : b; }
62 inline long max (int a, long b) { return (a>b) ? a : b; }
63 inline long max (long a, int b) { return (a>b) ? a : b; }
64
65 inline float max (float a, float b) { return (a>b) ? a : b; }
66 inline float max (int a, float b) { return (a>b) ? a : b; }
67 inline float max (float a, int b) { return (a>b) ? a : b; }
68 inline float max (long a, float b) { return (a>b) ? a : b; }
69 inline float max (float a, long b) { return (a>b) ? a : b; }
70
71 inline double max (double a, double b) { return (a>b) ? a : b; }
72 inline double max (int a, double b) { return (a>b) ? a : b; }
73 inline double max (double a, int b) { return (a>b) ? a : b; }
74 inline double max (long a, double b) { return (a>b) ? a : b; }
75 inline double max (double a, long b) { return (a>b) ? a : b; }
76 inline double max (float a, double b) { return (a>b) ? a : b; }
77 inline double max (double a, float b) { return (a>b) ? a : b; }
78
79
80 inline int min (int a, int b) { return (a<b) ? a : b; }
81
82 inline long min (long a, long b) { return (a<b) ? a : b; }
83 inline long min (int a, long b) { return (a<b) ? a : b; }
84 inline long min (long a, int b) { return (a<b) ? a : b; }
85
86 inline float min (float a, float b) { return (a<b) ? a : b; }
87 inline float min (int a, float b) { return (a<b) ? a : b; }
88 inline float min (float a, int b) { return (a<b) ? a : b; }
89 inline float min (long a, float b) { return (a<b) ? a : b; }
90 inline float min (float a, long b) { return (a<b) ? a : b; }
91
92 inline double min (double a, double b) { return (a<b) ? a : b; }
93 inline double min (int a, double b) { return (a<b) ? a : b; }
94 inline double min (double a, int b) { return (a<b) ? a : b; }
95 inline double min (long a, double b) { return (a<b) ? a : b; }
96 inline double min (double a, long b) { return (a<b) ? a : b; }
97 inline double min (float a, double b) { return (a<b) ? a : b; }
98 inline double min (double a, float b) { return (a<b) ? a : b; }
99
100 // abs is now predefined
101 //template<typename T> T abs (T a) { return (a<T(0)) ? -a : a; }
102
103
104 inline int lsr (int x, int n) { return int(((unsigned int)x) >> n); }
105
106 /******************************************************************************
107 *******************************************************************************
108
109 VECTOR INTRINSICS
110
111 *******************************************************************************
112 *******************************************************************************/
113
114 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((unsigned)(calloc((nmemb*size)+15,sizeof(char)))+15 & 0xfffffff0); }
115 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((size_t)(calloc((nmemb*size)+15,sizeof(char)))+15 & ~15); }
116
117 <<includeIntrinsic>>
118
119 /******************************************************************************
120 *******************************************************************************
121
122 ABSTRACT USER INTERFACE
123
124 *******************************************************************************
125 *******************************************************************************/
126
127 class UI
128 {
129 bool fStopped;
130 public:
131
132 UI() : fStopped(false) {}
133 virtual ~UI() {}
134
135 virtual void addButton(const char* label, float* zone) = 0;
136 virtual void addToggleButton(const char* label, float* zone) = 0;
137 virtual void addCheckButton(const char* label, float* zone) = 0;
138 virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
139 virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
140 virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step) = 0;
141
142 virtual void addNumDisplay(const char* label, float* zone, int precision) = 0;
143 virtual void addTextDisplay(const char* label, float* zone, const char* names[], float min, float max) = 0;
144 virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) = 0;
145 virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) = 0;
146
147 virtual void openFrameBox(const char* label) = 0;
148 virtual void openTabBox(const char* label) = 0;
149 virtual void openHorizontalBox(const char* label) = 0;
150 virtual void openVerticalBox(const char* label) = 0;
151 virtual void closeBox() = 0;
152
153 virtual void run() = 0;
154
155 void stop() { fStopped = true; }
156 bool stopped() { return fStopped; }
157
158 virtual void declare(float* zone, const char* key, const char* value) {}
159 };
160
161 /***************************************************************************
162 Pd UI interface
163 ***************************************************************************/
164
165 enum ui_elem_type_t {
166 UI_BUTTON, UI_TOGGLE_BUTTON, UI_CHECK_BUTTON,
167 UI_V_SLIDER, UI_H_SLIDER, UI_NUM_ENTRY,
168 UI_V_BARGRAPH, UI_H_BARGRAPH,
169 UI_END_GROUP, UI_V_GROUP, UI_H_GROUP, UI_T_GROUP
170 };
171
172 struct ui_elem_t {
173 ui_elem_type_t type;
174 char *label;
175 float *zone;
176 float init, min, max, step;
177 };
178
179 class PdUI : public UI
180 {
181 public:
182 int nelems;
183 ui_elem_t *elems;
184
185 PdUI();
186 PdUI(const char *s);
187 virtual ~PdUI();
188
189 protected:
190 string path;
191 void add_elem(ui_elem_type_t type, const char *label = NULL);
192 void add_elem(ui_elem_type_t type, const char *label, float *zone);
193 void add_elem(ui_elem_type_t type, const char *label, float *zone,
194 float init, float min, float max, float step);
195 void add_elem(ui_elem_type_t type, const char *label, float *zone,
196 float min, float max);
197
198 public:
199 virtual void addButton(const char* label, float* zone);
200 virtual void addToggleButton(const char* label, float* zone);
201 virtual void addCheckButton(const char* label, float* zone);
202 virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step);
203 virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step);
204 virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step);
205
206 virtual void addNumDisplay(const char* label, float* zone, int precision);
207 virtual void addTextDisplay(const char* label, float* zone, const char* names[], float min, float max);
208 virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max);
209 virtual void addVerticalBargraph(const char* label, float* zone, float min, float max);
210
211 virtual void openFrameBox(const char* label);
212 virtual void openTabBox(const char* label);
213 virtual void openHorizontalBox(const char* label);
214 virtual void openVerticalBox(const char* label);
215 virtual void closeBox();
216
217 virtual void run();
218 };
219
220 static string mangle(const char *s)
221 {
222 const char *s0 = s;
223 string t = "";
224 if (!s) return t;
225 while (*s)
226 if (isalnum(*s))
227 t += *(s++);
228 else {
229 const char *s1 = s;
230 while (*s && !isalnum(*s)) ++s;
231 if (s1 != s0 && *s) t += "-";
232 }
233 return t;
234 }
235
236 static string normpath(string path)
237 {
238 path = string("/")+path;
239 int pos = path.find("//");
240 while (pos >= 0) {
241 path.erase(pos, 1);
242 pos = path.find("//");
243 }
244 return path;
245 }
246
247 static string pathcat(string path, string label)
248 {
249 if (path.empty())
250 return normpath(label);
251 else if (label.empty())
252 return normpath(path);
253 else
254 return normpath(path+"/"+label);
255 }
256
257 PdUI::PdUI()
258 {
259 nelems = 0;
260 elems = NULL;
261 path = "";
262 }
263
264 PdUI::PdUI(const char *s)
265 {
266 nelems = 0;
267 elems = NULL;
268 path = s?s:"";
269 }
270
271 PdUI::~PdUI()
272 {
273 if (elems) {
274 for (int i = 0; i < nelems; i++)
275 if (elems[i].label)
276 free(elems[i].label);
277 free(elems);
278 }
279 }
280
281 inline void PdUI::add_elem(ui_elem_type_t type, const char *label)
282 {
283 ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t));
284 if (elems1)
285 elems = elems1;
286 else
287 return;
288 string s = pathcat(path, mangle(label));
289 elems[nelems].type = type;
290 elems[nelems].label = strdup(s.c_str());
291 elems[nelems].zone = NULL;
292 elems[nelems].init = 0.0;
293 elems[nelems].min = 0.0;
294 elems[nelems].max = 0.0;
295 elems[nelems].step = 0.0;
296 nelems++;
297 }
298
299 inline void PdUI::add_elem(ui_elem_type_t type, const char *label, float *zone)
300 {
301 ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t));
302 if (elems1)
303 elems = elems1;
304 else
305 return;
306 string s = pathcat(path, mangle(label));
307 elems[nelems].type = type;
308 elems[nelems].label = strdup(s.c_str());
309 elems[nelems].zone = zone;
310 elems[nelems].init = 0.0;
311 elems[nelems].min = 0.0;
312 elems[nelems].max = 1.0;
313 elems[nelems].step = 1.0;
314 nelems++;
315 }
316
317 inline void PdUI::add_elem(ui_elem_type_t type, const char *label, float *zone,
318 float init, float min, float max, float step)
319 {
320 ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t));
321 if (elems1)
322 elems = elems1;
323 else
324 return;
325 string s = pathcat(path, mangle(label));
326 elems[nelems].type = type;
327 elems[nelems].label = strdup(s.c_str());
328 elems[nelems].zone = zone;
329 elems[nelems].init = init;
330 elems[nelems].min = min;
331 elems[nelems].max = max;
332 elems[nelems].step = step;
333 nelems++;
334 }
335
336 inline void PdUI::add_elem(ui_elem_type_t type, const char *label, float *zone,
337 float min, float max)
338 {
339 ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t));
340 if (elems1)
341 elems = elems1;
342 else
343 return;
344 string s = pathcat(path, mangle(label));
345 elems[nelems].type = type;
346 elems[nelems].label = strdup(s.c_str());
347 elems[nelems].zone = zone;
348 elems[nelems].init = 0.0;
349 elems[nelems].min = min;
350 elems[nelems].max = max;
351 elems[nelems].step = 0.0;
352 nelems++;
353 }
354
355 void PdUI::addButton(const char* label, float* zone)
356 { add_elem(UI_BUTTON, label, zone); }
357 void PdUI::addToggleButton(const char* label, float* zone)
358 { add_elem(UI_TOGGLE_BUTTON, label, zone); }
359 void PdUI::addCheckButton(const char* label, float* zone)
360 { add_elem(UI_CHECK_BUTTON, label, zone); }
361 void PdUI::addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step)
362 { add_elem(UI_V_SLIDER, label, zone, init, min, max, step); }
363 void PdUI::addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step)
364 { add_elem(UI_H_SLIDER, label, zone, init, min, max, step); }
365 void PdUI::addNumEntry(const char* label, float* zone, float init, float min, float max, float step)
366 { add_elem(UI_NUM_ENTRY, label, zone, init, min, max, step); }
367
368 // FIXME: addNumDisplay and addTextDisplay not implemented in Faust yet?
369 void PdUI::addNumDisplay(const char* label, float* zone, int precision) {}
370 void PdUI::addTextDisplay(const char* label, float* zone, const char* names[], float min, float max) {}
371 void PdUI::addHorizontalBargraph(const char* label, float* zone, float min, float max)
372 { add_elem(UI_H_BARGRAPH, label, zone, min, max); }
373 void PdUI::addVerticalBargraph(const char* label, float* zone, float min, float max)
374 { add_elem(UI_V_BARGRAPH, label, zone, min, max); }
375
376 void PdUI::openFrameBox(const char* label)
377 {
378 if (!path.empty()) path += "/";
379 path += mangle(label);
380 }
381 void PdUI::openTabBox(const char* label)
382 {
383 if (!path.empty()) path += "/";
384 path += mangle(label);
385 }
386 void PdUI::openHorizontalBox(const char* label)
387 {
388 if (!path.empty()) path += "/";
389 path += mangle(label);
390 }
391 void PdUI::openVerticalBox(const char* label)
392 {
393 if (!path.empty()) path += "/";
394 path += mangle(label);
395 }
396 void PdUI::closeBox()
397 {
398 int pos = path.rfind("/");
399 if (pos < 0) pos = 0;
400 path.erase(pos);
401 }
402
403 void PdUI::run() {}
404
405 /******************************************************************************
406 *******************************************************************************
407
408 FAUST DSP
409
410 *******************************************************************************
411 *******************************************************************************/
412
413
414
415 //----------------------------------------------------------------
416 // abstract definition of a signal processor
417 //----------------------------------------------------------------
418
419 class dsp {
420 protected:
421 int fSamplingFreq;
422 public:
423 dsp() {}
424 virtual ~dsp() {}
425 virtual int getNumInputs() = 0;
426 virtual int getNumOutputs() = 0;
427 virtual void buildUserInterface(UI* interface) = 0;
428 virtual void init(int samplingRate) = 0;
429 virtual void compute(int len, float** inputs, float** outputs) = 0;
430 };
431
432 //----------------------------------------------------------------------------
433 // FAUST generated signal processor
434 //----------------------------------------------------------------------------
435
436
437 <<includeclass>>
438
439 #include <stdio.h>
440 #include <string.h>
441 #include "m_pd.h"
442
443 #define faust_setup(name) xfaust_setup(name)
444 #define xfaust_setup(name) name ## _tilde_setup(void)
445 #define sym(name) xsym(name)
446 #define xsym(name) #name
447
448 // time for "active" toggle xfades in secs
449 #define XFADE_TIME 0.1f
450
451 static t_class *faust_class;
452
453 struct t_faust {
454 t_object x_obj;
455 #ifdef __MINGW32__
456 /* This seems to be necessary as some as yet undetermined Pd routine seems
457 to write past the end of x_obj on Windows. */
458 int fence; /* dummy field (not used) */
459 #endif
460 mydsp *dsp;
461 PdUI *ui;
462 string *label;
463 int active, xfade, n_xfade, rate, n_in, n_out;
464 t_sample **inputs, **outputs, **buf;
465 t_outlet *out;
466 t_sample f;
467 };
468
469 static t_symbol *s_button, *s_checkbox, *s_vslider, *s_hslider, *s_nentry,
470 *s_vbargraph, *s_hbargraph;
471
472 static inline void zero_samples(int k, int n, t_sample **out)
473 {
474 for (int i = 0; i < k; i++)
475 #ifdef __STDC_IEC_559__
476 /* IEC 559 a.k.a. IEEE 754 floats can be initialized faster like this */
477 memset(out[i], 0, n*sizeof(t_sample));
478 #else
479 for (int j = 0; j < n; j++)
480 out[i][j] = 0.0f;
481 #endif
482 }
483
484 static inline void copy_samples(int k, int n, t_sample **out, t_sample **in)
485 {
486 for (int i = 0; i < k; i++)
487 memcpy(out[i], in[i], n*sizeof(t_sample));
488 }
489
490 static t_int *faust_perform(t_int *w)
491 {
492 t_faust *x = (t_faust *)(w[1]);
493 int n = (int)(w[2]);
494 if (!x->dsp || !x->buf) return (w+3);
495 AVOIDDENORMALS;
496 if (x->xfade > 0) {
497 float d = 1.0f/x->n_xfade, f = (x->xfade--)*d;
498 d = d/n;
499 x->dsp->compute(n, x->inputs, x->buf);
500 if (x->active)
501 if (x->n_in == x->n_out)
502 /* xfade inputs -> buf */
503 for (int j = 0; j < n; j++, f -= d)
504 for (int i = 0; i < x->n_out; i++)
505 x->outputs[i][j] = f*x->inputs[i][j]+(1.0f-f)*x->buf[i][j];
506 else
507 /* xfade 0 -> buf */
508 for (int j = 0; j < n; j++, f -= d)
509 for (int i = 0; i < x->n_out; i++)
510 x->outputs[i][j] = (1.0f-f)*x->buf[i][j];
511 else
512 if (x->n_in == x->n_out)
513 /* xfade buf -> inputs */
514 for (int j = 0; j < n; j++, f -= d)
515 for (int i = 0; i < x->n_out; i++)
516 x->outputs[i][j] = f*x->buf[i][j]+(1.0f-f)*x->inputs[i][j];
517 else
518 /* xfade buf -> 0 */
519 for (int j = 0; j < n; j++, f -= d)
520 for (int i = 0; i < x->n_out; i++)
521 x->outputs[i][j] = f*x->buf[i][j];
522 } else if (x->active) {
523 x->dsp->compute(n, x->inputs, x->buf);
524 copy_samples(x->n_out, n, x->outputs, x->buf);
525 } else if (x->n_in == x->n_out) {
526 copy_samples(x->n_out, n, x->buf, x->inputs);
527 copy_samples(x->n_out, n, x->outputs, x->buf);
528 } else
529 zero_samples(x->n_out, n, x->outputs);
530 return (w+3);
531 }
532
533 static void faust_dsp(t_faust *x, t_signal **sp)
534 {
535 int n = sp[0]->s_n, sr = (int)sp[0]->s_sr;
536 if (x->rate <= 0) {
537 /* default sample rate is whatever Pd tells us */
538 PdUI *ui = x->ui;
539 float *z = NULL;
540 if (ui->nelems > 0 &&
541 (z = (float*)malloc(ui->nelems*sizeof(float)))) {
542 /* save the current control values */
543 for (int i = 0; i < ui->nelems; i++)
544 if (ui->elems[i].zone)
545 z[i] = *ui->elems[i].zone;
546 }
547 /* set the proper sample rate; this requires reinitializing the dsp */
548 x->rate = sr;
549 x->dsp->init(sr);
550 if (z) {
551 /* restore previous control values */
552 for (int i = 0; i < ui->nelems; i++)
553 if (ui->elems[i].zone)
554 *ui->elems[i].zone = z[i];
555 free(z);
556 }
557 }
558 if (n > 0)
559 x->n_xfade = (int)(x->rate*XFADE_TIME/n);
560 dsp_add(faust_perform, 2, x, n);
561 for (int i = 0; i < x->n_in; i++)
562 x->inputs[i] = sp[i+1]->s_vec;
563 for (int i = 0; i < x->n_out; i++)
564 x->outputs[i] = sp[x->n_in+i+1]->s_vec;
565 if (x->buf != NULL)
566 for (int i = 0; i < x->n_out; i++) {
567 x->buf[i] = (t_sample*)malloc(n*sizeof(t_sample));
568 if (x->buf[i] == NULL) {
569 for (int j = 0; j < i; j++)
570 free(x->buf[j]);
571 free(x->buf);
572 x->buf = NULL;
573 break;
574 }
575 }
576 }
577
578 static int pathcmp(const char *s, const char *t)
579 {
580 int n = strlen(s), m = strlen(t);
581 if (n == 0 || m == 0)
582 return 0;
583 else if (t[0] == '/')
584 return strcmp(s, t);
585 else if (n <= m || s[n-m-1] != '/')
586 return strcmp(s+1, t);
587 else
588 return strcmp(s+n-m, t);
589 }
590
591 static void faust_any(t_faust *x, t_symbol *s, int argc, t_atom *argv)
592 {
593 if (!x->dsp) return;
594 PdUI *ui = x->ui;
595 if (s == &s_bang) {
596 for (int i = 0; i < ui->nelems; i++)
597 if (ui->elems[i].label && ui->elems[i].zone) {
598 t_atom args[6];
599 t_symbol *_s;
600 switch (ui->elems[i].type) {
601 case UI_BUTTON:
602 _s = s_button;
603 break;
604 case UI_TOGGLE_BUTTON:
605 case UI_CHECK_BUTTON:
606 _s = s_checkbox;
607 break;
608 case UI_V_SLIDER:
609 _s = s_vslider;
610 break;
611 case UI_H_SLIDER:
612 _s = s_hslider;
613 break;
614 case UI_NUM_ENTRY:
615 _s = s_nentry;
616 break;
617 case UI_V_BARGRAPH:
618 _s = s_vbargraph;
619 break;
620 case UI_H_BARGRAPH:
621 _s = s_hbargraph;
622 break;
623 default:
624 continue;
625 }
626 SETSYMBOL(&args[0], gensym(ui->elems[i].label));
627 SETFLOAT(&args[1], *ui->elems[i].zone);
628 SETFLOAT(&args[2], ui->elems[i].init);
629 SETFLOAT(&args[3], ui->elems[i].min);
630 SETFLOAT(&args[4], ui->elems[i].max);
631 SETFLOAT(&args[5], ui->elems[i].step);
632 outlet_anything(x->out, _s, 6, args);
633 }
634 } else {
635 const char *label = s->s_name;
636 int count = 0;
637 for (int i = 0; i < ui->nelems; i++)
638 if (ui->elems[i].label &&
639 pathcmp(ui->elems[i].label, label) == 0) {
640 if (argc == 0) {
641 if (ui->elems[i].zone) {
642 t_atom arg;
643 SETFLOAT(&arg, *ui->elems[i].zone);
644 outlet_anything(x->out, gensym(ui->elems[i].label), 1, &arg);
645 }
646 ++count;
647 } else if (argc == 1 &&
648 (argv[0].a_type == A_FLOAT ||
649 argv[0].a_type == A_DEFFLOAT) &&
650 ui->elems[i].zone) {
651 float f = atom_getfloat(argv);
652 *ui->elems[i].zone = f;
653 ++count;
654 } else
655 pd_error(x, "[faust] %s: bad control argument: %s",
656 x->label->c_str(), label);
657 }
658 if (count == 0 && strcmp(label, "active") == 0) {
659 if (argc == 0) {
660 t_atom arg;
661 SETFLOAT(&arg, (float)x->active);
662 outlet_anything(x->out, gensym((char*)"active"), 1, &arg);
663 } else if (argc == 1 &&
664 (argv[0].a_type == A_FLOAT ||
665 argv[0].a_type == A_DEFFLOAT)) {
666 float f = atom_getfloat(argv);
667 x->active = (int)f;
668 x->xfade = x->n_xfade;
669 }
670 }
671 }
672 }
673
674 static void faust_free(t_faust *x)
675 {
676 if (x->label) delete x->label;
677 if (x->dsp) delete x->dsp;
678 if (x->ui) delete x->ui;
679 if (x->inputs) free(x->inputs);
680 if (x->outputs) free(x->outputs);
681 if (x->buf) {
682 for (int i = 0; i < x->n_out; i++)
683 if (x->buf[i]) free(x->buf[i]);
684 free(x->buf);
685 }
686 }
687
688 static void *faust_new(t_symbol *s, int argc, t_atom *argv)
689 {
690 t_faust *x = (t_faust*)pd_new(faust_class);
691 int sr = -1;
692 t_symbol *id = NULL;
693 x->active = 1;
694 for (int i = 0; i < argc; i++)
695 if (argv[i].a_type == A_FLOAT || argv[i].a_type == A_DEFFLOAT)
696 sr = (int)argv[i].a_w.w_float;
697 else if (argv[i].a_type == A_SYMBOL || argv[i].a_type == A_DEFSYMBOL)
698 id = argv[i].a_w.w_symbol;
699 x->rate = sr;
700 if (sr <= 0) sr = 44100;
701 x->xfade = 0; x->n_xfade = (int)(sr*XFADE_TIME/64);
702 x->inputs = x->outputs = x->buf = NULL;
703 x->label = new string(sym(mydsp) "~");
704 x->dsp = new mydsp();
705 x->ui = new PdUI(id?id->s_name:NULL);
706 if (!x->dsp || !x->ui || !x->label) goto error;
707 if (id) {
708 *x->label += " ";
709 *x->label += id->s_name;
710 }
711 x->n_in = x->dsp->getNumInputs();
712 x->n_out = x->dsp->getNumOutputs();
713 if (x->n_in > 0)
714 x->inputs = (t_sample**)malloc(x->n_in*sizeof(t_sample*));
715 if (x->n_out > 0) {
716 x->outputs = (t_sample**)malloc(x->n_out*sizeof(t_sample*));
717 x->buf = (t_sample**)malloc(x->n_out*sizeof(t_sample*));
718 }
719 if ((x->n_in > 0 && x->inputs == NULL) ||
720 (x->n_out > 0 && (x->outputs == NULL || x->buf == NULL)))
721 goto error;
722 for (int i = 0; i < x->n_out; i++)
723 x->buf[i] = NULL;
724 x->dsp->init(sr);
725 x->dsp->buildUserInterface(x->ui);
726 for (int i = 0; i < x->n_in; i++)
727 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
728 x->out = outlet_new(&x->x_obj, 0);
729 for (int i = 0; i < x->n_out; i++)
730 outlet_new(&x->x_obj, &s_signal);
731 return (void *)x;
732 error:
733 faust_free(x);
734 x->dsp = NULL; x->ui = NULL;
735 x->inputs = x->outputs = x->buf = NULL;
736 return (void *)x;
737 }
738
739 extern "C" void faust_setup(mydsp)
740 {
741 t_symbol *s = gensym(sym(mydsp) "~");
742 faust_class =
743 class_new(s, (t_newmethod)faust_new, (t_method)faust_free,
744 sizeof(t_faust), CLASS_DEFAULT,
745 A_GIMME, A_NULL);
746 class_addmethod(faust_class, (t_method)faust_dsp, gensym((char*)"dsp"), A_NULL);
747 class_addanything(faust_class, faust_any);
748 class_addmethod(faust_class, nullfn, &s_signal, A_NULL);
749 s_button = gensym((char*)"button");
750 s_checkbox = gensym((char*)"checkbox");
751 s_vslider = gensym((char*)"vslider");
752 s_hslider = gensym((char*)"hslider");
753 s_nentry = gensym((char*)"nentry");
754 s_vbargraph = gensym((char*)"vbargraph");
755 s_hbargraph = gensym((char*)"hbargrap");
756 /* give some indication that we're loaded and ready to go */
757 mydsp dsp = mydsp();
758 post("[faust] %s: %d inputs, %d outputs", sym(mydsp) "~",
759 dsp.getNumInputs(), dsp.getNumOutputs());
760 }