1 // If other than 'faust2sc --prefix Faust' is used, sed this as well:
2 #define SC_FAUST_PREFIX "Faust"
4 //-------------------------------------------------------------------
5 // FAUST architecture file for SuperCollider.
6 // Copyright (C) 2005-2008 Stefan Kersten.
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.
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.
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
22 //-------------------------------------------------------------------
29 #include <SC_PlugIn.h>
31 #if defined(__GNUC__) && __GNUC__ >= 4
32 # define FAUST_EXPORT __attribute__((visibility("default")))
34 # define FAUST_EXPORT /* NOP */
37 //-------------------------------------------------------------------
38 // Generic min and max using C++ inline
39 //-------------------------------------------------------------------
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
; }
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
; }
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
; }
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
; }
63 inline int min (int a
, int b
) { return (a
<b
) ? a
: b
; }
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
; }
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
; }
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
; }
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
; }
87 /******************************************************************************
88 *******************************************************************************
92 *******************************************************************************
93 *******************************************************************************/
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
)
98 return (void*)((size_t)(calloc((nmemb
*size
)+15,sizeof(char)))+15 & ~15);
103 /******************************************************************************
104 *******************************************************************************
108 *******************************************************************************
109 *******************************************************************************/
111 struct Meta
: std::map
<std::string
, std::string
>
113 void declare(const char* key
, const char* value
)
115 (*this)[key
] = value
;
119 /******************************************************************************
120 *******************************************************************************
122 GRAPHIC USER INTERFACE
124 *******************************************************************************
125 *******************************************************************************/
127 //----------------------------------------------------------------------------
128 // Abstract user interface
129 //----------------------------------------------------------------------------
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;
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;
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;
157 virtual void declare(float* zone
, const char* key
, const char* value
) {}
160 //----------------------------------------------------------------------------
162 //----------------------------------------------------------------------------
164 class ControlCounter
: public UI
168 : mNumControlInputs(0),
169 mNumControlOutputs(0)
172 size_t getNumControls() const { return getNumControlInputs(); }
173 size_t getNumControlInputs() const { return mNumControlInputs
; }
174 size_t getNumControlOutputs() const { return mNumControlOutputs
; }
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(); }
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(); }
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() { }
204 void addControlInput() { mNumControlInputs
++; }
205 void addControlOutput() { mNumControlOutputs
++; }
208 size_t mNumControlInputs
;
209 size_t mNumControlOutputs
;
212 //----------------------------------------------------------------------------
214 //----------------------------------------------------------------------------
218 typedef void (*UpdateFunction
)(Control
* self
, float value
);
220 UpdateFunction updateFunction
;
221 float min
, max
, step
;
224 inline void update(float value
)
226 (*updateFunction
)(this, value
);
229 static void simpleUpdate(Control
* self
, float value
)
233 static void boundedUpdate(Control
* self
, float value
)
235 *self
->zone
= sc_clip(value
, self
->min
, self
->max
);
239 //----------------------------------------------------------------------------
241 //----------------------------------------------------------------------------
243 class ControlAllocator
: public UI
246 ControlAllocator(Control
* controls
)
247 : mControls(controls
)
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
); }
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
) { }
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() { }
278 void addControl(Control::UpdateFunction updateFunction
, float* zone
, float min
, float max
, float step
)
280 Control
* ctrl
= mControls
++;
281 ctrl
->updateFunction
= updateFunction
;
287 void addSimpleControl(float* zone
)
289 addControl(Control::simpleUpdate
, zone
, 0.f
, 0.f
, 0.f
);
291 void addBoundedControl(float* zone
, float min
, float max
, float step
)
293 addControl(Control::boundedUpdate
, zone
, min
, max
, step
);
301 /******************************************************************************
302 *******************************************************************************
306 *******************************************************************************
307 *******************************************************************************/
309 //----------------------------------------------------------------------------
310 // Abstract DSP interface
311 //----------------------------------------------------------------------------
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;
329 //----------------------------------------------------------------------------
330 // FAUST generated code
331 //----------------------------------------------------------------------------
336 /******************************************************************************
337 *******************************************************************************
339 SUPERCOLLIDER DSP INTERFACE
341 *******************************************************************************
342 *******************************************************************************/
344 struct Faust
: public Unit
346 // Faust dsp instance
348 // Buffers for control to audio rate conversion
353 // NOTE: This needs to be the last field!
355 // The unit allocates additional memory according to the number
357 Control mControls
[0];
359 int getNumAudioInputs() { return mDSP
.getNumInputs(); }
364 static size_t g_numControls
; // Number of controls
365 static const char* g_unitName
; // Unit name
367 // Initialize the global state with unit name and sample rate.
368 void initState(const std::string
& name
, int sampleRate
);
370 // Return the unit size in bytes, including static fields and controls.
371 static size_t unitSize();
373 // Convert a file name to a valid unit name.
374 static std::string
fileNameToUnitName(const std::string
& fileName
);
376 // Convert the XML unit name to a valid class name.
377 static std::string
normalizeClassName(const std::string
& name
);
379 void initState(const std::string
& name
, int sampleRate
)
381 g_unitName
= strdup(name
.c_str());
383 mydsp
* dsp
= new mydsp
;
384 ControlCounter
* cc
= new ControlCounter
;
386 dsp
->classInit(sampleRate
);
387 dsp
->buildUserInterface(cc
);
388 g_numControls
= cc
->getNumControls();
396 return sizeof(Faust
) + g_numControls
* sizeof(Control
);
399 std::string
fileNameToUnitName(const std::string
& fileName
)
402 size_t lpos
= fileName
.rfind('/', fileName
.size());
403 if (lpos
== std::string::npos
) lpos
= 0;
405 // Strip extension(s)
406 size_t rpos
= fileName
.find('.', lpos
);
408 return fileName
.substr(lpos
, rpos
> lpos
? rpos
- lpos
: 0);
413 static InterfaceTable
*ft
;
415 // The SuperCollider UGen class name generated here must match
416 // that generated by faust2sc:
417 static std::string
normalizeClassName(const std::string
& name
)
424 while (c
=name
[i
++]) {
425 if (upnext
) { c
= toupper(c
); upnext
=false; }
426 if ( (c
== '_') || (c
== '-') || isspace(c
)) { upnext
=true; continue; }
428 if (i
> 31) { break; }
436 int api_version(void);
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
*);
446 inline static void fillBuffer(float* dst
, int n
, float v
)
451 inline static void fillBuffer(float* dst
, int n
, float v0
, float v1
)
453 Fill(n
, dst
, v0
, (v1
- v0
) / n
);
456 inline static void copyBuffer(float* dst
, int n
, float* src
)
461 inline static void Faust_updateControls(Faust
* unit
)
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
);
473 void Faust_next(Faust
* unit
, int inNumSamples
)
476 Faust_updateControls(unit
);
478 unit
->mDSP
.compute(inNumSamples
, unit
->mInBuf
, unit
->mOutBuf
);
481 void Faust_next_copy(Faust
* unit
, int inNumSamples
)
484 Faust_updateControls(unit
);
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
]);
492 // Control rate: linearly interpolate input
494 fillBuffer(b
, inNumSamples
, unit
->mInBufValue
[i
], v1
);
495 unit
->mInBufValue
[i
] = v1
;
499 unit
->mDSP
.compute(inNumSamples
, unit
->mInBufCopy
, unit
->mOutBuf
);
502 void Faust_next_clear(Faust
* unit
, int inNumSamples
)
504 ClearUnitOutputs(unit
, inNumSamples
);
507 void Faust_Ctor(Faust
* unit
) // module constructor
510 unit
->mDSP
.instanceInit((int)SAMPLERATE
);
513 unit
->mNumControls
= g_numControls
;
514 ControlAllocator
ca(unit
->mControls
);
515 unit
->mDSP
.buildUserInterface(&ca
);
516 unit
->mInBufCopy
= 0;
517 unit
->mInBufValue
= 0;
519 // check input/output channel configuration
520 const size_t numInputs
= unit
->mDSP
.getNumInputs() + unit
->mNumControls
;
521 const size_t numOutputs
= unit
->mDSP
.getNumOutputs();
523 bool channelsValid
= (numInputs
== unit
->mNumInputs
)
524 && (numOutputs
== unit
->mNumOutputs
);
527 bool rateValid
= true;
528 for (int i
= 0; i
< unit
->getNumAudioInputs(); ++i
) {
529 if (INRATE(i
) != calc_FullRate
) {
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
;
551 SETCALC(Faust_next_copy
);
554 Print("Faust[%s]:\n", g_unitName
);
555 Print(" Inputs: %d\n"
558 numInputs
, numOutputs
,
559 unit
->mCalcFunc
== (UnitCalcFunc
)Faust_next
? "zero-copy" : "copy");
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
);
573 void Faust_Dtor(Faust
* unit
) // module destructor
575 if (unit
->mInBufValue
) {
576 RTFree(unit
->mWorld
, unit
->mInBufValue
);
578 if (unit
->mInBufCopy
) {
579 if (unit
->mInBufCopy
[0]) {
580 RTFree(unit
->mWorld
, unit
->mInBufCopy
[0]);
582 RTFree(unit
->mWorld
, unit
->mInBufCopy
);
587 FAUST_EXPORT
int api_version(void) { return sc_api_version
; }
590 FAUST_EXPORT
void load(InterfaceTable
* inTable
)
596 mydsp::metadata(&meta
);
598 std::string name
= meta
["name"];
601 name
= fileNameToUnitName(__FILE__
);
604 name
= normalizeClassName(name
);
606 #if !defined(NDEBUG) & defined(SC_API_EXPORT)
607 Print("*** Faust: supercollider.cpp: sc_api_version = %d\n",sc_api_version
);
612 Print("*** Faust: supercollider.cpp: "
613 "Could not create unit-generator module name from filename\n"
614 " bailing out ...\n");
618 if (strncmp(name
.c_str(),SC_FAUST_PREFIX
,strlen(SC_FAUST_PREFIX
))!=0){
619 name
= SC_FAUST_PREFIX
+ name
;
622 // Initialize global data
623 // TODO: Use correct sample rate
624 initState(name
, 48000);
630 (UnitCtorFunc
)&Faust_Ctor
,
631 (UnitDtorFunc
)&Faust_Dtor
,
632 kUnitDef_CantAliasInputsToOutputs
636 Print("Faust: %s numControls=%d\n", name
.c_str(), g_numControls
);