1 /************************************************************************
2 FAUST Architecture File
3 Copyright (C) 2021 GRAME, Centre National de Creation Musicale
4 ---------------------------------------------------------------------
5 This Architecture section is free software; you can redistribute it
6 and/or modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 3 of
8 the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; If not, see <http://www.gnu.org/licenses/>.
17
18 EXCEPTION : As a special exception, you may create a larger work
19 that contains this FAUST architecture section and distribute
20 that work under terms of your choice, so long as this FAUST
21 architecture section is not modified.
22
23 ************************************************************************/
24
25 #include <libgen.h>
26 #include <iostream>
27 #include <string>
28 #include <vector>
29
30 #include "faust/dsp/libfaust-box.h"
31 #include "faust/dsp/llvm-dsp.h"
32 #include "faust/dsp/interpreter-dsp.h"
33 #include "faust/dsp/poly-dsp.h"
34 #include "faust/audio/jack-dsp.h"
35 #include "faust/gui/GTKUI.h"
36 #include "faust/gui/MidiUI.h"
37 #include "faust/misc.h"
38
39 using namespace std;
40
41 /**
42 * Return the current runtime sample rate.
43 *
44 * Reproduce the 'SR' definition in platform.lib: SR = min(192000.0, max(1.0, fconstant(int fSamplingFreq, <math.h>)));
45 *
46 * @return the current runtime sample rate.
47 */
getSampleRate()48 inline Box getSampleRate()
49 {
50 return boxMin(boxReal(192000.0), boxMax(boxReal(1.0), boxFConst(SType::kSInt, "fSamplingFreq", "<math.h>")));
51 }
52
53 /**
54 * Return the current runtime buffer size.
55 *
56 * Reproduce the 'BS' definition in platform.lib: BS = fvariable(int count, <math.h>);
57 *
58 * @return the current runtime buffer size.
59 */
getBufferSize()60 inline Box getBufferSize()
61 {
62 return boxFVar(SType::kSInt, "count", "<math.h>");
63 }
64
65 #define COMPILER(exp) \
66 { \
67 createLibContext(); \
68 exp \
69 destroyLibContext(); \
70 } \
71
compile(const string & name,Box box,int argc=0,const char * argv[]=nullptr)72 static void compile(const string& name, Box box, int argc = 0, const char* argv[] = nullptr)
73 {
74 string error_msg;
75 dsp_factory_base* factory = createCPPDSPFactoryFromBoxes(name, box, argc, argv, error_msg);
76 if (factory) {
77 factory->write(&cout);
78 delete(factory);
79 } else {
80 cerr << error_msg;
81 }
82 }
83
84 // process = 7,3.14;
85
test1()86 static void test1()
87 {
88 COMPILER
89 (
90 Box box = boxPar(boxInt(7), boxReal(3.14));
91
92 compile("test1", box);
93 )
94 }
95
96 // process = _,3.14 : +;
97
test2()98 static void test2()
99 {
100 COMPILER
101 (
102 Box box = boxSeq(boxPar(boxWire(), boxReal(3.14)), boxAdd());
103
104 compile("test2", box);
105 )
106 }
107
108 // Alternate version with the binary 'boxAdd' version
109 // process = +(_,3.14);
110
test3()111 static void test3()
112 {
113 COMPILER
114 (
115 Box box = boxAdd(boxWire(), boxReal(3.14));
116
117 compile("test3", box);
118 )
119 }
120
121
122 // process = _,_ : +;
123
test4()124 static void test4()
125 {
126 COMPILER
127 (
128 Box box = boxSeq(boxPar(boxWire(), boxWire()), boxAdd());
129
130 compile("test4", box);
131 )
132 }
133
134 // Connection error
135 // process = _ : +;
136
test5()137 static void test5()
138 {
139 COMPILER
140 (
141 Box box = boxSeq(boxWire(), boxMul());
142
143 compile("test5", box);
144 )
145 }
146
147 // process = @(_,7);
148
test6()149 static void test6()
150 {
151 COMPILER
152 (
153 Box box = boxDelay(boxWire(), boxInt(7));
154
155 compile("test6", box);
156 )
157 }
158
159 // process = @(_,7);
160
test7()161 static void test7()
162 {
163 createLibContext();
164 Box box = boxDelay(boxWire(), boxInt(7));
165
166 compile("test7", box, 3, (const char* []){ "-vec", "-lv", "1" });
167 destroyLibContext();
168 }
169
170
171 // process = _ <: @(500) + 0.5, @(3000) * 1.5;
172
test8()173 static void test8()
174 {
175 COMPILER
176 (
177 Box box = boxSplit(boxWire(), boxPar(boxAdd(boxDelay(boxWire(), boxReal(500)), boxReal(0.5)),
178 boxMul(boxDelay(boxWire(), boxReal(3000)), boxReal(1.5))));
179
180 compile("test8", box);
181 )
182 }
183
184 // Equivalent signal expressions
185
equivalent1()186 static void equivalent1()
187 {
188 COMPILER
189 (
190 Box b1 = boxAdd(boxDelay(boxWire(), boxReal(500)), boxReal(0.5));
191 Box box = boxPar(b1, b1);
192
193 compile("equivalent1", box);
194 )
195 }
196
equivalent2()197 static void equivalent2()
198 {
199 COMPILER
200 (
201 Box box = boxPar(boxAdd(boxDelay(boxWire(), boxReal(500)), boxReal(0.5)),
202 boxAdd(boxDelay(boxWire(), boxReal(500)), boxReal(0.5)));
203
204 compile("equivalent2", box);
205 )
206 }
207
208 // process = _,hslider("Freq [midi:ctrl 7][style:knob]", 100, 100, 2000, 1) : *;
209
test9()210 static void test9()
211 {
212 COMPILER
213 (
214 Box box = boxMul(boxWire(), boxHSlider("Freq [midi:ctrl 7][style:knob]", boxReal(100), boxReal(100), boxReal(2000), boxReal(1)));
215
216 compile("test9", box);
217 )
218 }
219
220 /*
221 import("stdfaust.lib");
222
223 freq = vslider("h:Oscillator/freq", 440, 50, 1000, 0.1);
224 gain = vslider("h:Oscillator/gain", 0, 0, 1, 0.01);
225
226 process = freq * gain;
227 */
228
test10()229 static void test10()
230 {
231 COMPILER
232 (
233 Box box = boxMul(boxVSlider("h:Oscillator/freq", boxReal(440), boxReal(50), boxReal(1000), boxReal(0.1)),
234 boxVSlider("h:Oscillator/gain", boxReal(0), boxReal(0), boxReal(1), boxReal(0.01)));
235
236 compile("test10", box);
237 )
238 }
239
240 // import("stdfaust.lib");
241 // process = ma.SR, ma.BS;
242
test11()243 static void test11()
244 {
245 COMPILER
246 (
247 Box box = boxPar(getSampleRate(), getBufferSize());
248
249 compile("test11", box);
250 )
251 }
252
253 // process = waveform { 0, 100, 200, 300, 400 };
254
test12()255 static void test12()
256 {
257 COMPILER
258 (
259 tvec waveform;
260 // Fill the waveform content vector
261 for (int i = 0; i < 5; i++) {
262 waveform.push_back(boxReal(100*i));
263 }
264 Box box = boxWaveform(waveform); // the waveform content
265
266 compile("test12", box);
267 )
268 }
269
270 // process = _ <: +;
271
test13()272 static void test13()
273 {
274 COMPILER
275 (
276 Box box = boxSplit(boxWire(), boxAdd());
277
278 compile("test13", box);
279 )
280 }
281
282 // process = _,_ <: !,_,_,! :> _,_;
283
test14()284 static void test14()
285 {
286 COMPILER
287 (
288 Box box = boxSplit(boxPar(boxWire(), boxWire()),
289 boxMerge(boxPar4(boxCut(), boxWire(), boxWire(), boxCut()),
290 boxPar(boxWire(), boxWire())));
291
292 compile("test14", box);
293 )
294 }
295
296 // process = + ~ _;
297
test15()298 static void test15()
299 {
300 COMPILER
301 (
302 Box box = boxRec(boxAdd(), boxWire());
303
304 compile("test15", box);
305 )
306 }
307
308 /*
309 import("stdfaust.lib");
310 process = phasor(440)
311 with {
312 decimalpart = _,int(_) : -;
313 phasor(f) = f/ma.SR : (+ <: decimalpart) ~ _;
314 };
315 */
316
decimalpart()317 static Box decimalpart()
318 {
319 return boxSub(boxWire(), boxIntCast(boxWire()));
320 }
321
phasor(Box f)322 static Box phasor(Box f)
323 {
324 return boxSeq(boxDiv(f, getSampleRate()), boxRec(boxSplit(boxAdd(), decimalpart()), boxWire()));
325 }
326
test16()327 static void test16()
328 {
329 COMPILER
330 (
331 Box box = phasor(boxReal(440));
332
333 compile("test16", box);
334 )
335 }
336
337 /*
338 import("stdfaust.lib");
339 process = osc(440), osc(440)
340 with {
341 decimalpart(x) = x-int(x);
342 phasor(f) = f/ma.SR : (+ : decimalpart) ~ _;
343 osc(f) = sin(2 * ma.PI * phasor(f));
344 };
345 */
346
osc(Box f)347 static Box osc(Box f)
348 {
349 return boxSin(boxMul(boxMul(boxReal(2.0), boxReal(3.141592653)), phasor(f)));
350 }
351
test17()352 static void test17()
353 {
354 COMPILER
355 (
356 Box box = boxPar(osc(boxReal(440)), osc(boxReal(440)));
357
358 compile("test17", box);
359 )
360 }
361
362 // process = 0,0 : soundfile("sound[url:{'tango.wav'}]", 2);
363
test18()364 static void test18()
365 {
366 COMPILER
367 (
368 Box box = boxSoundfile("sound[url:{'tango.wav'}]", boxInt(2), boxInt(0), boxInt(0));
369
370 compile("test18", box);
371 )
372 }
373
374 // process = 10,1,int(_) : rdtable;
375
test19()376 static void test19()
377 {
378 COMPILER
379 (
380 Box box = boxReadOnlyTable(boxInt(10), boxInt(1), boxIntCast(boxWire()));
381
382 compile("test19", box);
383 )
384 }
385
386 // process = 10,1,int(_),int(_),int(_) : rwtable;
387
test20()388 static void test20()
389 {
390 COMPILER
391 (
392 Box box = boxWriteReadTable(boxInt(10), boxInt(1), boxIntCast(boxWire()), boxIntCast(boxWire()), boxIntCast(boxWire()));
393
394 compile("test20", box);
395 )
396 }
397
398 /*
399 import("stdfaust.lib");
400 process = osc(f1), osc(f2)
401 with {
402 decimalpart(x) = x-int(x);
403 phasor(f) = f/ma.SR : (+ : decimalpart) ~ _;
404 osc(f) = sin(2 * ma.PI * phasor(f));
405 f1 = vslider("Freq1", 300, 100, 2000, 0.01);
406 f2 = vslider("Freq2", 500, 100, 2000, 0.01);
407 };
408 */
409
410 // Using the LLVM backend.
test21(int argc,char * argv[])411 static void test21(int argc, char* argv[])
412 {
413 createLibContext();
414 {
415 Box sl1 = boxVSlider("h:Oscillator/Freq1", boxReal(300), boxReal(100), boxReal(2000), boxReal(0.01));
416 Box sl2 = boxVSlider("h:Oscillator/Freq2", boxReal(300), boxReal(100), boxReal(2000), boxReal(0.01));
417 Box box = boxPar(osc(sl1), osc(sl2));
418
419 string error_msg;
420 llvm_dsp_factory* factory = createDSPFactoryFromBoxes("FaustDSP", box, 0, nullptr, "", error_msg);
421
422 if (factory) {
423 dsp* dsp = factory->createDSPInstance();
424 assert(dsp);
425
426 // Allocate audio driver
427 jackaudio audio;
428 audio.init("Test", dsp);
429
430 // Create GUI
431 GTKUI gtk_ui = GTKUI((char*)"Organ", &argc, &argv);
432 dsp->buildUserInterface(>k_ui);
433
434 // Start real-time processing
435 audio.start();
436
437 // Start GUI
438 gtk_ui.run();
439
440 // Cleanup
441 audio.stop();
442 delete dsp;
443 deleteDSPFactory(factory);
444 } else {
445 cerr << "Cannot create factory" << error_msg << endl;
446 }
447 }
448 destroyLibContext();
449 }
450
451 // Using the Interpreter backend.
test22(int argc,char * argv[])452 static void test22(int argc, char* argv[])
453 {
454 createLibContext();
455 {
456 Box sl1 = boxHSlider("v:Oscillator/Freq1", boxReal(300), boxReal(100), boxReal(2000), boxReal(0.01));
457 Box sl2 = boxHSlider("v:Oscillator/Freq2", boxReal(300), boxReal(100), boxReal(2000), boxReal(0.01));
458 Box box = boxPar(osc(sl1), osc(sl2));
459
460 string error_msg;
461 interpreter_dsp_factory* factory = createInterpreterDSPFactoryFromBoxes("FaustDSP", box, 0, nullptr, error_msg);
462
463 if (factory) {
464 dsp* dsp = factory->createDSPInstance();
465 assert(dsp);
466
467 // Allocate audio driver
468 jackaudio audio;
469 audio.init("Test", dsp);
470
471 // Create GUI
472 GTKUI gtk_ui = GTKUI((char*)"Organ", &argc, &argv);
473 dsp->buildUserInterface(>k_ui);
474
475 // Start real-time processing
476 audio.start();
477
478 // Start GUI
479 gtk_ui.run();
480
481 // Cleanup
482 audio.stop();
483 delete dsp;
484 deleteInterpreterDSPFactory(factory);
485 } else {
486 cerr << "Cannot create factory" << error_msg << endl;
487 }
488 }
489 destroyLibContext();
490 }
491
492 // Using the Interpreter backend.
test23(int argc,char * argv[])493 static void test23(int argc, char* argv[])
494 {
495 interpreter_dsp_factory* factory = nullptr;
496 string error_msg;
497
498 createLibContext();
499 {
500 Box sl1 = boxHSlider("v:Oscillator/Freq1", boxReal(300),
501 boxReal(100), boxReal(2000), boxReal(0.01));
502 Box sl2 = boxHSlider("v:Oscillator/Freq2", boxReal(300),
503 boxReal(100), boxReal(2000), boxReal(0.01));
504 Box box = boxPar(osc(sl1), osc(sl2));
505
506 // Compile the 'bo'x to 'signals'
507 tvec signals = boxesToSignals(box, error_msg);
508
509 // Then compile the 'signals' to a DSP factory
510 factory = createInterpreterDSPFactoryFromSignals("FaustDSP",
511 signals, 0,
512 nullptr, error_msg);
513 }
514 destroyLibContext();
515
516 // Use factory outside of the createLibContext/destroyLibContext scope
517 if (factory) {
518 dsp* dsp = factory->createDSPInstance();
519 assert(dsp);
520
521 // Allocate audio driver
522 jackaudio audio;
523 audio.init("Test", dsp);
524
525 // Create GUI
526 GTKUI gtk_ui = GTKUI("Organ", &argc, &argv);
527 dsp->buildUserInterface(>k_ui);
528
529 // Start real-time processing
530 audio.start();
531
532 // Start GUI
533 gtk_ui.run();
534
535 // Cleanup
536 audio.stop();
537 delete dsp;
538 deleteInterpreterDSPFactory(factory);
539 } else {
540 cerr << error_msg;
541 }
542 }
543
544 /*
545 import("stdfaust.lib");
546 process = organ, organ
547 with {
548 decimalpart(x) = x-int(x);
549 phasor(f) = f/ma.SR : (+ : decimalpart) ~ _;
550 osc(f) = sin(2 * ma.PI * phasor(f));
551 freq = nentry("freq", 100, 100, 3000, 0.01);
552 gate = button("gate");
553 gain = nentry("gain", 0.5, 0, 1, 0.01);
554 organ = gate * (osc(freq) * gain + osc(2 * freq) * gain);
555 };
556 */
557
558 // Simple polyphonic DSP.
test24(int argc,char * argv[])559 static void test24(int argc, char* argv[])
560 {
561 interpreter_dsp_factory* factory = nullptr;
562 string error_msg;
563
564 createLibContext();
565 {
566 // Follow the freq/gate/gain convention, see: https://faustdoc.grame.fr/manual/midi/#standard-polyphony-parameters
567 Box freq = boxNumEntry("freq", boxReal(100), boxReal(100), boxReal(3000), boxReal(0.01));
568 Box gate = boxButton("gate");
569 Box gain = boxNumEntry("gain", boxReal(0.5), boxReal(0), boxReal(1), boxReal(0.01));
570 Box organ = boxMul(gate, boxAdd(boxMul(osc(freq), gain), boxMul(osc(boxMul(freq, boxInt(2))), gain)));
571 // Stereo
572 Box box = boxPar(organ, organ);
573
574 factory = createInterpreterDSPFactoryFromBoxes("FaustDSP", box, 0, nullptr, error_msg);
575 }
576 destroyLibContext();
577
578 // Use factory outside of the createLibContext/destroyLibContext scope
579 if (factory) {
580 dsp* dsp = factory->createDSPInstance();
581 assert(dsp);
582
583 // Allocate polyphonic DSP
584 dsp = new mydsp_poly(dsp, 8, true, true);
585
586 // Allocate MIDI/audio driver
587 jackaudio_midi audio;
588 audio.init("Organ", dsp);
589
590 // Create GUI
591 GTKUI gtk_ui = GTKUI((char*)"Organ", &argc, &argv);
592 dsp->buildUserInterface(>k_ui);
593
594 // Create MIDI controller
595 MidiUI midi_ui = MidiUI(&audio);
596 dsp->buildUserInterface(&midi_ui);
597
598 // Start real-time processing
599 audio.start();
600
601 // Start MIDI
602 midi_ui.run();
603
604 // Start GUI
605 gtk_ui.run();
606
607 // Cleanup
608 audio.stop();
609 delete dsp;
610 deleteInterpreterDSPFactory(factory);
611 } else {
612 cerr << "Cannot create factory" << error_msg << endl;
613 }
614 }
615
616 list<GUI*> GUI::fGuiList;
617 ztimedmap GUI::gTimedZoneMap;
618
main(int argc,char * argv[])619 int main(int argc, char* argv[])
620 {
621 test1();
622 test2();
623 test3();
624 test4();
625 test5();
626 test6();
627 test7();
628 equivalent1();
629 equivalent2();
630 test8();
631 test9();
632 test10();
633 test11();
634 test12();
635 test13();
636 test14();
637 test15();
638 test16();
639 test17();
640 test18();
641 test19();
642 test20();
643
644 // Test with audio, GUI and LLVM backend
645 test21(argc, argv);
646
647 // Test with audio, GUI and Interp backend
648 test22(argc, argv);
649
650 // Test with audio, GUI and Interp backend and using 'boxesToSignals' function
651 test23(argc, argv);
652
653 // Test with audio, GUI, MIDI and Interp backend
654 test24(argc, argv);
655
656 return 0;
657 }
658
659