diff options
Diffstat (limited to 'oscbank~.c')
-rw-r--r-- | oscbank~.c | 286 |
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); +} |