Initial import.
[Faustine.git] / interpretor / faust-0.9.47mr3 / architecture / pure.cpp
1 /************************************************************************
2 ************************************************************************
3 FAUST Architecture File
4 Copyright (C) 2009-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 /* Pure architecture for Faust. This is similar to the Q architecture, but
24 uses double precision for the audio buffers and control variables. See
25 http://pure-lang.googlecode.com for a Pure module which can load these
26 extensions. */
27
28 #include <stdlib.h>
29 #include <math.h>
30 #include <list>
31 #include <map>
32
33 using namespace std;
34
35 typedef pair<const char*,const char*> strpair;
36
37 struct Meta
38 {
39 list< strpair > data;
40 void declare (const char* key, const char* value)
41 { data.push_back(strpair(key, value)); }
42 };
43
44 //-------------------------------------------------------------------
45 // Generic min and max using c++ inline
46 //-------------------------------------------------------------------
47
48 inline int max (unsigned int a, unsigned int b) { return (a>b) ? a : b; }
49 inline int max (int a, int b) { return (a>b) ? a : b; }
50
51 inline long max (long a, long b) { return (a>b) ? a : b; }
52 inline long max (int a, long b) { return (a>b) ? a : b; }
53 inline long max (long a, int b) { return (a>b) ? a : b; }
54
55 inline float max (float a, float b) { return (a>b) ? a : b; }
56 inline float max (int a, float b) { return (a>b) ? a : b; }
57 inline float max (float a, int b) { return (a>b) ? a : b; }
58 inline float max (long a, float b) { return (a>b) ? a : b; }
59 inline float max (float a, long b) { return (a>b) ? a : b; }
60
61 inline double max (double a, double b) { return (a>b) ? a : b; }
62 inline double max (int a, double b) { return (a>b) ? a : b; }
63 inline double max (double a, int b) { return (a>b) ? a : b; }
64 inline double max (long a, double b) { return (a>b) ? a : b; }
65 inline double max (double a, long b) { return (a>b) ? a : b; }
66 inline double max (float a, double b) { return (a>b) ? a : b; }
67 inline double max (double a, float b) { return (a>b) ? a : b; }
68
69
70 inline int min (int a, int b) { return (a<b) ? a : b; }
71
72 inline long min (long a, long b) { return (a<b) ? a : b; }
73 inline long min (int a, long b) { return (a<b) ? a : b; }
74 inline long min (long a, int b) { return (a<b) ? a : b; }
75
76 inline float min (float a, float b) { return (a<b) ? a : b; }
77 inline float min (int a, float b) { return (a<b) ? a : b; }
78 inline float min (float a, int b) { return (a<b) ? a : b; }
79 inline float min (long a, float b) { return (a<b) ? a : b; }
80 inline float min (float a, long b) { return (a<b) ? a : b; }
81
82 inline double min (double a, double b) { return (a<b) ? a : b; }
83 inline double min (int a, double b) { return (a<b) ? a : b; }
84 inline double min (double a, int b) { return (a<b) ? a : b; }
85 inline double min (long a, double b) { return (a<b) ? a : b; }
86 inline double min (double a, long b) { return (a<b) ? a : b; }
87 inline double min (float a, double b) { return (a<b) ? a : b; }
88 inline double min (double a, float b) { return (a<b) ? a : b; }
89
90 // abs is now predefined
91 //template<typename T> T abs (T a) { return (a<T(0)) ? -a : a; }
92
93 inline int lsr (int x, int n) { return int(((unsigned int)x) >> n); }
94
95 /******************************************************************************
96 *******************************************************************************
97
98 VECTOR INTRINSICS
99
100 *******************************************************************************
101 *******************************************************************************/
102
103 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((unsigned)(calloc((nmemb*size)+15,sizeof(char)))+15 & 0xfffffff0); }
104 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((size_t)(calloc((nmemb*size)+15,sizeof(char)))+15 & ~15); }
105
106 <<includeIntrinsic>>
107
108 /******************************************************************************
109 *******************************************************************************
110
111 ABSTRACT USER INTERFACE
112
113 *******************************************************************************
114 *******************************************************************************/
115
116 class UI
117 {
118 bool fStopped;
119 public:
120
121 UI() : fStopped(false) {}
122 virtual ~UI() {}
123
124 virtual void addButton(const char* label, double* zone) = 0;
125 virtual void addToggleButton(const char* label, double* zone) = 0;
126 virtual void addCheckButton(const char* label, double* zone) = 0;
127 virtual void addVerticalSlider(const char* label, double* zone, float init, float min, float max, float step) = 0;
128 virtual void addHorizontalSlider(const char* label, double* zone, float init, float min, float max, float step) = 0;
129 virtual void addNumEntry(const char* label, double* zone, float init, float min, float max, float step) = 0;
130
131 virtual void addNumDisplay(const char* label, double* zone, int precision) = 0;
132 virtual void addTextDisplay(const char* label, double* zone, char* names[], float min, float max) = 0;
133 virtual void addHorizontalBargraph(const char* label, double* zone, float min, float max) = 0;
134 virtual void addVerticalBargraph(const char* label, double* zone, float min, float max) = 0;
135
136 virtual void openFrameBox(const char* label) = 0;
137 virtual void openTabBox(const char* label) = 0;
138 virtual void openHorizontalBox(const char* label) = 0;
139 virtual void openVerticalBox(const char* label) = 0;
140 virtual void closeBox() = 0;
141
142 virtual void run() = 0;
143
144 void stop() { fStopped = true; }
145 bool stopped() { return fStopped; }
146
147 virtual void declare(double* zone, const char* key, const char* value) {}
148 };
149
150 /***************************************************************************
151 Pure UI interface
152 ***************************************************************************/
153
154 enum ui_elem_type_t {
155 UI_BUTTON, UI_TOGGLE_BUTTON, UI_CHECK_BUTTON,
156 UI_V_SLIDER, UI_H_SLIDER, UI_NUM_ENTRY,
157 UI_V_BARGRAPH, UI_H_BARGRAPH,
158 UI_END_GROUP, UI_V_GROUP, UI_H_GROUP, UI_T_GROUP
159 };
160
161 struct ui_elem_t {
162 ui_elem_type_t type;
163 const char *label;
164 double *zone;
165 void *ref;
166 float init, min, max, step;
167 };
168
169 class PureUI : public UI
170 {
171 public:
172 int nelems;
173 ui_elem_t *elems;
174 map< int, list<strpair> > metadata;
175
176 PureUI();
177 virtual ~PureUI();
178
179 protected:
180 void add_elem(ui_elem_type_t type, const char *label = NULL);
181 void add_elem(ui_elem_type_t type, const char *label, double *zone);
182 void add_elem(ui_elem_type_t type, const char *label, double *zone,
183 float init, float min, float max, float step);
184 void add_elem(ui_elem_type_t type, const char *label, double *zone,
185 float min, float max);
186
187 public:
188 virtual void addButton(const char* label, double* zone);
189 virtual void addToggleButton(const char* label, double* zone);
190 virtual void addCheckButton(const char* label, double* zone);
191 virtual void addVerticalSlider(const char* label, double* zone, float init, float min, float max, float step);
192 virtual void addHorizontalSlider(const char* label, double* zone, float init, float min, float max, float step);
193 virtual void addNumEntry(const char* label, double* zone, float init, float min, float max, float step);
194
195 virtual void addNumDisplay(const char* label, double* zone, int precision);
196 virtual void addTextDisplay(const char* label, double* zone, char* names[], float min, float max);
197 virtual void addHorizontalBargraph(const char* label, double* zone, float min, float max);
198 virtual void addVerticalBargraph(const char* label, double* zone, float min, float max);
199
200 virtual void openFrameBox(const char* label);
201 virtual void openTabBox(const char* label);
202 virtual void openHorizontalBox(const char* label);
203 virtual void openVerticalBox(const char* label);
204 virtual void closeBox();
205
206 virtual void run();
207
208 virtual void declare(double* zone, const char* key, const char* value);
209 };
210
211 PureUI::PureUI()
212 {
213 nelems = 0;
214 elems = NULL;
215 }
216
217 PureUI::~PureUI()
218 {
219 if (elems) free(elems);
220 }
221
222 void PureUI::declare(double* zone, const char* key, const char* value)
223 {
224 map< int, list<strpair> >::iterator it = metadata.find(nelems);
225 if (it != metadata.end())
226 it->second.push_back(strpair(key, value));
227 else
228 metadata[nelems] = list<strpair>(1, strpair(key, value));
229 }
230
231 inline void PureUI::add_elem(ui_elem_type_t type, const char *label)
232 {
233 ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t));
234 if (elems1)
235 elems = elems1;
236 else
237 return;
238 elems[nelems].type = type;
239 elems[nelems].label = label;
240 elems[nelems].zone = NULL;
241 elems[nelems].ref = NULL;
242 elems[nelems].init = 0.0;
243 elems[nelems].min = 0.0;
244 elems[nelems].max = 0.0;
245 elems[nelems].step = 0.0;
246 nelems++;
247 }
248
249 inline void PureUI::add_elem(ui_elem_type_t type, const char *label, double *zone)
250 {
251 ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t));
252 if (elems1)
253 elems = elems1;
254 else
255 return;
256 elems[nelems].type = type;
257 elems[nelems].label = label;
258 elems[nelems].zone = zone;
259 elems[nelems].ref = NULL;
260 elems[nelems].init = 0.0;
261 elems[nelems].min = 0.0;
262 elems[nelems].max = 0.0;
263 elems[nelems].step = 0.0;
264 nelems++;
265 }
266
267 inline void PureUI::add_elem(ui_elem_type_t type, const char *label, double *zone,
268 float init, float min, float max, float step)
269 {
270 ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t));
271 if (elems1)
272 elems = elems1;
273 else
274 return;
275 elems[nelems].type = type;
276 elems[nelems].label = label;
277 elems[nelems].zone = zone;
278 elems[nelems].ref = NULL;
279 elems[nelems].init = init;
280 elems[nelems].min = min;
281 elems[nelems].max = max;
282 elems[nelems].step = step;
283 nelems++;
284 }
285
286 inline void PureUI::add_elem(ui_elem_type_t type, const char *label, double *zone,
287 float min, float max)
288 {
289 ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t));
290 if (elems1)
291 elems = elems1;
292 else
293 return;
294 elems[nelems].type = type;
295 elems[nelems].label = label;
296 elems[nelems].zone = zone;
297 elems[nelems].ref = NULL;
298 elems[nelems].init = 0.0;
299 elems[nelems].min = min;
300 elems[nelems].max = max;
301 elems[nelems].step = 0.0;
302 nelems++;
303 }
304
305 void PureUI::addButton(const char* label, double* zone)
306 { add_elem(UI_BUTTON, label, zone); }
307 void PureUI::addToggleButton(const char* label, double* zone)
308 { add_elem(UI_TOGGLE_BUTTON, label, zone); }
309 void PureUI::addCheckButton(const char* label, double* zone)
310 { add_elem(UI_CHECK_BUTTON, label, zone); }
311 void PureUI::addVerticalSlider(const char* label, double* zone, float init, float min, float max, float step)
312 { add_elem(UI_V_SLIDER, label, zone, init, min, max, step); }
313 void PureUI::addHorizontalSlider(const char* label, double* zone, float init, float min, float max, float step)
314 { add_elem(UI_H_SLIDER, label, zone, init, min, max, step); }
315 void PureUI::addNumEntry(const char* label, double* zone, float init, float min, float max, float step)
316 { add_elem(UI_NUM_ENTRY, label, zone, init, min, max, step); }
317
318 // FIXME: addNumDisplay and addTextDisplay not implemented in Faust yet?
319 void PureUI::addNumDisplay(const char* label, double* zone, int precision) {}
320 void PureUI::addTextDisplay(const char* label, double* zone, char* names[], float min, float max) {}
321 void PureUI::addHorizontalBargraph(const char* label, double* zone, float min, float max)
322 { add_elem(UI_H_BARGRAPH, label, zone, min, max); }
323 void PureUI::addVerticalBargraph(const char* label, double* zone, float min, float max)
324 { add_elem(UI_V_BARGRAPH, label, zone, min, max); }
325
326 void PureUI::openFrameBox(const char* label) {}
327 void PureUI::openTabBox(const char* label)
328 { add_elem(UI_T_GROUP, label); }
329 void PureUI::openHorizontalBox(const char* label)
330 { add_elem(UI_H_GROUP, label); }
331 void PureUI::openVerticalBox(const char* label)
332 { add_elem(UI_V_GROUP, label); }
333 void PureUI::closeBox()
334 { add_elem(UI_END_GROUP); }
335
336 void PureUI::run() {}
337
338 /******************************************************************************
339 *******************************************************************************
340
341 FAUST DSP
342
343 *******************************************************************************
344 *******************************************************************************/
345
346 //----------------------------------------------------------------
347 // abstract definition of a signal processor
348 //----------------------------------------------------------------
349
350 class dsp {
351 protected:
352 int fSamplingFreq;
353 public:
354 // internal freelist for custom voice allocation
355 dsp *prev, *next;
356 dsp() {}
357 virtual ~dsp() {}
358 virtual int getNumInputs() = 0;
359 virtual int getNumOutputs() = 0;
360 virtual void buildUserInterface(UI* interface) = 0;
361 virtual void init(int samplingRate) = 0;
362 virtual void compute(int len, double** inputs, double** outputs) = 0;
363 };
364
365 //----------------------------------------------------------------------------
366 // FAUST generated signal processor
367 //----------------------------------------------------------------------------
368
369 /* Define FAUSTFLOAT so that audio buffers and control values are always
370 represented as double pointers. This probably requires a recent Faust
371 version (0.9.9.6 or later should be ok). */
372
373 #define FAUSTFLOAT double
374
375 <<includeclass>>
376
377 #include <assert.h>
378
379 // Define this to get some debugging output.
380 //#define DEBUG
381 #ifdef DEBUG
382 #include <stdio.h>
383 #define FAUST_CN "mydsp"
384 #endif
385
386 /* Dynamic voice allocation. We go to some lengths here to make this as
387 realtime-friendly as possible. The idea is that we keep a pool of allocated
388 mydsp instances. When a dsp is freed with deldsp(), it's in fact never
389 deleted, but put at the end of a freelist from where it may eventually be
390 reused by a subsequent call to newdsp(). By these means, the number of
391 actual calls to malloc() can be kept to a minimum. In addition, a small
392 number of voices are preallocated in static memory (1 by default in the
393 present implementation, but you can set this at compile time by redefining
394 the NVOICES constant accordingly). If you choose a suitable NVOICES value,
395 chances are that your application may never need to allocate dsp instances
396 on the heap at all. Also, even if dsp instances have to be created
397 dynamically, they are allocated in chunks of NVOICES units, in order to
398 reduce the calls to malloc(). Thus we generally recommend to set NVOICES to
399 a value >1 which best suits your application. */
400
401 #ifndef NVOICES
402 #define NVOICES 1
403 #endif
404
405 // Make sure that NVOICES is at least 1.
406 #if NVOICES<1
407 #undefine NVOICES
408 #define NVOICES 1
409 #endif
410
411 struct dspmem_t {
412 char x[sizeof(mydsp)];
413 };
414
415 struct mem_t {
416 dspmem_t mem[NVOICES];
417 mem_t *next;
418 };
419
420 // statically and dynamically allocated dsp instances
421 static mem_t mem0, *mem;
422 // beginning and end of the freelist
423 static mydsp *first, *last;
424
425 /* This is supposed to be executed when the module gets unloaded. You'll need
426 a recent gcc version (or compatible) to make this work. */
427
428 void __attribute__ ((destructor)) mydsp_fini(void)
429 {
430 if (!mem) return;
431 mem = mem->next;
432 while (mem) {
433 mem_t *mem1 = mem->next;
434 free(mem); mem = mem1;
435 }
436 }
437
438 /* The class factory, used to create and destroy mydsp objects in the client.
439 This is implemented using C linkage to facilitate dlopen access. */
440
441 #include <new>
442
443 extern "C" mydsp *newdsp()
444 {
445 if (!mem) {
446 mem = &mem0; mem->next = 0;
447 // initialize the freelist with the statically allocated voices
448 mydsp *prev = 0, *next = (mydsp*)&mem->mem[0];
449 first = next;
450 for (int i = 0; i < NVOICES; i++) {
451 void *p = &mem->mem[i];
452 mydsp *d = new(p) mydsp;
453 d->prev = prev; prev = d;
454 d->next = ++next;
455 }
456 last = prev; last->next = 0;
457 #ifdef DEBUG
458 fprintf(stderr, ">>> %s: preallocated %d voices\n", FAUST_CN, NVOICES);
459 #endif
460 }
461 assert(mem);
462 if (!first) {
463 // allocate a new chunk of voices and add them to the freelist
464 mem_t *block = (mem_t*)calloc(1, sizeof(mem_t));
465 block->next = mem->next; mem->next = block;
466 mydsp *prev = 0, *next = (mydsp*)&block->mem[0];
467 first = next;
468 for (int i = 0; i < NVOICES; i++) {
469 void *p = &block->mem[i];;
470 mydsp *d = new(p) mydsp;
471 d->prev = prev; prev = d;
472 d->next = ++next;
473 }
474 last = prev; last->next = 0;
475 #ifdef DEBUG
476 fprintf(stderr, ">>> %s: allocated %d voices\n", FAUST_CN, NVOICES);
477 #endif
478 }
479 assert(first && last);
480 mydsp *d = first;
481 if (first == last) {
482 // freelist is now empty
483 first = last = 0;
484 } else {
485 // remove d from the freelist
486 first = (mydsp*)first->next;
487 }
488 d->prev = d->next = 0;
489 #ifdef DEBUG
490 fprintf(stderr, ">>> %s: allocating instance %p\n", FAUST_CN, d);
491 #endif
492 return d;
493 }
494
495 extern "C" void deldsp(mydsp* d)
496 {
497 #ifdef DEBUG
498 fprintf(stderr, ">>> %s: freeing instance %p\n", FAUST_CN, d);
499 #endif
500 // add d to the freelist
501 assert(!d->prev && !d->next);
502 if (last) {
503 last->next = d; d->prev = last; last = d;
504 } else
505 first = last = d;
506 }
507
508 extern "C" Meta *newmeta()
509 {
510 Meta *m = new Meta;
511 mydsp::metadata(m);
512 return m;
513 }
514
515 extern "C" void delmeta(Meta* m)
516 {
517 delete m;
518 }