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-signal.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 /**
43 * Return the current runtime sample rate.
44 *
45 * Reproduce the 'SR' definition in platform.lib: SR = min(192000.0, max(1.0, fconstant(int fSamplingFreq, <math.h>)));
46 *
47 * @return the current runtime sample rate.
48 */
getSampleRate()49 inline Signal getSampleRate()
50 {
51 return sigMin(sigReal(192000.0), sigMax(sigReal(1.0), sigFConst(SType::kSInt, "fSamplingFreq", "<math.h>")));
52 }
53
54 /**
55 * Return the current runtime buffer size.
56 *
57 * Reproduce the 'BS' definition in platform.lib: BS = fvariable(int count, <math.h>);
58 *
59 * @return the current runtime buffer size.
60 */
getBufferSize()61 inline Signal getBufferSize()
62 {
63 return sigFVar(SType::kSInt, "count", "<math.h>");
64 }
65
66
67 #define COMPILER(exp) \
68 { \
69 createLibContext(); \
70 exp \
71 destroyLibContext(); \
72 } \
73
compile(const string & name,tvec signals,int argc=0,const char * argv[]=nullptr)74 static void compile(const string& name, tvec signals, int argc = 0, const char* argv[] = nullptr)
75 {
76 string error_msg;
77 dsp_factory_base* factory = createCPPDSPFactoryFromSignals(name, signals, argc, argv, error_msg);
78 if (factory) {
79 factory->write(&cout);
80 delete(factory);
81 } else {
82 cerr << error_msg;
83 }
84 }
85
86 // process = 0.5;
87
test1()88 static void test1()
89 {
90 COMPILER
91 (
92 tvec signals;
93 signals.push_back(sigReal(0.5));
94
95 compile("test1", signals);
96 )
97 }
98
99 // process = _ <: +(0.5), *(1.5);
100
test2()101 static void test2()
102 {
103 COMPILER
104 (
105 tvec signals;
106 Signal in1 = sigInput(0);
107 signals.push_back(sigAdd(in1, sigReal(0.5)));
108 signals.push_back(sigMul(in1, sigReal(1.5)));
109
110 compile("test2", signals);
111 )
112 }
113
114 // process = _ <: @(+(0.5), 500), @(*(1.5), 3000);
115
test3()116 static void test3()
117 {
118 COMPILER
119 (
120 tvec signals;
121 Signal in1 = sigInput(0);
122 signals.push_back(sigDelay(sigAdd(in1, sigReal(0.5)), sigReal(500)));
123 signals.push_back(sigDelay(sigMul(in1, sigReal(1.5)), sigReal(3000)));
124
125 compile("test3", signals);
126 )
127 }
128
129 // process = _ <: @(500) + 0.5, @(3000) * 1.5;
130
test4()131 static void test4()
132 {
133 COMPILER
134 (
135 tvec signals;
136 Signal in1 = sigInput(0);
137 signals.push_back(sigAdd(sigDelay(in1, sigReal(500)), sigReal(0.5)));
138 signals.push_back(sigMul(sigDelay(in1, sigReal(3000)), sigReal(1.5)));
139
140 compile("test4", signals);
141 )
142 }
143
144 // process = _ <: @(+(0.5), 500), sin(@(@(+(0.5), 500), 600));
145
test5()146 static void test5()
147 {
148 COMPILER
149 (
150 tvec signals;
151 Signal in1 = sigInput(0);
152 signals.push_back(sigDelay(sigAdd(in1, sigReal(0.5)), sigReal(500)));
153 signals.push_back(sigSin(sigDelay(sigDelay(sigAdd(in1, sigReal(0.5)), sigReal(500)), sigReal(600))));
154
155 compile("test5", signals);
156 )
157 }
158
159 // process = _ <: @(+(0.5), 500), @(*(1.5), 3000);
160
test6()161 static void test6()
162 {
163 createLibContext();
164
165 tvec signals;
166 Signal in1 = sigInput(0);
167 signals.push_back(sigDelay(sigAdd(in1, sigReal(0.5)), sigReal(500)));
168 signals.push_back(sigDelay(sigMul(in1, sigReal(1.5)), sigReal(3000)));
169
170 // Vector compilation
171 compile("test6", signals, 4, (const char* []){ "-vec", "-lv", "1" , "-double"});
172
173 destroyLibContext();
174 }
175
176 // process = _ <: @(+(0.5), 500), atan2(@(*(1.5), 3000), 0.5);
177
test7()178 static void test7()
179 {
180 COMPILER
181 (
182 tvec signals;
183 Signal in1 = sigInput(0);
184 signals.push_back(sigDelay(sigAdd(in1, sigReal(0.5)), sigReal(500)));
185 signals.push_back(sigAtan2(sigDelay(sigMul(in1, sigReal(1.5)), sigReal(3000)), sigReal(0.5)));
186
187 compile("test7", signals);
188 )
189 }
190
191 // Equivalent signal expressions
192
equivalent1()193 static void equivalent1()
194 {
195 COMPILER
196 (
197 tvec signals;
198 Signal s1 = sigAdd(sigDelay(sigInput(0), sigReal(500)), sigReal(0.5));
199 signals.push_back(s1);
200 signals.push_back(s1);
201
202 compile("equivalent1", signals);
203 )
204 }
205
equivalent2()206 static void equivalent2()
207 {
208 COMPILER
209 (
210 tvec signals;
211 signals.push_back(sigAdd(sigDelay(sigInput(0), sigReal(500)), sigReal(0.5)));
212 signals.push_back(sigAdd(sigDelay(sigInput(0), sigReal(500)), sigReal(0.5)));
213
214 compile("equivalent2", signals);
215 )
216 }
217
218 // process = @(+(0.5), 500) * vslider("Vol", 0.5, 0, 1, 0.01);
219
test8()220 static void test8()
221 {
222 COMPILER
223 (
224 tvec signals;
225 Signal in1 = sigInput(0);
226 Signal slider = sigVSlider("Vol", sigReal(0.5), sigReal(0.0), sigReal(1.0), sigReal(0.01));
227 signals.push_back(sigMul(slider, sigDelay(sigAdd(in1, sigReal(0.5)), sigReal(500))));
228
229 compile("test8", signals);
230 )
231 }
232
233 /*
234 import("stdfaust.lib");
235
236 freq = vslider("h:Oscillator/freq", 440, 50, 1000, 0.1);
237 gain = vslider("h:Oscillator/gain", 0, 0, 1, 0.01);
238
239 process = freq * gain;
240 */
241
test9()242 static void test9()
243 {
244 COMPILER
245 (
246 tvec signals;
247 Signal freq = sigVSlider("h:Oscillator/freq", sigReal(440), sigReal(50), sigReal(1000), sigReal(0.1));
248 Signal gain = sigVSlider("h:Oscillator/gain", sigReal(0), sigReal(0), sigReal(1), sigReal(0.011));
249 signals.push_back(sigMul(freq, sigMul(gain, sigInput(0))));
250
251 compile("test9", signals);
252 )
253 }
254
255 // process = + ~ _;
256
test10()257 static void test10()
258 {
259 COMPILER
260 (
261 tvec signals;
262 Signal in1 = sigInput(0);
263 signals.push_back(sigRecursion(sigAdd(sigSelf(), in1)));
264
265 compile("test10", signals);
266 )
267 }
268
269 // import("stdfaust.lib");
270 // process = ma.SR, ma.BS;
271
test11()272 static void test11()
273 {
274 COMPILER
275 (
276 tvec signals;
277 signals.push_back(getSampleRate());
278 signals.push_back(getBufferSize());
279
280 compile("test11", signals);
281 )
282 }
283
284 // process = waveform { 0, 100, 200, 300, 400 };
285
test12()286 static void test12()
287 {
288 COMPILER
289 (
290 tvec waveform;
291 // Fill the waveform content vector
292 for (int i = 0; i < 5; i++) {
293 waveform.push_back(sigReal(100*i));
294 }
295 tvec signals;
296 signals.push_back(sigInt(waveform.size())); // the waveform size
297 signals.push_back(sigWaveform(waveform)); // the waveform content
298
299 compile("test12", signals);
300 )
301 }
302
303 // process = waveform { 100+0, 100+100, 100+200, 100+300, 100+400 }; ==> failure
304
test13()305 static void test13()
306 {
307 COMPILER
308 (
309 tvec waveform;
310 for (int i = 0; i < 5; i++) {
311 waveform.push_back(sigAdd(sigReal(100), sigReal(100*i)));
312 }
313 tvec signals;
314 signals.push_back(sigInt(waveform.size())); // the waveform size
315 signals.push_back(sigWaveform(waveform)); // the waveform content
316
317 compile("test13", signals);
318 )
319 }
320
321 // process = _ <: +;
322
test14()323 static void test14()
324 {
325 COMPILER
326 (
327 tvec signals;
328 Signal in1 = sigInput(0);
329 signals.push_back(sigAdd(in1, in1));
330
331 compile("test14", signals);
332 )
333 }
334
335 // process = _,_ <: !,_,_,! :> _,_;
336
test15()337 static void test15()
338 {
339 COMPILER
340 (
341 tvec signals;
342 Signal in1 = sigInput(0);
343 Signal in2 = sigInput(1);
344 signals.push_back(in2);
345 signals.push_back(in1);
346
347 compile("test15", signals);
348 )
349 }
350
351 // process = _,_,_,_ : _,!,!,_;
352
test16()353 static void test16()
354 {
355 COMPILER
356 (
357 tvec signals;
358 Signal in1 = sigInput(0);
359 Signal in3 = sigInput(3);
360 signals.push_back(in1);
361 signals.push_back(in3);
362
363 compile("test16", signals);
364 )
365 }
366
367 /*
368 import("stdfaust.lib");
369 process = phasor(440)
370 with {
371 decimalpart(x) = x-int(x);
372 phasor(f) = f/ma.SR : (+ : decimalpart) ~ _;
373 };
374 */
375
decimalpart(Signal x)376 static Signal decimalpart(Signal x)
377 {
378 return sigSub(x, sigIntCast(x));
379 }
380
phasor(Signal f)381 static Signal phasor(Signal f)
382 {
383 return sigRecursion(decimalpart(sigAdd(sigSelf(), sigDiv(f, getSampleRate()))));
384 }
385
test17()386 static void test17()
387 {
388 COMPILER
389 (
390 tvec signals;
391 signals.push_back(phasor(sigReal(440.0)));
392
393 compile("test17", signals);
394 )
395 }
396
397 /*
398 import("stdfaust.lib");
399 process = osc(440), osc(440)
400 with {
401 decimalpart(x) = x-int(x);
402 phasor(f) = f/ma.SR : (+ : decimalpart) ~ _;
403 osc(f) = sin(2 * ma.PI * phasor(f));
404 };
405 */
406
osc(Signal f)407 static Signal osc(Signal f)
408 {
409 return sigSin(sigMul(phasor(f), sigMul(sigReal(2.0), sigReal(3.141592653))));
410 }
411
test18()412 static void test18()
413 {
414 COMPILER
415 (
416 tvec signals;
417 signals.push_back(osc(sigReal(440.0)));
418 signals.push_back(osc(sigReal(440.0)));
419
420 compile("test18", signals);
421 )
422 }
423
424 // process = 0,0 : soundfile("sound[url:{'tango.wav'}]", 2);
425
test19()426 static void test19()
427 {
428 COMPILER
429 (
430 tvec signals;
431 // Soundfile definition
432 Signal sf = sigSoundfile("sound[url:{'tango.wav'}]");
433 // Simple read index of 0
434 Signal rdx = sigInt(0);
435 // Part 0
436 Signal part = sigInt(0);
437 // Wrapped index to avoid reading outside the buffer
438 Signal wridx = sigIntCast(sigMax(sigInt(0), sigMin(rdx, sigSub(sigSoundfileLength(sf, sigInt(0)), sigInt(1)))));
439 // Accessing part 0
440 signals.push_back(sigSoundfileLength(sf, part));
441 // Accessing part 0
442 signals.push_back(sigSoundfileRate(sf, part));
443 // Accessing chan 0 and part 0, with a wrapped read index
444 signals.push_back(sigSoundfileBuffer(sf, sigInt(0), part, wridx));
445 // Accessing chan 1 and part 0, with a wrapped read index
446 signals.push_back(sigSoundfileBuffer(sf, sigInt(1), part, wridx));
447
448 compile("test19", signals);
449 )
450 }
451
452 // process = 10,1,int(_) : rdtable;
453
test20()454 static void test20()
455 {
456 COMPILER
457 (
458 tvec signals;
459 signals.push_back(sigReadOnlyTable(sigInt(10), sigInt(1), sigIntCast(sigInput(0))));
460
461 compile("test20", signals);
462 )
463 }
464
465 // process = 10,1,int(_),int(_),int(_) : rwtable;
466
test21()467 static void test21()
468 {
469 COMPILER
470 (
471 tvec signals;
472 signals.push_back(sigWriteReadTable(sigInt(10), sigInt(1), sigIntCast(sigInput(0)), sigIntCast(sigInput(1)), sigIntCast(sigInput(2))));
473
474 compile("test21", signals);
475 )
476 }
477
478 /*
479 import("stdfaust.lib");
480 process = osc(f1), osc(f2)
481 with {
482 decimalpart(x) = x-int(x);
483 phasor(f) = f/ma.SR : (+ : decimalpart) ~ _;
484 osc(f) = sin(2 * ma.PI * phasor(f));
485 f1 = vslider("Freq1", 300, 100, 2000, 0.01);
486 f2 = vslider("Freq2", 500, 100, 2000, 0.01);
487 };
488 */
489
490 // Using the LLVM backend.
test22(int argc,char * argv[])491 static void test22(int argc, char* argv[])
492 {
493 createLibContext();
494 {
495 tvec signals;
496 signals.push_back(osc(sigVSlider("h:Oscillator/Freq1", sigReal(300), sigReal(100), sigReal(2000), sigReal(0.01))));
497 signals.push_back(osc(sigVSlider("h:Oscillator/Freq2", sigReal(500), sigReal(100), sigReal(2000), sigReal(0.01))));
498
499 string error_msg;
500 llvm_dsp_factory* factory = createDSPFactoryFromSignals("FaustDSP", signals, 0, nullptr, "", error_msg);
501
502 if (factory) {
503 dsp* dsp = factory->createDSPInstance();
504 assert(dsp);
505
506 // Allocate audio driver
507 jackaudio audio;
508 audio.init("Test", dsp);
509
510 // Create GUI
511 GTKUI gtk_ui = GTKUI((char*)"Organ", &argc, &argv);
512 dsp->buildUserInterface(>k_ui);
513
514 // Start real-time processing
515 audio.start();
516
517 // Start GUI
518 gtk_ui.run();
519
520 // Cleanup
521 audio.stop();
522 delete dsp;
523 deleteDSPFactory(factory);
524 } else {
525 cerr << "Cannot create factory" << error_msg << endl;
526 }
527 }
528 destroyLibContext();
529 }
530
531 // Using the Interpreter backend.
test23(int argc,char * argv[])532 static void test23(int argc, char* argv[])
533 {
534 interpreter_dsp_factory* factory = nullptr;
535 string error_msg;
536
537 createLibContext();
538 {
539 tvec signals;
540 signals.push_back(osc(sigHSlider("v:Oscillator/Freq1", sigReal(300), sigReal(100), sigReal(2000), sigReal(0.01))));
541 signals.push_back(osc(sigHSlider("v:Oscillator/Freq2", sigReal(500), sigReal(100), sigReal(2000), sigReal(0.01))));
542
543 factory = createInterpreterDSPFactoryFromSignals("FaustDSP", signals, 0, nullptr, error_msg);
544 }
545 destroyLibContext();
546
547 // Use factory outside of the createLibContext/destroyLibContext scope
548 if (factory) {
549 dsp* dsp = factory->createDSPInstance();
550 assert(dsp);
551
552 // Allocate audio driver
553 jackaudio audio;
554 audio.init("Test", dsp);
555
556 // Create GUI
557 GTKUI gtk_ui = GTKUI((char*)"Organ", &argc, &argv);
558 dsp->buildUserInterface(>k_ui);
559
560 // Start real-time processing
561 audio.start();
562
563 // Start GUI
564 gtk_ui.run();
565
566 // Cleanup
567 audio.stop();
568 delete dsp;
569 deleteInterpreterDSPFactory(factory);
570 } else {
571 cerr << "Cannot create factory" << error_msg << endl;
572 }
573 }
574
575 /*
576 import("stdfaust.lib");
577 process = organ, organ
578 with {
579 decimalpart(x) = x-int(x);
580 phasor(f) = f/ma.SR : (+ : decimalpart) ~ _;
581 osc(f) = sin(2 * ma.PI * phasor(f));
582 freq = nentry("freq", 100, 100, 3000, 0.01);
583 gate = button("gate");
584 gain = nentry("gain", 0.5, 0, 1, 0.01);
585 organ = gate * (osc(freq) * gain + osc(2 * freq) * gain);
586 };
587 */
588
589 // Simple polyphonic DSP.
test24(int argc,char * argv[])590 static void test24(int argc, char* argv[])
591 {
592 interpreter_dsp_factory* factory = nullptr;
593 string error_msg;
594
595 createLibContext();
596 {
597 tvec signals;
598
599 // Follow the freq/gate/gain convention, see: https://faustdoc.grame.fr/manual/midi/#standard-polyphony-parameters
600 Signal freq = sigNumEntry("freq", sigReal(100), sigReal(100), sigReal(3000), sigReal(0.01));
601 Signal gate = sigButton("gate");
602 Signal gain = sigNumEntry("gain", sigReal(0.5), sigReal(0), sigReal(1), sigReal(0.01));
603 Signal organ = sigMul(gate, sigAdd(sigMul(osc(freq), gain), sigMul(osc(sigMul(freq, sigInt(2))), gain)));
604 // Stereo
605 signals.push_back(organ);
606 signals.push_back(organ);
607
608 factory = createInterpreterDSPFactoryFromSignals("FaustDSP", signals, 0, nullptr, error_msg);
609 }
610 destroyLibContext();
611
612 // Use factory outside of the createLibContext/destroyLibContext scope
613 if (factory) {
614 dsp* dsp = factory->createDSPInstance();
615 assert(dsp);
616
617 // Allocate polyphonic DSP
618 dsp = new mydsp_poly(dsp, 8, true, true);
619
620 // Allocate MIDI/audio driver
621 jackaudio_midi audio;
622 audio.init("Organ", dsp);
623
624 // Create GUI
625 GTKUI gtk_ui = GTKUI((char*)"Organ", &argc, &argv);
626 dsp->buildUserInterface(>k_ui);
627
628 // Create MIDI controller
629 MidiUI midi_ui = MidiUI(&audio);
630 dsp->buildUserInterface(&midi_ui);
631
632 // Start real-time processing
633 audio.start();
634
635 // Start MIDI
636 midi_ui.run();
637
638 // Start GUI
639 gtk_ui.run();
640
641 // Cleanup
642 audio.stop();
643 delete dsp;
644 deleteInterpreterDSPFactory(factory);
645 } else {
646 cerr << "Cannot create factory" << error_msg << endl;
647 }
648 }
649
650 list<GUI*> GUI::fGuiList;
651 ztimedmap GUI::gTimedZoneMap;
652
main(int argc,char * argv[])653 int main(int argc, char* argv[])
654 {
655 test1();
656 test2();
657 test3();
658 test4();
659 test5();
660 test6();
661 test7();
662 equivalent1();
663 equivalent2();
664 test8();
665 test9();
666 test10();
667 test11();
668 test12();
669 test13();
670 test14();
671 test15();
672 test16();
673 test17();
674 test18();
675 test19();
676 test20();
677 test21();
678
679 // Test with audio, GUI and LLVM backend
680 test22(argc, argv);
681
682 // Test with audio, GUI and Interp backend
683 test23(argc, argv);
684
685 // Test with audio, GUI, MIDI and Interp backend
686 test24(argc, argv);
687
688 return 0;
689 }
690
691