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