aboutsummaryrefslogtreecommitdiff
path: root/oscbank~.c
diff options
context:
space:
mode:
Diffstat (limited to 'oscbank~.c')
-rw-r--r--oscbank~.c286
1 files changed, 286 insertions, 0 deletions
diff --git a/oscbank~.c b/oscbank~.c
new file mode 100644
index 0000000..5369670
--- /dev/null
+++ b/oscbank~.c
@@ -0,0 +1,286 @@
+/* ------------------------ oscbank~ 0.1 ----------------------------- */
+// oscillator bank using 3 seperate float inlets with interpolation
+// author - Richie Eakin reakinator@gmail.com 10-15-2007
+/* ----------------------------------------------------------------*/
+
+#include "m_pd.h"
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#define inline
+#endif
+
+#define WAVETABLESIZE 65536 //2^16
+#define DEFAULT_NPARTIALS 100
+#define DEFAULT_interp_incr 0.0045 //per sample, this is 20 ms @ 44k sr
+
+static t_class *oscbank_class;
+
+//t_partial represents one partial member in the bank
+typedef struct _partial
+{
+ int index;
+ float fCurr;
+ float freq;
+ float fIncr;
+ float aCurr;
+ float amp;
+ float aIncr;
+ float phase;
+ unsigned long nInterp;
+} t_partial;
+
+typedef struct _oscbank
+{
+ t_object x_obj;
+ float *wavetable;
+ int wavetablesize;
+ int got_a_table;
+ t_partial *pBank;
+ float infreq;
+ float inamp;
+ float sampleRate;
+ float sampleperiod;
+ float interp_incr;
+ long interpSamples;
+ int sp;
+ int nPartials;
+} t_oscbank;
+
+/*----- Interpolation Time -----
+ milleseconds to interpolate over; so samples = (n*SR)/1000
+ divide only when converting the interp time to samples(here),since it
+ is only used as a denominator to find the increment proportion:
+ SP= 1/SR, 1/(n*SR/1000) = (1000*SP)/n
+*/
+static void oscbank_interpMs(t_oscbank *x, t_floatarg n)
+{
+
+ if(n > 0) x->interp_incr =(1000* x->sampleperiod)/ n ;
+ else x->interp_incr = x->sampleperiod;
+
+ x->interpSamples = (unsigned long)((n *.001) * x->sampleRate);
+}
+
+static void oscbank_nPartials(t_oscbank *x, t_floatarg n)
+{
+ x->pBank = (t_partial *)resizebytes( x->pBank, x->nPartials * sizeof(t_partial), \
+ n * sizeof(t_partial));
+ x->nPartials = n;
+ post("max partials: %d", x->nPartials);
+}
+
+static void oscbank_index(t_oscbank *x, t_floatarg in)
+{
+ int i, iindex;
+ iindex = (int)in;
+ t_partial *bank = x->pBank;
+
+
+ if( iindex < 0)
+ {
+ error("negative index rejected");
+ return;
+ }
+
+//TODO: find open index in first loop, use that instead of second loop
+//check if continuing partial
+ for(i =0; i < x->nPartials; i++)
+ {
+ if( bank[i].index == iindex)
+ {//recaluclate increment slope from current interpolated positions and update goal
+ if(bank[i].aCurr == 0) bank[i].aCurr = 0.0000001;
+ bank[i].fIncr = (x->infreq - bank[i].fCurr) * x->interp_incr;
+ bank[i].aIncr = (x->inamp - bank[i].aCurr) * x->interp_incr;
+ bank[i].freq = x->infreq;
+ bank[i].amp = x->inamp;
+ bank[i].nInterp = x->interpSamples;
+ return;
+ }
+ } //end continuing partial
+
+ //new partial, see if there is an empty slot for the new partial
+ for(i =0; i < x->nPartials; i++)
+ {
+ if(bank[i].aCurr == 0)
+ { //new partial, only ramp amp from zero,
+ bank[i].index = iindex;
+ bank[i].fCurr = x->infreq;
+ bank[i].fIncr = 0;
+ bank[i].freq = x->infreq;
+ bank[i].amp = x->inamp;
+ bank[i].nInterp = x->interpSamples;
+ bank[i].aCurr = 0.0000001;
+ bank[i].aIncr = x->inamp * x->interp_incr;
+ return;
+ }
+ } //end new partial for
+
+ //oscbank is full, steal oldest partial (creates a pop) and ramp amp from zero
+ bank[x->sp].index = iindex;
+ bank[x->sp].fCurr = x->infreq;
+ bank[x->sp].fIncr = 0;
+ bank[x->sp].freq = x->infreq;
+ bank[x->sp].amp = x->inamp;
+ bank[x->sp].nInterp = x->interpSamples;
+ bank[x->sp].aCurr = 0.0000001;
+ bank[x->sp].aIncr = x->inamp * x->interp_incr;
+ x->sp++;
+ if(x->sp == x->nPartials) x->sp = 0;
+}
+
+static void oscbank_table(t_oscbank *x, t_symbol *tablename)
+{
+ if(!x->got_a_table) free(x->wavetable);
+
+ t_garray *a;
+
+ if (!(a = (t_garray *)pd_findbyclass(tablename, garray_class)))
+ pd_error(x, "%s: no such array", tablename->s_name);
+ else if (!garray_getfloatarray(a, &x->wavetablesize, &x->wavetable))
+ pd_error(x, "%s: bad template for tabread", tablename->s_name);
+ else //table exists
+ {
+ post("wavetablesize: %d", x->wavetablesize );
+ }
+ x->got_a_table = 1;
+}
+
+static void oscbank_print(t_oscbank *x)
+{
+ t_partial *bank = x->pBank;
+
+ post("#. Index, Freq, Amp");
+ int i;
+
+ for(i=0; i < x->nPartials; i++)//for every partial
+ {
+ if(bank[i].aCurr)
+ {
+ post("%d. index: %d,freq: %f,amp: %f", i, bank[i].index,
+ bank[i].freq, bank[i].amp );
+ }
+ }
+}
+
+//TODO: this is crashing shit... whhhaaat
+static void oscbank_reset(t_oscbank *x)
+{
+ memset(x->pBank, 0, x->nPartials * sizeof(t_partial));
+}
+
+static t_int *oscbank_perform(t_int *w)
+{
+ t_oscbank *x = (t_oscbank *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ t_int n = (t_int)(w[3]);
+ t_int i, sample;
+ t_float phaseincrement;
+ t_float sample_sum, freq, amp;
+ t_int lookup;
+ t_partial *bank = x->pBank;
+
+ //clear output buffer so we can add to it starting at 0
+ memset( out , 0, n *sizeof( t_float ));
+
+ for(i=0; i < x->nPartials; i++)//for every partial
+ {
+ if(bank[i].aCurr != 0)
+ {
+ for(sample = 0; sample < n; sample++)//and every sample..
+ {
+ if(bank[i].nInterp > 0)
+ {
+ bank[i].fCurr += bank[i].fIncr;
+ bank[i].aCurr += bank[i].aIncr;
+ --bank[i].nInterp;
+ }
+ else
+ {
+ bank[i].fCurr = bank[i].freq;
+ bank[i].aCurr = bank[i].amp;
+ }
+
+ // get the phase increment freq = cyc/sec,
+ //sr = samp/sec, phaseinc = cyc/samp = freq/sr = freq * sampleperiod
+ phaseincrement = bank[i].fCurr * x->sampleperiod;
+ bank[i].phase += phaseincrement;
+ while(bank[i].phase >= 1.0f) //..and wrap
+ bank[i].phase -= 1.0f;
+ while(bank[i].phase < 0.0f)
+ bank[i].phase += 1.0f;
+
+ lookup = (int)(x->wavetablesize * bank[i].phase);
+
+ *(out+sample) += *(x->wavetable + lookup) * bank[i].aCurr;
+ }//end for samples
+ } //end if x->index
+ }//end for partials
+ return (w+4);
+}
+
+static void oscbank_dsp(t_oscbank *x, t_signal **sp)
+{
+ x->sampleRate = sp[0]->s_sr;
+ x->sampleperiod = 1 / x->sampleRate;
+ dsp_add(oscbank_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+}
+
+static void *oscbank_new(void)
+{
+ t_oscbank *x = (t_oscbank *)pd_new(oscbank_class);
+
+ float twopi, size;
+ int i;
+
+ outlet_new(&x->x_obj, gensym("signal"));
+ floatinlet_new(&x->x_obj, &x->infreq);
+ floatinlet_new(&x->x_obj, &x->inamp);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("interp"));
+
+ //hardcoded because dsp hasn't been turned on yet
+ //prevents devide by zero in oscbank_index()
+ x->sampleRate = 48000;
+ x->sampleperiod = 1 / x->sampleRate;
+ oscbank_interpMs( x, 20.0);
+
+ x->got_a_table = 0;
+ x->sp = 0;
+ x->nPartials = DEFAULT_NPARTIALS;
+ x->pBank = (t_partial *)getbytes( x->nPartials * sizeof(t_partial));
+ memset(x->pBank, 0, x->nPartials * sizeof(t_partial));
+
+ twopi = 8.0f * atan(1.0f);
+ x->wavetablesize = WAVETABLESIZE;
+ float *sinewave;
+ sinewave = (t_float *)malloc(x->wavetablesize * sizeof(t_float));
+ for(i = 0; i < x->wavetablesize; i++)
+ sinewave[i] = sin(twopi * (float)i/ x->wavetablesize);
+
+ x->wavetable = &sinewave[0];
+
+ return (x);
+}
+
+static void oscbank_free(t_oscbank *x)
+{
+ free(x->pBank);
+ if(!x->got_a_table)
+ free(x->wavetable);
+}
+
+void oscbank_tilde_setup(void)
+{
+ oscbank_class = class_new(gensym("oscbank~"),(t_newmethod)oscbank_new,\
+ (t_method)oscbank_free,sizeof(t_oscbank), 0, A_DEFFLOAT, 0);
+ class_addfloat(oscbank_class, oscbank_index);
+ class_addmethod(oscbank_class, (t_method)oscbank_table, gensym("table"), A_SYMBOL);
+ class_addmethod(oscbank_class, (t_method)oscbank_interpMs, gensym("interp"), A_FLOAT, 0);
+ class_addmethod(oscbank_class, (t_method)oscbank_dsp, gensym("dsp"), (t_atomtype)0);
+ class_addmethod(oscbank_class, (t_method)oscbank_print, gensym("print"), 0);
+ class_addmethod(oscbank_class, (t_method)oscbank_reset, gensym("reset"), 0);
+ class_addmethod(oscbank_class, (t_method)oscbank_nPartials, gensym("partials"), A_FLOAT, 0);
+}