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(&gtk_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(&gtk_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(&gtk_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