1 /************************************************************************
3 IMPORTANT NOTE : this file contains two clearly delimited sections :
4 the ARCHITECTURE section (in two parts) and the USER section. Each section
5 is governed by its own copyright and license. Please check individually
6 each section for license and copyright information.
7 *************************************************************************/
9 /*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/
11 /************************************************************************
12 FAUST Architecture File
13 Copyright (C) 2010-2011 Travis Skare
14 ---------------------------------------------------------------------
15 This Architecture section is free software; you can redistribute it
16 and/or modify it under the terms of the GNU General Public License
17 as published by the Free Software Foundation; either version 3 of
18 the License, or (at your option) any later version.
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program; If not, see <http://www.gnu.org/licenses/>.
28 EXCEPTION : As a special exception, you may create a larger work that
29 contains this FAUST architecture section and distribute
30 that work under terms of your choice, so long as that this FAUST
31 architecture section is not modified.
34 ************************************************************************
35 ************************************************************************/
37 // Faust -> Alchemy -> ActionScript C++ Architecture File
40 // math.h is needed for many faust examples, so include it.
41 // otherwise we have to hand-edit c++.
47 #define max(x,y) (((x)>(y)) ? (x) : (y))
48 #define min(x,y) (((x)<(y)) ? (x) : (y))
50 // abs is now predefined
51 //template<typename T> T abs (T a) { return (a<T(0)) ? -a : a; }
53 inline int lsr (int x
, int n
) { return int(((unsigned int)x
) >> n
); }
56 /******************************************************************************
57 *******************************************************************************
61 *******************************************************************************
62 *******************************************************************************/
64 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((unsigned)(calloc((nmemb*size)+15,sizeof(char)))+15 & 0xfffffff0); }
65 inline void *aligned_calloc(size_t nmemb
, size_t size
) { return (void*)((size_t)(calloc((nmemb
*size
)+15,sizeof(char)))+15 & ~15); }
69 /******************************************************************************
70 *******************************************************************************
72 ABSTRACT USER INTERFACE
74 *******************************************************************************
75 *******************************************************************************/
82 UI() : fStopped(false) {}
85 virtual void addButton(char* label
, float* zone
) = 0;
86 virtual void addToggleButton(char* label
, float* zone
) = 0;
87 virtual void addCheckButton(char* label
, float* zone
) = 0;
88 virtual void addVerticalSlider(char* label
, float* zone
, float init
, float min
, float max
, float step
) = 0;
89 virtual void addHorizontalSlider(char* label
, float* zone
, float init
, float min
, float max
, float step
) = 0;
90 virtual void addNumEntry(char* label
, float* zone
, float init
, float min
, float max
, float step
) = 0;
92 virtual void openFrameBox(char* label
) = 0;
93 virtual void openTabBox(char* label
) = 0;
94 virtual void openHorizontalBox(char* label
) = 0;
95 virtual void openVerticalBox(char* label
) = 0;
96 virtual void closeBox() = 0;
98 virtual void run() = 0;
100 void stop() { fStopped
= true; }
101 bool stopped() { return fStopped
; }
105 ////// Implementation of UI
107 // Faust UI hookup is straightforward
108 // We subclass from UI and then these methods will get called by compiled
109 // Faust which assembles controls. We handle all UI as needed, and when
110 // things changed we need to set *zone=(some value).
111 // This is a little more complicated when jumping between alchemy/script.
112 // So rather than deal with marshalling pointers, just cheat and use an int:pointer map.
113 // NOTE: I should have used an STL map but that wasn't working back when I used gcc.
114 // I'll investigate since that would clean up the code quite a bit.
116 // upper bound on number of controls
117 #define MAX_CONTROLS 25
118 // map of unique ui control id to a float* where faust reads the corresponding value.
119 static float* uidToZone
[MAX_CONTROLS
];
120 // Counter that assigns control IDs.
121 static int uiMap_id
= 0;
123 // I wasn't able to properly thunk the UI actionscrpit methods to C.
124 // Since we know the complete UI at the time of creation, a collection of
125 // ui creation info is passed back from faust_init, and actionscript
126 // can read it and create the UI.
127 // This is a little messy and was done last-minute.
128 const int TYPE_BUTTON
= 0;
129 const int TYPE_TOGGLE
= 1;
130 const int TYPE_SLIDER
= 2;
131 // max length for a label - more than 50 chars will get cut.
136 char label
[LABEL_LEN
+1];
142 uiElemInfo uielems
[MAX_CONTROLS
];
143 static int uielems_size
= 0;
145 // todo: stdio.h has strncpy, I just got paranoid about extra includes making the code bigger :)
146 void strcopy(char *src
, char *dst
) {
147 dst
[LABEL_LEN
] = '\0';
148 for (int i
= 0; i
< LABEL_LEN
; ++i
) {
149 if (0 == (dst
[i
] = src
[i
])) return;
153 void BuildUIArray(AS3_Val
&array
) {
154 for (int i
= 0; i
< uielems_size
; ++i
) {
155 AS3_Val result
= AS3_Object( "type:AS3ValType,id:AS3ValType,label:AS3ValType,min:AS3ValType,max:AS3ValType,init:AS3ValType,step:AS3ValType",
156 AS3_Int(uielems
[i
].type
),
157 AS3_Int(uielems
[i
].id
),
158 AS3_String(uielems
[i
].label
),
159 AS3_Number(uielems
[i
].min
),
160 AS3_Number(uielems
[i
].max
),
161 AS3_Number(uielems
[i
].init
),
162 AS3_Number(uielems
[i
].step
)
164 AS3_Set(array
, AS3_Int(i
), result
);
165 // decrease refcount? todo: this may leak memory...
166 //AS3_Release(result);
170 class ActionScriptUI
: public UI
{
176 virtual ~ActionScriptUI() {
179 // Pass in a zone, get back a unique ID.
180 int registerControl(float *zone
) {
183 uidToZone
[uiMap_id
] = zone
;
187 // Called from Flash when any control is updated.
188 // Results will take effect on the next dsp callback
189 // since everything runs in the same thread.
190 void updateControl(int id
, float value
) {
191 *(uidToZone
[id
]) = value
;
195 virtual void addButton(char* label
, float* zone
) {
196 int id
= registerControl(zone
);
197 uielems
[uielems_size
].type
= TYPE_BUTTON
;
198 uielems
[uielems_size
].id
= id
;
199 strcopy(label
, uielems
[uielems_size
].label
);
200 uielems
[uielems_size
].min
= 0;
201 uielems
[uielems_size
].max
= 0;
202 uielems
[uielems_size
].init
= 0;
203 uielems
[uielems_size
].step
= 0;
206 virtual void addToggleButton(char* label
, float* zone
) {
207 int id
= registerControl(zone
);
208 uielems
[uielems_size
].type
= TYPE_TOGGLE
;
209 uielems
[uielems_size
].id
= id
;
210 strcopy(label
, uielems
[uielems_size
].label
);
211 uielems
[uielems_size
].min
= 0;
212 uielems
[uielems_size
].max
= 0;
213 uielems
[uielems_size
].init
= 0;
214 uielems
[uielems_size
].step
= 0;
217 virtual void addCheckButton(char* label
, float* zone
) {
218 return addToggleButton(label
, zone
);
220 virtual void addVerticalSlider(char* label
, float* zone
, float init
, float min
, float max
, float step
) {
221 return addHorizontalSlider(label
, zone
, init
, min
, max
, step
);
223 virtual void addHorizontalSlider(char* label
, float* zone
, float init
, float min
, float max
, float step
) {
224 int id
= registerControl(zone
);
225 uielems
[uielems_size
].type
= TYPE_SLIDER
;
226 uielems
[uielems_size
].id
= id
;
227 strcopy(label
, uielems
[uielems_size
].label
);
228 uielems
[uielems_size
].min
= min
;
229 uielems
[uielems_size
].max
= max
;
230 uielems
[uielems_size
].init
= init
;
231 uielems
[uielems_size
].step
= step
;
234 virtual void addNumEntry(char* label
, float* zone
, float init
, float min
, float max
, float step
) {
235 return addHorizontalSlider(label
, zone
, init
, min
, max
, step
);
238 // Not implemented yet - these only affect UI layout and aren't critical.
239 // See actionscript comments for details.
240 virtual void openFrameBox(char* label
) {}
241 virtual void openTabBox(char* label
) {}
242 virtual void openHorizontalBox(char* label
) {}
243 virtual void openVerticalBox(char* label
) {}
244 virtual void closeBox() {}
245 virtual void run() { }
248 /******************************************************************************
249 *******************************************************************************
253 *******************************************************************************
254 *******************************************************************************/
258 //----------------------------------------------------------------
259 // abstract definition of a signal processor
260 //----------------------------------------------------------------
269 virtual int getNumInputs() = 0;
270 virtual int getNumOutputs() = 0;
271 virtual void buildUserInterface(UI
* interface
) = 0;
272 virtual void init(int samplingRate
) = 0;
273 virtual void compute(int len
, float** inputs
, float** outputs
) = 0;
277 //----------------------------------------------------------------------------
278 // FAUST generated signal processor
279 //----------------------------------------------------------------------------
283 /********************END ARCHITECTURE SECTION (part 1/2)****************/
285 /**************************BEGIN USER SECTION **************************/
289 /***************************END USER SECTION ***************************/
291 /*******************BEGIN ARCHITECTURE SECTION (part 2/2)***************/
300 // mydsp will be defined by faust in 'includeclass'
302 ui_
= new ActionScriptUI();
303 dsp_
->buildUserInterface(ui_
);
304 dsp_
->init(44100); // 44.1k, 2 channels, @ 32-bit is hardcoded into flash player 10.
308 if (dsp_
) delete dsp_
;
313 public: // we're all friends here
321 // Alchemy wrapper interface code
322 static AS3_Val
api_init(void *thisPtr
, AS3_Val args
) {
324 AS3_Val array
= AS3_Array("");
329 static AS3_Val
api_shutdown(void *thisPtr
, AS3_Val args
) {
335 // args = int id, float value
336 static AS3_Val
api_onControlChange(void *thisPtr
, AS3_Val args
) {
337 if (!faust
) return AS3_Int(0);
339 // Marshall the arguments in.
342 AS3_ArrayValue(args
, "IntType, AS3ValType", &id
, &controlVal
);
343 double control_double
= AS3_NumberValue(controlVal
);
345 // loss of precision is ok.
346 float value
= (float)control_double
;
348 // Call the actual update function
349 faust
->ui_
->updateControl(id
, value
);
353 #define MAX_FLASH_BUFFER 8192
354 // output buffers - L/R channels separate
355 static float bufferL
[MAX_FLASH_BUFFER
];
356 static float bufferR
[MAX_FLASH_BUFFER
];
357 // output buffer - construct interleaved output
358 static float bufferSum
[2*MAX_FLASH_BUFFER
];
360 // input buffers - L/R separate
361 static float inputL
[MAX_FLASH_BUFFER
];
362 static float inputR
[MAX_FLASH_BUFFER
];
363 // input buffer scratch space - interleaved
364 static float bufferInSum
[2*MAX_FLASH_BUFFER
];
366 // This is the most 'interesting' function of the file - it takes in flash sound buffers
367 // and sends them through Faust DSP code.
368 // args = int nsamples, float* buffer (byte[] in flash)
369 static AS3_Val
api_tick(void *thisPtr
, AS3_Val args
) {
370 if (!faust
) return AS3_Int(0);
372 // Marshall arguments in.
377 AS3_ArrayValue(args
, "IntType, IntType, AS3ValType, AS3ValType", &nsamples
, &use_input
, &input
, &buffer
);
379 float* outputs
[2] = {bufferL
, bufferR
};
380 float* inputs
[2] = {inputL
, inputR
};
382 //AS3_ByteArray_seek(input, 0, 0);
383 // we need (#samples * sizeof(float) * 2 channels) bytes.
384 AS3_ByteArray_readBytes((char*)bufferInSum
, input
, nsamples
* 4 * 2);
385 char *src
= (char*)bufferInSum
;
386 char *dl
= (char*)inputL
, *dr
= (char*)inputR
;
387 for (int i
= 0; i
< nsamples
; ++i
) {
404 faust
->dsp_
->compute(nsamples
, inputs
, outputs
);
407 // Post-process: interleave arrays.
408 // Faust outputs to two separate arrays (which are probably contiguous in memory - see above)
409 // Flash's sound callback needs this as LRLRLRLR...
410 // For added fun, LLVM internal float seems to be the opposite endianness
411 // as what Flash uses, so we have to do this byte-by-byte.
412 char *copyL
= (char*)bufferL
;
413 char *copyR
= (char*)bufferR
;
414 char *tape_head
= (char*)bufferSum
;
415 for (int i
= 0; i
< nsamples
; ++i
) {
416 *tape_head
++ = copyL
[3];
417 *tape_head
++ = copyL
[2];
418 *tape_head
++ = copyL
[1];
419 *tape_head
++ = copyL
[0];
420 *tape_head
++ = copyR
[3];
421 *tape_head
++ = copyR
[2];
422 *tape_head
++ = copyR
[1];
423 *tape_head
++ = copyR
[0];
427 AS3_ByteArray_writeBytes(buffer
, bufferSum
, 4 * nsamples
* 2);
433 //Alchemy entry point
434 // Here we are responsible for contructing an API object to pass back to Flash.
435 // This must contain pointers to all functions which may be called.
438 //define the methods exposed to ActionScript
439 //typed as an ActionScript Function instance
440 AS3_Val methodInit
= AS3_Function( NULL
, api_init
);
441 AS3_Val methodShutdown
= AS3_Function( NULL
, api_shutdown
);
442 AS3_Val methodOnControlChange
= AS3_Function( NULL
, api_onControlChange
);
443 AS3_Val methodTick
= AS3_Function( NULL
, api_tick
);
445 // construct an API lookup table with references to all functions
446 // In flash we'll instantiate one of these and call methods on it
447 // e.g. faust.api_tick().
448 AS3_Val result
= AS3_Object(
449 "api_init:AS3ValType, api_shutdown:AS3ValType, api_onControlChange:AS3ValType, api_tick:AS3ValType",
450 methodInit
, methodShutdown
, methodOnControlChange
, methodTick
);
452 AS3_Release(methodInit
);
453 AS3_Release(methodShutdown
);
454 AS3_Release(methodOnControlChange
);
455 AS3_Release(methodTick
);
457 // notify Flash of our functions and run -- this function never returns.
462 /********************END ARCHITECTURE SECTION (part 2/2)****************/