diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/Makefile | 3 | ||||
-rw-r--r-- | modules/bfft.c | 41 | ||||
-rw-r--r-- | modules/bitsplit.c | 107 | ||||
-rw-r--r-- | modules/blocknorm.c | 129 | ||||
-rw-r--r-- | modules/cmath.c | 176 | ||||
-rw-r--r-- | modules/dynwav.c | 2 | ||||
-rw-r--r-- | modules/ead.c | 43 | ||||
-rw-r--r-- | modules/eadsr.c | 47 | ||||
-rw-r--r-- | modules/ear.c | 8 | ||||
-rw-r--r-- | modules/eblosc.c | 599 | ||||
-rw-r--r-- | modules/fdn.c | 4 | ||||
-rw-r--r-- | modules/lattice.c | 11 | ||||
-rw-r--r-- | modules/matrix.c | 4 | ||||
-rw-r--r-- | modules/permut.c | 9 | ||||
-rw-r--r-- | modules/ramp.c | 66 | ||||
-rw-r--r-- | modules/resofilt.c | 397 | ||||
-rw-r--r-- | modules/sbosc.c | 175 | ||||
-rw-r--r-- | modules/scrollgrid1D.c | 220 | ||||
-rw-r--r-- | modules/statwav.c | 8 |
19 files changed, 1946 insertions, 103 deletions
diff --git a/modules/Makefile b/modules/Makefile index b5e6093..f054566 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -3,7 +3,8 @@ include ../Makefile.config current: ead.o ear.o eadsr.o dist.o tabreadmix.o xfm.o qmult.o qnorm.o \ cheby.o abs.o ramp.o dwt.o bfft.o dynwav.o statwav.o bdiag.o \ diag.o matrix.o permut.o lattice.o ratio.o ffpoly.o fwarp.o \ - junction.o fdn.o window.o + junction.o fdn.o window.o cmath.o eblosc.o bitsplit.o sbosc.o \ + blocknorm.o resofilt.o scrollgrid1D.o clean: diff --git a/modules/bfft.c b/modules/bfft.c index 76b0254..750f020 100644 --- a/modules/bfft.c +++ b/modules/bfft.c @@ -1,5 +1,5 @@ /* - * bfft.c - code for fourrier transform + * bfft.c - code for some fourrier transform variants and utility functions * data organization is in (real, imag) pairs * the first 2 components are (DC, NY) * Copyright (c) 2000-2003 by Tom Schouten @@ -29,17 +29,19 @@ typedef struct bfftctl { - t_int c_levels; - char c_name[16]; - t_int *c_clutter; - t_int *c_unclutter; + t_int c_levels; + char c_name[16]; + t_int *c_clutter; + t_int *c_unclutter; + t_int c_kill_DC; + t_int c_kill_NY; } t_bfftctl; typedef struct bfft { - t_object x_obj; - t_float x_f; - t_bfftctl x_ctl; + t_object x_obj; + t_float x_f; + t_bfftctl x_ctl; } t_bfft; t_class *bfft_class, *ibfft_class, *fht_class; @@ -127,10 +129,16 @@ static t_int *ibfft_perform(t_int *w) t_float scale = sqrt(1.0f / (float)(n)); + if (ctl->c_kill_DC) {out[0] = 0.0f;} + if (ctl->c_kill_NY) {out[1] = 0.0f;} + bfft_perform_permutation(out, n, ctl->c_clutter); mayer_fht(out, n); + + while (n--) *out++ *= scale; + return (w+5); } @@ -240,13 +248,22 @@ static void *bfft_new(void) } -static void *ibfft_new(void) +static void *ibfft_new(t_symbol *s) { t_bfft *x = (t_bfft *)pd_new(ibfft_class); int i; outlet_new(&x->x_obj, gensym("signal")); + if (s == gensym("killDCNY")){ + x->x_ctl.c_kill_DC = 1; + x->x_ctl.c_kill_NY = 1; + post("ibfft: removing DC and NY components."); + } + else{ + x->x_ctl.c_kill_DC = 0; + x->x_ctl.c_kill_NY = 0; + } x->x_ctl.c_clutter = NULL; x->x_ctl.c_unclutter = NULL; @@ -286,7 +303,11 @@ void bfft_tilde_setup(void) ibfft_class = class_new(gensym("ibfft~"), (t_newmethod)ibfft_new, - (t_method)bfft_free, sizeof(t_bfft), 0, 0); + (t_method)bfft_free, sizeof(t_bfft), 0, A_DEFSYMBOL, A_NULL); + + /* add the more logical bifft~ alias */ + class_addcreator((t_newmethod)ibfft_new, + gensym("bifft~"), 0, A_DEFSYMBOL, A_NULL); CLASS_MAINSIGNALIN(ibfft_class, t_bfft, x_f); class_addmethod(ibfft_class, (t_method)ibfft_dsp, gensym("dsp"), 0); diff --git a/modules/bitsplit.c b/modules/bitsplit.c new file mode 100644 index 0000000..9239d0b --- /dev/null +++ b/modules/bitsplit.c @@ -0,0 +1,107 @@ +/* + * bitsplit.c - convert a signal to a binary vector + * Copyright (c) 2000-2003 by Tom Schouten + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "m_pd.h" +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <math.h> + +#define MAXCHANNELS 24 + +typedef struct bitsplitctl +{ + t_int c_outputs; + t_float *c_input; + t_float **c_output; +} t_bitsplitctl; + +typedef struct bitsplit +{ + t_object x_obj; + t_float x_f; + t_bitsplitctl x_ctl; +} t_bitsplit; + + +static t_int *bitsplit_perform(t_int *word) +{ + + t_bitsplitctl *ctl = (t_bitsplitctl *)(word[1]); + t_int n = (t_int)(word[2]); + t_float *in = ctl->c_input; + t_int outputs = ctl->c_outputs; + t_float **out = ctl->c_output; + t_int i,j; + + for (i=0;i<n;i++){ + long word = (in[i] * (float)(0x7fffffff)); + for (j=0; j<outputs; j++){ + out[j][i] = (float)((word >> 31) & 1); + word <<= 1; + } + } + + return (word+3); +} + + + +static void bitsplit_dsp(t_bitsplit *x, t_signal **sp) +{ + + int i; + x->x_ctl.c_input = sp[0]->s_vec; + for (i=0;i<x->x_ctl.c_outputs;i++){ + x->x_ctl.c_output[i] = sp[i+1]->s_vec; + } + dsp_add(bitsplit_perform, 2, &x->x_ctl, sp[0]->s_n); +} + + +static void bitsplit_free(t_bitsplit *x) +{ + free (x->x_ctl.c_output); +} + +t_class *bitsplit_class; + +static void *bitsplit_new(t_floatarg channels) +{ + int i = (int)channels; + t_bitsplit *x = (t_bitsplit *)pd_new(bitsplit_class); + + if (i<1) i = 1; + if (i>MAXCHANNELS) i = MAXCHANNELS; + x->x_ctl.c_outputs = i; + x->x_ctl.c_output = malloc(sizeof(float)*i); + + while (i--) outlet_new(&x->x_obj, gensym("signal")); + + return (void *)x; +} + +void bitsplit_tilde_setup(void) +{ + bitsplit_class = class_new(gensym("bitsplit~"), (t_newmethod)bitsplit_new, + (t_method)bitsplit_free, sizeof(t_bitsplit), 0, A_DEFFLOAT, 0); + CLASS_MAINSIGNALIN(bitsplit_class, t_bitsplit, x_f); + class_addmethod(bitsplit_class, (t_method)bitsplit_dsp, gensym("dsp"), 0); +} + diff --git a/modules/blocknorm.c b/modules/blocknorm.c new file mode 100644 index 0000000..bcf695a --- /dev/null +++ b/modules/blocknorm.c @@ -0,0 +1,129 @@ +/* + * blocknorm.c - normalize an array of dsp blocks (for spectral processing) + * Copyright (c) 2000-2003 by Tom Schouten + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "m_pd.h" +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <math.h> + +#define MAXCHANNELS 32 + +typedef struct blocknormctl +{ + t_int c_channels; + t_float **c_input; + t_float **c_output; +} t_blocknormctl; + +typedef struct blocknorm +{ + t_object x_obj; + t_float x_f; + t_blocknormctl x_ctl; +} t_blocknorm; + + +static t_int *blocknorm_perform(t_int *word) +{ + + t_blocknormctl *ctl = (t_blocknormctl *)(word[1]); + t_int n = (t_int)(word[2]); + t_float **in = ctl->c_input; + t_float **out = ctl->c_output; + t_int c = ctl->c_channels; + t_int i,j; + + t_float p = 0.0f; + t_float x, s; + + /* get power */ + for (j=0;j<c;j++){ + for (i=0;i<n;i++){ + x = in[j][i]; + p += x*x; + } + } + + /* compute normalization */ + if (p == 0.0f) s = 1.0f; + else s =sqrt(((float)(c * n)) / p); + + /* normalize */ + for (j=0;j<c;j++){ + for (i=0;i<n;i++){ + out[j][i] *= s; + } + } + + + + return (word+3); +} + + + +static void blocknorm_dsp(t_blocknorm *x, t_signal **sp) +{ + + int i; + int c = x->x_ctl.c_channels; + for (i=0;i<c;i++){ + x->x_ctl.c_input[i] = sp[i]->s_vec; + x->x_ctl.c_output[i] = sp[c+i]->s_vec; + } + dsp_add(blocknorm_perform, 2, &x->x_ctl, sp[0]->s_n); +} + + +static void blocknorm_free(t_blocknorm *x) +{ + free (x->x_ctl.c_output); + free (x->x_ctl.c_input); +} + +t_class *blocknorm_class; + +static void *blocknorm_new(t_floatarg channels) +{ + int i = (int)channels; + int j; + t_blocknorm *x = (t_blocknorm *)pd_new(blocknorm_class); + + if (i<1) i = 1; + if (i>MAXCHANNELS) i = MAXCHANNELS; + x->x_ctl.c_channels = i; + x->x_ctl.c_input = malloc(sizeof(float)*i); + x->x_ctl.c_output = malloc(sizeof(float)*i); + + j = i; + while (--j) inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal")); + while (i--) outlet_new(&x->x_obj, gensym("signal")); + + return (void *)x; +} + +void blocknorm_tilde_setup(void) +{ + blocknorm_class = class_new(gensym("blocknorm~"), (t_newmethod)blocknorm_new, + (t_method)blocknorm_free, sizeof(t_blocknorm), 0, A_DEFFLOAT, 0); + CLASS_MAINSIGNALIN(blocknorm_class, t_blocknorm, x_f); + class_addmethod(blocknorm_class, (t_method)blocknorm_dsp, gensym("dsp"), 0); +} + diff --git a/modules/cmath.c b/modules/cmath.c new file mode 100644 index 0000000..3bd63a9 --- /dev/null +++ b/modules/cmath.c @@ -0,0 +1,176 @@ +/* + * cmath.c - some complex math dsp objects + * Copyright (c) 2000-2003 by Tom Schouten + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "m_pd.h" +#include <math.h> + +#define MINNORM 0.0000000001 + +typedef struct cmath +{ + t_object x_obj; + t_float x_f; + t_perfroutine x_perf; +} t_cmath; + + +static t_int *cmath_perform_clog(t_int *w) +{ + t_float *inx = (float *)(w[2]); + t_float *iny = (float *)(w[3]); + t_float *outx = (float *)(w[4]); + t_float *outy = (float *)(w[5]); + t_int i; + t_int n = (t_int)(w[1]); + t_float x; + + while (n--){ + float x = *inx++; + float y = *iny++; + float norm = sqrt(x*x + y*y); + float arg = atan2(y, x); + if (norm < MINNORM){ + norm = MINNORM; + } + *outx++ = log(norm); + *outy++ = arg; + } + + return (w+6); +} + + +static t_int *cmath_perform_cexp(t_int *w) +{ + t_float *inx = (float *)(w[2]); + t_float *iny = (float *)(w[3]); + t_float *outx = (float *)(w[4]); + t_float *outy = (float *)(w[5]); + t_int i; + t_int n = (t_int)(w[1]); + t_float x; + + while (n--){ + float x = *inx++; + float y = *iny++; + float norm = exp(x); + *outx++ = norm * cos(y); + *outy++ = norm * sin(y); + } + + return (w+6); +} + +static t_int *cmath_perform_nfft(t_int *w) +{ + t_float *inx = (float *)(w[2]); + t_float *iny = (float *)(w[3]); + t_float *outx = (float *)(w[4]); + t_float *outy = (float *)(w[5]); + t_int i; + t_int n = (t_int)(w[1]); + t_float x; + t_float scale = 1.0f / (sqrt((float)n)); + + mayer_fft(n, inx, outx); + + while (n--){ + float x = *inx++; + float y = *iny++; + *outx++ = scale * x; + *outy++ = scale * y; + } + + return (w+6); +} + +static t_int *cmath_perform_nifft(t_int *w) +{ + t_float *inx = (float *)(w[2]); + t_float *iny = (float *)(w[3]); + t_float *outx = (float *)(w[4]); + t_float *outy = (float *)(w[5]); + t_int i; + t_int n = (t_int)(w[1]); + t_float x; + t_float scale = 1.0f / (sqrt((float)n)); + + mayer_ifft(n, inx, outx); + + while (n--){ + float x = *inx++; + float y = *iny++; + *outx++ = scale * x; + *outy++ = scale * y; + } + + return (w+6); +} + +static void cmath_dsp(t_cmath *x, t_signal **sp) +{ + dsp_add(x->x_perf, 5, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); + +} +void cmath_free(void) +{ + +} + +t_class *cmath_class; + +t_cmath *cmath_new_common(void) +{ + t_cmath *x = (t_cmath *)pd_new(cmath_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal")); + outlet_new(&x->x_obj, gensym("signal")); + outlet_new(&x->x_obj, gensym("signal")); + return x; +} + +#define DEFNEWCMATH(name, perfmethod) \ +void * name (void) \ +{ \ + t_cmath *x = cmath_new_common(); \ + x->x_perf = perfmethod ; \ + return (void*)x; \ +} + +DEFNEWCMATH(cmath_new_clog, cmath_perform_clog) +DEFNEWCMATH(cmath_new_cexp, cmath_perform_cexp) +DEFNEWCMATH(cmath_new_nfft, cmath_perform_nfft) +DEFNEWCMATH(cmath_new_nifft, cmath_perform_nifft) + + +void cmath_tilde_setup(void) +{ + //post("cmath~ v0.1"); + cmath_class = class_new(gensym("clog~"), (t_newmethod)cmath_new_clog, + (t_method)cmath_free, sizeof(t_cmath), 0, 0); + + class_addcreator((t_newmethod)cmath_new_cexp, gensym("cexp~"), A_NULL); + class_addcreator((t_newmethod)cmath_new_nfft, gensym("nfft~"), A_NULL); + class_addcreator((t_newmethod)cmath_new_nifft, gensym("nifft~"), A_NULL); + + CLASS_MAINSIGNALIN(cmath_class, t_cmath, x_f); + + class_addmethod(cmath_class, (t_method)cmath_dsp, gensym("dsp"), 0); +} + diff --git a/modules/dynwav.c b/modules/dynwav.c index 0ff75f3..9157f12 100644 --- a/modules/dynwav.c +++ b/modules/dynwav.c @@ -1,5 +1,5 @@ /* - * dynwav.c - dynamic wavetable oscillator + * blosc.c - bandlimited oscillators * data organization is in (real, imag) pairs * the first 2 components are (DC, NY) * Copyright (c) 2000-2003 by Tom Schouten diff --git a/modules/ead.c b/modules/ead.c index 4d301b8..88fc6ec 100644 --- a/modules/ead.c +++ b/modules/ead.c @@ -29,7 +29,7 @@ typedef struct eadctl t_float c_attack; t_float c_decay; t_float c_state; - t_float c_target; + t_int c_target; } t_eadctl; @@ -54,7 +54,13 @@ static void ead_decay(t_ead *x, t_floatarg f) static void ead_start(t_ead *x) { - x->x_ctl.c_target = 1; + /* reset state if necessary to prevent skipping */ + + // always reset, seems to be safest + //if (x->x_ctl.c_target == 1) + + x->x_ctl.c_state = 0.0f; + x->x_ctl.c_target = 1; } @@ -68,7 +74,6 @@ static t_int *ead_perform(t_int *w) t_float attack = ctl->c_attack; t_float decay = ctl->c_decay; t_float state = ctl->c_state; - t_float target = ctl->c_target; t_int n = (t_int)(w[2]); t_int i; @@ -76,29 +81,27 @@ static t_int *ead_perform(t_int *w) /* A/D code */ - if (target == 1) - /* attack phase */ - { - for (i = 0; i < n; i++) - { + for (i = 0; i < n; i++){ + switch(ctl->c_target){ + case 1: + /* attack phase */ *out++ = state; state += attack*(1 - state); - } - if (state > ENVELOPE_MAX) - ctl->c_target = 0; - } - - else - /* decay phase */ - for (i = 0; i < n; i++) - { - *out++ = state; - state -= decay*state; + ctl->c_target = (state <= ENVELOPE_MAX); + break; + default: + /* decay phase */ + *out++ = state; + state -= decay*state; + break; } + + } + /* save state */ ctl->c_state = IS_DENORMAL(state) ? 0 : state; - return (w+4); /* pd quirk: pointer for sequencer */ + return (w+4); } diff --git a/modules/eadsr.c b/modules/eadsr.c index bba96cd..332ddf4 100644 --- a/modules/eadsr.c +++ b/modules/eadsr.c @@ -63,6 +63,7 @@ void eadsr_release(t_eadsr *x, t_floatarg f) void eadsr_start(t_eadsr *x) { x->x_ctl.c_target = 1; + x->x_ctl.c_state = 0.0f; } @@ -72,6 +73,12 @@ void eadsr_stop(t_eadsr *x) } +void eadsr_float(t_eadsr *x, t_floatarg f) +{ + if (f == 0.0f) eadsr_stop(x); + else eadsr_start(x); +} + static t_int *eadsr_perform(t_int *w) { t_float *out = (float *)(w[3]); @@ -87,35 +94,28 @@ static t_int *eadsr_perform(t_int *w) t_int i; - if (target == 1) - /* attack phase */ - { - for (i = 0; i < n; i++) - { + for (i = 0; i < n; i++){ + if (target == 1.0f){ + /* attack */ *out++ = state; state += attack*(1 - state); - } - if (state > ENVELOPE_MAX) - ctl->c_target = sustain; - } - - else if (target == 0) - /* release phase */ - for (i = 0; i < n; i++) - { - *out++ = state; - state -= release*state; + target = (state > ENVELOPE_MAX) ? sustain : 1.0f; } - - else - /* decay phase */ - for (i = 0; i < n; i++) - { - *out++ = state; - state -= decay*(state-sustain); + else if (target == 0.0f){ + /* release */ + *out++ = state; + state -= release*state; + } + else{ + /* decay */ + *out++ = state; + state -= decay*(state-sustain); } + } + /* save state */ ctl->c_state = IS_DENORMAL(state) ? 0 : state; + ctl->c_target = target; return (w+4); } @@ -157,6 +157,7 @@ void eadsr_tilde_setup(void) //post("eadsr~ v0.1"); eadsr_class = class_new(gensym("eadsr~"), (t_newmethod)eadsr_new, (t_method)eadsr_free, sizeof(t_eadsr), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod(eadsr_class, (t_method)eadsr_float, gensym("float"), A_FLOAT, 0); class_addmethod(eadsr_class, (t_method)eadsr_start, gensym("start"), 0); class_addmethod(eadsr_class, (t_method)eadsr_start, gensym("bang"), 0); class_addmethod(eadsr_class, (t_method)eadsr_stop, gensym("stop"), 0); diff --git a/modules/ear.c b/modules/ear.c index d842065..28fe097 100644 --- a/modules/ear.c +++ b/modules/ear.c @@ -47,6 +47,7 @@ void ear_release(t_ear *x, t_floatarg f) void ear_start(t_ear *x) { x->x_ctl.c_target = 1; + x->x_ctl.c_state = 0.0f; } @@ -56,6 +57,12 @@ void ear_stop(t_ear *x) } +void ear_float(t_ear *x, t_floatarg f) +{ + if (f == 0.0f) ear_stop(x); + else ear_start(x); +} + static t_int *ear_perform(t_int *w) { t_float *out = (float *)(w[3]); @@ -120,6 +127,7 @@ void ear_tilde_setup(void) //post("ear~ v0.1"); ear_class = class_new(gensym("ear~"), (t_newmethod)ear_new, (t_method)ear_free, sizeof(t_ear), 0, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod(ear_class, (t_method)ear_float, gensym("float"), A_FLOAT, 0); class_addmethod(ear_class, (t_method)ear_start, gensym("start"), 0); class_addmethod(ear_class, (t_method)ear_start, gensym("bang"), 0); class_addmethod(ear_class, (t_method)ear_stop, gensym("stop"), 0); diff --git a/modules/eblosc.c b/modules/eblosc.c new file mode 100644 index 0000000..df1b059 --- /dev/null +++ b/modules/eblosc.c @@ -0,0 +1,599 @@ +/* + * eblosc.c - bandlimited oscillators with infinite support discontinuities + * using minimum phase impulse, step & ramp + * Copyright (c) 2000-2003 by Tom Schouten + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "m_pd.h" +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "filters.h" + + +typedef unsigned long long u64; +typedef unsigned long u32; + + + +#define LPHASOR (8*sizeof(u32)) // the phasor logsize +#define VOICES 8 // the number of oscillators +#define CUTOFF 0.8f // fraction of nyquist for impulse cutoff + + + +typedef struct ebloscctl +{ + t_float c_pole[VOICES*2]; // complex poles + t_float c_gain[VOICES*2]; // complex gains (waveform specific constants) + t_float c_state[VOICES*2]; // complex state + + u32 c_phase; // phase of main oscillator + u32 c_phase2; // phase of secondairy oscillator + t_float c_prev_amp; // previous input of comparator + t_float c_phase_inc_scale; + t_float c_scale; + t_float c_scale_update; + t_symbol *c_waveform; + +} t_ebloscctl; + +typedef struct eblosc +{ + t_object x_obj; + t_float x_f; + t_ebloscctl x_ctl; +} t_eblosc; + + +/* phase converters */ +static inline float _phase_to_float(u32 p){return ((float)p) * (1.0f / 4294967296.0f);} +static inline u32 _float_to_phase(float f){return (u32)(f * 4294967296.0f);} + + + +/* get one sample from the oscillator bank and perform time tick */ +static inline t_float _osc_tick(t_ebloscctl *ctl) +{ + float sum = 0.0f; + int i; + /* sum all voices */ + for (i=0; i<VOICES*2; i+=2){ + /* rotate state */ + vcmul2(ctl->c_state+i, ctl->c_pole+i); + + /* get real part and add to output */ + sum += ctl->c_state[0]; + } + + return sum; +} + +/* add shifted impulse */ +static inline void _add_impulse(t_ebloscctl *ctl, t_float t0) +{ + int i; + for (i=0; i<VOICES*2; i+=2){ + /* contribution is a_i z_i^t_0 */ + + float real = 1.0f; + float imag = 0.0f; + + ctl->c_state[0] += real; + ctl->c_state[1] += imag; + } +} + + +/* add step */ +static inline void _add_step(t_ebloscctl *ctl) +{ + int i; + for (i=0; i<VOICES*2; i+=2){ + /* contribution is a_i (1 - z_i) */ + + float real = 1.0f; + float imag = 0.0f; + + ctl->c_state[0] += real; + ctl->c_state[1] += imag; + } +} + + +/* add shifted step */ +static inline void _add_shifted_step(t_ebloscctl *ctl, t_float t0) +{ + int i; + for (i=0; i<VOICES*2; i+=2){ + /* contribution is a_i (1 - z_i^t_0) */ + + float real = 1.0f; + float imag = 0.0f; + + ctl->c_state[0] += real; + ctl->c_state[1] += imag; + } +} + + +#if 0 +/* update waveplayers on zero cross */ +static void _bang_comparator(t_ebloscctl *ctl, float prev, float curr) +{ + + /* check for sign change */ + if ((prev * curr) < 0.0f){ + + int voice; + + /* determine the location of the discontinuity (in oversampled coordiates + using linear interpolation */ + + float f = (float)S * curr / (curr - prev); + + /* get the offset in the oversample table */ + + u32 table_index = (u32)f; + + /* determine the fractional part (in oversampled coordinates) + for linear interpolation */ + + float table_frac_index = f - (float)table_index; + + /* set state (+ or -) */ + + ctl->c_state = (curr > 0.0f) ? 0.5f : -0.5f; + + /* steal the oldest voice */ + + voice = ctl->c_next_voice++; + ctl->c_next_voice &= VOICES-1; + + /* initialize the new voice index and interpolation fraction */ + + ctl->c_index[voice] = table_index; + ctl->c_frac[voice] = table_frac_index; + ctl->c_vscale[voice] = -ctl->c_scale * 2.0f * ctl->c_state; + + } + +} + +/* advance phasor and update waveplayers on phase wrap */ +static void _bang_phasor(t_ebloscctl *ctl, float freq) +{ + u32 phase = ctl->c_phase; + u32 phase_inc; + u32 oldphase; + int voice; + float scale = ctl->c_scale; + + /* get increment */ + float inc = freq * ctl->c_phase_inc_scale; + + /* calculate new phase + the increment (and the phase) should be a multiple of S */ + if (inc < 0.0f) inc = -inc; + phase_inc = ((u32)inc) & ~(S-1); + oldphase = phase; + phase += phase_inc; + + + /* check for phase wrap */ + if (phase < oldphase){ + u32 phase_inc_decimated = phase_inc >> LOVERSAMPLE; + u32 table_index; + u32 table_phase; + + /* steal the oldest voice if we have a phase wrap */ + + voice = ctl->c_next_voice++; + ctl->c_next_voice &= VOICES-1; + + /* determine the location of the discontinuity (in oversampled coordinates) + which is S * (new phase) / (increment) */ + + table_index = phase / phase_inc_decimated; + + /* determine the fractional part (in oversampled coordinates) + for linear interpolation */ + + table_phase = phase - (table_index * phase_inc_decimated); + + /* use it to initialize the new voice index and interpolation fraction */ + + ctl->c_index[voice] = table_index; + ctl->c_frac[voice] = (float)table_phase / (float)phase_inc_decimated; + ctl->c_vscale[voice] = scale; + scale = scale * ctl->c_scale_update; + + } + + /* save state */ + ctl->c_phase = phase; + ctl->c_scale = scale; +} + + +/* the 2 oscillator version: + the second osc can reset the first osc's phase (hence it determines the pitch) + the first osc determines the waveform */ + +static void _bang_hardsync_phasor(t_ebloscctl *ctl, float freq, float freq2) +{ + u32 phase = ctl->c_phase; + u32 phase2 = ctl->c_phase2; + u32 phase_inc; + u32 phase_inc2; + u32 oldphase; + u32 oldphase2; + int voice; + float scale = ctl->c_scale; + + + /* get increment */ + float inc = freq * ctl->c_phase_inc_scale; + float inc2 = freq2 * ctl->c_phase_inc_scale; + + /* calculate new phases + the increment (and the phase) should be a multiple of S */ + + /* save previous phases */ + oldphase = phase; + oldphase2 = phase2; + + /* update second osc */ + if (inc2 < 0.0f) inc2 = -inc2; + phase_inc2 = ((u32)inc2) & ~(S-1); + phase2 += phase_inc2; + + /* update first osc (freq should be >= freq of sync osc */ + if (inc < 0.0f) inc = -inc; + phase_inc = ((u32)inc) & ~(S-1); + if (phase_inc < phase_inc2) phase_inc = phase_inc2; + phase += phase_inc; + + + /* check for sync discontinuity (osc 2) */ + if (phase2 < oldphase2) { + + /* adjust phase depending on the location of the discontinuity in phase2: + phase/phase_inc == phase2/phase_inc2 */ + + u64 pi = phase_inc >> LOVERSAMPLE; + u64 pi2 = phase_inc2 >> LOVERSAMPLE; + u64 lphase = ((u64)phase2 * pi) / pi2; + phase = lphase & ~(S-1); + } + + + /* check for phase discontinuity (osc 1) */ + if (phase < oldphase){ + u32 phase_inc_decimated = phase_inc >> LOVERSAMPLE; + u32 table_index; + u32 table_phase; + float stepsize; + + /* steal the oldest voice if we have a phase wrap */ + + voice = ctl->c_next_voice++; + ctl->c_next_voice &= VOICES-1; + + /* determine the location of the discontinuity (in oversampled coordinates) + which is S * (new phase) / (increment) */ + + table_index = phase / phase_inc_decimated; + + /* determine the fractional part (in oversampled coordinates) + for linear interpolation */ + + table_phase = phase - (table_index * phase_inc_decimated); + + /* determine the step size + as opposed to saw/impulse waveforms, the step is not always equal to one. it is: + oldphase - phase + phase_inc + but for the unit step this will overflow to zero, so we + reduce the bit depth to prevent overflow */ + + stepsize = _phase_to_float(((oldphase-phase) >> LOVERSAMPLE) + + phase_inc_decimated) * (float)S; + + /* use it to initialize the new voice index and interpolation fraction */ + + ctl->c_index[voice] = table_index; + ctl->c_frac[voice] = (float)table_phase / (float)phase_inc_decimated; + ctl->c_vscale[voice] = scale * stepsize; + scale = scale * ctl->c_scale_update; + + } + + /* save state */ + ctl->c_phase = phase; + ctl->c_phase2 = phase2; + ctl->c_scale = scale; +} + + +static t_int *eblosc_perform_hardsync_saw(t_int *w) +{ + t_float *freq = (float *)(w[3]); + t_float *freq2 = (float *)(w[4]); + t_float *out = (float *)(w[5]); + t_ebloscctl *ctl = (t_ebloscctl *)(w[1]); + t_int n = (t_int)(w[2]); + t_int i; + + /* set postfilter cutoff */ + ctl->c_butter->setButterHP(0.85f * (*freq / sys_getsr())); + + while (n--) { + float frequency = *freq++; + float frequency2 = *freq2++; + + /* get the bandlimited discontinuity */ + float sample = _get_bandlimited_discontinuity(ctl, bls); + + /* add aliased sawtooth wave */ + sample += _phase_to_float(ctl->c_phase) - 0.5f; + + /* highpass filter output to remove DC offset and low frequency aliasing */ + ctl->c_butter->BangSmooth(sample, sample, 0.05f); + + /* send to output */ + *out++ = sample; + + /* advance phasor */ + _bang_hardsync_phasor(ctl, frequency2, frequency); + + } + + return (w+6); +} + +static t_int *eblosc_perform_saw(t_int *w) +{ + t_float *freq = (float *)(w[3]); + t_float *out = (float *)(w[4]); + t_ebloscctl *ctl = (t_ebloscctl *)(w[1]); + t_int n = (t_int)(w[2]); + t_int i; + + while (n--) { + float frequency = *freq++; + + /* get the bandlimited discontinuity */ + float sample = _get_bandlimited_discontinuity(ctl, bls); + + /* add aliased sawtooth wave */ + sample += _phase_to_float(ctl->c_phase) - 0.5f; + + /* send to output */ + *out++ = sample; + + /* advance phasor */ + _bang_phasor(ctl, frequency); + + } + + return (w+5); +} + + + +static t_int *eblosc_perform_pulse(t_int *w) +{ + t_float *freq = (float *)(w[3]); + t_float *out = (float *)(w[4]); + t_ebloscctl *ctl = (t_ebloscctl *)(w[1]); + t_int n = (t_int)(w[2]); + t_int i; + + + /* set postfilter cutoff */ + ctl->c_butter->setButterHP(0.85f * (*freq / sys_getsr())); + + while (n--) { + float frequency = *freq++; + + /* get the bandlimited discontinuity */ + float sample = _get_bandlimited_discontinuity(ctl, bli); + + /* highpass filter output to remove DC offset and low frequency aliasing */ + ctl->c_butter->BangSmooth(sample, sample, 0.05f); + + /* send to output */ + *out++ = sample; + + /* advance phasor */ + _bang_phasor(ctl, frequency); + + } + + return (w+5); +} + +static t_int *eblosc_perform_comparator(t_int *w) +{ + t_float *amp = (float *)(w[3]); + t_float *out = (float *)(w[4]); + t_ebloscctl *ctl = (t_ebloscctl *)(w[1]); + t_int n = (t_int)(w[2]); + t_int i; + t_float prev_amp = ctl->c_prev_amp; + + while (n--) { + float curr_amp = *amp++; + + /* exact zero won't work for zero detection (sic) */ + if (curr_amp == 0.0f) curr_amp = 0.0000001f; + + /* get the bandlimited discontinuity */ + float sample = _get_bandlimited_discontinuity(ctl, bls); + + /* add the block wave state */ + sample += ctl->c_state; + + /* send to output */ + *out++ = sample; + + /* advance phasor */ + _bang_comparator(ctl, prev_amp, curr_amp); + + prev_amp = curr_amp; + + } + + ctl->c_prev_amp = prev_amp; + + return (w+5); +} + +static void eblosc_phase(t_eblosc *x, t_float f) +{ + x->x_ctl.c_phase = _float_to_phase(f); + x->x_ctl.c_phase2 = _float_to_phase(f); +} + +static void eblosc_phase1(t_eblosc *x, t_float f) +{ + x->x_ctl.c_phase = _float_to_phase(f); +} + +static void eblosc_phase2(t_eblosc *x, t_float f) +{ + x->x_ctl.c_phase2 = _float_to_phase(f); +} + +static void eblosc_dsp(t_eblosc *x, t_signal **sp) +{ + int n = sp[0]->s_n; + + /* set sampling rate scaling for phasors */ + x->x_ctl.c_phase_inc_scale = 4.0f * (float)(1<<(LPHASOR-2)) / sys_getsr(); + + + /* setup & register the correct process routine depending on the waveform */ + + /* 2 osc */ + if (x->x_ctl.c_waveform == gensym("syncsaw")){ + x->x_ctl.c_scale = 1.0f; + x->x_ctl.c_scale_update = 1.0f; + dsp_add(eblosc_perform_hardsync_saw, 5, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); + } + + /* 1 osc */ + else if (x->x_ctl.c_waveform == gensym("pulse")){ + x->x_ctl.c_scale = 1.0f; + x->x_ctl.c_scale_update = 1.0f; + dsp_add(eblosc_perform_pulse, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + } + else if (x->x_ctl.c_waveform == gensym("pulse2")){ + x->x_ctl.c_phase_inc_scale *= 2; + x->x_ctl.c_scale = 1.0f; + x->x_ctl.c_scale_update = -1.0f; + dsp_add(eblosc_perform_pulse, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + } + else if (x->x_ctl.c_waveform == gensym("comparator")){ + x->x_ctl.c_scale = 1.0f; + x->x_ctl.c_scale_update = 1.0f; + dsp_add(eblosc_perform_comparator, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + } + else{ + x->x_ctl.c_scale = 1.0f; + x->x_ctl.c_scale_update = 1.0f; + dsp_add(eblosc_perform_saw, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + } + + + +} +static void eblosc_free(t_eblosc *x) +{ + delete x->x_ctl.c_butter; +} + +t_class *eblosc_class; + +static void *eblosc_new(t_symbol *s) +{ + t_eblosc *x = (t_eblosc *)pd_new(eblosc_class); + int i; + + /* out 1 */ + outlet_new(&x->x_obj, gensym("signal")); + + /* optional signal inlets */ + if (s == gensym("syncsaw")){ + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal")); + } + + /* optional phase inlet */ + if (s != gensym("comparator")){ + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("phase")); + } + + /* create the postfilter */ + x->x_ctl.c_butter = new DSPIfilterSeries(3); + + /* init oscillators */ + for (i=0; i<VOICES; i++) { + x->x_ctl.c_index[i] = N-2; + x->x_ctl.c_frac[i] = 0.0f; + } + + /* init rest of state data */ + eblosc_phase(x, 0); + eblosc_phase2(x, 0); + x->x_ctl.c_state = 0.0; + x->x_ctl.c_prev_amp = 0.0; + x->x_ctl.c_next_voice = 0; + x->x_ctl.c_scale = 1.0f; + x->x_ctl.c_scale_update = 1.0f; + x->x_ctl.c_waveform = s; + + return (void *)x; +} + + + + + +extern "C" +{ + void eblosc_tilde_setup(void) + { + //post("eblosc~ v0.1"); + + build_tables(); + + eblosc_class = class_new(gensym("eblosc~"), (t_newmethod)eblosc_new, + (t_method)eblosc_free, sizeof(t_eblosc), 0, A_DEFSYMBOL, A_NULL); + CLASS_MAINSIGNALIN(eblosc_class, t_eblosc, x_f); + class_addmethod(eblosc_class, (t_method)eblosc_dsp, gensym("dsp"), A_NULL); + class_addmethod(eblosc_class, (t_method)eblosc_phase, gensym("phase"), A_FLOAT, A_NULL); + class_addmethod(eblosc_class, (t_method)eblosc_phase2, gensym("phase2"), A_FLOAT, A_NULL); + + + } + +} + +#endif diff --git a/modules/fdn.c b/modules/fdn.c index 22fcc40..9fbfee7 100644 --- a/modules/fdn.c +++ b/modules/fdn.c @@ -311,11 +311,11 @@ static void fdn_updatedamping(t_fdn *x) } static void fdn_timelow(t_fdn *x, t_float f){ - x->x_ctl.c_timelow = f; + x->x_ctl.c_timelow = fabs(f); fdn_updatedamping(x); } static void fdn_timehigh(t_fdn *x, t_float f){ - x->x_ctl.c_timehigh = f; + x->x_ctl.c_timehigh = fabs(f); fdn_updatedamping(x); } diff --git a/modules/lattice.c b/modules/lattice.c index 9403393..6f8e816 100644 --- a/modules/lattice.c +++ b/modules/lattice.c @@ -22,7 +22,8 @@ #include "m_pd.h" #include <math.h> -#define maxorder 1024 +#define MAXORDER 1024 +#define MAXREFCO 0.9999f typedef struct latticesegment { @@ -32,7 +33,7 @@ typedef struct latticesegment typedef struct latticectl { - t_latticesegment c_segment[maxorder]; // array of lattice segment data + t_latticesegment c_segment[MAXORDER]; // array of lattice segment data t_int c_segments; } t_latticectl; @@ -98,8 +99,8 @@ static void lattice_rc(t_lattice *x, t_float segment, t_float refco) { t_int seg = (t_float)segment; if ((seg >= 0) && (seg < x->x_ctl.c_segments)){ - if (refco > 1.0f) refco = 1.0f; - if (refco < -1.0f) refco = -1.0f; + if (refco >= MAXREFCO) refco = MAXREFCO; + if (refco <= -MAXREFCO) refco = -MAXREFCO; x->x_ctl.c_segment[seg].rc = refco; } } @@ -120,7 +121,7 @@ static void *lattice_new(t_floatarg segments) outlet_new(&x->x_obj, gensym("signal")); if (seg < 1) seg = 1; - if (seg > maxorder) seg = maxorder; + if (seg > MAXORDER) seg = MAXORDER; x->x_ctl.c_segments = seg; diff --git a/modules/matrix.c b/modules/matrix.c index 6fd55b7..b59d4d6 100644 --- a/modules/matrix.c +++ b/modules/matrix.c @@ -140,10 +140,10 @@ static void *matrix_new(t_floatarg order) return (void *)x; } -void matrix_tilde_setup(void) +void bmatrix_tilde_setup(void) { //post("matrix~ v0.1"); - matrix_class = class_new(gensym("matrix~"), (t_newmethod)matrix_new, + matrix_class = class_new(gensym("bmatrix~"), (t_newmethod)matrix_new, (t_method)matrix_free, sizeof(t_matrix), 0, A_DEFFLOAT, 0); CLASS_MAINSIGNALIN(matrix_class, t_matrix, x_f); class_addmethod(matrix_class, (t_method)matrix_dsp, gensym("dsp"), 0); diff --git a/modules/permut.c b/modules/permut.c index bc143d2..7738f84 100644 --- a/modules/permut.c +++ b/modules/permut.c @@ -20,9 +20,10 @@ */ -#include "m_pd.h" #include <math.h> #include <stdlib.h> +//#include "m_pd.h" +#include "extlib_util.h" @@ -64,7 +65,8 @@ static void permut_random(t_permut *x, t_floatarg seed) int *p = x->x_ctl.c_permutationtable; int r, last = 0; - srand(* ((unsigned int *)(&seed))); + //srand(* ((unsigned int *)(&seed))); + srand (((t_flint)seed).i); if(p) { @@ -91,7 +93,8 @@ static void permut_random(t_permut *x, t_floatarg seed) static void permut_bang(t_permut *x) { unsigned int r = rand(); - permut_random(x, *((float *)(&r))); + //permut_random(x, *((float *)(&r))); + permut_random(x, ((t_flint)r).f); } static void permut_resize_table(t_permut *x, int size) diff --git a/modules/ramp.c b/modules/ramp.c index ad13582..526ec4e 100644 --- a/modules/ramp.c +++ b/modules/ramp.c @@ -24,64 +24,53 @@ typedef struct rampctl { - t_float c_offset; - t_float c_looppoint; + t_float c_offset; + t_int c_blockscale; } t_rampctl; typedef struct ramp { - t_object x_obj; - t_float x_f; - t_rampctl x_ctl; + t_object x_obj; + t_float x_f; + t_rampctl x_ctl; } t_ramp; void ramp_offset(t_ramp *x, t_floatarg f) { - - x->x_ctl.c_offset = f; - -} - -void ramp_looppoint(t_ramp *x, t_floatarg f) -{ - - x->x_ctl.c_looppoint = f; - + x->x_ctl.c_offset = f; } void ramp_bang(t_ramp *x) { - ramp_offset(x, 0); - + ramp_offset(x, 0); } static t_int *ramp_perform(t_int *w) { + t_float *out = (float *)(w[3]); + t_rampctl *ctl = (t_rampctl *)(w[1]); + t_int i; + t_int n = (t_int)(w[2]); + t_float x; - - t_float *out = (float *)(w[3]); - t_rampctl *ctl = (t_rampctl *)(w[1]); - t_int i; - t_int n = (t_int)(w[2]); - t_float x; - + t_float scale = ctl->c_blockscale ? 1.0f / (float)n : 1.0f; - x = ctl->c_offset; - - for (i = 0; i < n; i++) - { - *out++ = (float)x++; - } + x = ctl->c_offset; + + for (i = 0; i < n; i++) + { + *out++ = ((float)x++) * scale; + } - ctl->c_offset = x; /* save state */ + ctl->c_offset = x; /* save state */ - return (w+4); + return (w+4); } static void ramp_dsp(t_ramp *x, t_signal **sp) @@ -99,18 +88,27 @@ t_class *ramp_class; void *ramp_new(void) { t_ramp *x = (t_ramp *)pd_new(ramp_class); - /* inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("looppoint"));*/ outlet_new(&x->x_obj, gensym("signal")); - + x->x_ctl.c_blockscale = 0; ramp_bang(x); return (void *)x; } +void *blockramp_new(void) +{ + t_ramp *x = (t_ramp *)ramp_new(); + x->x_ctl.c_blockscale = 1; + return (void *)x; +} + void ramp_tilde_setup(void) { //post("ramp~ v0.1"); ramp_class = class_new(gensym("ramp~"), (t_newmethod)ramp_new, (t_method)ramp_free, sizeof(t_ramp), 0, 0); + + class_addcreator((t_newmethod)blockramp_new, gensym("blockramp~"), A_NULL); + class_addmethod(ramp_class, (t_method)ramp_bang, gensym("bang"), 0); class_addmethod(ramp_class, (t_method)ramp_dsp, gensym("dsp"), 0); class_addfloat(ramp_class, (t_method)ramp_offset); diff --git a/modules/resofilt.c b/modules/resofilt.c new file mode 100644 index 0000000..ba74532 --- /dev/null +++ b/modules/resofilt.c @@ -0,0 +1,397 @@ +/* + * resofilt.c - some high quality time variant filters + * Copyright (c) 2000-2003 by Tom Schouten + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +/* some (expensive) time variant iir filters, + i.e. moog 4-pole transfer function using the impulse + invariant transform with self osc and + signal freq and reso inputs */ + + +#include "m_pd.h" +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "filters.h" + + +typedef struct resofiltctl +{ + t_float c_state[4]; /* filter state */ + t_float c_f_prev; + t_float c_r_prev; + +} t_resofiltctl; + +typedef struct resofilt +{ + t_object x_obj; + t_float x_f; + t_resofiltctl x_ctl; + t_perfroutine x_dsp; +} t_resofilt; + + +static inline void _sat_state(t_float *x) +{ + const float norm_squared_max = 1.0f; + float norm_squared = x[0] * x[0] + x[1] * x[1]; + + if (norm_squared > norm_squared_max){ + float scale = 1.0f / sqrt(norm_squared); + x[0] *= scale; + x[1] *= scale; + } +} + + +/* the moog vcf discretized with an impulse invariant transform */ + +static t_int *resofilt_perform_fourpole(t_int *w) +{ + + t_resofiltctl *ctl = (t_resofiltctl *)(w[1]); + t_int n = (t_int)(w[2]); + t_float *in = (float *)(w[3]); + t_float *freq = (float *)(w[4]); + t_float *reso = (float *)(w[5]); + t_float *out = (float *)(w[6]); + + int i; + t_float inv_n = 1.0f / ((float)n); + t_float inv_sr = 1.0f / sys_getsr(); + + t_float phasor[2], phasor_rot[2]; + t_float radior[2], radior_rot[2]; + t_float scalor, scalor_inc; + + t_float f,r,freq_rms,reso_rms; + t_float f_prev = ctl->c_f_prev; + t_float r_prev = ctl->c_r_prev; + + /* use rms of input to drive freq and reso + this is such that connecting a dsp signal to the inlets has a reasonable result, + even if the inputs are oscillatory. the rms values will be interpolated linearly + (that is, linearly in the "analog" domain, so exponentially in the z-domain) */ + + reso_rms = freq_rms = 0.0f; + for (i=0; i<n; i++){ + t_float _freq = *freq++; /* first input is the reso frequency (absolute) */ + t_float _reso = *reso++; /* second input is the resonnance (0->1), >1 == self osc */ + freq_rms += _freq * _freq; + reso_rms += _reso * _reso; + } + freq_rms = sqrt(freq_rms * inv_n) * inv_sr; + reso_rms = sqrt(reso_rms * inv_n); + f = (freq_rms > 0.5f) ? 0.5f : freq_rms; + r = sqrt(sqrt(reso_rms)); + + + /* calculate the new pole locations + we use an impulse invariant transform: the moog vcf poles are located at + s_p = (-1 +- r \sqrt{+- j}, with r = (k/4)^(1/4) \in [0,1] + + the poles are always complex, so we can use an orthogonal implementation + both conj pole pairs have the same angle, so we can use one phasor and 2 radii + */ + + /* compute phasor, radius and update eqs + since these are at k-rate, the expense is justifyable */ + phasor[0] = cos(2.0 * M_PI * r_prev * f_prev); + phasor[1] = sin(2.0 * M_PI * r_prev * f_prev); + phasor_rot[0] = cos(2.0 * M_PI * (r*f - r_prev*f_prev) * inv_n); + phasor_rot[1] = sin(2.0 * M_PI * (r*f - r_prev*f_prev) * inv_n); + + radior[0] = exp(f_prev * (-1.0 + r_prev)); /* dominant radius */ + radior[1] = exp(f_prev * (-1.0 - r_prev)); + radior_rot[0] = exp((f*(-1.0f + r) - f_prev * (-1.0 + r_prev)) * inv_n); + radior_rot[1] = exp((f*(-1.0f - r) - f_prev * (-1.0 - r_prev)) * inv_n); + + /* moog like scaling */ + if (1){ + float r2 = r_prev * r_prev; + float r4 = r2 * r2; + scalor = 1.0f + (1.0f + 4.0f * r4); + r2 = r * r; + r4 = r2 * r2; + scalor_inc = ((1.0f + (1.0f + 4.0f * r4)) - scalor) * inv_n; + } + + /* no scaling */ + else{ + scalor = 1.0f; + scalor_inc = 0.0f; + } + + ctl->c_f_prev = f; + ctl->c_r_prev = r; + + + + + + /* perform filtering */ + for (i=0; i<n; i++){ + float poleA[2], poleB[2]; + float *stateA = ctl->c_state; + float *stateB = ctl->c_state+2; + + float x; + + /* compute poles */ + poleA[0] = radior[0] * phasor[0]; + poleA[1] = radior[0] * phasor[1]; + poleB[0] = radior[1] * phasor[0]; + poleB[1] = radior[1] * phasor[1]; + + + /* perform filtering: use 2 DC normalized complex one-poles: + y[k] = x[k] + a(y[k-1] - x[k]) or y(z) = (1-a)/(1-az^{-1}) x(z) */ + + x = *in++ * scalor; + + /* nondominant pole first */ + stateB[0] -= x; + vcmul2(stateB, poleB); + x = stateB[0] += x; + + /* dominant pole second */ + stateA[0] -= x; + vcmul2(stateA, poleA); + x = stateA[0] += x; + + *out++ = x; + + /* saturate (normalize if pow > 1) state to prevent explosion and to allow self-osc */ + _sat_state(stateA); + _sat_state(stateB); + + /* interpolate filter coefficients */ + vcmul2(phasor, phasor_rot); + radior[0] *= radior_rot[0]; + radior[1] *= radior_rot[1]; + scalor += scalor_inc; + + } + + return (w+7); +} + + + + + +/* 303-style modified moog vcf (3-pole) */ + +static t_int *resofilt_perform_threepole(t_int *w) +{ + + t_resofiltctl *ctl = (t_resofiltctl *)(w[1]); + t_int n = (t_int)(w[2]); + t_float *in = (float *)(w[3]); + t_float *freq = (float *)(w[4]); + t_float *reso = (float *)(w[5]); + t_float *out = (float *)(w[6]); + + int i; + t_float inv_n = 1.0f / ((float)n); + t_float inv_sr = 1.0f / sys_getsr(); + + t_float phasor[2], phasor_rot[2]; + t_float radior[2], radior_rot[2]; + t_float scalor, scalor_inc; + + t_float f,r,freq_rms,reso_rms; + t_float f_prev = ctl->c_f_prev; + t_float r_prev = ctl->c_r_prev; + + t_float sqrt5 = sqrtf(5.0f); + + /* use rms of input to drive freq and reso */ + reso_rms = freq_rms = 0.0f; + for (i=0; i<n; i++){ + t_float _freq = *freq++; /* first input is the reso frequency (absolute) */ + t_float _reso = *reso++; /* second input is the resonnance (0->1), >1 == self osc */ + freq_rms += _freq * _freq; + reso_rms += _reso * _reso; + } + freq_rms = sqrt(freq_rms * inv_n) * inv_sr; + reso_rms = sqrt(reso_rms * inv_n); + f = (freq_rms > 0.5f) ? 0.25f : freq_rms * 0.5f; + r = cbrt(reso_rms); + + + /* calculate the new pole locations + we use an impulse invariant transform: the 303 vcf poles are located at + s_p = omega(-1 + r sqrt(5) e^{pi/3(1+2p)}) + + real pole: omega * (-1 -r) + complex pole: + real = omega (-1 + r) + imag = omega (+- 2 r) + + + this is a strange beast. legend goes it was "invented" by taking the moog vcf + and moving one cap up, such that the not-so controllable 3-pole that emerged + would avoid the moog patent.. + + so, the sound is not so much the locations of the poles, but how the filter + reacts to time varying controls. i.e. the pole movement with constant reso, + used in the tb-303. + + */ + + /* compute phasor, radius and update eqs */ + phasor[0] = cos(2.0 * M_PI * r_prev * f_prev * 2.0f); + phasor[1] = sin(2.0 * M_PI * r_prev * f_prev * 2.0f); + phasor_rot[0] = cos(2.0 * M_PI * (r*f - r_prev*f_prev) * 2.0f * inv_n); + phasor_rot[1] = sin(2.0 * M_PI * (r*f - r_prev*f_prev) * 2.0f * inv_n); + + radior[0] = exp(f_prev * (-1.0 + r_prev)); /* dominant radius */ + radior[1] = exp(f_prev * (-1.0 - sqrt5 * r_prev)); + radior_rot[0] = exp((f*(-1.0f + r) - f_prev * (-1.0 + r_prev)) * inv_n); + radior_rot[1] = exp((f*(-1.0f - r) - f_prev * (-1.0 - sqrt5 * r_prev)) * inv_n); + + /* 303 like scaling */ + if (1){ + float r3 = r_prev * r_prev * r_prev; + scalor = 1.0f + (1.0f + 3.0f * r_prev); + r3 = r * r * r; + scalor_inc = ((1.0f + (1.0f + 3.0f * r3)) - scalor) * inv_n; + } + + /* no scaling */ + else{ + scalor = 1.0f; + scalor_inc = 0.0f; + } + + ctl->c_f_prev = f; + ctl->c_r_prev = r; + + + ctl->c_state[3] = 0.0f; + /* perform filtering */ + for (i=0; i<n; i++){ + float poleA[2], poleB[2]; + float *stateA = ctl->c_state; + float *stateB = ctl->c_state+2; + + float x; + + /* compute poles */ + poleA[0] = radior[0] * phasor[0]; + poleA[1] = radior[0] * phasor[1]; + + poleB[0] = radior[1]; + + + /* perform filtering: use (real part of) 2 DC normalized complex one-poles: + y[k] = x[k] + a(y[k-1] - x[k]) or y(z) = (1-a)/(1-az^{-1}) x(z) */ + + x = *in++ * scalor; + + /* nondominant pole first */ + stateB[0] -= x; + stateB[0] *= poleB[0]; + x = stateB[0] += x; + + /* dominant pole second */ + stateA[0] -= x; + vcmul2(stateA, poleA); + x = stateA[0] += x; + + *out++ = x; + + /* saturate (normalize if pow > 1) state to prevent explosion and to allow self-osc */ + _sat_state(stateA); + _sat_state(stateB); + + /* interpolate filter coefficients */ + vcmul2(phasor, phasor_rot); + radior[0] *= radior_rot[0]; + radior[1] *= radior_rot[1]; + scalor += scalor_inc; + + } + + return (w+7); +} + + + + + +static void resofilt_dsp(t_resofilt *x, t_signal **sp) +{ + int n = sp[0]->s_n; + + dsp_add(x->x_dsp, + 6, + &x->x_ctl, + sp[0]->s_n, + sp[0]->s_vec, + sp[1]->s_vec, + sp[2]->s_vec, + sp[3]->s_vec); + +} +static void resofilt_free(t_resofilt *x) +{ + + +} + +t_class *resofilt_class; + +static void *resofilt_new(t_floatarg algotype) +{ + t_resofilt *x = (t_resofilt *)pd_new(resofilt_class); + + /* in */ + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal")); + + /* out */ + outlet_new(&x->x_obj, gensym("signal")); + + + /* set algo type */ + if (algotype == 3.0f){ + post("resofilt~: 3-pole lowpass ladder vcf"); + x->x_dsp = resofilt_perform_threepole; + } + else { + post("resofilt~: 4-pole lowpass ladder vcf"); + x->x_dsp = resofilt_perform_fourpole; + } + + + return (void *)x; +} + +void resofilt_tilde_setup(void) +{ + resofilt_class = class_new(gensym("resofilt~"), (t_newmethod)resofilt_new, + (t_method)resofilt_free, sizeof(t_resofilt), 0, A_DEFFLOAT, 0); + CLASS_MAINSIGNALIN(resofilt_class, t_resofilt, x_f); + class_addmethod(resofilt_class, (t_method)resofilt_dsp, gensym("dsp"), 0); +} + diff --git a/modules/sbosc.c b/modules/sbosc.c new file mode 100644 index 0000000..511c770 --- /dev/null +++ b/modules/sbosc.c @@ -0,0 +1,175 @@ +/* + * sbosc.c - smallband oscillator. periodic, linear interpolated frequency center. + * data organization is in (real, imag) pairs + * the first 2 components are (DC, NY) + * Copyright (c) 2000-2003 by Tom Schouten + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "m_pd.h" +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#define LOGTABSIZE 10 +#define TABSIZE (1<<LOGTABSIZE) +#define MASKTABSIZE (TABSIZE-1) + +#define SHIFTTABSIZE ((sizeof(unsigned int) * 8) - LOGTABSIZE) +#define FRACTABSIZE (1<<SHIFTTABSIZE) +#define INVFRACTABSIZE (1.0f / (float)(FRACTABSIZE)) +#define MASKFRACTABSIZE (FRACTABSIZE-1) + +#define PITCHLIMIT 20.0f + +static float costable[TABSIZE]; + +static inline void _exp_j2pi(unsigned int t, float *real, float *imag) +{ + unsigned int i1 = t >> SHIFTTABSIZE; + float f2 = (t & MASKFRACTABSIZE) * INVFRACTABSIZE; + unsigned int i2 = (i1+1) & MASKTABSIZE; + unsigned int i3 = (i1 - (TABSIZE>>2)) & MASKTABSIZE; + unsigned int i4 = (i2 + 1 - (TABSIZE>>2)) & MASKTABSIZE; + float f1 = 1.0f - f2; + float a1 = f1 * costable[i1]; + float a2 = f2 * costable[i2]; + float b1 = f1 * costable[i3]; + float b2 = f2 * costable[i4]; + *real = a1 + a2; + *imag = b1 + b2; +} + +static t_class *sbosc_tilde_class; + +typedef struct _sbosc_tilde +{ + t_object x_obj; + float x_f; + + /* state vars */ + unsigned int x_phase; // phase of main pitch osc + unsigned int x_phase_inc; // frequency of main pitch osc + unsigned int x_harmonic; // first harmonic + float x_frac; // fraction of first harmonic + + +} t_sbosc_tilde; + +static void *sbosc_tilde_new(void) +{ + t_sbosc_tilde *x = (t_sbosc_tilde *)pd_new(sbosc_tilde_class); + x->x_phase = 0; + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("phase")); + outlet_new(&x->x_obj, gensym("signal")); + outlet_new(&x->x_obj, gensym("signal")); + x->x_f = 0; + return (x); +} + + +static t_int *sbosc_tilde_perform(t_int *w) +{ + t_sbosc_tilde *x = (t_sbosc_tilde *)(w[1]); + t_float *pitch = (t_float *)(w[2]); + t_float *center= (t_float *)(w[3]); + t_float *out_real = (t_float *)(w[4]); + t_float *out_imag = (t_float *)(w[5]); + int n = (int)(w[6]); + int i; + + t_float pitch_to_phase = 4294967295.0f / sys_getsr(); + + for (i = 0; i < n; i++) + { + float p = *pitch++; + float c = *center++; + float r1,r2,i1,i2; + + /* compute harmonic mixture */ + unsigned int h1 = x->x_phase * x->x_harmonic; + unsigned int h2 = h1 + x->x_phase; + _exp_j2pi(h1, &r1, &i1); + _exp_j2pi(h2, &r2, &i2); + r1 *= x->x_frac; + i1 *= x->x_frac; + r2 *= 1.0f - x->x_frac; + i2 *= 1.0f - x->x_frac; + + *out_real++ = r1 + r2; + *out_imag++ = i1 + i2; + + + x->x_phase += x->x_phase_inc; + + /* check for phase wrap & update osc */ + if ((x->x_phase <= x->x_phase_inc)) + { + float p_plus = (p < 0.0f) ? -p : p; + float p_limit = (p_plus < PITCHLIMIT) ? PITCHLIMIT : p_plus; + float c_plus = (c < 0.0f) ? -c : c; + float harmonic = c_plus/p_limit; + x->x_phase_inc = pitch_to_phase * p_limit; + x->x_harmonic = harmonic; + x->x_frac = 1.0f - (harmonic - x->x_harmonic); + } + + + } + + return (w+7); +} + +static void sbosc_tilde_dsp(t_sbosc_tilde *x, t_signal **sp) +{ + dsp_add(sbosc_tilde_perform, 6, x, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[0]->s_n); + +} + +static void sbosc_tilde_free(t_sbosc_tilde *x) +{ +} + +static void sbosc_tilde_phase(t_sbosc_tilde *x, t_floatarg f) +{ + x->x_phase = f * (1.0f / 4294967295.0f); +} + +void sbosc_tilde_setup(void) +{ + int i; + + // init tables + for (i=0; i<TABSIZE; i++) + costable[i] = cos(2.0 * M_PI * (double)i / (double)TABSIZE); + + + + // class setup + sbosc_tilde_class = class_new(gensym("sbosc~"), + (t_newmethod)sbosc_tilde_new, (t_method)sbosc_tilde_free, + sizeof(t_sbosc_tilde), 0, A_DEFSYM, 0); + CLASS_MAINSIGNALIN(sbosc_tilde_class, t_sbosc_tilde, x_f); + class_addmethod(sbosc_tilde_class, (t_method)sbosc_tilde_dsp, + gensym("dsp"), 0); + class_addmethod(sbosc_tilde_class, (t_method)sbosc_tilde_phase, + gensym("phase"), A_FLOAT, 0); +} + diff --git a/modules/scrollgrid1D.c b/modules/scrollgrid1D.c new file mode 100644 index 0000000..bcac7fe --- /dev/null +++ b/modules/scrollgrid1D.c @@ -0,0 +1,220 @@ +/* + * scrollgrid1D.c - 1D scroll grid attractor + * Copyright (c) 2000-2003 by Tom Schouten + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +/* 1D scroll grid attractor + for more information see: + + Yalcin M., Ozoguz S., Suykens J.A.K., Vandewalle J., + ``Families of Scroll Grid Attractors'', + International Journal of Bifurcation and Chaos, vol. 12, no. 1, Jan. 2002, pp. 23-41. + + this file implements a digital variant of the method introduced in the paper, + so that it can be used as a parametrizable, bounded chatotic oscillator. + in short it is a switched linear system, with some added hard limiting to + convert unstable oscillations into stable ones. + +*/ + +#include "m_pd.h" +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "filters.h" + + +typedef struct scrollgrid1Dctl +{ + t_float c_x, c_y, c_z; /* state */ + +} t_scrollgrid1Dctl; + +typedef struct scrollgrid1D +{ + t_object x_obj; + t_float x_f; + t_scrollgrid1Dctl x_ctl; +} t_scrollgrid1D; + + +static inline float _fixedpoint(float x, int n) +{ + int ix = (x + 0.5f); + if (ix < 0) ix = 0; + else if (ix >= n) ix = n-1; + return (float)ix; +} + +static inline float _sat(float x, float upper) +{ + float lower = -1.0f; + if (x < lower) x = lower; + else if (x > upper) x = upper; + return x; +} + +static t_int *scrollgrid1D_perform(t_int *w) +{ + + + t_float *freq = (float *)(w[3]); + t_float *t1 = (float *)(w[4]); + t_float *t2 = (float *)(w[5]); + t_float *order = (float *)(w[6]); + t_float *outx = (float *)(w[7]); + t_float *outy = (float *)(w[8]); + t_float *outz = (float *)(w[9]); + t_scrollgrid1Dctl *ctl = (t_scrollgrid1Dctl *)(w[1]); + t_int n = (t_int)(w[2]); + + t_int i; + t_float inv_sr = 1.0f /sys_getsr(); + t_float state[3] = {ctl->c_x, ctl->c_y, ctl->c_z}; + t_float c,f; + t_float pole[2], r1, r2; + t_int o; + t_float x,y,z; + + + for (i=0; i<n; i++){ + + /* get params */ + r1 = exp(1000.0f * inv_sr / (0.01f + fabs(*t1++))); + r2 = exp(-1000.0f * inv_sr / (0.01f + fabs(*t2++))); + f = *freq++; + o = (int)(*order++); + if (o < 2) o = 2; + pole[0] = r1 * cos(2.0f * M_PI * inv_sr * f); + pole[1] = r1 * sin(2.0f * M_PI * inv_sr * f); + + /* debug */ + //post("%f", r1); + + /* base transform + clipping to prevent blowup */ + x = _sat(0.5f * (state[0] - state[2]), (float)o); /* projection onto axis containing fixed */ + y = _sat(0.5f * state[1], 1.0f); /* the "pure" oscillation axis */ + z = _sat(0.5f * (state[0] + state[2]), 1.0f); /* orthogonal complement of x */ + + /* output */ + *outx++ = x; + *outy++ = y; + *outz++ = z; + + + /* calculate fixed point location (c, 0, -c) */ + c = _fixedpoint(x, o); + + /* inverse base transform */ + state[0] = x + z; + state[1] = 2.0f * y; + state[2] = -x + z; + + + /* update transformed linear system around unstable fixed point */ + state[0] -= c; + state[2] += c; + vcmul2(state, pole); + state[2] *= r2; + state[0] += c; + state[2] -= c; + + } + + + + ctl->c_x = state[0]; + ctl->c_y = state[1]; + ctl->c_z = state[2]; + + return (w+10); +} + +static void scrollgrid1D_dsp(t_scrollgrid1D *x, t_signal **sp) +{ + int n = sp[0]->s_n; + int k; + + + dsp_add(scrollgrid1D_perform, + 9, + &x->x_ctl, + sp[0]->s_n, + sp[0]->s_vec, + sp[1]->s_vec, + sp[2]->s_vec, + sp[3]->s_vec, + sp[4]->s_vec, + sp[5]->s_vec, + sp[6]->s_vec); + + +} +static void scrollgrid1D_free(t_scrollgrid1D *x) +{ + + +} + + + + +static void scrollgrid1D_reset(t_scrollgrid1D *x) +{ + x->x_ctl.c_x = 1; + x->x_ctl.c_y = 1; + x->x_ctl.c_z = 1; +} + + +t_class *scrollgrid1D_class; + +static void *scrollgrid1D_new(t_floatarg algotype) +{ + t_scrollgrid1D *x = (t_scrollgrid1D *)pd_new(scrollgrid1D_class); + + /* ins */ + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal")); + + /* outs */ + outlet_new(&x->x_obj, gensym("signal")); + outlet_new(&x->x_obj, gensym("signal")); + outlet_new(&x->x_obj, gensym("signal")); + + + /* init data */ + scrollgrid1D_reset(x); + + return (void *)x; +} + +void scrollgrid1D_tilde_setup(void) +{ + //post("scrollgrid1D~ v0.1"); + scrollgrid1D_class = class_new(gensym("scrollgrid1D~"), (t_newmethod)scrollgrid1D_new, + (t_method)scrollgrid1D_free, sizeof(t_scrollgrid1D), 0, A_DEFFLOAT, 0); + CLASS_MAINSIGNALIN(scrollgrid1D_class, t_scrollgrid1D, x_f); + class_addmethod(scrollgrid1D_class, (t_method)scrollgrid1D_dsp, gensym("dsp"), 0); + class_addmethod(scrollgrid1D_class, (t_method)scrollgrid1D_reset, gensym("reset"), 0); + + +} + diff --git a/modules/statwav.c b/modules/statwav.c index 52c6a0b..13d9c9f 100644 --- a/modules/statwav.c +++ b/modules/statwav.c @@ -67,11 +67,15 @@ static t_int *statwav_tilde_perform(t_int *w) { float phase = *in++; float modphase = phase - (int)phase; - float findex = modphase * maxindex; - int index = findex; + float findex; + int index; int ia, ib, ic, id; float frac, a, b, c, d, cminusb; static int count; + + if (modphase < 0.0f) modphase += 1.0f; + findex = modphase * maxindex; + index = findex; frac = findex - index; |