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