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