--- /dev/null
+/* octave.cpp
+ Copyright (C) 2009 by Bjoern Anton Erlach. */
+
+// OCTAVE architecture file for faust.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+// 02111-1307 USA
+//-------------------------------------------------------------------
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <math.h>
+#include <errno.h>
+#include <time.h>
+#include <vector>
+#include <string>
+#include <map>
+#include <iostream>
+#include <oct.h>
+
+
+using namespace std;
+
+// TODO: find out what to do with this Meta thing
+struct Meta : map<const char*, const char*>
+{
+ void declare (const char* key, const char* value) { (*this)[key]=value; }
+};
+
+
+#define max(x,y) (((x)>(y)) ? (x) : (y))
+#define min(x,y) (((x)<(y)) ? (x) : (y))
+
+// abs is now predefined
+//template<typename T> T abs (T a) { return (a<T(0)) ? -a : a; }
+
+
+inline int lsr (int x, int n) { return int(((unsigned int)x) >> n); }
+
+/******************************************************************************
+*******************************************************************************
+
+ VECTOR INTRINSICS
+
+*******************************************************************************
+*******************************************************************************/
+
+//inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((unsigned)(calloc((nmemb*size)+15,sizeof(char)))+15 & 0xfffffff0); }
+//inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((size_t)(calloc((nmemb*size)+15,sizeof(char)))+15 & ~15); }
+
+
+<<includeIntrinsic>>
+
+/******************************************************************************
+*******************************************************************************
+
+ ABSTRACT USER INTERFACE
+
+*******************************************************************************
+*******************************************************************************/
+
+
+class UI
+{
+ bool fStopped;
+public:
+
+ UI() : fStopped(false) {}
+ virtual ~UI() {}
+
+ // -- active widgets
+
+ virtual void addButton(const char* label, float* zone) = 0;
+ virtual void addToggleButton(const char* label, float* zone) = 0;
+ virtual void addCheckButton(const char* label, float* zone) = 0;
+ virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
+ virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
+ virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step) = 0;
+
+ // -- passive widgets
+
+ virtual void addNumDisplay(const char* label, float* zone, int precision) = 0;
+ virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max) = 0;
+ virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) = 0;
+ virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) = 0;
+
+ // -- frames and labels
+
+ virtual void openFrameBox(const char* label) = 0;
+ virtual void openTabBox(const char* label) = 0;
+ virtual void openHorizontalBox(const char* label) = 0;
+ virtual void openVerticalBox(const char* label) = 0;
+ virtual void closeBox() = 0;
+
+ virtual void show() = 0;
+ virtual void run() = 0;
+
+ void stop() { fStopped = true; }
+ bool stopped() { return fStopped; }
+
+ virtual void declare(float* zone, const char* key, const char* value) {}
+};
+
+
+struct param {
+ string fName; float *fVals; float* fZone; float fMin; float fMax;
+ param(string name, float* z, float init, float a, float b) : fName(name), fVals(NULL), fZone(z), fMin(a), fMax(b) { *z = init; }
+};
+
+
+class FNUI : public UI
+{
+ vector<param> fParam;
+ int numOptions;
+
+
+public:
+ FNUI() : UI() { numOptions=0; }
+ virtual ~FNUI() {}
+
+
+ void addOption(const char* label, float* zone, float init, float min, float max)
+ {
+ string fullname = label;
+ fParam.push_back(param(fullname, zone, init, min, max));
+ numOptions++;
+ }
+
+ virtual vector<param> getOpts () { return fParam; }
+
+ virtual void addButton(const char* label, float* zone)
+ {
+ addOption(label,zone,0,0,1);
+ }
+
+ virtual int getNumOptions() { return numOptions; }
+
+ virtual void addToggleButton(const char* label, float* zone)
+ {
+ addOption(label,zone,0,0,1);
+ }
+
+ virtual void addCheckButton(const char* label, float* zone)
+ {
+ addOption(label,zone,0,0,1);
+ }
+
+ virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step)
+ {
+ addOption(label,zone,init,min,max);
+ }
+
+ virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step)
+ {
+ addOption(label,zone,init,min,max);
+ }
+
+ virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step)
+ {
+ addOption(label,zone,init,min,max);
+ }
+
+ // -- passive widgets
+
+ virtual void addNumDisplay(const char* label, float* zone, int precision) {}
+ virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max) {}
+ virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) {}
+ virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) {}
+
+
+ virtual void openFrameBox(const char* label) { }
+ virtual void openTabBox(const char* label) { }
+ virtual void openHorizontalBox(const char* label) { }
+ virtual void openVerticalBox(const char* label) { }
+
+ // virtual void openFrameBox(const char* label) { openAnyBox(label); }
+ //virtual void openTabBox(const char* label) { openAnyBox(label); }
+ //virtual void openHorizontalBox(const char* label) { openAnyBox(label); }
+ //virtual void openVerticalBox(const char* label) { openAnyBox(label); }
+
+ //virtual void closeBox() { fPrefix.pop(); }
+ virtual void closeBox() { }
+ virtual void run() {}
+ virtual void show() {}
+
+};
+
+
+
+/******************************************************************************
+*******************************************************************************
+
+ FAUST DSP
+
+*******************************************************************************
+*******************************************************************************/
+
+
+
+//----------------------------------------------------------------
+// abstract definition of a signal processor
+//----------------------------------------------------------------
+
+class dsp {
+ protected:
+ int fSamplingFreq;
+ public:
+ dsp() {}
+ virtual ~dsp() {}
+
+ virtual int getNumInputs() = 0;
+ virtual int getNumOutputs() = 0;
+ virtual void buildUserInterface(UI* interface) = 0;
+ virtual void init(int samplingRate) = 0;
+ virtual void compute(int len, float** inputs, float** outputs) = 0;
+};
+
+
+//----------------------------------------------------------------------------
+// FAUST generated signal processor
+//----------------------------------------------------------------------------
+
+
+<<includeclass>>
+
+
+//----------------------------------------------------------------------------
+// Octave interface
+//----------------------------------------------------------------------------
+
+// Prefered way to allocate memory
+#define ALLOC(x) alloca(x)
+#define FREE(x) ((void)0)
+// if ALLOCA is not available use MALLOC
+//#define ALLOC(x) malloc(x)
+//#define FREE(x) free(x)
+
+#define QUOTEME(x) #x
+
+#define DEFAULT_SAMPLERATE 44100
+#define DEFAULT_BLOCKSIZE 64
+
+// linear interpolation for vector valued control inputs
+void
+interpolate_ctrlin (float *vals, NDArray in, int n)
+{
+ int nin = in.length();
+ double ratio = (double)(n-1)/(double)(nin-1);
+ int irat = (int) ratio;
+ double frat = ratio - (double) irat;
+ double rest = 0;
+ int i = 0;
+ float x;
+
+ for (int j=0; j<(nin-1); j++) {
+ float del;
+ int seglength = irat;
+ rest += frat;
+ if (rest >= 1.0) {
+ seglength ++;
+ rest -= 1.0;
+ }
+ del = (in(j+1) - in(j)) / (float) seglength;
+ x = in(j);
+ for (int k=0; k<seglength; k++) {
+ vals[i++] = x;
+ x += del;
+ }
+ }
+ for (; i<n; i++) {
+ vals[i] = in(nin-1);
+ }
+}
+
+
+
+DEFUN_DLD (FAUST_FUNC_NAME, args, nargout,
+ "type " QUOTEME(FAUST_FUNC_NAME) "() to see the arguments.\n")
+{
+ int nargin = args.length();
+ int numIn;
+ int numOut;
+ int numOpts;
+ int maxInputLength = 0;
+ mydsp DSP;
+ int ngivenctrls;
+ float **finputs;
+ float **foutputs;
+ float **controlinputs;
+ int ctrllength;
+ int ctrlargoff;
+ int allscalarctrls = 1;
+ // TODO: float **controloutputs;
+ int i;
+ vector<param> opts;
+ int bsize;
+ int srate;
+ octave_value_list retval;
+ octave_value tmp;
+
+ FNUI* interface = new FNUI();
+ DSP.buildUserInterface(interface);
+
+ // check if global variable FAUST_BLOCKSIZE is set.
+ tmp = get_global_value ("FAUST_BLOCKSIZE", true);
+ if (tmp.is_defined ())
+ bsize = (int) tmp.scalar_value();
+ else {
+ bsize = DEFAULT_BLOCKSIZE;
+ }
+
+ // check if global variable FAUST_SAMPLERATE is set.
+ tmp = get_global_value ("FAUST_SAMPLERATE", true);
+ if (tmp.is_defined ())
+ srate = (int) tmp.scalar_value();
+ else {
+ srate = DEFAULT_SAMPLERATE;
+ }
+
+ DSP.init(srate);
+ opts = interface->getOpts();
+
+ numIn = DSP.getNumInputs();
+ numOut = DSP.getNumOutputs();
+ numOpts = interface->getNumOptions();
+
+ // print a usage message in case the function is called with too few arguments
+ if (nargin < numIn || nargin == 0) {
+ if (numOut>1) {
+ octave_stdout << "[out1";
+ for (i=2; i<=numOut; i++)
+ octave_stdout << ",out" << i;
+ octave_stdout << "] = " << QUOTEME(FAUST_FUNC_NAME) << "(";
+ } else {
+ octave_stdout << "out = " << QUOTEME(FAUST_FUNC_NAME) << "(";
+ }
+ if (numIn == 0)
+ octave_stdout << "numsamps";
+ else
+ octave_stdout << "in1";
+ for (i=2; i<=numIn; i++)
+ octave_stdout << ", in" << i;
+ for (i=0; i<numOpts; i++)
+ octave_stdout << ", " << opts[i].fName;
+ octave_stdout << ")\n";
+ delete interface;
+ return retval;
+ }
+
+ // If we have inputs we use the length of the longest input vector
+ // as length of the output to be produced.
+ // If we don't have inputs, the first argument specifies the number of
+ // samples to be produced.
+ if (numIn == 0) {
+ maxInputLength = args(0).scalar_value();
+ ctrlargoff = 1;
+ } else {
+ ctrlargoff = numIn;
+ for (i=0; i<numIn; i++) {
+ octave_idx_type nr = args(i).matrix_value().rows();
+ octave_idx_type nc = args(i).matrix_value().columns();
+ if (nr == 1) {
+ if (nc > maxInputLength)
+ maxInputLength = nc;
+ } else if (nc == 1) {
+ if (nr > maxInputLength)
+ maxInputLength = nr;
+ } else {
+ maxInputLength = nc;
+ octave_stdout << "Argument " << i << " has wrong dimensions " << nr << "x" << nc << "\n";
+ }
+ }
+ }
+
+
+ ctrllength = (maxInputLength+bsize-1)/bsize;
+
+ // check for arguments that should serve as control inputs
+ for (i=ctrlargoff; i<nargin; i++) {
+ if ((i-ctrlargoff) < numOpts) {
+ NDArray v = args(i).array_value();
+ if (v.length() > 1) {
+ allscalarctrls = 0;
+ opts[i-ctrlargoff].fVals = (float*) ALLOC(sizeof(float)*ctrllength);
+ interpolate_ctrlin(opts[i-ctrlargoff].fVals, v, ctrllength);
+ *opts[i-ctrlargoff].fZone = (float) v(0);
+ } else {
+ *opts[i-ctrlargoff].fZone = (float) args(i).scalar_value();
+ }
+ }
+ }
+
+ for (i=0; i<numOpts; i++) {
+ octave_stdout << "Parameter " << opts[i].fName << ": " << *opts[i].fZone << "\n";
+ }
+
+ finputs = (float**) ALLOC(sizeof(float*) * numIn);
+ foutputs = (float**) ALLOC(sizeof(float*) * numOut);
+
+ // Copy the matrix and convert to floats - This is a real slowdown!
+ for (i=0; i<numIn; i++) {
+ Matrix m = args(i).matrix_value();
+ float *p;
+ finputs[i] = (float*) ALLOC(maxInputLength * sizeof(float));
+ memset(finputs[i], 0, sizeof(float)*maxInputLength);
+ p = finputs[i];
+ if (m.rows() > m.columns()) {
+ for (int j=0; j<m.rows(); j++) {
+ *p++ = (float) m(j,0);
+ }
+ } else {
+ for (int j=0; j<m.columns(); j++) {
+ *p++ = (float) m(0,j);
+ }
+ }
+ }
+
+ // allocate output vectors
+ for (i=0; i<numOut; i++) {
+ foutputs[i] = (float*) ALLOC(maxInputLength * sizeof(float));
+ memset(foutputs[i], 0, sizeof(float)*maxInputLength);
+ }
+
+ if (allscalarctrls) {
+ DSP.compute(maxInputLength, finputs, foutputs);
+ } else {
+ int nleft = maxInputLength;
+ int k = 0;
+ float **fins;
+ float **fouts;
+ fins = (float**) ALLOC(sizeof(float*) * numIn);
+ fouts = (float**) ALLOC(sizeof(float*) * numOut);
+ memcpy(fins, finputs, sizeof(float*)*numIn);
+ memcpy(fouts, foutputs, sizeof(float*)*numOut);
+ while (nleft > 0) {
+ int n = min(bsize, nleft);
+ for (i=0; i<numOpts; i++) {
+ if (opts[i].fVals) {
+ *opts[i].fZone = opts[i].fVals[k];
+ }
+ }
+ DSP.compute(n, fins, fouts);
+ nleft -= n;
+ k++;
+ for (i=0; i<numIn; i++)
+ fins[i] += n;
+ for (i=0; i<numOut; i++)
+ fouts[i] += n;
+ }
+ FREE(fins);
+ FREE(fouts);
+ }
+
+ // copy the output from the float arrays (and free all tmp memory if malloc is used)
+ for (i=0; i<numOut; i++) {
+ Matrix output = Matrix(1, maxInputLength);
+ for (int j=0; j<maxInputLength; j++)
+ output(0, j) = (double) foutputs[i][j];
+ FREE(foutputs[i]);
+ retval(i) = output;
+ }
+ for (i=0; i<numOpts; i++) {
+ if (opts[i].fVals) {
+ FREE(opts[i].fVals);
+ }
+ }
+ for (i=0; i<numIn; i++) {
+ FREE(finputs[i]);
+ }
+ FREE(foutputs);
+ FREE(finputs);
+
+ delete interface;
+ return retval;
+}