Bug of vector wave output error fixed.
[Faustine.git] / interpretor / faust-0.9.47mr3 / architecture / octave.cpp
1 /* octave.cpp
2 Copyright (C) 2009 by Bjoern Anton Erlach. */
3
4 // OCTAVE architecture file for faust.
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License as
8 // published by the Free Software Foundation; either version 2 of the
9 // License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 // 02111-1307 USA
20 //-------------------------------------------------------------------
21
22 #include <assert.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <limits.h>
27 #include <math.h>
28 #include <errno.h>
29 #include <time.h>
30 #include <vector>
31 #include <string>
32 #include <map>
33 #include <iostream>
34 #include <oct.h>
35
36
37 using namespace std;
38
39 // TODO: find out what to do with this Meta thing
40 struct Meta : map<const char*, const char*>
41 {
42 void declare (const char* key, const char* value) { (*this)[key]=value; }
43 };
44
45
46 #define max(x,y) (((x)>(y)) ? (x) : (y))
47 #define min(x,y) (((x)<(y)) ? (x) : (y))
48
49 // abs is now predefined
50 //template<typename T> T abs (T a) { return (a<T(0)) ? -a : a; }
51
52
53 inline int lsr (int x, int n) { return int(((unsigned int)x) >> n); }
54
55 /******************************************************************************
56 *******************************************************************************
57
58 VECTOR INTRINSICS
59
60 *******************************************************************************
61 *******************************************************************************/
62
63 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((unsigned)(calloc((nmemb*size)+15,sizeof(char)))+15 & 0xfffffff0); }
64 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((size_t)(calloc((nmemb*size)+15,sizeof(char)))+15 & ~15); }
65
66
67 <<includeIntrinsic>>
68
69 /******************************************************************************
70 *******************************************************************************
71
72 ABSTRACT USER INTERFACE
73
74 *******************************************************************************
75 *******************************************************************************/
76
77
78 class UI
79 {
80 bool fStopped;
81 public:
82
83 UI() : fStopped(false) {}
84 virtual ~UI() {}
85
86 // -- active widgets
87
88 virtual void addButton(const char* label, float* zone) = 0;
89 virtual void addToggleButton(const char* label, float* zone) = 0;
90 virtual void addCheckButton(const char* label, float* zone) = 0;
91 virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
92 virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
93 virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step) = 0;
94
95 // -- passive widgets
96
97 virtual void addNumDisplay(const char* label, float* zone, int precision) = 0;
98 virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max) = 0;
99 virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) = 0;
100 virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) = 0;
101
102 // -- frames and labels
103
104 virtual void openFrameBox(const char* label) = 0;
105 virtual void openTabBox(const char* label) = 0;
106 virtual void openHorizontalBox(const char* label) = 0;
107 virtual void openVerticalBox(const char* label) = 0;
108 virtual void closeBox() = 0;
109
110 virtual void show() = 0;
111 virtual void run() = 0;
112
113 void stop() { fStopped = true; }
114 bool stopped() { return fStopped; }
115
116 virtual void declare(float* zone, const char* key, const char* value) {}
117 };
118
119
120 struct param {
121 string fName; float *fVals; float* fZone; float fMin; float fMax;
122 param(string name, float* z, float init, float a, float b) : fName(name), fVals(NULL), fZone(z), fMin(a), fMax(b) { *z = init; }
123 };
124
125
126 class FNUI : public UI
127 {
128 vector<param> fParam;
129 int numOptions;
130
131
132 public:
133 FNUI() : UI() { numOptions=0; }
134 virtual ~FNUI() {}
135
136
137 void addOption(const char* label, float* zone, float init, float min, float max)
138 {
139 string fullname = label;
140 fParam.push_back(param(fullname, zone, init, min, max));
141 numOptions++;
142 }
143
144 virtual vector<param> getOpts () { return fParam; }
145
146 virtual void addButton(const char* label, float* zone)
147 {
148 addOption(label,zone,0,0,1);
149 }
150
151 virtual int getNumOptions() { return numOptions; }
152
153 virtual void addToggleButton(const char* label, float* zone)
154 {
155 addOption(label,zone,0,0,1);
156 }
157
158 virtual void addCheckButton(const char* label, float* zone)
159 {
160 addOption(label,zone,0,0,1);
161 }
162
163 virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step)
164 {
165 addOption(label,zone,init,min,max);
166 }
167
168 virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step)
169 {
170 addOption(label,zone,init,min,max);
171 }
172
173 virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step)
174 {
175 addOption(label,zone,init,min,max);
176 }
177
178 // -- passive widgets
179
180 virtual void addNumDisplay(const char* label, float* zone, int precision) {}
181 virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max) {}
182 virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) {}
183 virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) {}
184
185
186 virtual void openFrameBox(const char* label) { }
187 virtual void openTabBox(const char* label) { }
188 virtual void openHorizontalBox(const char* label) { }
189 virtual void openVerticalBox(const char* label) { }
190
191 //virtual void openFrameBox(const char* label) { openAnyBox(label); }
192 //virtual void openTabBox(const char* label) { openAnyBox(label); }
193 //virtual void openHorizontalBox(const char* label) { openAnyBox(label); }
194 //virtual void openVerticalBox(const char* label) { openAnyBox(label); }
195
196 //virtual void closeBox() { fPrefix.pop(); }
197 virtual void closeBox() { }
198 virtual void run() {}
199 virtual void show() {}
200
201 };
202
203
204
205 /******************************************************************************
206 *******************************************************************************
207
208 FAUST DSP
209
210 *******************************************************************************
211 *******************************************************************************/
212
213
214
215 //----------------------------------------------------------------
216 // abstract definition of a signal processor
217 //----------------------------------------------------------------
218
219 class dsp {
220 protected:
221 int fSamplingFreq;
222 public:
223 dsp() {}
224 virtual ~dsp() {}
225
226 virtual int getNumInputs() = 0;
227 virtual int getNumOutputs() = 0;
228 virtual void buildUserInterface(UI* interface) = 0;
229 virtual void init(int samplingRate) = 0;
230 virtual void compute(int len, float** inputs, float** outputs) = 0;
231 };
232
233
234 //----------------------------------------------------------------------------
235 // FAUST generated signal processor
236 //----------------------------------------------------------------------------
237
238
239 <<includeclass>>
240
241
242 //----------------------------------------------------------------------------
243 // Octave interface
244 //----------------------------------------------------------------------------
245
246 // Prefered way to allocate memory
247 #define ALLOC(x) alloca(x)
248 #define FREE(x) ((void)0)
249 // if ALLOCA is not available use MALLOC
250 //#define ALLOC(x) malloc(x)
251 //#define FREE(x) free(x)
252
253 #define QUOTEME(x) #x
254
255 #define DEFAULT_SAMPLERATE 44100
256 #define DEFAULT_BLOCKSIZE 64
257
258 // linear interpolation for vector valued control inputs
259 void
260 interpolate_ctrlin (float *vals, NDArray in, int n)
261 {
262 int nin = in.length();
263 double ratio = (double)(n-1)/(double)(nin-1);
264 int irat = (int) ratio;
265 double frat = ratio - (double) irat;
266 double rest = 0;
267 int i = 0;
268 float x;
269
270 for (int j=0; j<(nin-1); j++) {
271 float del;
272 int seglength = irat;
273 rest += frat;
274 if (rest >= 1.0) {
275 seglength ++;
276 rest -= 1.0;
277 }
278 del = (in(j+1) - in(j)) / (float) seglength;
279 x = in(j);
280 for (int k=0; k<seglength; k++) {
281 vals[i++] = x;
282 x += del;
283 }
284 }
285 for (; i<n; i++) {
286 vals[i] = in(nin-1);
287 }
288 }
289
290
291
292 DEFUN_DLD (FAUST_FUNC_NAME, args, nargout,
293 "type " QUOTEME(FAUST_FUNC_NAME) "() to see the arguments.\n")
294 {
295 int nargin = args.length();
296 int numIn;
297 int numOut;
298 int numOpts;
299 int maxInputLength = 0;
300 mydsp DSP;
301 int ngivenctrls;
302 float **finputs;
303 float **foutputs;
304 float **controlinputs;
305 int ctrllength;
306 int ctrlargoff;
307 int allscalarctrls = 1;
308 // TODO: float **controloutputs;
309 int i;
310 vector<param> opts;
311 int bsize;
312 int srate;
313 octave_value_list retval;
314 octave_value tmp;
315
316 FNUI* interface = new FNUI();
317 DSP.buildUserInterface(interface);
318
319 // check if global variable FAUST_BLOCKSIZE is set.
320 tmp = get_global_value ("FAUST_BLOCKSIZE", true);
321 if (tmp.is_defined ())
322 bsize = (int) tmp.scalar_value();
323 else {
324 bsize = DEFAULT_BLOCKSIZE;
325 }
326
327 // check if global variable FAUST_SAMPLERATE is set.
328 tmp = get_global_value ("FAUST_SAMPLERATE", true);
329 if (tmp.is_defined ())
330 srate = (int) tmp.scalar_value();
331 else {
332 srate = DEFAULT_SAMPLERATE;
333 }
334
335 DSP.init(srate);
336 opts = interface->getOpts();
337
338 numIn = DSP.getNumInputs();
339 numOut = DSP.getNumOutputs();
340 numOpts = interface->getNumOptions();
341
342 // print a usage message in case the function is called with too few arguments
343 if (nargin < numIn || nargin == 0) {
344 if (numOut>1) {
345 octave_stdout << "[out1";
346 for (i=2; i<=numOut; i++)
347 octave_stdout << ",out" << i;
348 octave_stdout << "] = " << QUOTEME(FAUST_FUNC_NAME) << "(";
349 } else {
350 octave_stdout << "out = " << QUOTEME(FAUST_FUNC_NAME) << "(";
351 }
352 if (numIn == 0)
353 octave_stdout << "numsamps";
354 else
355 octave_stdout << "in1";
356 for (i=2; i<=numIn; i++)
357 octave_stdout << ", in" << i;
358 for (i=0; i<numOpts; i++)
359 octave_stdout << ", " << opts[i].fName;
360 octave_stdout << ")\n";
361 delete interface;
362 return retval;
363 }
364
365 // If we have inputs we use the length of the longest input vector
366 // as length of the output to be produced.
367 // If we don't have inputs, the first argument specifies the number of
368 // samples to be produced.
369 if (numIn == 0) {
370 maxInputLength = args(0).scalar_value();
371 ctrlargoff = 1;
372 } else {
373 ctrlargoff = numIn;
374 for (i=0; i<numIn; i++) {
375 octave_idx_type nr = args(i).matrix_value().rows();
376 octave_idx_type nc = args(i).matrix_value().columns();
377 if (nr == 1) {
378 if (nc > maxInputLength)
379 maxInputLength = nc;
380 } else if (nc == 1) {
381 if (nr > maxInputLength)
382 maxInputLength = nr;
383 } else {
384 maxInputLength = nc;
385 octave_stdout << "Argument " << i << " has wrong dimensions " << nr << "x" << nc << "\n";
386 }
387 }
388 }
389
390
391 ctrllength = (maxInputLength+bsize-1)/bsize;
392
393 // check for arguments that should serve as control inputs
394 for (i=ctrlargoff; i<nargin; i++) {
395 if ((i-ctrlargoff) < numOpts) {
396 NDArray v = args(i).array_value();
397 if (v.length() > 1) {
398 allscalarctrls = 0;
399 opts[i-ctrlargoff].fVals = (float*) ALLOC(sizeof(float)*ctrllength);
400 interpolate_ctrlin(opts[i-ctrlargoff].fVals, v, ctrllength);
401 *opts[i-ctrlargoff].fZone = (float) v(0);
402 } else {
403 *opts[i-ctrlargoff].fZone = (float) args(i).scalar_value();
404 }
405 }
406 }
407
408 for (i=0; i<numOpts; i++) {
409 octave_stdout << "Parameter " << opts[i].fName << ": " << *opts[i].fZone << "\n";
410 }
411
412 finputs = (float**) ALLOC(sizeof(float*) * numIn);
413 foutputs = (float**) ALLOC(sizeof(float*) * numOut);
414
415 // Copy the matrix and convert to floats - This is a real slowdown!
416 for (i=0; i<numIn; i++) {
417 Matrix m = args(i).matrix_value();
418 float *p;
419 finputs[i] = (float*) ALLOC(maxInputLength * sizeof(float));
420 memset(finputs[i], 0, sizeof(float)*maxInputLength);
421 p = finputs[i];
422 if (m.rows() > m.columns()) {
423 for (int j=0; j<m.rows(); j++) {
424 *p++ = (float) m(j,0);
425 }
426 } else {
427 for (int j=0; j<m.columns(); j++) {
428 *p++ = (float) m(0,j);
429 }
430 }
431 }
432
433 // allocate output vectors
434 for (i=0; i<numOut; i++) {
435 foutputs[i] = (float*) ALLOC(maxInputLength * sizeof(float));
436 memset(foutputs[i], 0, sizeof(float)*maxInputLength);
437 }
438
439 if (allscalarctrls) {
440 DSP.compute(maxInputLength, finputs, foutputs);
441 } else {
442 int nleft = maxInputLength;
443 int k = 0;
444 float **fins;
445 float **fouts;
446 fins = (float**) ALLOC(sizeof(float*) * numIn);
447 fouts = (float**) ALLOC(sizeof(float*) * numOut);
448 memcpy(fins, finputs, sizeof(float*)*numIn);
449 memcpy(fouts, foutputs, sizeof(float*)*numOut);
450 while (nleft > 0) {
451 int n = min(bsize, nleft);
452 for (i=0; i<numOpts; i++) {
453 if (opts[i].fVals) {
454 *opts[i].fZone = opts[i].fVals[k];
455 }
456 }
457 DSP.compute(n, fins, fouts);
458 nleft -= n;
459 k++;
460 for (i=0; i<numIn; i++)
461 fins[i] += n;
462 for (i=0; i<numOut; i++)
463 fouts[i] += n;
464 }
465 FREE(fins);
466 FREE(fouts);
467 }
468
469 // copy the output from the float arrays (and free all tmp memory if malloc is used)
470 for (i=0; i<numOut; i++) {
471 Matrix output = Matrix(1, maxInputLength);
472 for (int j=0; j<maxInputLength; j++)
473 output(0, j) = (double) foutputs[i][j];
474 FREE(foutputs[i]);
475 retval(i) = output;
476 }
477 for (i=0; i<numOpts; i++) {
478 if (opts[i].fVals) {
479 FREE(opts[i].fVals);
480 }
481 }
482 for (i=0; i<numIn; i++) {
483 FREE(finputs[i]);
484 }
485 FREE(foutputs);
486 FREE(finputs);
487
488 delete interface;
489 return retval;
490 }