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 max-msp.cpp ****************/
10 /************************************************************************
11 FAUST Architecture File
12 Copyright (C) 2004-2018 GRAME, Centre National de Creation Musicale
13 ---------------------------------------------------------------------
14 This Architecture section is free software; you can redistribute it
15 and/or modify it under the terms of the GNU Lesser General Public
16 License as published by the Free Software Foundation; either version 3
17 of the License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU Lesser General Public License for more details.
23
24 You should have received a copy of the GNU Lesser General Public License
25 along with this program; If not, see <http://www.gnu.org/licenses/>.
26
27 EXCEPTION : As a special exception, you may create a larger work
28 that contains this FAUST architecture section and distribute
29 that work under terms of your choice, so long as this FAUST
30 architecture section is not modified.
31
32 MAX MSP SDK : in order to compile a MaxMSP external with this
33 architecture file you will need the official MaxMSP SDK from
34 cycling'74. Please check the corresponding license.
35
36 ************************************************************************
37 ************************************************************************/
38
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <limits.h>
43 #include <errno.h>
44 #include <time.h>
45 #include <unistd.h>
46 #include <fcntl.h>
47 #include <assert.h>
48 #include <string>
49 #include <vector>
50 #include <map>
51 #include <iostream>
52 #include <fstream>
53 #include <sstream>
54 #include <list>
55
56 #ifdef __APPLE__
57 #include <Carbon/Carbon.h>
58 #include <unistd.h>
59 #endif
60
61 #ifdef WIN32
62 #ifndef NAN
63 static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff};
64 #define NAN (*(const float *) __nan)
65 #endif
66 #endif
67
68 #include "faust/gui/UI.h"
69 #include "faust/gui/SimpleParser.h"
70 #include "faust/gui/PathBuilder.h"
71 #include "faust/dsp/dsp-combiner.h"
72 #include "faust/dsp/dsp-adapter.h"
73 #include "faust/dsp/dsp.h"
74 #include "faust/misc.h"
75 #include "faust/gui/SaveUI.h"
76
77 // Always included
78 #include "faust/gui/OSCUI.h"
79
80 #ifdef POLY2
81 #include "effect.h"
82 #endif
83
84 #if SOUNDFILE
85 #include "faust/gui/SoundUI.h"
86 #endif
87
88 // For FAUST_CLASS_NAME to be defined
89 #define FAUST_UIMACROS
90
91 // but we will ignore most of them
92 #define FAUST_ADDBUTTON(l,f)
93 #define FAUST_ADDCHECKBOX(l,f)
94 #define FAUST_ADDVERTICALSLIDER(l,f,i,a,b,s)
95 #define FAUST_ADDHORIZONTALSLIDER(l,f,i,a,b,s)
96 #define FAUST_ADDNUMENTRY(l,f,i,a,b,s)
97 #define FAUST_ADDVERTICALBARGRAPH(l,f,a,b)
98 #define FAUST_ADDHORIZONTALBARGRAPH(l,f,a,b)
99 #define FAUST_ADDSOUNDFILE(s,f)
100
101 using namespace std;
102
103 /******************************************************************************
104 *******************************************************************************
105
106 VECTOR INTRINSICS
107
108 *******************************************************************************
109 *******************************************************************************/
110
111 <<includeIntrinsic>>
112
113 /********************END ARCHITECTURE SECTION (part 1/2)****************/
114
115 /**************************BEGIN USER SECTION **************************/
116
117 <<includeclass>>
118
119 /***************************END USER SECTION ***************************/
120
121 /*******************BEGIN ARCHITECTURE SECTION (part 2/2)***************/
122
123 /* Faust code wrapper ------- */
124
125 #include "ext.h"
126 #include "ext_obex.h"
127 #include "z_dsp.h"
128 #include "jpatcher_api.h"
129 #include <string.h>
130
131 #define ASSIST_INLET 1
132 #define ASSIST_OUTLET 2
133
134 #define EXTERNAL_VERSION "0.84"
135 #define STR_SIZE 512
136
137 #include "faust/gui/GUI.h"
138 #include "faust/gui/MidiUI.h"
139 #include "faust/gui/mspUI.h"
140 #include "faust/dsp/poly-dsp.h"
141
142 list<GUI*> GUI::fGuiList;
143 ztimedmap GUI::gTimedZoneMap;
144
145 static t_class* faust_class;
146
147 /*--------------------------------------------------------------------------*/
148 typedef struct faust
149 {
150 t_pxobject m_ob;
151 t_atom *m_seen, *m_want;
152 map<string, vector<t_object*> > m_output_table;
153 short m_where;
154 bool m_mute;
155 void** m_args;
156 mspUI* m_dspUI;
157 dsp* m_dsp;
158 void* m_control_outlet;
159 char* m_json;
160 t_systhread_mutex m_mutex;
161 int m_Inputs;
162 int m_Outputs;
163 SaveUI* m_savedUI;
164 #ifdef MIDICTRL
165 MidiUI* m_midiUI;
166 max_midi* m_midiHandler;
167 void* m_midi_outlet;
168 #endif
169 #ifdef SOUNDFILE
170 SoundUI* m_soundInterface;
171 #endif
172 #ifdef OSCCTRL
173 OSCUI* m_oscInterface;
174 #endif
175 } t_faust;
176
177 void faust_create_jsui(t_faust* x);
178 void faust_make_json(t_faust* x);
179
180 /*--------------------------------------------------------------------------*/
faust_allocate(t_faust * x,int nvoices)181 void faust_allocate(t_faust* x, int nvoices)
182 {
183 // Delete old
184 delete x->m_dsp;
185 if (x->m_dspUI) x->m_dspUI->clear();
186
187 if (nvoices > 0) {
188 post("polyphonic DSP voices = %d", nvoices);
189 x->m_dsp = new mydsp_poly(new mydsp(), nvoices, true, true);
190 #ifdef POLY2
191 x->m_dsp = new dsp_sequencer(x->m_dsp, new effect());
192 #endif
193 } else {
194 post("monophonic DSP");
195 // Create a DS/US + Filter adapted DSP
196 x->m_dsp = createSRAdapter<FAUSTFLOAT>(new mydsp(), DOWN_SAMPLING, UP_SAMPLING, FILTER_TYPE);
197 }
198
199 #ifdef MIDICTRL
200 x->m_dsp->buildUserInterface(x->m_midiUI);
201 #endif
202 }
203
204 /*--------------------------------------------------------------------------*/
faust_anything(t_faust * obj,t_symbol * s,short ac,t_atom * av)205 void faust_anything(t_faust* obj, t_symbol* s, short ac, t_atom* av)
206 {
207 bool res = false;
208 string name = string((s)->s_name);
209
210 // If no argument is there, consider it as a toggle message for a button
211 if (ac == 0 && obj->m_dspUI->isValue(name)) {
212
213 FAUSTFLOAT off = FAUSTFLOAT(0.0);
214 FAUSTFLOAT on = FAUSTFLOAT(1.0);
215 obj->m_dspUI->setValue(name, off);
216 obj->m_dspUI->setValue(name, on);
217
218 av[0].a_type = A_FLOAT;
219 av[0].a_w.w_float = off;
220 faust_anything(obj, s, 1, av);
221
222 } else if (mspUI::checkDigit(name)) { // List of values
223
224 int pos, ndigit = 0;
225 for (pos = name.size() - 1; pos >= 0; pos--) {
226 if (isdigit(name[pos]) || name[pos] == ' ') {
227 ndigit++;
228 } else {
229 break;
230 }
231 }
232 pos++;
233
234 string prefix = name.substr(0, pos);
235 string num_base = name.substr(pos);
236 int num = atoi(num_base.c_str());
237
238 int i;
239 t_atom* ap;
240
241 // Increment ap each time to get to the next atom
242 for (i = 0, ap = av; i < ac; i++, ap++) {
243 FAUSTFLOAT value;
244 switch (atom_gettype(ap)) {
245 case A_LONG:
246 value = FAUSTFLOAT(ap[0].a_w.w_long);
247 break;
248 case A_FLOAT:
249 value = FAUSTFLOAT(ap[0].a_w.w_float);
250 break;
251 default:
252 post("Invalid argument in parameter setting");
253 return;
254 }
255
256 string num_val = to_string(num + i);
257 stringstream param_name; param_name << prefix;
258 for (int i = 0; i < ndigit - mspUI::countDigit(num_val); i++) {
259 param_name << ' ';
260 }
261 param_name << num_val;
262
263 // Try special naming scheme for list of parameters
264 res = obj->m_dspUI->setValue(param_name.str(), value);
265
266 // Otherwise try standard name
267 if (!res) {
268 res = obj->m_dspUI->setValue(name, value);
269 }
270 if (!res) {
271 post("Unknown parameter : %s", (s)->s_name);
272 }
273 }
274
275 } else {
276 // Standard parameter name
277 FAUSTFLOAT value = (av[0].a_type == A_LONG) ? FAUSTFLOAT(av[0].a_w.w_long) : FAUSTFLOAT(av[0].a_w.w_float);
278 res = obj->m_dspUI->setValue(name, value);
279 if (!res) {
280 post("Unknown parameter : %s", (s)->s_name);
281 }
282 }
283 }
284
285 /*--------------------------------------------------------------------------*/
faust_polyphony(t_faust * x,t_symbol * s,short ac,t_atom * av)286 void faust_polyphony(t_faust* x, t_symbol* s, short ac, t_atom* av)
287 {
288 if (systhread_mutex_lock(x->m_mutex) == MAX_ERR_NONE) {
289 faust_allocate(x, av[0].a_w.w_long);
290 systhread_mutex_unlock(x->m_mutex);
291 } else {
292 post("Mutex lock cannot be taken...");
293 }
294 }
295
296 /*--------------------------------------------------------------------------*/
297 #ifdef MIDICTRL
faust_midievent(t_faust * x,t_symbol * s,short ac,t_atom * av)298 void faust_midievent(t_faust* x, t_symbol* s, short ac, t_atom* av)
299 {
300 if (ac > 0) {
301 int type = (int)av[0].a_w.w_long & 0xf0;
302 int channel = (int)av[0].a_w.w_long & 0x0f;
303
304 if (ac == 1) {
305 x->m_midiHandler->handleSync(0.0, av[0].a_w.w_long);
306 } else if (ac == 2) {
307 x->m_midiHandler->handleData1(0.0, type, channel, av[1].a_w.w_long);
308 } else if (ac == 3) {
309 x->m_midiHandler->handleData2(0.0, type, channel, av[1].a_w.w_long, av[2].a_w.w_long);
310 }
311 }
312 }
313 #endif
314
315 /*--------------------------------------------------------------------------*/
faust_create_jsui(t_faust * x)316 void faust_create_jsui(t_faust* x)
317 {
318 t_object *patcher, *box, *obj;
319 object_obex_lookup((t_object*)x, gensym("#P"), &patcher);
320
321 for (box = jpatcher_get_firstobject(patcher); box; box = jbox_get_nextobject(box)) {
322 obj = jbox_get_object(box);
323 // Notify JSON
324 if (obj && strcmp(object_classname(obj)->s_name, "js") == 0) {
325 t_atom json;
326 atom_setsym(&json, gensym(x->m_json));
327 object_method_typed(obj, gensym("anything"), 1, &json, 0);
328 }
329 }
330
331 // Keep all outputs to be notified in update_outputs
332 x->m_output_table.clear();
333 for (box = jpatcher_get_firstobject(patcher); box; box = jbox_get_nextobject(box)) {
334 obj = jbox_get_object(box);
335 t_symbol* scriptingname = jbox_get_varname(obj); // scripting name
336 // Keep control outputs
337 if (scriptingname && x->m_dspUI->isOutputValue(scriptingname->s_name)) {
338 x->m_output_table[scriptingname->s_name].push_back(obj);
339 }
340 }
341 }
342
343 /*--------------------------------------------------------------------------*/
faust_update_outputs(t_faust * x)344 void faust_update_outputs(t_faust* x)
345 {
346 for (const auto& it1 : x->m_output_table) {
347 bool new_val = false;
348 FAUSTFLOAT value = x->m_dspUI->getOutputValue(it1.first, new_val);
349 if (new_val) {
350 t_atom at_value;
351 atom_setfloat(&at_value, value);
352 for (const auto& it2 : it1.second) {
353 object_method_typed(it2, gensym("float"), 1, &at_value, 0);
354 }
355 }
356 }
357 }
358
359 /*--------------------------------------------------------------------------*/
faust_make_json(t_faust * x)360 void faust_make_json(t_faust* x)
361 {
362 // Prepare JSON
363 if (x->m_json) free(x->m_json);
364 JSONUI builder(x->m_dsp->getNumInputs(), x->m_dsp->getNumOutputs());
365 x->m_dsp->metadata(&builder);
366 x->m_dsp->buildUserInterface(&builder);
367 x->m_json = strdup(builder.JSON().c_str());
368 }
369
370 /*--------------------------------------------------------------------------*/
faust_new(t_symbol * s,short ac,t_atom * av)371 void* faust_new(t_symbol* s, short ac, t_atom* av)
372 {
373 bool midi_sync = false;
374 int nvoices = 0;
375 t_faust* x = (t_faust*)object_alloc(faust_class);
376
377 mydsp* tmp_dsp = new mydsp();
378 MidiMeta::analyse(tmp_dsp, midi_sync, nvoices);
379 #ifdef SOUNDFILE
380 Max_Meta3 meta3;
381 tmp_dsp->metadata(&meta3);
382 string bundle_path_str = SoundUI::getBinaryPathFrom(meta3.fName);
383 if (bundle_path_str == "") {
384 post("Bundle_path '%s' cannot be found!", meta3.fName.c_str());
385 }
386 x->m_soundInterface = new SoundUI(bundle_path_str);
387 #endif
388 delete tmp_dsp;
389
390 x->m_savedUI = new SaveLabelUI();
391 x->m_dspUI = new mspUI();
392 x->m_dsp = NULL;
393 x->m_json = NULL;
394 x->m_mute = false;
395 x->m_control_outlet = outlet_new((t_pxobject*)x, (char*)"list");
396
397 #ifdef MIDICTRL
398 x->m_midi_outlet = outlet_new((t_pxobject*)x, NULL);
399 x->m_midiHandler = new max_midi(x->m_midi_outlet);
400 x->m_midiUI = new MidiUI(x->m_midiHandler);
401 #endif
402
403 faust_allocate(x, nvoices);
404
405 if (systhread_mutex_new(&x->m_mutex, SYSTHREAD_MUTEX_NORMAL) != MAX_ERR_NONE) {
406 post("Cannot allocate mutex...");
407 }
408
409 int num_input;
410 if (x->m_dspUI->isMulti()) {
411 num_input = x->m_dsp->getNumInputs() + 1;
412 } else {
413 num_input = x->m_dsp->getNumInputs();
414 }
415
416 x->m_args = (void**)calloc((num_input + x->m_dsp->getNumOutputs()) + 2, sizeof(void*));
417
418 /* Multi in */
419 dsp_setup((t_pxobject*)x, num_input);
420
421 /* Multi out */
422 for (int i = 0; i < x->m_dsp->getNumOutputs(); i++) {
423 outlet_new((t_pxobject*)x, (char*)"signal");
424 }
425
426 ((t_pxobject*)x)->z_misc = Z_NO_INPLACE; // To assure input and output buffers are actually different
427
428 // Display controls
429 #ifdef POST
430 x->m_dspUI->displayControls();
431 #endif
432
433 // Get attributes values
434 attr_args_process(x, ac, av);
435 return x;
436 }
437
438 #ifdef OSCCTRL
439 /*--------------------------------------------------------------------------*/
440 // osc 'IP inport outport xmit bundle'
faust_osc(t_faust * x,t_symbol * s,short ac,t_atom * av)441 void faust_osc(t_faust* x, t_symbol* s, short ac, t_atom* av)
442 {
443 if (ac == 5) {
444 if (systhread_mutex_lock(x->m_mutex) == MAX_ERR_NONE) {
445
446 delete x->m_oscInterface;
447
448 const char* argv1[32];
449 int argc1 = 0;
450
451 argv1[argc1++] = "Faust";
452
453 argv1[argc1++] = "-desthost";
454 argv1[argc1++] = atom_getsym(&av[0])->s_name;
455
456 char inport[32];
457 snprintf(inport, 32, "%ld", long(av[1].a_w.w_long));
458 argv1[argc1++] = "-port";
459 argv1[argc1++] = inport;
460
461 char outport[32];
462 snprintf(outport, 32, "%ld", long(av[2].a_w.w_long));
463 argv1[argc1++] = "-outport";
464 argv1[argc1++] = outport;
465
466 char xmit[32];
467 snprintf(xmit, 32, "%ld", long(av[3].a_w.w_long));
468 argv1[argc1++] = "-xmit";
469 argv1[argc1++] = xmit;
470
471 char bundle[32];
472 snprintf(bundle, 32, "%ld", long(av[4].a_w.w_long));
473 argv1[argc1++] = "-bundle";
474 argv1[argc1++] = bundle;
475
476 x->m_oscInterface = new OSCUI("Faust", argc1, (char**)argv1);
477 x->m_dsp->buildUserInterface(x->m_oscInterface);
478 x->m_oscInterface->run();
479
480 post(x->m_oscInterface->getInfos().c_str());
481 systhread_mutex_unlock(x->m_mutex);
482 } else {
483 post("Mutex lock cannot be taken...");
484 }
485 } else {
486 post("Should be : osc 'IP inport outport xmit(0|1|2) bundle(0|1)'");
487 }
488 }
489 #endif
490
491 /*--------------------------------------------------------------------------*/
492 // Reset controllers to init value and send [path, init, min, max]
faust_init(t_faust * x,t_symbol * s,short ac,t_atom * av)493 void faust_init(t_faust* x, t_symbol* s, short ac, t_atom* av)
494 {
495 // Reset internal state
496 x->m_savedUI->reset();
497
498 // Input controllers
499 for (mspUI::iterator it = x->m_dspUI->begin2(); it != x->m_dspUI->end2(); it++) {
500 t_atom myList[4];
501 atom_setsym(&myList[0], gensym((*it).first.c_str()));
502 atom_setfloat(&myList[1], (*it).second->getInitValue()); // init value
503 atom_setfloat(&myList[2], (*it).second->getMinValue());
504 atom_setfloat(&myList[3], (*it).second->getMaxValue());
505 outlet_list(x->m_control_outlet, 0, 4, myList);
506 }
507 // Output controllers
508 for (mspUI::iterator it = x->m_dspUI->begin4(); it != x->m_dspUI->end4(); it++) {
509 t_atom myList[4];
510 atom_setsym(&myList[0], gensym((*it).first.c_str()));
511 atom_setfloat(&myList[1], (*it).second->getInitValue()); // init value
512 atom_setfloat(&myList[2], (*it).second->getMinValue());
513 atom_setfloat(&myList[3], (*it).second->getMaxValue());
514 outlet_list(x->m_control_outlet, 0, 4, myList);
515 }
516 }
517
518 /*--------------------------------------------------------------------------*/
faust_dump_inputs(t_faust * x)519 void faust_dump_inputs(t_faust* x)
520 {
521 // Input controllers
522 for (mspUI::iterator it = x->m_dspUI->begin2(); it != x->m_dspUI->end2(); it++) {
523 t_atom myList[4];
524 atom_setsym(&myList[0], gensym((*it).first.c_str()));
525 atom_setfloat(&myList[1], (*it).second->getValue()); // cur value
526 atom_setfloat(&myList[2], (*it).second->getMinValue());
527 atom_setfloat(&myList[3], (*it).second->getMaxValue());
528 outlet_list(x->m_control_outlet, 0, 4, myList);
529 }
530 }
531
532 /*--------------------------------------------------------------------------*/
faust_dump_outputs(t_faust * x)533 void faust_dump_outputs(t_faust* x)
534 {
535 // Output controllers
536 for (mspUI::iterator it = x->m_dspUI->begin4(); it != x->m_dspUI->end4(); it++) {
537 t_atom myList[4];
538 atom_setsym(&myList[0], gensym((*it).first.c_str()));
539 atom_setfloat(&myList[1], (*it).second->getValue()); // cur value
540 atom_setfloat(&myList[2], (*it).second->getMinValue());
541 atom_setfloat(&myList[3], (*it).second->getMaxValue());
542 outlet_list(x->m_control_outlet, 0, 4, myList);
543 }
544 }
545
546 /*--------------------------------------------------------------------------*/
547 // Dump controllers as list of [path, cur, min, max]
faust_dump(t_faust * x,t_symbol * s,short ac,t_atom * av)548 void faust_dump(t_faust* x, t_symbol* s, short ac, t_atom* av)
549 {
550 faust_dump_inputs(x);
551 faust_dump_outputs(x);
552 }
553
554 /*--------------------------------------------------------------------------*/
faust_dblclick(t_faust * x,long inlet)555 void faust_dblclick(t_faust* x, long inlet)
556 {
557 x->m_dspUI->displayControls();
558 }
559
560 /*--------------------------------------------------------------------------*/
561 //11/13/2015 : faust_assist is actually called at each click in the patcher, so we now use 'faust_dblclick' to display the parameters...
faust_assist(t_faust * x,void * b,long msg,long a,char * dst)562 void faust_assist(t_faust* x, void* b, long msg, long a, char* dst)
563 {
564 if (msg == ASSIST_INLET) {
565 if (a == 0) {
566 if (x->m_dsp->getNumInputs() == 0) {
567 sprintf(dst, "(messages)");
568 } else {
569 sprintf(dst, "(messages/signal) : Audio Input %ld", (a+1));
570 }
571 } else if (a < x->m_dsp->getNumInputs()) {
572 sprintf(dst, "(signal) : Audio Input %ld", (a+1));
573 }
574 } else if (msg == ASSIST_OUTLET) {
575 if (a < x->m_dsp->getNumOutputs()) {
576 sprintf(dst, "(signal) : Audio Output %ld", (a+1));
577 } else if (a == x->m_dsp->getNumOutputs()) {
578 sprintf(dst, "(list) : [path, cur|init, min, max]*");
579 } else {
580 sprintf(dst, "(int) : raw MIDI bytes*");
581 }
582 }
583 }
584
585 /*--------------------------------------------------------------------------*/
faust_mute(t_faust * obj,t_symbol * s,short ac,t_atom * at)586 void faust_mute(t_faust* obj, t_symbol* s, short ac, t_atom* at)
587 {
588 if (atom_gettype(at) == A_LONG) {
589 obj->m_mute = atom_getlong(at);
590 }
591 }
592
593 /*--------------------------------------------------------------------------*/
faust_free(t_faust * x)594 void faust_free(t_faust* x)
595 {
596 dsp_free((t_pxobject*)x);
597 delete x->m_dsp;
598 delete x->m_dspUI;
599 delete x->m_savedUI;
600 if (x->m_args) free(x->m_args);
601 if (x->m_json) free(x->m_json);
602 systhread_mutex_free(x->m_mutex);
603 #ifdef MIDICTRL
604 // m_midiUI *must* be deleted before m_midiHandler
605 delete x->m_midiUI;
606 delete x->m_midiHandler;
607 #endif
608 #ifdef SOUNDFILE
609 delete x->m_soundInterface;
610 #endif
611 #ifdef OSCCTRL
612 delete x->m_oscInterface;
613 #endif
614 }
615
616 /*--------------------------------------------------------------------------*/
faust_perform(t_int * w)617 t_int* faust_perform(t_int* w)
618 {
619 AVOIDDENORMALS;
620 t_faust* x = (t_faust*) (w[1]);
621 long n = w[2];
622 int offset = 3;
623 if (!x->m_mute && systhread_mutex_trylock(x->m_mutex) == MAX_ERR_NONE) {
624 if (x->m_dsp) {
625 x->m_dsp->compute(n, ((float**)&w[offset]), ((float**)&w[offset + x->m_dsp->getNumInputs()]));
626 #ifdef OSCCTRL
627 if (x->m_oscInterface) x->m_oscInterface->endBundle();
628 #endif
629 //faust_update_outputs(x);
630 // Use the right outlet to output messages
631 faust_dump_outputs(x);
632 }
633 #if defined(MIDICTRL) || defined(OSCCTRL)
634 GUI::updateAllGuis();
635 #endif
636 systhread_mutex_unlock(x->m_mutex);
637 } else {
638 float** outputs = ((float**)&w[offset + x->m_Inputs]);
639 // Write null buffers to outs
640 for (int i = 0; i < x->m_Outputs; i++) {
641 memset(outputs[i], 0, sizeof(float) * n);
642 }
643 }
644 return (w + (x->m_Inputs + x->m_Outputs) + 2 + 1);
645 }
646
647 /*--------------------------------------------------------------------------*/
faust_dsp(t_faust * x,t_signal ** sp,short * count)648 void faust_dsp(t_faust* x, t_signal** sp, short* count)
649 {
650 x->m_args[0] = x;
651 x->m_args[1] = (void*)sp[0]->s_n;
652 for (int i = 0; i < (x->m_dsp->getNumInputs() + x->m_dsp->getNumOutputs()); i++) {
653 x->m_args[i + 2] = sp[i]->s_vec;
654 }
655 dsp_addv(faust_perform, (x->m_dsp->getNumInputs() + x->m_dsp->getNumOutputs()) + 2, x->m_args);
656 }
657
658 /*--------------------------------------------------------------------------*/
faust_attr_set(t_faust * x,t_object * attr,long ac,t_atom * av)659 t_max_err faust_attr_set(t_faust* x, t_object* attr, long ac, t_atom* av)
660 {
661 if (ac && av) {
662 t_symbol* attrname = (t_symbol*)object_method(attr, gensym("getname"));
663 // Redirect on the generic message handling method
664 faust_anything(x, attrname, ac, av);
665 }
666 return MAX_ERR_NONE;
667 }
668
669 /*--------------------------------------------------------------------------*/
670 #ifdef _WIN32
main(void)671 extern "C" int main(void)
672 #else
673 void ext_main(void* r)
674 #endif
675 {
676 string file_name = string(FAUST_FILE_NAME);
677 // Remove ".dsp" ending
678 string class_name = file_name.erase(file_name.size()-4) + "~";
679 t_class* c = class_new(class_name.c_str(), (method)faust_new, (method)faust_free, sizeof(t_faust), 0L, A_DEFFLOAT, 0);
680
681 class_addmethod(c, (method)faust_anything, "anything", A_GIMME, 0);
682 class_addmethod(c, (method)faust_polyphony, "polyphony", A_GIMME, 0);
683 #ifdef OSCCTRL
684 class_addmethod(c, (method)faust_osc, "osc", A_GIMME, 0);
685 #endif
686 class_addmethod(c, (method)faust_init, "init", A_GIMME, 0);
687 class_addmethod(c, (method)faust_dump, "dump", A_GIMME, 0);
688 #ifdef MIDICTRL
689 class_addmethod(c, (method)faust_midievent, "midievent", A_GIMME, 0);
690 #endif
691 class_addmethod(c, (method)faust_dsp, "dsp", A_CANT, 0);
692 class_addmethod(c, (method)faust_dblclick, "dblclick", A_CANT, 0);
693 class_addmethod(c, (method)faust_assist, "assist", A_CANT, 0);
694 class_addmethod(c, (method)faust_mute, "mute", A_GIMME, 0);
695
696 dsp* tmp_dsp = new mydsp();
697 mspUI tmp_UI;
698 tmp_dsp->buildUserInterface(&tmp_UI);
699
700 // Setup attribute
701 for (mspUI::iterator it = tmp_UI.begin1(); it != tmp_UI.end1(); it++) {
702 CLASS_ATTR_FLOAT(c, (*it).first.c_str(), 0, t_faust, m_ob);
703 CLASS_ATTR_ACCESSORS(c, (*it).first.c_str(), NULL, (method)faust_attr_set);
704 }
705
706 class_dspinit(c);
707 class_register(CLASS_BOX, c);
708 faust_class = c;
709
710 post((char*)"Faust DSP object v%s (sample = 32 bits code = 32 bits)", EXTERNAL_VERSION);
711 post((char*)"Copyright (c) 2012-2021 Grame");
712
713 Max_Meta1 meta1;
714 tmp_dsp->metadata(&meta1);
715 if (meta1.fCount > 0) {
716 Max_Meta2 meta2;
717 post("------------------------------");
718 tmp_dsp->metadata(&meta2);
719 post("------------------------------");
720 }
721 delete(tmp_dsp);
722 #ifdef _WIN32
723 return 0;
724 #endif
725 }
726
727 /******************* END max-msp.cpp ****************/
728