User Manual first draft.
[Faustine.git] / interpreter / preprocessor / faust-0.9.47mr3 / architecture / supercollider.cpp
1 // If other than 'faust2sc --prefix Faust' is used, sed this as well:
2 #define SC_FAUST_PREFIX "Faust"
3
4 //-------------------------------------------------------------------
5 // FAUST architecture file for SuperCollider.
6 // Copyright (C) 2005-2008 Stefan Kersten.
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 // 02111-1307 USA
22 //-------------------------------------------------------------------
23
24 #include <ctype.h>
25 #include <limits.h>
26 #include <map>
27 #include <string>
28 #include <string.h>
29 #include <SC_PlugIn.h>
30
31 #if defined(__GNUC__) && __GNUC__ >= 4
32 # define FAUST_EXPORT __attribute__((visibility("default")))
33 #else
34 # define FAUST_EXPORT /* NOP */
35 #endif
36
37 //-------------------------------------------------------------------
38 // Generic min and max using C++ inline
39 //-------------------------------------------------------------------
40
41 inline int max (unsigned int a, unsigned int b) { return (a>b) ? a : b; }
42 inline int max (int a, int b) { return (a>b) ? a : b; }
43
44 inline long max (long a, long b) { return (a>b) ? a : b; }
45 inline long max (int a, long b) { return (a>b) ? a : b; }
46 inline long max (long a, int b) { return (a>b) ? a : b; }
47
48 inline float max (float a, float b) { return (a>b) ? a : b; }
49 inline float max (int a, float b) { return (a>b) ? a : b; }
50 inline float max (float a, int b) { return (a>b) ? a : b; }
51 inline float max (long a, float b) { return (a>b) ? a : b; }
52 inline float max (float a, long b) { return (a>b) ? a : b; }
53
54 inline double max (double a, double b) { return (a>b) ? a : b; }
55 inline double max (int a, double b) { return (a>b) ? a : b; }
56 inline double max (double a, int b) { return (a>b) ? a : b; }
57 inline double max (long a, double b) { return (a>b) ? a : b; }
58 inline double max (double a, long b) { return (a>b) ? a : b; }
59 inline double max (float a, double b) { return (a>b) ? a : b; }
60 inline double max (double a, float b) { return (a>b) ? a : b; }
61
62
63 inline int min (int a, int b) { return (a<b) ? a : b; }
64
65 inline long min (long a, long b) { return (a<b) ? a : b; }
66 inline long min (int a, long b) { return (a<b) ? a : b; }
67 inline long min (long a, int b) { return (a<b) ? a : b; }
68
69 inline float min (float a, float b) { return (a<b) ? a : b; }
70 inline float min (int a, float b) { return (a<b) ? a : b; }
71 inline float min (float a, int b) { return (a<b) ? a : b; }
72 inline float min (long a, float b) { return (a<b) ? a : b; }
73 inline float min (float a, long b) { return (a<b) ? a : b; }
74
75 inline double min (double a, double b) { return (a<b) ? a : b; }
76 inline double min (int a, double b) { return (a<b) ? a : b; }
77 inline double min (double a, int b) { return (a<b) ? a : b; }
78 inline double min (long a, double b) { return (a<b) ? a : b; }
79 inline double min (double a, long b) { return (a<b) ? a : b; }
80 inline double min (float a, double b) { return (a<b) ? a : b; }
81 inline double min (double a, float b) { return (a<b) ? a : b; }
82
83 inline int lsr (int x, int n) { return int(((unsigned int)x) >> n); }
84 inline int int2pow2 (int x) { int r=0; while ((1<<r)<x) r++; return r; }
85
86
87 /******************************************************************************
88 *******************************************************************************
89
90 VECTOR INTRINSICS
91
92 *******************************************************************************
93 *******************************************************************************/
94
95 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((unsigned)(calloc((nmemb*size)+15,sizeof(char)))+15 & 0xfffffff0); }
96 inline void *aligned_calloc(size_t nmemb, size_t size)
97 {
98 return (void*)((size_t)(calloc((nmemb*size)+15,sizeof(char)))+15 & ~15);
99 }
100
101 <<includeIntrinsic>>
102
103 /******************************************************************************
104 *******************************************************************************
105
106 META DATA
107
108 *******************************************************************************
109 *******************************************************************************/
110
111 struct Meta : std::map<std::string, std::string>
112 {
113 void declare(const char* key, const char* value)
114 {
115 (*this)[key] = value;
116 }
117 };
118
119 /******************************************************************************
120 *******************************************************************************
121
122 GRAPHIC USER INTERFACE
123
124 *******************************************************************************
125 *******************************************************************************/
126
127 //----------------------------------------------------------------------------
128 // Abstract user interface
129 //----------------------------------------------------------------------------
130
131 class UI
132 {
133 public:
134 virtual ~UI() { }
135
136 // active widgets
137 virtual void addButton(const char* label, float* zone) = 0;
138 virtual void addToggleButton(const char* label, float* zone) = 0;
139 virtual void addCheckButton(const char* label, float* zone) = 0;
140 virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
141 virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
142 virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step) = 0;
143
144 // passive widgets
145 virtual void addNumDisplay(const char* label, float* zone, int precision) = 0;
146 virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max) = 0;
147 virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) = 0;
148 virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) = 0;
149
150 // layout widgets
151 virtual void openFrameBox(const char* label) = 0;
152 virtual void openTabBox(const char* label) = 0;
153 virtual void openHorizontalBox(const char* label) = 0;
154 virtual void openVerticalBox(const char* label) = 0;
155 virtual void closeBox() = 0;
156
157 virtual void declare(float* zone, const char* key, const char* value) {}
158 };
159
160 //----------------------------------------------------------------------------
161 // Control counter
162 //----------------------------------------------------------------------------
163
164 class ControlCounter : public UI
165 {
166 public:
167 ControlCounter()
168 : mNumControlInputs(0),
169 mNumControlOutputs(0)
170 { }
171
172 size_t getNumControls() const { return getNumControlInputs(); }
173 size_t getNumControlInputs() const { return mNumControlInputs; }
174 size_t getNumControlOutputs() const { return mNumControlOutputs; }
175
176 // active widgets
177 virtual void addButton(const char* label, float* zone)
178 { addControlInput(); }
179 virtual void addToggleButton(const char* label, float* zone)
180 { addControlInput(); }
181 virtual void addCheckButton(const char* label, float* zone)
182 { addControlInput(); }
183 virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step)
184 { addControlInput(); }
185 virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step)
186 { addControlInput(); }
187 virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step)
188 { addControlInput(); }
189
190 // passive widgets
191 virtual void addNumDisplay(const char* label, float* zone, int precision) { addControlOutput(); }
192 virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max) { addControlOutput(); }
193 virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) { addControlOutput(); }
194 virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) { addControlOutput(); }
195
196 // layout widgets
197 virtual void openFrameBox(const char* label) { }
198 virtual void openTabBox(const char* label) { }
199 virtual void openHorizontalBox(const char* label) { }
200 virtual void openVerticalBox(const char* label) { }
201 virtual void closeBox() { }
202
203 protected:
204 void addControlInput() { mNumControlInputs++; }
205 void addControlOutput() { mNumControlOutputs++; }
206
207 private:
208 size_t mNumControlInputs;
209 size_t mNumControlOutputs;
210 };
211
212 //----------------------------------------------------------------------------
213 // UI control
214 //----------------------------------------------------------------------------
215
216 struct Control
217 {
218 typedef void (*UpdateFunction)(Control* self, float value);
219
220 UpdateFunction updateFunction;
221 float min, max, step;
222 float* zone;
223
224 inline void update(float value)
225 {
226 (*updateFunction)(this, value);
227 }
228
229 static void simpleUpdate(Control* self, float value)
230 {
231 *self->zone = value;
232 }
233 static void boundedUpdate(Control* self, float value)
234 {
235 *self->zone = sc_clip(value, self->min, self->max);
236 }
237 };
238
239 //----------------------------------------------------------------------------
240 // Control allocator
241 //----------------------------------------------------------------------------
242
243 class ControlAllocator : public UI
244 {
245 public:
246 ControlAllocator(Control* controls)
247 : mControls(controls)
248 { }
249
250 // active widgets
251 virtual void addButton(const char* label, float* zone)
252 { addSimpleControl(zone); }
253 virtual void addToggleButton(const char* label, float* zone)
254 { addSimpleControl(zone); }
255 virtual void addCheckButton(const char* label, float* zone)
256 { addSimpleControl(zone); }
257 virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step)
258 { addBoundedControl(zone, min, max, step); }
259 virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step)
260 { addBoundedControl(zone, min, max, step); }
261 virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step)
262 { addBoundedControl(zone, min, max, step); }
263
264 // passive widgets
265 virtual void addNumDisplay(const char* label, float* zone, int precision) { }
266 virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max) { }
267 virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) { }
268 virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) { }
269
270 // layout widgets
271 virtual void openFrameBox(const char* label) { }
272 virtual void openTabBox(const char* label) { }
273 virtual void openHorizontalBox(const char* label) { }
274 virtual void openVerticalBox(const char* label) { }
275 virtual void closeBox() { }
276
277 private:
278 void addControl(Control::UpdateFunction updateFunction, float* zone, float min, float max, float step)
279 {
280 Control* ctrl = mControls++;
281 ctrl->updateFunction = updateFunction;
282 ctrl->min = min;
283 ctrl->max = max;
284 ctrl->step = step;
285 ctrl->zone = zone;
286 }
287 void addSimpleControl(float* zone)
288 {
289 addControl(Control::simpleUpdate, zone, 0.f, 0.f, 0.f);
290 }
291 void addBoundedControl(float* zone, float min, float max, float step)
292 {
293 addControl(Control::boundedUpdate, zone, min, max, step);
294 }
295
296 private:
297 Control* mControls;
298 };
299
300
301 /******************************************************************************
302 *******************************************************************************
303
304 FAUST DSP
305
306 *******************************************************************************
307 *******************************************************************************/
308
309 //----------------------------------------------------------------------------
310 // Abstract DSP interface
311 //----------------------------------------------------------------------------
312
313 class dsp
314 {
315 public:
316 virtual ~dsp();
317 virtual int getNumInputs() = 0;
318 virtual int getNumOutputs() = 0;
319 virtual void buildUserInterface(UI* interface) = 0;
320 virtual void init(int samplingRate) = 0;
321 virtual void compute(int len, float** inputs, float** outputs) = 0;
322
323 protected:
324 int fSamplingFreq;
325 };
326
327 dsp::~dsp() { }
328
329 //----------------------------------------------------------------------------
330 // FAUST generated code
331 //----------------------------------------------------------------------------
332
333 <<includeclass>>
334
335
336 /******************************************************************************
337 *******************************************************************************
338
339 SUPERCOLLIDER DSP INTERFACE
340
341 *******************************************************************************
342 *******************************************************************************/
343
344 struct Faust : public Unit
345 {
346 // Faust dsp instance
347 mydsp mDSP;
348 // Buffers for control to audio rate conversion
349 float** mInBufCopy;
350 float* mInBufValue;
351 // Controls
352 size_t mNumControls;
353 // NOTE: This needs to be the last field!
354 //
355 // The unit allocates additional memory according to the number
356 // of controls.
357 Control mControls[0];
358
359 int getNumAudioInputs() { return mDSP.getNumInputs(); }
360 };
361
362 // Global state
363
364 static size_t g_numControls; // Number of controls
365 static const char* g_unitName; // Unit name
366
367 // Initialize the global state with unit name and sample rate.
368 void initState(const std::string& name, int sampleRate);
369
370 // Return the unit size in bytes, including static fields and controls.
371 static size_t unitSize();
372
373 // Convert a file name to a valid unit name.
374 static std::string fileNameToUnitName(const std::string& fileName);
375
376 // Convert the XML unit name to a valid class name.
377 static std::string normalizeClassName(const std::string& name);
378
379 void initState(const std::string& name, int sampleRate)
380 {
381 g_unitName = strdup(name.c_str());
382
383 mydsp* dsp = new mydsp;
384 ControlCounter* cc = new ControlCounter;
385
386 dsp->classInit(sampleRate);
387 dsp->buildUserInterface(cc);
388 g_numControls = cc->getNumControls();
389
390 delete dsp;
391 delete cc;
392 }
393
394 size_t unitSize()
395 {
396 return sizeof(Faust) + g_numControls * sizeof(Control);
397 }
398
399 std::string fileNameToUnitName(const std::string& fileName)
400 {
401 // Extract basename
402 size_t lpos = fileName.rfind('/', fileName.size());
403 if (lpos == std::string::npos) lpos = 0;
404 else lpos += 1;
405 // Strip extension(s)
406 size_t rpos = fileName.find('.', lpos);
407 // Return substring
408 return fileName.substr(lpos, rpos > lpos ? rpos - lpos : 0);
409 }
410
411 // Globals
412
413 static InterfaceTable *ft;
414
415 // The SuperCollider UGen class name generated here must match
416 // that generated by faust2sc:
417 static std::string normalizeClassName(const std::string& name)
418 {
419 std::string s;
420 char c;
421
422 unsigned int i=0;
423 bool upnext=true;
424 while (c=name[i++]) {
425 if (upnext) { c = toupper(c); upnext=false; }
426 if ( (c == '_') || (c == '-') || isspace(c)) { upnext=true; continue; }
427 s += c;
428 if (i > 31) { break; }
429 }
430 return s;
431 }
432
433 extern "C"
434 {
435 #ifdef SC_API_EXPORT
436 int api_version(void);
437 #endif
438 void load(InterfaceTable*);
439 void Faust_next(Faust*, int);
440 void Faust_next_copy(Faust*, int);
441 void Faust_next_clear(Faust*, int);
442 void Faust_Ctor(Faust*);
443 void Faust_Dtor(Faust*);
444 };
445
446 inline static void fillBuffer(float* dst, int n, float v)
447 {
448 Fill(n, dst, v);
449 }
450
451 inline static void fillBuffer(float* dst, int n, float v0, float v1)
452 {
453 Fill(n, dst, v0, (v1 - v0) / n);
454 }
455
456 inline static void copyBuffer(float* dst, int n, float* src)
457 {
458 Copy(n, dst, src);
459 }
460
461 inline static void Faust_updateControls(Faust* unit)
462 {
463 Control* controls = unit->mControls;
464 int numControls = unit->mNumControls;
465 int curControl = unit->mDSP.getNumInputs();
466 for (int i=0; i < numControls; ++i) {
467 float value = IN0(curControl);
468 (controls++)->update(value);
469 curControl++;
470 }
471 }
472
473 void Faust_next(Faust* unit, int inNumSamples)
474 {
475 // update controls
476 Faust_updateControls(unit);
477 // dsp computation
478 unit->mDSP.compute(inNumSamples, unit->mInBuf, unit->mOutBuf);
479 }
480
481 void Faust_next_copy(Faust* unit, int inNumSamples)
482 {
483 // update controls
484 Faust_updateControls(unit);
485 // Copy buffers
486 for (int i = 0; i < unit->getNumAudioInputs(); ++i) {
487 float* b = unit->mInBufCopy[i];
488 if (INRATE(i) == calc_FullRate) {
489 // Audio rate: copy buffer
490 copyBuffer(b, inNumSamples, unit->mInBuf[i]);
491 } else {
492 // Control rate: linearly interpolate input
493 float v1 = IN0(i);
494 fillBuffer(b, inNumSamples, unit->mInBufValue[i], v1);
495 unit->mInBufValue[i] = v1;
496 }
497 }
498 // dsp computation
499 unit->mDSP.compute(inNumSamples, unit->mInBufCopy, unit->mOutBuf);
500 }
501
502 void Faust_next_clear(Faust* unit, int inNumSamples)
503 {
504 ClearUnitOutputs(unit, inNumSamples);
505 }
506
507 void Faust_Ctor(Faust* unit) // module constructor
508 {
509 // init dsp
510 unit->mDSP.instanceInit((int)SAMPLERATE);
511
512 // allocate controls
513 unit->mNumControls = g_numControls;
514 ControlAllocator ca(unit->mControls);
515 unit->mDSP.buildUserInterface(&ca);
516 unit->mInBufCopy = 0;
517 unit->mInBufValue = 0;
518
519 // check input/output channel configuration
520 const size_t numInputs = unit->mDSP.getNumInputs() + unit->mNumControls;
521 const size_t numOutputs = unit->mDSP.getNumOutputs();
522
523 bool channelsValid = (numInputs == unit->mNumInputs)
524 && (numOutputs == unit->mNumOutputs);
525
526 if (channelsValid) {
527 bool rateValid = true;
528 for (int i = 0; i < unit->getNumAudioInputs(); ++i) {
529 if (INRATE(i) != calc_FullRate) {
530 rateValid = false;
531 break;
532 }
533 }
534 if (rateValid) {
535 SETCALC(Faust_next);
536 } else {
537 unit->mInBufCopy = (float**)RTAlloc(unit->mWorld, unit->getNumAudioInputs()*sizeof(float*));
538 // Allocate memory for input buffer copies (numInputs * bufLength)
539 // and linear interpolation state (numInputs)
540 // = numInputs * (bufLength + 1)
541 unit->mInBufValue = (float*)RTAlloc(unit->mWorld, unit->getNumAudioInputs()*sizeof(float));
542 float* mem = (float*)RTAlloc(unit->mWorld, unit->getNumAudioInputs()*BUFLENGTH*sizeof(float));
543 // Aquire memory for interpolator state.
544 for (int i=0; i < unit->getNumAudioInputs(); ++i) {
545 // Initialize interpolator.
546 unit->mInBufValue[i] = IN0(i);
547 // Aquire buffer memory.
548 unit->mInBufCopy[i] = mem;
549 mem += BUFLENGTH;
550 }
551 SETCALC(Faust_next_copy);
552 }
553 #if !defined(NDEBUG)
554 Print("Faust[%s]:\n", g_unitName);
555 Print(" Inputs: %d\n"
556 " Outputs: %d\n"
557 " Callback: %s\n",
558 numInputs, numOutputs,
559 unit->mCalcFunc == (UnitCalcFunc)Faust_next ? "zero-copy" : "copy");
560 #endif
561 } else {
562 Print("Faust[%s]:\n", g_unitName);
563 Print(" Input/Output channel mismatch\n"
564 " Inputs: faust %d, unit %d\n"
565 " Outputs: faust %d, unit %d\n",
566 numInputs, unit->mNumInputs,
567 numOutputs, unit->mNumOutputs);
568 Print(" Generating silence ...\n");
569 SETCALC(Faust_next_clear);
570 }
571 }
572
573 void Faust_Dtor(Faust* unit) // module destructor
574 {
575 if (unit->mInBufValue) {
576 RTFree(unit->mWorld, unit->mInBufValue);
577 }
578 if (unit->mInBufCopy) {
579 if (unit->mInBufCopy[0]) {
580 RTFree(unit->mWorld, unit->mInBufCopy[0]);
581 }
582 RTFree(unit->mWorld, unit->mInBufCopy);
583 }
584 }
585
586 #ifdef SC_API_EXPORT
587 FAUST_EXPORT int api_version(void) { return sc_api_version; }
588 #endif
589
590 FAUST_EXPORT void load(InterfaceTable* inTable)
591 {
592
593 ft = inTable;
594
595 Meta meta;
596 mydsp::metadata(&meta);
597
598 std::string name = meta["name"];
599
600 if (name.empty()) {
601 name = fileNameToUnitName(__FILE__);
602 }
603
604 name = normalizeClassName(name);
605
606 #if !defined(NDEBUG) & defined(SC_API_EXPORT)
607 Print("*** Faust: supercollider.cpp: sc_api_version = %d\n",sc_api_version);
608 #endif
609
610 if (name.empty()) {
611 // Catch empty name
612 Print("*** Faust: supercollider.cpp: "
613 "Could not create unit-generator module name from filename\n"
614 " bailing out ...\n");
615 return;
616 }
617
618 if (strncmp(name.c_str(),SC_FAUST_PREFIX,strlen(SC_FAUST_PREFIX))!=0){
619 name = SC_FAUST_PREFIX + name;
620 }
621
622 // Initialize global data
623 // TODO: Use correct sample rate
624 initState(name, 48000);
625
626 // Register ugen
627 (*ft->fDefineUnit)(
628 (char*)name.c_str(),
629 unitSize(),
630 (UnitCtorFunc)&Faust_Ctor,
631 (UnitDtorFunc)&Faust_Dtor,
632 kUnitDef_CantAliasInputsToOutputs
633 );
634
635 #if !defined(NDEBUG)
636 Print("Faust: %s numControls=%d\n", name.c_str(), g_numControls);
637 #endif // NDEBUG
638 }
639
640 // EOF