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