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.
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.
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
20 ************************************************************************
21 ************************************************************************/
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
35 typedef pair
<const char*,const char*> strpair
;
40 void declare (const char* key
, const char* value
)
41 { data
.push_back(strpair(key
, value
)); }
44 //-------------------------------------------------------------------
45 // Generic min and max using c++ inline
46 //-------------------------------------------------------------------
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
; }
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
; }
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
; }
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
; }
70 inline int min (int a
, int b
) { return (a
<b
) ? a
: b
; }
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
; }
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
; }
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
; }
90 // abs is now predefined
91 //template<typename T> T abs (T a) { return (a<T(0)) ? -a : a; }
93 inline int lsr (int x
, int n
) { return int(((unsigned int)x
) >> n
); }
95 /******************************************************************************
96 *******************************************************************************
100 *******************************************************************************
101 *******************************************************************************/
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); }
108 /******************************************************************************
109 *******************************************************************************
111 ABSTRACT USER INTERFACE
113 *******************************************************************************
114 *******************************************************************************/
121 UI() : fStopped(false) {}
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;
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;
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;
142 virtual void run() = 0;
144 void stop() { fStopped
= true; }
145 bool stopped() { return fStopped
; }
147 virtual void declare(double* zone
, const char* key
, const char* value
) {}
150 /***************************************************************************
152 ***************************************************************************/
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
166 float init
, min
, max
, step
;
169 class PureUI
: public UI
174 map
< int, list
<strpair
> > metadata
;
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
);
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
);
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
);
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();
208 virtual void declare(double* zone
, const char* key
, const char* value
);
219 if (elems
) free(elems
);
222 void PureUI::declare(double* zone
, const char* key
, const char* value
)
224 map
< int, list
<strpair
> >::iterator it
= metadata
.find(nelems
);
225 if (it
!= metadata
.end())
226 it
->second
.push_back(strpair(key
, value
));
228 metadata
[nelems
] = list
<strpair
>(1, strpair(key
, value
));
231 inline void PureUI::add_elem(ui_elem_type_t type
, const char *label
)
233 ui_elem_t
*elems1
= (ui_elem_t
*)realloc(elems
, (nelems
+1)*sizeof(ui_elem_t
));
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;
249 inline void PureUI::add_elem(ui_elem_type_t type
, const char *label
, double *zone
)
251 ui_elem_t
*elems1
= (ui_elem_t
*)realloc(elems
, (nelems
+1)*sizeof(ui_elem_t
));
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;
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
)
270 ui_elem_t
*elems1
= (ui_elem_t
*)realloc(elems
, (nelems
+1)*sizeof(ui_elem_t
));
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
;
286 inline void PureUI::add_elem(ui_elem_type_t type
, const char *label
, double *zone
,
287 float min
, float max
)
289 ui_elem_t
*elems1
= (ui_elem_t
*)realloc(elems
, (nelems
+1)*sizeof(ui_elem_t
));
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;
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
); }
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
); }
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
); }
336 void PureUI::run() {}
338 /******************************************************************************
339 *******************************************************************************
343 *******************************************************************************
344 *******************************************************************************/
346 //----------------------------------------------------------------
347 // abstract definition of a signal processor
348 //----------------------------------------------------------------
354 // internal freelist for custom voice allocation
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;
365 //----------------------------------------------------------------------------
366 // FAUST generated signal processor
367 //----------------------------------------------------------------------------
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). */
373 #define FAUSTFLOAT double
379 // Define this to get some debugging output.
383 #define FAUST_CN "mydsp"
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. */
405 // Make sure that NVOICES is at least 1.
412 char x
[sizeof(mydsp
)];
416 dspmem_t mem
[NVOICES
];
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
;
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. */
428 void __attribute__ ((destructor
)) mydsp_fini(void)
433 mem_t
*mem1
= mem
->next
;
434 free(mem
); mem
= mem1
;
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. */
443 extern "C" mydsp
*newdsp()
446 mem
= &mem0
; mem
->next
= 0;
447 // initialize the freelist with the statically allocated voices
448 mydsp
*prev
= 0, *next
= (mydsp
*)&mem
->mem
[0];
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
;
456 last
= prev
; last
->next
= 0;
458 fprintf(stderr
, ">>> %s: preallocated %d voices\n", FAUST_CN
, NVOICES
);
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];
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
;
474 last
= prev
; last
->next
= 0;
476 fprintf(stderr
, ">>> %s: allocated %d voices\n", FAUST_CN
, NVOICES
);
479 assert(first
&& last
);
482 // freelist is now empty
485 // remove d from the freelist
486 first
= (mydsp
*)first
->next
;
488 d
->prev
= d
->next
= 0;
490 fprintf(stderr
, ">>> %s: allocating instance %p\n", FAUST_CN
, d
);
495 extern "C" void deldsp(mydsp
* d
)
498 fprintf(stderr
, ">>> %s: freeing instance %p\n", FAUST_CN
, d
);
500 // add d to the freelist
501 assert(!d
->prev
&& !d
->next
);
503 last
->next
= d
; d
->prev
= last
; last
= d
;
508 extern "C" Meta
*newmeta()
515 extern "C" void delmeta(Meta
* m
)