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 
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 {
declareMeta42     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 
lsr(int x,int n)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 
UI()83 	UI() : fStopped(false) {}
~UI()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 
stop()113 	void stop()		{ fStopped = true; }
stopped()114 	bool stopped() 	{ return fStopped; }
115 
declare(float * zone,const char * key,const char * value)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;
paramparam122 	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:
FNUI()133 	FNUI() : UI() { numOptions=0; }
~FNUI()134 	virtual ~FNUI() {}
135 
136 
addOption(const char * label,float * zone,float init,float min,float max)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 
getOpts()144 	virtual vector<param> getOpts () { return fParam; }
145 
addButton(const char * label,float * zone)146 	virtual void addButton(const char* label, float* zone)
147 	{
148 		addOption(label,zone,0,0,1);
149 	}
150 
getNumOptions()151 	virtual int getNumOptions() { return numOptions; }
152 
addToggleButton(const char * label,float * zone)153 	virtual void addToggleButton(const char* label, float* zone)
154 	{
155 		addOption(label,zone,0,0,1);
156 	}
157 
addCheckButton(const char * label,float * zone)158 	virtual void addCheckButton(const char* label, float* zone)
159 	{
160 		addOption(label,zone,0,0,1);
161 	}
162 
addVerticalSlider(const char * label,float * zone,float init,float min,float max,float step)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 
addHorizontalSlider(const char * label,float * zone,float init,float min,float max,float step)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 
addNumEntry(const char * label,float * zone,float init,float min,float max,float step)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 
addNumDisplay(const char * label,float * zone,int precision)180 	virtual void addNumDisplay(const char* label, float* zone, int precision) {}
addTextDisplay(const char * label,float * zone,char * names[],float min,float max)181 	virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max) {}
addHorizontalBargraph(const char * label,float * zone,float min,float max)182 	virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) {}
addVerticalBargraph(const char * label,float * zone,float min,float max)183 	virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) {}
184 
185 
openFrameBox(const char * label)186 	virtual void openFrameBox(const char* label)		{ }
openTabBox(const char * label)187 	virtual void openTabBox(const char* label)              { }
openHorizontalBox(const char * label)188 	virtual void openHorizontalBox(const char* label)	{ }
openVerticalBox(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(); }
closeBox()197 	virtual void closeBox() { }
run()198 	virtual void run() 	{}
show()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:
dsp()223 	dsp() {}
~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 sample_rate)              = 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 }
491