Merge branch 'OOP' of https://scm.cri.ensmp.fr/git/Faustine into OOP
[Faustine.git] / interpretor / faust-0.9.47mr3 / architecture / max-msp.cpp
1 /************************************************************************
2
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 *************************************************************************/
8
9 /*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/
10
11 /************************************************************************
12 FAUST Architecture File
13 Copyright (C) 2004-2011 GRAME, Centre National de Creation Musicale
14 ---------------------------------------------------------------------
15 This Architecture section is free software; you can redistribute it
16 and/or modify it under the terms of the GNU Lesser General Public
17 License as published by the Free Software Foundation; either version 3
18 of the License, or (at your option) any later version.
19
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 Lesser General Public License for more details.
24
25 You should have received a copy of the GNU Lesser General Public License
26 along with this program; If not, see <http://www.gnu.org/licenses/>.
27
28 EXCEPTION : As a special exception, you may create a larger work
29 that contains this FAUST architecture section and distribute
30 that work under terms of your choice, so long as this FAUST
31 architecture section is not modified.
32
33 MAX MSP SDK : in order to compile a MaxMSP external with this
34 architecture file you will need the official MaxMSP SDK from
35 cycling'74. Please check the corresponding license.
36
37 ************************************************************************
38 ************************************************************************/
39
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <limits.h>
44 #include <math.h>
45 #include <errno.h>
46 #include <time.h>
47 #include <unistd.h>
48 #include <fcntl.h>
49 #include <assert.h>
50 #include <string>
51 #include <vector>
52 #include <map>
53 #include <math.h>
54
55 #ifdef __APPLE__
56 #include <Carbon/Carbon.h>
57 #include <unistd.h>
58 #endif
59
60 #include "gui/GUI.h"
61 #include "audio/dsp.h"
62 #include "misc.h"
63
64 using namespace std ;
65
66 // There is a bug with powf() when cross compiling with mingw
67 // the following macro avoid the problem
68 #ifdef WIN32
69 #define powf(x,y) pow(x,y)
70 #define expf(x) exp(x)
71 #endif
72
73 #ifdef __GNUC__
74
75 //-------------------------------------------------------------------
76 // Generic min and max using gcc extensions
77 //-------------------------------------------------------------------
78
79 #define max(x,y) (((x)>(y)) ? (x) : (y))
80 #define min(x,y) (((x)<(y)) ? (x) : (y))
81
82 #else
83
84 //-------------------------------------------------------------------
85 // Generic min and max using c++ inline
86 //-------------------------------------------------------------------
87
88 inline int max(unsigned int a, unsigned int b) { return (a>b) ? a : b; }
89 inline int max(int a, int b) { return (a>b) ? a : b; }
90
91 inline long max(long a, long b) { return (a>b) ? a : b; }
92 inline long max(int a, long b) { return (a>b) ? a : b; }
93 inline long max(long a, int b) { return (a>b) ? a : b; }
94
95 inline float max(float a, float b) { return (a>b) ? a : b; }
96 inline float max(int a, float b) { return (a>b) ? a : b; }
97 inline float max(float a, int b) { return (a>b) ? a : b; }
98 inline float max(long a, float b) { return (a>b) ? a : b; }
99 inline float max(float a, long b) { return (a>b) ? a : b; }
100
101 inline double max(double a, double b) { return (a>b) ? a : b; }
102 inline double max(int a, double b) { return (a>b) ? a : b; }
103 inline double max(double a, int b) { return (a>b) ? a : b; }
104 inline double max(long a, double b) { return (a>b) ? a : b; }
105 inline double max(double a, long b) { return (a>b) ? a : b; }
106 inline double max(float a, double b) { return (a>b) ? a : b; }
107 inline double max(double a, float b) { return (a>b) ? a : b; }
108
109
110 inline int min(int a, int b) { return (a<b) ? a : b; }
111
112 inline long min(long a, long b) { return (a<b) ? a : b; }
113 inline long min(int a, long b) { return (a<b) ? a : b; }
114 inline long min(long a, int b) { return (a<b) ? a : b; }
115
116 inline float min(float a, float b) { return (a<b) ? a : b; }
117 inline float min(int a, float b) { return (a<b) ? a : b; }
118 inline float min(float a, int b) { return (a<b) ? a : b; }
119 inline float min(long a, float b) { return (a<b) ? a : b; }
120 inline float min(float a, long b) { return (a<b) ? a : b; }
121
122 inline double min(double a, double b) { return (a<b) ? a : b; }
123 inline double min(int a, double b) { return (a<b) ? a : b; }
124 inline double min(double a, int b) { return (a<b) ? a : b; }
125 inline double min(long a, double b) { return (a<b) ? a : b; }
126 inline double min(double a, long b) { return (a<b) ? a : b; }
127 inline double min(float a, double b) { return (a<b) ? a : b; }
128 inline double min(double a, float b) { return (a<b) ? a : b; }
129
130 #endif
131
132 /******************************************************************************
133 *******************************************************************************
134
135 VECTOR INTRINSICS
136
137 *******************************************************************************
138 *******************************************************************************/
139
140 <<includeIntrinsic>>
141
142 /********************END ARCHITECTURE SECTION (part 1/2)****************/
143
144 /**************************BEGIN USER SECTION **************************/
145
146 <<includeclass>>
147
148 /***************************END USER SECTION ***************************/
149
150 /*******************BEGIN ARCHITECTURE SECTION (part 2/2)***************/
151
152
153 /* Faust code wrapper ------- */
154
155 #include "ext.h"
156 #include "z_dsp.h"
157 #include <string.h>
158
159 #define ASSIST_INLET 1 /* should be defined somewhere ?? */
160 #define ASSIST_OUTLET 2 /* should be defined somewhere ?? */
161
162 class mspUI;
163
164 /*--------------------------------------------------------------------------*/
165 typedef struct faust
166 {
167 t_pxobject m_ob;
168 t_atom *m_seen,*m_want;
169 short m_where;
170 void** args;
171 mspUI* dspUI;
172 mydsp* dsp;
173 } t_faust;
174
175 void *faust_class;
176
177 /*--------------------------------------------------------------------------*/
178 class mspUIObject {
179
180 protected:
181
182 string fLabel;
183 float* fZone;
184
185 float range(float min, float max, float val) {return (val < min) ? min : (val > max) ? max : val;}
186
187 public:
188
189 mspUIObject(const char* label, float* zone):fLabel(label),fZone(zone) {}
190 virtual ~mspUIObject() {}
191
192 virtual void SetValue(double f) {*fZone = range(0.0,1.0,f);}
193 virtual void toString(char* buffer) {}
194 virtual string GetName() {return fLabel;}
195 };
196
197 /*--------------------------------------------------------------------------*/
198 class mspToggleButton : public mspUIObject {
199
200 public:
201
202 mspToggleButton(const char* label, float* zone):mspUIObject(label,zone) {}
203 virtual ~mspToggleButton() {}
204
205 void toString(char* buffer)
206 {
207 #ifdef WIN32
208 sprintf(buffer, "ToggleButton(float): %s", fLabel.c_str());
209 #else
210 std::sprintf(buffer, "ToggleButton(float): %s", fLabel.c_str());
211 #endif
212 }
213 };
214
215 /*--------------------------------------------------------------------------*/
216 class mspCheckButton : public mspUIObject {
217
218 public:
219
220 mspCheckButton(const char* label, float* zone):mspUIObject(label,zone) {}
221 virtual ~mspCheckButton() {}
222
223 void toString(char* buffer)
224 {
225 #ifdef WIN32
226 sprintf(buffer, "CheckButton(float): %s", fLabel.c_str());
227 #else
228 std::sprintf(buffer, "CheckButton(float): %s", fLabel.c_str());
229 #endif
230 }
231 };
232
233 /*--------------------------------------------------------------------------*/
234 class mspButton : public mspUIObject {
235
236 public:
237
238 mspButton(const char* label, float* zone):mspUIObject(label,zone) {}
239 virtual ~mspButton() {}
240
241 void toString(char* buffer)
242 {
243 #ifdef WIN32
244 sprintf(buffer, "Button(float): %s", fLabel.c_str());
245 #else
246 std::sprintf(buffer, "Button(float): %s", fLabel.c_str());
247 #endif
248 }
249 };
250
251 /*--------------------------------------------------------------------------*/
252 class mspSlider : public mspUIObject{
253
254 private:
255
256 float fInit;
257 float fMin;
258 float fMax;
259 float fStep;
260
261 public:
262
263 mspSlider(const char* label, float* zone, float init, float min, float max, float step)
264 :mspUIObject(label,zone),fInit(init),fMin(min),fMax(max),fStep(step) {}
265 virtual ~mspSlider() {}
266
267 void toString(char* buffer)
268 {
269 #ifdef WIN32
270 sprintf(buffer, "Slider(float): %s [%.1f:%.1f:%.1f]", fLabel.c_str(), fMin, fInit, fMax);
271 #else
272 std::sprintf(buffer, "Slider(float): %s [%.1f:%.1f:%.1f]", fLabel.c_str(), fMin, fInit, fMax);
273 #endif
274 }
275
276 void SetValue(double f) {*fZone = range(fMin,fMax,f);}
277 };
278
279 /*--------------------------------------------------------------------------*/
280 class mspUI : public UI
281 {
282 private:
283
284 map<string,mspUIObject*> fUITable;
285
286 public:
287 typedef map<string,mspUIObject*>::iterator iterator;
288
289 mspUI(){}
290 virtual ~mspUI()
291 {
292 for (iterator iter = fUITable.begin(); iter != fUITable.end(); iter++)
293 delete (iter->second);
294 }
295
296 void addButton(const char* label, float* zone) {fUITable[string(label)] = new mspButton(label, zone);}
297
298 void addToggleButton(const char* label, float* zone) {fUITable[string(label)] = new mspToggleButton(label, zone);}
299
300 void addCheckButton(const char* label, float* zone) {fUITable[string(label)] = new mspCheckButton(label, zone);}
301
302 void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step)
303 {
304 fUITable[string(label)] = new mspSlider(label, zone, init, min, max, step);
305 }
306
307 void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step)
308 {
309 fUITable[string(label)] = new mspSlider(label, zone, init, min, max, step);
310 }
311
312 void addNumEntry(const char* label, float* zone, float init, float min, float max, float step)
313 {
314 fUITable[string(label)] = new mspSlider(label, zone, init, min, max, step);
315 }
316
317 void openFrameBox(const char* label) {}
318 void openTabBox(const char* label) {}
319 void openHorizontalBox(const char* label) {}
320 void openVerticalBox(const char* label) {}
321 void closeBox() {}
322
323 void SetValue(string name, double f)
324 {
325 if(fUITable.count(name))
326 fUITable[name]->SetValue(f);
327 }
328 iterator begin() {return fUITable.begin();}
329 iterator end() {return fUITable.end();}
330
331 // To be implemented
332 void addNumDisplay(const char* label, float* zone, int precision) {}
333 void addTextDisplay(const char* label, float* zone, const char* names[], float min, float max) {}
334 void addHorizontalBargraph(const char* label, float* zone, float min, float max) {}
335 void addVerticalBargraph(const char* label, float* zone, float min, float max) {}
336 };
337
338 //--------------------------------------------------------------------------
339 void faust_method(t_faust *obj, t_symbol *s, short ac, t_atom *at)
340 {
341 if(ac < 0) return;
342 if(at[0].a_type != A_FLOAT) return;
343
344 string name = string( (s)->s_name );
345 float value = at[0].a_w.w_float;
346
347 // lookup du nom dans une std::map<string,mspUIObject *>
348 // ou une std::map<string,float *>
349 // et affectation de value;
350 obj->dspUI->SetValue(name,value); // doesn't have any effect if name is unknown
351 }
352
353 /*--------------------------------------------------------------------------*/
354 void *faust_new(t_symbol *s, short ac, t_atom *av)
355 {
356 t_faust *x = (t_faust *)newobject(faust_class);
357
358 x->dsp = new mydsp();
359 x->dspUI= new mspUI();
360
361 x->dsp->init(long(sys_getsr()));
362 x->dsp->buildUserInterface(x->dspUI);
363
364 x->args = (void**)calloc((x->dsp->getNumInputs()+x->dsp->getNumOutputs())+2, sizeof(void*));
365
366 /* Multi in */
367 dsp_setup((t_pxobject *)x, x->dsp->getNumInputs());
368
369 /* Multi out */
370 for (int i = 0; i< x->dsp->getNumOutputs(); i++)
371 outlet_new((t_pxobject *)x, (char*)"signal");
372
373 ((t_pxobject *)x)->z_misc = Z_NO_INPLACE; // To assure input and output buffers are actually different
374 return x;
375 }
376
377 /*--------------------------------------------------------------------------*/
378 void faust_assist(t_faust *x, void *b, long msg, long a, char *dst)
379 {
380 if (msg == ASSIST_INLET) {
381 if (a == 0) {
382 if (x->dsp->getNumInputs() == 0) {
383 #ifdef WIN32
384 sprintf(dst, "(signal) : Unused Input");
385 #else
386 std::sprintf(dst, "(signal) : Unused Input");
387 #endif
388 } else {
389 #ifdef WIN32
390 sprintf(dst, "(signal) : Audio Input %ld", (a+1));
391 #else
392 std::sprintf(dst, "(signal) : Audio Input %ld", (a+1));
393 #endif
394 }
395 post((char*)"------------------");
396 for (mspUI::iterator it = x->dspUI->begin(); it != x->dspUI->end(); ++it) {
397 char param[64];
398 it->second->toString(param);
399 post(param);
400 }
401 } else if (a < x->dsp->getNumInputs()) {
402 #ifdef WIN32
403 sprintf(dst, "(signal) : Audio Input %ld", (a+1));
404 #else
405 std::sprintf(dst, "(signal) : Audio Input %ld", (a+1));
406 #endif
407 }
408 } else if (msg == ASSIST_OUTLET) {
409 #ifdef WIN32
410 sprintf(dst, "(signal) : Audio Output %ld", (a+1));
411 #else
412 std::sprintf(dst, "(signal) : Audio Output %ld", (a+1));
413 #endif
414 }
415 }
416
417 /*--------------------------------------------------------------------------*/
418 void faust_free(t_faust *x)
419 {
420 dsp_free((t_pxobject *)x);
421 if (x->dsp) delete x->dsp;
422 if (x->dspUI) delete x->dspUI;
423 if (x->args)free(x->args);
424 }
425
426 /*--------------------------------------------------------------------------*/
427 t_int *faust_perform(t_int *w)
428 {
429 t_faust* x = (t_faust*) (w[1]);
430 long n = w[2];
431 int offset = 3;
432 AVOIDDENORMALS;
433 x->dsp->compute(n, ((float**)&w[offset]), ((float**)&w[offset+x->dsp->getNumInputs()]));
434 return (w + (x->dsp->getNumInputs()+x->dsp->getNumOutputs())+2+1);
435 }
436
437 /*--------------------------------------------------------------------------*/
438 void faust_dsp(t_faust *x, t_signal **sp, short *count)
439 {
440 x->args[0] = x;
441 x->args[1] = (void*)sp[0]->s_n;
442 for (int i = 0; i<(x->dsp->getNumInputs()+x->dsp->getNumOutputs()); i++)
443 x->args[i+2] = sp[i]->s_vec;
444 dsp_addv(faust_perform, (x->dsp->getNumInputs()+x->dsp->getNumOutputs())+2, x->args);
445 }
446
447 /*--------------------------------------------------------------------------*/
448 int main()
449 {
450 setup((t_messlist **)&faust_class, (method)faust_new, (method)faust_free,
451 (short)sizeof(t_faust), 0L, A_DEFFLOAT, 0);
452
453 dsp *thedsp = new mydsp();
454 mspUI *dspUI= new mspUI();
455 thedsp->buildUserInterface(dspUI);
456
457 // Add the same method for every parameters and use the symbol as a selector
458 // inside thid method
459 for (mspUI::iterator it = dspUI->begin(); it != dspUI->end(); ++it) {
460 char *name = const_cast<char *>(it->second->GetName().c_str());
461 addmess((method)faust_method, name, A_GIMME, 0);
462 }
463
464 addmess((method)faust_dsp, (char*)"dsp", A_CANT, 0);
465 addmess((method)faust_assist, (char*)"assist", A_CANT, 0);
466 dsp_initclass();
467
468 delete(dspUI);
469 delete(thedsp);
470 post((char*)"Faust DSP object");
471 return 0;
472 }
473
474 /********************END ARCHITECTURE SECTION (part 2/2)****************/
475
476
477
478