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