User Manual first draft.
[Faustine.git] / interpreter / preprocessor / faust-0.9.47mr3 / architecture / synthfile.cpp
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 ARCHITECTURE SECTION (part 1/2)****************/
10
11 /************************************************************************
12 FAUST Architecture File
13 Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
14 ---------------------------------------------------------------------
15 This Architecture section is free software; you can redistribute it
16 and/or modify it under the terms of the GNU General Public License
17 as published by the Free Software Foundation; either version 3 of
18 the License, or (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; If not, see <http://www.gnu.org/licenses/>.
27
28 EXCEPTION : As a special exception, you may create a larger work
29 that contains this FAUST architecture section and distribute
30 that work under terms of your choice, so long as this FAUST
31 architecture section is not modified.
32
33
34 ************************************************************************
35 ************************************************************************/
36
37
38 #include <errno.h>
39 #include <limits.h>
40 #include <math.h>
41 #include <sndfile.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include <iostream>
47 #include <map>
48 #include <stack>
49 #include <string>
50 #include <time.h>
51 #include <vector>
52
53 // g++ -O3 -lm -lsynthfile myfx.cpp
54
55 using namespace std;
56
57 struct Meta : map<const char*, const char*>
58 {
59 void declare (const char* key, const char* value) { (*this)[key]=value; }
60 };
61
62
63 #define max(x,y) (((x)>(y)) ? (x) : (y))
64 #define min(x,y) (((x)<(y)) ? (x) : (y))
65
66 // abs is now predefined
67 //template<typename T> T abs (T a) { return (a<T(0)) ? -a : a; }
68
69
70 inline int lsr (int x, int n) { return int(((unsigned int)x) >> n); }
71
72
73 /******************************************************************************
74 *******************************************************************************
75
76 VECTOR INTRINSICS
77
78 *******************************************************************************
79 *******************************************************************************/
80
81
82 <<includeIntrinsic>>
83
84
85
86
87 /******************************************************************************
88 *******************************************************************************
89
90 USER INTERFACE
91
92 *******************************************************************************
93 *******************************************************************************/
94
95 class UI
96 {
97 bool fStopped;
98 public:
99
100 UI() : fStopped(false) {}
101 virtual ~UI() {}
102
103 // -- active widgets
104
105 virtual void addButton(const char* label, float* zone) = 0;
106 virtual void addToggleButton(const char* label, float* zone) = 0;
107 virtual void addCheckButton(const char* label, float* zone) = 0;
108 virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
109 virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
110 virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step) = 0;
111
112 // -- passive widgets
113
114 virtual void addNumDisplay(const char* label, float* zone, int precision) = 0;
115 virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max) = 0;
116 virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) = 0;
117 virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) = 0;
118
119 // -- frames and labels
120
121 virtual void openFrameBox(const char* label) = 0;
122 virtual void openTabBox(const char* label) = 0;
123 virtual void openHorizontalBox(const char* label) = 0;
124 virtual void openVerticalBox(const char* label) = 0;
125 virtual void closeBox() = 0;
126
127 virtual void show() = 0;
128 virtual void run() = 0;
129
130 void stop() { fStopped = true; }
131 bool stopped() { return fStopped; }
132
133 virtual void declare(float* zone, const char* key, const char* value) {}
134 };
135
136 struct param {
137 float* fZone; float fMin; float fMax;
138 param(float* z, float init, float a, float b) : fZone(z), fMin(a), fMax(b) { *z = init; }
139 };
140
141
142 class CMDUI : public UI
143 {
144 int fArgc;
145 char** fArgv;
146 char* fOutFile;
147 long fNumframes;
148 stack<string> fPrefix;
149 map<string, param> fKeyParam;
150
151 void openAnyBox(const char* label)
152 {
153 string prefix;
154
155 if (label && label[0]) {
156 prefix = fPrefix.top() + "-" + label;
157 } else {
158 prefix = fPrefix.top();
159 }
160 fPrefix.push(prefix);
161 }
162
163 string simplify(const string& src)
164 {
165 int i=0;
166 int level=0;
167 string dst;
168
169 while (src[i] ) {
170
171 switch (level) {
172
173 case 0 :
174 case 1 :
175 case 2 :
176 // Skip the begin of the label "--foo-"
177 // until 3 '-' have been read
178 if (src[i]=='-') { level++; }
179 break;
180
181 case 3 :
182 // copy the content, but skip non alphnum
183 // and content in parenthesis
184 switch (src[i]) {
185 case '(' :
186 case '[' :
187 level++;
188 break;
189
190 case '-' :
191 dst += '-';
192 break;
193
194 default :
195 if (isalnum(src[i])) {
196 dst+= tolower(src[i]);
197 }
198
199 }
200 break;
201
202 default :
203 // here we are inside parenthesis and
204 // we skip the content until we are back to
205 // level 3
206 switch (src[i]) {
207
208 case '(' :
209 case '[' :
210 level++;
211 break;
212
213 case ')' :
214 case ']' :
215 level--;
216 break;
217
218 default :
219 break;
220 }
221
222 }
223 i++;
224 }
225 return dst;
226 }
227
228
229 public:
230
231 CMDUI(int argc, char *argv[]) : UI(), fArgc(argc), fArgv(argv), fNumframes(44100), fOutFile("out.wav")
232 { fPrefix.push("-"); }
233 virtual ~CMDUI() {}
234
235
236 void addOption(const char* label, float* zone, float init, float min, float max)
237 {
238 string fullname = "-" + simplify(fPrefix.top() + "-" + label);
239 fKeyParam.insert(make_pair(fullname, param(zone, init, min, max)));
240 }
241
242
243 virtual void addButton(const char* label, float* zone)
244 {
245 addOption(label,zone,0,0,1);
246 }
247
248 virtual void addToggleButton(const char* label, float* zone)
249 {
250 addOption(label,zone,0,0,1);
251 }
252
253 virtual void addCheckButton(const char* label, float* zone)
254 {
255 addOption(label,zone,0,0,1);
256 }
257
258 virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step)
259 {
260 addOption(label,zone,init,min,max);
261 }
262
263 virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step)
264 {
265 addOption(label,zone,init,min,max);
266 }
267
268 virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step)
269 {
270 addOption(label,zone,init,min,max);
271 }
272
273 // -- passive widgets
274
275 virtual void addNumDisplay(const char* label, float* zone, int precision) {}
276 virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max) {}
277 virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) {}
278 virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) {}
279
280 virtual void openFrameBox(const char* label) { openAnyBox(label); }
281 virtual void openTabBox(const char* label) { openAnyBox(label); }
282 virtual void openHorizontalBox(const char* label) { openAnyBox(label); }
283 virtual void openVerticalBox(const char* label) { openAnyBox(label); }
284
285 virtual void closeBox() { fPrefix.pop(); }
286
287 virtual void show() {}
288 virtual void run() {}
289
290 void printhelp()
291 {
292 cerr << "usage: " << fArgv[0] << " [options]" << endl;
293 cerr << " [options]: " << endl;
294 cerr << " samples: number of samples to generate, default is 44100 (1 second of sound)" << endl;
295 cerr << " -o outfile: name of the output file, default is 'out.wav'" << endl;
296
297 if (fKeyParam.size()) {
298 map<string, param>::iterator i;
299 cerr << " [faust module options]: \n";
300 for (i = fKeyParam.begin(); i != fKeyParam.end(); i++) {
301 cout << " " << i->first << " [" << i->second.fMin << ".." << i->second.fMax <<" ] \n";
302 }
303 }
304 exit(1);
305 }
306
307 void process_command()
308 {
309 map<string, param>::iterator p;
310
311 for (int i = 1; i < fArgc; i++) {
312 if (fArgv[i][0] == '-') {
313 if ( (strcmp(fArgv[i], "-help") == 0)
314 || (strcmp(fArgv[i], "-h") == 0)
315 || (strcmp(fArgv[i], "--help") == 0) ) {
316 printhelp();
317 }
318
319 if (strcmp(fArgv[i], "-o") == 0) {
320 fOutFile = fArgv[i+1];
321 }
322 else {
323 p = fKeyParam.find(fArgv[i]);
324 if (p == fKeyParam.end()) {
325 cout << fArgv[0] << ": unrecognized option " << fArgv[i] << "\n";
326 printhelp();
327 }
328 *(p->second.fZone) = float(strtod(fArgv[i+1], NULL));
329 }
330 i++;
331 }
332 else {
333 fNumframes = strtol(fArgv[i], NULL, 10);
334 if (fNumframes <= 0 ) printhelp();
335 }
336 }
337 }
338
339 char* output_file() { return fOutFile; }
340 long num_frames() { return fNumframes; }
341
342 void process_init()
343 {
344 map<string, param>::iterator p;
345 for (int i = 1; i < fArgc; i++) {
346 if (fArgv[i][0] == '-') {
347 p = fKeyParam.find(fArgv[i]);
348 if (p != fKeyParam.end()) {
349 *(p->second.fZone) = float(strtod(fArgv[i+1], NULL));
350 i++;
351 }
352 }
353 }
354 }
355 };
356
357
358 //----------------------------------------------------------------
359 // d�inition du processeur de signal
360 //----------------------------------------------------------------
361
362 class dsp {
363 protected:
364 int fSamplingFreq;
365 public:
366 dsp() {}
367 virtual ~dsp() {}
368
369 virtual int getNumInputs() = 0;
370 virtual int getNumOutputs() = 0;
371 virtual void buildUserInterface(UI* interface) = 0;
372 virtual void init(int samplingRate) = 0;
373 virtual void compute(int len, float** inputs, float** outputs) = 0;
374 virtual void conclude() {}
375 };
376
377 /********************END ARCHITECTURE SECTION (part 1/2)****************/
378
379 /**************************BEGIN USER SECTION **************************/
380
381 <<includeclass>>
382
383 /***************************END USER SECTION ***************************/
384
385 /*******************BEGIN ARCHITECTURE SECTION (part 2/2)***************/
386
387 mydsp DSP;
388
389 class Interleaver
390 {
391 int fNumFrames;
392 int fNumInputs;
393 int fNumOutputs;
394
395 float* fInputs[256];
396 float* fOutput;
397
398 public:
399
400 Interleaver(int numFrames, int numInputs, int numOutputs)
401 {
402 fNumFrames = numFrames;
403 fNumInputs = max(numInputs, numOutputs);
404 fNumOutputs = numOutputs;
405
406 // allocate separate input channels
407 for (int i = 0; i < fNumInputs; i++) {
408 fInputs[i] = (float*) calloc (fNumFrames, sizeof(float));
409 }
410
411 // allocate interleaved output channel
412 fOutput = (float*) calloc(fNumFrames*fNumOutputs, sizeof(float));
413
414 }
415
416 ~Interleaver()
417 {
418 // free separate input channels
419 for (int i = 0; i < fNumInputs; i++) {
420 free(fInputs[i]);
421 }
422
423 // free interleaved output channel
424 free(fOutput);
425 }
426
427 float** inputs() { return fInputs; }
428 float* output() { return fOutput; }
429
430 void interleave()
431 {
432 for (int s = 0; s < fNumFrames; s++) {
433 for (int c = 0; c < fNumOutputs; c++) {
434 fOutput[c + s*fNumOutputs] = fInputs[c][s];
435 }
436 }
437 }
438 };
439
440 #define kFrames 512
441 #define kSampleRate 44100
442
443 int main(int argc, char *argv[] )
444 {
445 CMDUI* interface = new CMDUI(argc, argv);
446 DSP.buildUserInterface(interface);
447 interface->process_command();
448
449 // open output file
450 SNDFILE* out_sf;
451 SF_INFO out_info = { interface->num_frames(), kSampleRate, DSP.getNumOutputs(),
452 SF_FORMAT_WAV|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE, 0, 0};
453 out_sf = sf_open(interface->output_file(), SFM_WRITE, &out_info);
454 if (out_sf == NULL) {
455 cerr << "Error: ";
456 sf_perror(out_sf);
457 exit(1);
458 }
459
460 // create interleaver
461 Interleaver ilv (kFrames, DSP.getNumOutputs(), DSP.getNumOutputs());
462
463 // init signal processor
464 DSP.init(kSampleRate);
465 interface->process_init();
466
467 // process all samples
468 int frames = interface->num_frames();
469 int nbf;
470 do {
471 if (frames > kFrames) {
472 nbf = kFrames;
473 frames -= kFrames;
474 }
475 else {
476 nbf = frames;
477 frames = 0;
478 }
479 DSP.compute(nbf, 0, ilv.inputs());
480 ilv.interleave();
481 sf_writef_float(out_sf, ilv.output(), nbf);
482 } while (nbf);
483
484 sf_close(out_sf);
485 }
486 /********************END ARCHITECTURE SECTION (part 2/2)****************/
487