1 #include <string>
2 #include <map>
3 #include <iostream>
4 #include <sstream>
5 #include <math.h>
6 #include <list>
7
8 #define MEMORY_READER
9 #include "faust/gui/SoundUI.h"
10
11 #include "faust/dsp/llvm-dsp.h"
12 #include "faust/dsp/one-sample-dsp.h"
13 #include "faust/gui/GUI.h"
14 #include "faust/dsp/poly-dsp.h"
15 #include "faust/audio/channels.h"
16 #include "faust/gui/DecoratorUI.h"
17 #include "faust/gui/FUI.h"
18 #include "faust/gui/MidiUI.h"
19 #include "faust/midi/midi.h"
20 #include "faust/misc.h"
21
22 using std::max;
23 using std::min;
24
25 #define kFrames 64
26
27 using namespace std;
28
29 std::list<GUI*> GUI::fGuiList;
30 ztimedmap GUI::gTimedZoneMap;
31
32 //----------------------------------------------------------------------------
33 // Test MemoryReader
34 //----------------------------------------------------------------------------
35
36 struct TestMemoryReader : public MemoryReader {
37
checkFileTestMemoryReader38 virtual bool checkFile(const std::string& path_name)
39 {
40 return true;
41 }
42
getParamsFileTestMemoryReader43 virtual void getParamsFile(const std::string& path_name, int& channels, int& length)
44 {
45 channels = SOUND_CHAN;
46 length = SOUND_LENGTH;
47 }
48
readFileTestMemoryReader49 virtual void readFile(Soundfile* soundfile, const std::string& path_name, int part, int& offset, int max_chan)
50 {
51 soundfile->fLength[part] = SOUND_LENGTH;
52 soundfile->fSR[part] = SOUND_SR;
53 soundfile->fOffset[part] = offset;
54
55 // Audio frames have to be written for each chan
56 if (soundfile->fIsDouble) {
57 for (int sample = 0; sample < SOUND_LENGTH; sample++) {
58 for (int chan = 0; chan < SOUND_CHAN; chan++) {
59 static_cast<double**>(soundfile->fBuffers)[chan][offset + sample] = std::sin(part + (2 * M_PI * double(sample)/SOUND_LENGTH));
60 }
61 }
62 } else {
63 for (int sample = 0; sample < SOUND_LENGTH; sample++) {
64 for (int chan = 0; chan < SOUND_CHAN; chan++) {
65 static_cast<float**>(soundfile->fBuffers)[chan][offset + sample] = std::sin(part + (2 * M_PI * float(sample)/SOUND_LENGTH));
66 }
67 }
68 }
69
70 // Update offset
71 offset += SOUND_LENGTH;
72 }
73
74 };
75
76 //----------------------------------------------------------------------------
77 // DSP control UI
78 //----------------------------------------------------------------------------
79
80 struct CheckControlUI : public GenericUI {
81
82 map<FAUSTFLOAT*, FAUSTFLOAT> fControlZone;
83
addButtonCheckControlUI84 virtual void addButton(const char* label, FAUSTFLOAT* zone)
85 {
86 addItem(zone, FAUSTFLOAT(0));
87 }
addCheckButtonCheckControlUI88 virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
89 {
90 addItem(zone, FAUSTFLOAT(0));
91 }
addVerticalSliderCheckControlUI92 virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
93 {
94 addItem(zone, init);
95 }
addHorizontalSliderCheckControlUI96 virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
97 {
98 addItem(zone, init);
99 }
addNumEntryCheckControlUI100 virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
101 {
102 addItem(zone, init);
103 }
104
addItemCheckControlUI105 void addItem(FAUSTFLOAT* zone, FAUSTFLOAT init)
106 {
107 fControlZone[zone] = init;
108 }
109
checkDefaultsCheckControlUI110 bool checkDefaults()
111 {
112 for (const auto& it : fControlZone) {
113 if (*it.first != it.second) return false;
114 }
115 return true;
116 }
117
initRandomCheckControlUI118 void initRandom()
119 {
120 for (const auto& it : fControlZone) {
121 *it.first = 0.123456789;
122 }
123 }
124 };
125
126 //----------------------------------------------------------------------------
127 // Test memory manager
128 //----------------------------------------------------------------------------
129
130 struct malloc_memory_manager : public dsp_memory_manager {
131
allocatemalloc_memory_manager132 virtual void* allocate(size_t size)
133 {
134 void* res = malloc(size);
135 memset(res, 0, size);
136 return res;
137 }
138
destroymalloc_memory_manager139 virtual void destroy(void* ptr)
140 {
141 free(ptr);
142 }
143
144 };
145
printHeader(dsp * DSP,int nbsamples)146 static void printHeader(dsp* DSP, int nbsamples)
147 {
148 // Print general informations
149 printf("number_of_inputs : %3d\n", DSP->getNumInputs());
150 printf("number_of_outputs : %3d\n", DSP->getNumOutputs());
151 printf("number_of_frames : %6d\n", nbsamples);
152 }
153
normalize(FAUSTFLOAT f)154 static inline FAUSTFLOAT normalize(FAUSTFLOAT f)
155 {
156 if (std::isnan(f)) {
157 cerr << "ERROR : isnan" << std::endl;
158 throw -1;
159 } else if (std::isinf(f)) {
160 cerr << "ERROR : isinf" << std::endl;
161 throw -1;
162 }
163 return (fabs(f) < FAUSTFLOAT(0.000001) ? FAUSTFLOAT(0.0) : f);
164 }
165
166 // To be used in static context
167 static void runPolyDSP(dsp* dsp, int& linenum, int nbsamples, int num_voices = 4)
168 {
169 mydsp_poly* DSP = new mydsp_poly(dsp, num_voices, true, false);
170
171 // Soundfile
172 TestMemoryReader memory_reader;
173 SoundUI sound_ui("", -1, &memory_reader, (sizeof(FAUSTFLOAT) == sizeof(double)));
174 DSP->buildUserInterface(&sound_ui);
175
176 // Get control and then 'initRandom'
177 CheckControlUI controlui;
178 DSP->buildUserInterface(&controlui);
179 controlui.initRandom();
180
181 // init signal processor and the user interface values:
182 DSP->init(44100);
183
184 // Check getSampleRate
185 if (DSP->getSampleRate() != 44100) {
186 cerr << "ERROR runPolyDSP in getSampleRate : " << DSP->getSampleRate() << std::endl;
187 }
188
189 // Check default after 'init'
190 if (!controlui.checkDefaults()) {
191 cerr << "ERROR runPolyDSP in checkDefaults after 'init'" << std::endl;
192 }
193
194 // Check default after 'instanceResetUserInterface'
195 controlui.initRandom();
196 DSP->instanceResetUserInterface();
197 if (!controlui.checkDefaults()) {
198 cerr << "ERROR runPolyDSP in checkDefaults after 'instanceResetUserInterface'" << std::endl;
199 }
200
201 // Check default after 'instanceInit'
202 controlui.initRandom();
203 DSP->instanceInit(44100);
204 if (!controlui.checkDefaults()) {
205 cerr << "ERROR runPolyDSP in checkDefaults after 'instanceInit'" << std::endl;
206 }
207
208 // Init again
209 DSP->init(44100);
210
211 int nins = DSP->getNumInputs();
212 channels ichan(kFrames, nins);
213
214 int nouts = DSP->getNumOutputs();
215 channels ochan(kFrames, nouts);
216
217 // Test polyphony
218 for (int i = 0; i < num_voices; i++) {
219 DSP->keyOn(0, 60 + i*2, 100);
220 }
221
222 // Compute audio frames
223 while (nbsamples > 0) {
224 int nFrames = min(kFrames, nbsamples);
225 DSP->compute(nFrames, ichan.buffers(), ochan.buffers());
226 // Print samples
227 for (int i = 0; i < nFrames; i++) {
228 printf("%6d : ", linenum++);
229 for (int c = 0; c < nouts; c++) {
230 FAUSTFLOAT f = normalize(ochan.buffers()[c][i]);
231 printf(" %8.6f", f);
232 }
233 printf("\n");
234 }
235 nbsamples -= nFrames;
236 }
237
238 delete DSP;
239 }
240
241 // To be used in dynamic context (LLVM or interp backends)
242 static void runPolyDSP1(dsp_factory* factory, int& linenum, int nbsamples, int num_voices = 4, bool is_mem_alloc = false)
243 {
244 malloc_memory_manager manager;
245 factory->setMemoryManager((is_mem_alloc) ? &manager : nullptr);
246 runPolyDSP(factory->createDSPInstance(), linenum, nbsamples, num_voices);
247 }
248
249 // To be used in static context
250 static void runDSP(dsp* DSP, const string& file, int& linenum, int nbsamples, bool inpl = false, bool random = false)
251 {
252 char rcfilename[256];
253 string filename = file;
254 filename = filename.substr(0, filename.find ('.'));
255 snprintf(rcfilename, 255, "%src", filename.c_str());
256
257 FUI finterface;
258 DSP->buildUserInterface(&finterface);
259
260 // Soundfile
261 TestMemoryReader memory_reader;
262 SoundUI sound_ui("", -1, &memory_reader, (sizeof(FAUSTFLOAT) == sizeof(double)));
263 DSP->buildUserInterface(&sound_ui);
264
265 // Get control and then 'initRandom'
266 CheckControlUI controlui;
267 DSP->buildUserInterface(&controlui);
268 controlui.initRandom();
269
270 // MIDI control
271 midi_handler handler;
272 MidiUI midi_ui(&handler);
273 DSP->buildUserInterface(&midi_ui);
274
275 // Init signal processor and the user interface values
276 DSP->init(44100);
277
278 // Check getSampleRate
279 if (DSP->getSampleRate() != 44100) {
280 cerr << "ERROR runDSP in getSampleRate : " << DSP->getSampleRate() << std::endl;
281 }
282
283 // Check default after 'init'
284 if (!controlui.checkDefaults()) {
285 cerr << "ERROR runDSP in checkDefaults after 'init'" << std::endl;
286 }
287
288 // Check default after 'instanceResetUserInterface'
289 controlui.initRandom();
290 DSP->instanceResetUserInterface();
291 if (!controlui.checkDefaults()) {
292 cerr << "ERROR runDSP in checkDefaults after 'instanceResetUserInterface'" << std::endl;
293 }
294
295 // Check default after 'instanceInit'
296 controlui.initRandom();
297 DSP->instanceInit(44100);
298 if (!controlui.checkDefaults()) {
299 cerr << "ERROR runDSP in checkDefaults after 'instanceInit'" << std::endl;
300 }
301
302 // To test that instanceInit properly init a cloned DSP
303 DSP = DSP->clone();
304 DSP->instanceInit(44100);
305
306 // Init UIs on cloned DSP
307 DSP->buildUserInterface(&finterface);
308 DSP->buildUserInterface(&sound_ui);
309 DSP->buildUserInterface(&midi_ui);
310
311 int nins = DSP->getNumInputs();
312 int nouts = DSP->getNumOutputs();
313
314 channels* ichan = new channels(kFrames, ((inpl) ? std::max(nins, nouts) : nins));
315 channels* ochan = (inpl) ? ichan : new channels(kFrames, nouts);
316
317 int run = 0;
318
319 // recall saved state
320 finterface.recallState(rcfilename);
321
322 // Test MIDI control
323 for (int i = 0; i < 127; i++) {
324 handler.handleData2(0, midi::MidiStatus::MIDI_CONTROL_CHANGE, 0, i, 100);
325 handler.handleData2(0, midi::MidiStatus::MIDI_POLY_AFTERTOUCH, 0, i, 75);
326 handler.handleData2(0, midi::MidiStatus::MIDI_NOTE_ON, 0, i, 75);
327 handler.handleData2(0, midi::MidiStatus::MIDI_NOTE_OFF, 0, i, 75);
328 handler.handleData2(0, midi::MidiStatus::MIDI_PITCH_BEND, 0, i, 4000);
329 }
330 handler.handleData1(0, midi::MidiStatus::MIDI_PROGRAM_CHANGE, 0, 10);
331 handler.handleData1(0, midi::MidiStatus::MIDI_AFTERTOUCH, 0, 10);
332
333 GUI::updateAllGuis();
334
335 // print audio frames
336 int i = 0;
337 try {
338 while (nbsamples > 0) {
339 if (run == 0) {
340 ichan->impulse();
341 finterface.setButtons(true);
342 }
343 if (run >= 1) {
344 ichan->zero();
345 finterface.setButtons(false);
346 }
347 int nFrames = min(kFrames, nbsamples);
348
349 if (random) {
350 int randval = rand();
351 int n1 = randval % nFrames;
352 int n2 = nFrames - n1;
353 DSP->compute(n1, ichan->buffers(), ochan->buffers());
354 DSP->compute(n2, ichan->buffers(n1), ochan->buffers(n1));
355 } else {
356 DSP->compute(nFrames, ichan->buffers(), ochan->buffers());
357 }
358
359 run++;
360 // Print samples
361 for (i = 0; i < nFrames; i++) {
362 printf("%6d : ", linenum++);
363 for (int c = 0; c < nouts; c++) {
364 FAUSTFLOAT f = normalize(ochan->buffers()[c][i]);
365 printf(" %8.6f", f);
366 }
367 printf("\n");
368 }
369 nbsamples -= nFrames;
370 }
catch(...)371 } catch (...) {
372 cerr << "ERROR in '" << file << "' at line : " << i << std::endl;
373 }
374
375 delete ichan;
376 if (ochan != ichan) delete ochan;
377 delete DSP;
378 }
379
380 // To be used in dynamic context (LLVM or interp backends)
381 static void runDSP1(dsp_factory* factory, const string& file, int& linenum, int nbsamples, bool is_mem_alloc = false, bool inpl = false, bool random = false)
382 {
383 malloc_memory_manager manager;
384 factory->setMemoryManager((is_mem_alloc) ? &manager : nullptr);
385 runDSP(factory->createDSPInstance(), file, linenum, nbsamples, inpl, random);
386 }
387