diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/Makefile | 11 | ||||
-rw-r--r-- | modules/abs.c | 64 | ||||
-rw-r--r-- | modules/bdiag.c | 272 | ||||
-rw-r--r-- | modules/bfft.c | 304 | ||||
-rw-r--r-- | modules/cheby.c | 138 | ||||
-rw-r--r-- | modules/diag.c | 218 | ||||
-rw-r--r-- | modules/dist.c | 262 | ||||
-rw-r--r-- | modules/dwt.c | 893 | ||||
-rw-r--r-- | modules/dynwav.c | 318 | ||||
-rw-r--r-- | modules/ead.c | 153 | ||||
-rw-r--r-- | modules/eadsr.c | 171 | ||||
-rw-r--r-- | modules/ear.c | 134 | ||||
-rw-r--r-- | modules/ffpoly.c | 173 | ||||
-rw-r--r-- | modules/fwarp.c | 61 | ||||
-rw-r--r-- | modules/lattice.c | 143 | ||||
-rw-r--r-- | modules/matrix.c | 154 | ||||
-rw-r--r-- | modules/permut.c | 177 | ||||
-rw-r--r-- | modules/qmult.c | 165 | ||||
-rw-r--r-- | modules/qnorm.c | 137 | ||||
-rw-r--r-- | modules/ramp.c | 118 | ||||
-rw-r--r-- | modules/ratio.c | 66 | ||||
-rw-r--r-- | modules/statwav.c | 149 | ||||
-rw-r--r-- | modules/tabreadmix.c | 271 | ||||
-rw-r--r-- | modules/xfm.c | 271 |
24 files changed, 4823 insertions, 0 deletions
diff --git a/modules/Makefile b/modules/Makefile new file mode 100644 index 0000000..4e1cabd --- /dev/null +++ b/modules/Makefile @@ -0,0 +1,11 @@ +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 + + +clean: + rm -f *.o + rm -f *~ + diff --git a/modules/abs.c b/modules/abs.c new file mode 100644 index 0000000..4d8b8eb --- /dev/null +++ b/modules/abs.c @@ -0,0 +1,64 @@ +/* + * abs.c - computes absolute value of a signal + * 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> + +/* ------------------------- abs~ -------------------------- */ +static t_class *abs_class; + +typedef struct _abs +{ + t_object x_obj; +} t_abs; + +static t_int *abs_perform(t_int *w) +{ + t_abs *x = (t_abs *)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + while (n--) + { + float f = *in++; + if (f < 0) f = -f; + *out++ = f; + } + return (w+5); +} + +static void abs_dsp(t_abs *x, t_signal **sp) +{ + dsp_add(abs_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); +} + +static void *abs_new(void) +{ + t_abs *x = (t_abs *)pd_new(abs_class); + outlet_new(&x->x_obj, &s_signal); + return (x); +} + +void abs_tilde_setup(void) +{ + abs_class = class_new(gensym("abs~"), (t_newmethod)abs_new, 0, + sizeof(t_abs), 0, A_NULL); + class_addmethod(abs_class, (t_method)nullfn, &s_signal, A_NULL); + class_addmethod(abs_class, (t_method)abs_dsp, gensym("dsp"), A_NULL); +} diff --git a/modules/bdiag.c b/modules/bdiag.c new file mode 100644 index 0000000..37a0349 --- /dev/null +++ b/modules/bdiag.c @@ -0,0 +1,272 @@ +/* + * bdiag.c - block diagonal state space system + * treats input dsp block as n parallel signals + * + * s1 = (a * s1) + (b * s2) + u1; + * s2 = (a * s2) - (b * s1) + u2; + * + * 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> + +#define MAXORDER 64 + +typedef struct bdiagctl +{ + t_float *c_state; + t_float *c_eigen; + t_int c_order; +} t_bdiagctl; + +typedef struct bdiag +{ + t_object x_obj; + t_float x_f; + t_bdiagctl x_ctl; +} t_bdiag; + + +static float randfloat(void){ + float r = rand (); + r /= (RAND_MAX/2); + r -= 1; + return r; + +} + +static void bdiag_random(t_bdiag *x) +{ + int i; + + for (i=0; i<x->x_ctl.c_order; i++) + { + x->x_ctl.c_state[i] = randfloat(); + } + +} + + +static void bdiag_reset(t_bdiag *x) +{ + int i; + + for (i=0; i<x->x_ctl.c_order; i++) + { + x->x_ctl.c_state[i] = 0; + } + +} + + + + + + +static void bdiag_eigen(t_bdiag *x, t_floatarg index, t_floatarg aval, t_floatarg bval) +{ + int i = (int)index; + if (i<0) return; + if (i>=x->x_ctl.c_order/2) return; + x->x_ctl.c_eigen[2*i+0] = aval; + x->x_ctl.c_eigen[2*i+1] = bval; + +} + +/* set decay time and frequency of pole at index */ +static void bdiag_timefreq(t_bdiag *x, t_floatarg index, t_floatarg time, t_floatarg freq) +{ + float r,a,b,n; + float sr = sys_getsr() / (float)x->x_ctl.c_order; + + /* time in ms */ + time *= 0.001; + + if (time < 0.0f) time = 0.0f; + r = pow(0.001f, 1.0f / (time * sr)); + if (r < 0.0f) r = 0.0f; + if (r > 1.0f) r = 1.0f; + + a = cos(2*M_PI*freq/sr); + b = sin(2*M_PI*freq/sr); + + /* normalize to be sure */ + n = 1.0f / sqrt(a*a + b*b); + a *= n; + b *= n; + + bdiag_eigen(x, index, r*a, r*b); +} + +static void bdiag_preset(t_bdiag *x, t_floatarg preset) +{ + int p = preset; + int i; + float a, b, w, r; + + switch(p){ + case 0: + post("preset 0"); + for (i=0; i<x->x_ctl.c_order/2; i++){ + w = randfloat() * .001; + r = 1. - (((float)i + 1.)/1000.); + a = cos(w) * r; + b = sin(w) * r; + post("%f %f %f %f", w, r, a, b); + bdiag_eigen(x,i,a,b); + } + break; + case 1: + default: + break; + + } +} + +static t_int *bdiag_perform(t_int *w) +{ + + + t_float *in = (float *)(w[3]); + t_float *out = (float *)(w[4]); + t_bdiagctl *ctl = (t_bdiagctl *)(w[1]); + + t_float *eigen = ctl->c_eigen; + t_float *state = ctl->c_state; + t_int n = (t_int)(w[2]); + + t_float u1,u2,a,b,s1,s2,s1new,s2new; + + int i; + + for (i=0; i<n; i+=2) + { + u1 = *in++; + u2 = *in++; + a = *eigen++; /* real part */ + b = *eigen++; /* imag part */ + s1 = state[0]; + s2 = state[1]; + + + s1new = (a * s1) - (b * s2) + u1; /* update state */ + s2new = (a * s2) + (b * s1) + u2; + + *state++ = s1new; /* store state */ + *state++ = s2new; + + *out++ = s1new; /* output state */ + *out++ = s2new; + } + + return (w+5); +} + + +static void bdiag_dsp(t_bdiag *x, t_signal **sp) +{ + + int n = sp[0]->s_n; + int i; + + if (n == 1) + { + post("bdiag: doesnt work with blocksize == 1"); + dsp_add_copy(sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); + } + else + { + if (x->x_ctl.c_order != n) + { + if (x->x_ctl.c_state) free(x->x_ctl.c_state); + if (x->x_ctl.c_eigen) free(x->x_ctl.c_eigen); + + x->x_ctl.c_state = (t_float *)malloc(n*sizeof(t_float)); + x->x_ctl.c_eigen = (t_float *)malloc(n*sizeof(t_float)); + + for(i=0;i<n;i++) + { + x->x_ctl.c_state[i] = 0; + x->x_ctl.c_eigen[i] = 0; + } + + x->x_ctl.c_order = n; + } + + + dsp_add(bdiag_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + } + +} + +static void bdiag_free(t_bdiag *x) +{ + + if (x->x_ctl.c_state) free(x->x_ctl.c_state); + if (x->x_ctl.c_eigen) free(x->x_ctl.c_eigen); + + +} + +t_class *bdiag_class; + + +static void *bdiag_new(t_floatarg permute) +{ + t_bdiag *x = (t_bdiag *)pd_new(bdiag_class); + int i, n=64; + + outlet_new(&x->x_obj, gensym("signal")); + + x->x_ctl.c_state = (t_float *)malloc(n*sizeof(t_float)); + x->x_ctl.c_eigen = (t_float *)malloc(n*sizeof(t_float)); + + for(i=0;i<n;i++) + { + x->x_ctl.c_state[i] = 0; + x->x_ctl.c_eigen[i] = 0; + } + + x->x_ctl.c_order = n; + + + return (void *)x; + + +} + + +void bdiag_tilde_setup(void) +{ + //post("bdiag~ v0.1"); + bdiag_class = class_new(gensym("bdiag~"), (t_newmethod)bdiag_new, + (t_method)bdiag_free, sizeof(t_bdiag), 0, A_DEFFLOAT, 0); + CLASS_MAINSIGNALIN(bdiag_class, t_bdiag, x_f); + class_addmethod(bdiag_class, (t_method)bdiag_random, gensym("random"), 0); + class_addmethod(bdiag_class, (t_method)bdiag_random, gensym("bang"), 0); + class_addmethod(bdiag_class, (t_method)bdiag_reset, gensym("reset"), 0); + class_addmethod(bdiag_class, (t_method)bdiag_dsp, gensym("dsp"), 0); + + class_addmethod(bdiag_class, (t_method)bdiag_eigen, gensym("eigen"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod(bdiag_class, (t_method)bdiag_timefreq, gensym("timefreq"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod(bdiag_class, (t_method)bdiag_preset, gensym("preset"), A_DEFFLOAT, 0); +} + diff --git a/modules/bfft.c b/modules/bfft.c new file mode 100644 index 0000000..76b0254 --- /dev/null +++ b/modules/bfft.c @@ -0,0 +1,304 @@ +/* + * bfft.c - code for fourrier transform + * 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> + +#define MAXORDER 64 + +typedef struct bfftctl +{ + t_int c_levels; + char c_name[16]; + t_int *c_clutter; + t_int *c_unclutter; +} t_bfftctl; + +typedef struct bfft +{ + t_object x_obj; + t_float x_f; + t_bfftctl x_ctl; +} t_bfft; + +t_class *bfft_class, *ibfft_class, *fht_class; + + +static inline void bfft_perform_permutation(t_float *S, int n, t_int *f) +{ + t_int k,l; + t_float swap; + for(k=0; k<n; k++) + { + l = f[k]; + while (l<k) l = f[l]; + swap = S[k]; + S[k] = S[l]; + S[l] = swap; + } +} + +static void bfft_permutation(t_bfft *x, t_int n){ + + t_bfftctl *ctl = &x->x_ctl; + int i; + + if (ctl->c_clutter) free(ctl->c_clutter); + if (ctl->c_unclutter) free(ctl->c_unclutter); + + ctl->c_clutter = (t_int *)malloc(n*sizeof(t_int)); + ctl->c_unclutter = (t_int *)malloc(n*sizeof(t_int)); + + + ctl->c_unclutter[0] = 0; + ctl->c_unclutter[1] = n/2; + for (i=1; i<n/2; i++){ + ctl->c_unclutter[2*i] = i; + ctl->c_unclutter[2*i+1] = n-i; + } + + for(i=0; i<n; i++) + ctl->c_clutter[ctl->c_unclutter[i]] = i; + + return; + + /* debug */ + /* for(k=0; k<n; k++) + ** printf("clutter[%d] = %d\n", k, ctl->c_clutter[k]); + ** for(k=0; k<n; k++) + ** printf("unclutter[%d] = %d\n", k, ctl->c_unclutter[k]); + ** + ** exit(1); + */ +} + + + +static t_int *bfft_perform(t_int *w) +{ + + + t_float *in = (float *)(w[3]); + t_float *out = (float *)(w[4]); + t_bfftctl *ctl = (t_bfftctl *)(w[1]); + t_int n = (t_int)(w[2]); + t_float scale = sqrt(1.0f / (float)(n)); + + mayer_fht(out, n); + bfft_perform_permutation(out, n, ctl->c_unclutter); + + while (n--) *out++ *= scale; + + return (w+5); +} + + + + +static t_int *ibfft_perform(t_int *w) +{ + + + t_float *in = (float *)(w[3]); + t_float *out = (float *)(w[4]); + t_bfftctl *ctl = (t_bfftctl *)(w[1]); + t_int n = (t_int)(w[2]); + t_float scale = sqrt(1.0f / (float)(n)); + + + bfft_perform_permutation(out, n, ctl->c_clutter); + mayer_fht(out, n); + while (n--) *out++ *= scale; + + + return (w+5); +} + + +static t_int *fht_perform(t_int *w) +{ + + + t_float *in = (float *)(w[3]); + t_float *out = (float *)(w[4]); + t_bfftctl *ctl = (t_bfftctl *)(w[1]); + + + t_int n = (t_int)(w[2]); + + mayer_fht(out, n); + + return (w+5); +} + + +static void bfft_dsp(t_bfft *x, t_signal **sp) +{ + + int n = sp[0]->s_n; + t_float *in = sp[0]->s_vec; + t_float *out = sp[1]->s_vec; + + bfft_permutation(x, n); + + if (in != out) + { + dsp_add_copy(in,out,n); + in = out; + } + + dsp_add(bfft_perform, 4, &x->x_ctl, n, in, out); + +} + +static void ibfft_dsp(t_bfft *x, t_signal **sp) +{ + + int n = sp[0]->s_n; + t_float *in = sp[0]->s_vec; + t_float *out = sp[1]->s_vec; + + bfft_permutation(x, n); + + if (in != out) + { + dsp_add_copy(in,out,n); + in = out; + } + + dsp_add(ibfft_perform, 4, &x->x_ctl, n, in, out); + +} + +static void fht_dsp(t_bfft *x, t_signal **sp) +{ + + int n = sp[0]->s_n; + t_float *in = sp[0]->s_vec; + t_float *out = sp[1]->s_vec; + + + if (in != out) + { + dsp_add_copy(in,out,n); + in = out; + } + + dsp_add(fht_perform, 4, &x->x_ctl, n, in, out); + +} + + + +static void bfft_free(t_bfft *x) +{ + + if (x->x_ctl.c_clutter) free(x->x_ctl.c_clutter); + if (x->x_ctl.c_unclutter) free(x->x_ctl.c_unclutter); + +} + + + + +static void *bfft_new(void) +{ + t_bfft *x = (t_bfft *)pd_new(bfft_class); + int i; + + outlet_new(&x->x_obj, gensym("signal")); + + + sprintf(x->x_ctl.c_name,"bfft"); + + x->x_ctl.c_clutter = NULL; + x->x_ctl.c_unclutter = NULL; + + return (void *)x; + + +} + +static void *ibfft_new(void) +{ + t_bfft *x = (t_bfft *)pd_new(ibfft_class); + int i; + + outlet_new(&x->x_obj, gensym("signal")); + + + x->x_ctl.c_clutter = NULL; + x->x_ctl.c_unclutter = NULL; + + sprintf(x->x_ctl.c_name,"ibfft"); + + return (void *)x; +} + +static void *fht_new(void) +{ + t_bfft *x = (t_bfft *)pd_new(fht_class); + int i; + + outlet_new(&x->x_obj, gensym("signal")); + + + x->x_ctl.c_clutter = NULL; + x->x_ctl.c_unclutter = NULL; + + sprintf(x->x_ctl.c_name,"fht"); + + return (void *)x; +} + + + + +void bfft_tilde_setup(void) +{ + //post("bfft~ v0.1"); + bfft_class = class_new(gensym("bfft~"), (t_newmethod)bfft_new, + (t_method)bfft_free, sizeof(t_bfft), 0, 0); + CLASS_MAINSIGNALIN(bfft_class, t_bfft, x_f); + class_addmethod(bfft_class, (t_method)bfft_dsp, gensym("dsp"), 0); + + + + ibfft_class = class_new(gensym("ibfft~"), (t_newmethod)ibfft_new, + (t_method)bfft_free, sizeof(t_bfft), 0, 0); + + CLASS_MAINSIGNALIN(ibfft_class, t_bfft, x_f); + class_addmethod(ibfft_class, (t_method)ibfft_dsp, gensym("dsp"), 0); + + + + fht_class = class_new(gensym("fht~"), (t_newmethod)fht_new, + (t_method)bfft_free, sizeof(t_bfft), 0, 0); + + CLASS_MAINSIGNALIN(fht_class, t_bfft, x_f); + class_addmethod(fht_class, (t_method)fht_dsp, gensym("dsp"), 0); + + + +} diff --git a/modules/cheby.c b/modules/cheby.c new file mode 100644 index 0000000..2c32d68 --- /dev/null +++ b/modules/cheby.c @@ -0,0 +1,138 @@ +/* + * cheby.c - chebychev polynomial evaluation + * 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 MAX_ORDER 1024 +#define DEFAULT_ORDER 4 + +typedef struct chebyctl +{ + t_float c_gain[MAX_ORDER]; + t_int c_order; +} t_chebyctl; + +typedef struct cheby +{ + t_object x_obj; + t_float x_f; + t_chebyctl x_ctl; +} t_cheby; + +static void cheby_bang(t_cheby *x) +{ + +} + +static void cheby_coef(t_cheby *x, t_floatarg coef, t_floatarg f) +{ + int i = (int)coef; + if ((i > 0) && (i < x->x_ctl.c_order + 1)){ + x->x_ctl.c_gain[i-1] = f; + /* post("cheby: harmonic %d set to %f", i, f); */ + } +} + + +static t_int *cheby_perform(t_int *w) +{ + + + t_float *in = (float *)(w[3]); + t_float *out = (float *)(w[4]); + t_chebyctl *ctl = (t_chebyctl *)(w[1]); + t_float *gain = ctl->c_gain; + t_int i; + t_int n = (t_int)(w[2]), k; + t_float x,y,t1,t2,t,acc; + + + for (i = 0; i < n; i++) + { + x = *in++; + + gain = ctl->c_gain; + t2 = 1; /* T_0 */ + t1 = x; /* T_1 */ + + acc = *gain++ * x; /* a_1 T_1 */ + for (k=2; k<=ctl->c_order; k++){ + t = 2*x*t1 - t2; /* T_k = 2 x T_{k-1} - T_{k-2} */ + acc += *gain++ * t; /* a_k T_k */ + t2 = t1; + t1 = t; + } + + *out++ = acc; + + } + + + return (w+5); +} + +static void cheby_dsp(t_cheby *x, t_signal **sp) +{ + dsp_add(cheby_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + +} +static void cheby_free(void) +{ + +} + +t_class *cheby_class; + +static void *cheby_new(t_floatarg order_f) +{ + int i; + int order = (int)order_f; + + t_cheby *x = (t_cheby *)pd_new(cheby_class); + outlet_new(&x->x_obj, gensym("signal")); + + if (order < 1) order = DEFAULT_ORDER; /* default */ + if (order > MAX_ORDER) order = MAX_ORDER; /* maximum */ + + + //post("cheby: order = %d", order); + + x->x_ctl.c_order = order; + cheby_coef(x, 1, 1); + for (i=2; i<order+1; i++){ + cheby_coef(x, 0, i); + } + + return (void *)x; +} + +void cheby_tilde_setup(void) +{ + //post("cheby~ v0.1"); + cheby_class = class_new(gensym("cheby~"), (t_newmethod)cheby_new, + (t_method)cheby_free, sizeof(t_cheby), 0, A_DEFFLOAT, 0); + CLASS_MAINSIGNALIN(cheby_class, t_cheby, x_f); + class_addmethod(cheby_class, (t_method)cheby_bang, gensym("bang"), 0); + class_addmethod(cheby_class, (t_method)cheby_dsp, gensym("dsp"), 0); + class_addmethod(cheby_class, (t_method)cheby_coef, gensym("coef"), A_DEFFLOAT, A_DEFFLOAT, 0); + +} + diff --git a/modules/diag.c b/modules/diag.c new file mode 100644 index 0000000..5f7fe36 --- /dev/null +++ b/modules/diag.c @@ -0,0 +1,218 @@ +/* + * diag.c - diagonal state space system. + * treats input dsp block as n parallel signals + * + * s1 = (a * s1) + (b * s2) + u1; + * s2 = (a * s2) - (b * s1) + u2; + * + * 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> + +#define MAXORDER 64 + +typedef struct diagctl +{ + t_float *c_state; + t_float *c_eigen; + t_int c_order; +} t_diagctl; + +typedef struct diag +{ + t_object x_obj; + t_float x_f; + t_diagctl x_ctl; +} t_diag; + + +static float randfloat(void){ + float r = rand (); + r /= (RAND_MAX/2); + r -= 1; + return r; + +} + +static void diag_eigen(t_diag *x, t_floatarg index, t_floatarg val) +{ + int i = (int)index; + if (i<0) return; + if (i>=x->x_ctl.c_order) return; + x->x_ctl.c_eigen[i] = val; +} + +/* set decay time of pole at index */ +static void diag_time(t_diag *x, t_floatarg index, t_floatarg time) +{ + float r; + + /* time in ms */ + time *= 0.001; + + if (time < 0.0f) time = 0.0f; + r = pow(0.001f, (float)x->x_ctl.c_order / (time * sys_getsr())); + if (r < 0.0f) r = 0.0f; + if (r > 1.0f) r = 1.0f; + + diag_eigen(x, index, r); +} + + + +static void diag_reset(t_diag *x) +{ + int i; + + for (i=0; i<x->x_ctl.c_order; i++) + { + x->x_ctl.c_state[i] = 0; + } + +} + +static void diag_random(t_diag *x) +{ + int i; + + for (i=0; i<x->x_ctl.c_order; i++) + { + x->x_ctl.c_state[i] = randfloat(); + } + +} + + + +static t_int *diag_perform(t_int *w) +{ + + + t_float *in = (float *)(w[3]); + t_float *out = (float *)(w[4]); + t_diagctl *ctl = (t_diagctl *)(w[1]); + + t_float *eigen = ctl->c_eigen; + t_float *state = ctl->c_state; + t_int n = (t_int)(w[2]); + + t_float x; + + int i; + + for (i=0; i<n; i++) + { + x = *in; + *state += x; + *state *= *eigen; + *out = *state; + + in++; + out++; + state++; + eigen++; + } + + + + return (w+5); +} + + +static void diag_dsp(t_diag *x, t_signal **sp) +{ + + int n = sp[0]->s_n; + int i; + + if (x->x_ctl.c_order != n) + { + if (x->x_ctl.c_state) free(x->x_ctl.c_state); + if (x->x_ctl.c_eigen) free(x->x_ctl.c_eigen); + + x->x_ctl.c_state = (t_float *)malloc(n*sizeof(t_float)); + x->x_ctl.c_eigen = (t_float *)malloc(n*sizeof(t_float)); + + for(i=0;i<n;i++) + { + x->x_ctl.c_state[i] = 0; + x->x_ctl.c_eigen[i] = 0; + } + + x->x_ctl.c_order = n; + } + + + + dsp_add(diag_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + +} + +static void diag_free(t_diag *x) +{ + + if (x->x_ctl.c_state) free(x->x_ctl.c_state); + if (x->x_ctl.c_eigen) free(x->x_ctl.c_eigen); + + +} + +t_class *diag_class; + + +static void *diag_new(t_floatarg permute) +{ + t_diag *x = (t_diag *)pd_new(diag_class); + int i, n=64; + + outlet_new(&x->x_obj, gensym("signal")); + + x->x_ctl.c_state = (t_float *)malloc(n*sizeof(t_float)); + x->x_ctl.c_eigen = (t_float *)malloc(n*sizeof(t_float)); + + for(i=0;i<n;i++) + { + x->x_ctl.c_state[i] = 0; + x->x_ctl.c_eigen[i] = 0; + } + + x->x_ctl.c_order = n; + + + return (void *)x; +} + + +void diag_tilde_setup(void) +{ + //post("diag~ v0.1"); + diag_class = class_new(gensym("diag~"), (t_newmethod)diag_new, + (t_method)diag_free, sizeof(t_diag), 0, A_DEFFLOAT, 0); + CLASS_MAINSIGNALIN(diag_class, t_diag, x_f); + class_addmethod(diag_class, (t_method)diag_dsp, gensym("dsp"), 0); + class_addmethod(diag_class, (t_method)diag_reset, gensym("reset"), 0); + class_addmethod(diag_class, (t_method)diag_random, gensym("random"), 0); + class_addmethod(diag_class, (t_method)diag_random, gensym("bang"), 0); + class_addmethod(diag_class, (t_method)diag_eigen, gensym("eigen"), A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod(diag_class, (t_method)diag_time, gensym("time"), A_DEFFLOAT, A_DEFFLOAT, 0); + +} + diff --git a/modules/dist.c b/modules/dist.c new file mode 100644 index 0000000..578e2ef --- /dev/null +++ b/modules/dist.c @@ -0,0 +1,262 @@ +/* + * dist.c - wave shaping extern + * 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 "extlib_util.h" + + +#define CLIP 0 +#define INVERSE 1 +#define INVERSESQ 2 +#define INVERSECUB 3 +#define RAT1 4 +#define RAT2 5 +#define FULLRECT 6 +#define HALFRECT 7 +#define PULSE 8 +#define NEWTON1 9 +#define UPPERCLIP 10 + + + + +typedef struct distctl +{ + t_float c_gain; + t_float c_delay; + char c_type; +} t_distctl; + +typedef struct dist +{ + t_object x_obj; + t_float x_f; + t_distctl x_ctl; +} t_dist; + +void dist_bang(t_dist *x) +{ + +} + +void dist_gain(t_dist *x, t_floatarg f) +{ + x->x_ctl.c_gain = f; + +} + + +static t_int *dist_perform(t_int *w) +{ + + + t_float *in = (float *)(w[3]); + t_float *out = (float *)(w[4]); + t_distctl *ctl = (t_distctl *)(w[1]); + t_float gain = ctl->c_gain; + t_int i; + t_int n = (t_int)(w[2]); + t_float x,y,v; + t_float z = ctl->c_delay; + + switch(ctl->c_type){ + case CLIP: + for (i = 0; i < n; i++) + { + x = *in++ * gain; + x = (x > 1) ? ( 1.) : x; + x = (x < -1) ? (-1.) : x; + *out++ = 0.9999 * x; + + } + break; + + case INVERSE: + for (i = 0; i < n; i++) + { + x = *in++ * gain; + x = (x > 1) ? (2. - 1/x) : x; + x = (x < -1) ? (-2. - 1/x) : x; + *out++ = x/2.0001; + + } + break; + + case INVERSESQ: + for (i = 0; i < n; i++) + { + x = *in++ * gain; + x = (x > 1) ? (2. - 1/x) : x; + x = (x < -1) ? (-2. - 1/x) : x; + x /= 2; + *out++ = 1.999*x*x-1; + + } + break; + + case INVERSECUB: + for (i = 0; i < n; i++) + { + x = *in++ * gain; + x = (x > 1) ? (2. - 1/x) : x; + x = (x < -1) ? (-2. - 1/x) : x; + x /= 2; + *out++ = .9999 * x*x*x; + + } + break; + + case RAT1: /*(2*d./((1+(d).^2)))*/ + for (i = 0; i < n; i++) + { + x = *in++ * gain; + y = (1. + x*x); + x = 1.9999*x/y; + *out++ = x; + } + break; + + case RAT2: /*(2*d./((1+(d).^16)))*/ + for (i = 0; i < n; i++) + { + x = *in++ * gain; + y = x*x; + y *= y; + y *= y; + y *= y; + y = (1. + y); + x = 1.2*x/y; + *out++ = x; + } + break; + + case FULLRECT: + for (i = 0; i < n; i++) + { + x = *in++ * gain; + x = (x>0) ? x : -x; + x = (x>1) ? 1 : x; + *out++ = 1.9999*(x-.5); + } + break; + + case HALFRECT: + for (i = 0; i < n; i++) + { + x = *in++ * gain; + x = (x>0) ? x : 0; + x = (x>1) ? 1 : x; + *out++ = 1.9999*(x-.5); + } + break; + + case PULSE: + for (i = 0; i < n; i++) + { + x = *in++ * gain; + y = (x>0) ? (1):(-1); + x = (z*y > 0) ? (0) : (y); + *out++ = .9999 * x; + z = x; + + } + ctl->c_delay = z; + break; + + case NEWTON1: + for (i = 0; i < n; i++) + { + x = *in++ * gain; + y = 1./(1.+x*x); + + z = .5; + z = .5*(y/z + z); + z = .5*(y/z + z); + z = .5*(y/z + z); + + /* z = .5*(y/z + z); + * z = .5*(y/z + z); + * z = .5*(y/z + z); + */ + + *out++ = x * z; + + } + ctl->c_delay = z; + break; + + case UPPERCLIP: + for (i = 0; i < n; i++) + { + x = *in++ * gain; + + x = (x < 0.0f) ? 0.0f : x; + x = (x > 0.9999f) ? 0.9999f : x; + + *out++ = x; + + } + break; + + default: + + for (i = 0; i < n; i++) *out++ = *in++; + break; + + } + + return (w+5); +} + +static void dist_dsp(t_dist *x, t_signal **sp) +{ + dsp_add(dist_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + +} +void dist_free(void) +{ + +} + +t_class *dist_class; + +void *dist_new(t_floatarg type) +{ + t_dist *x = (t_dist *)pd_new(dist_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("gain")); + outlet_new(&x->x_obj, gensym("signal")); + + dist_gain(x, 1); + x->x_ctl.c_type = (char)type; + x->x_ctl.c_delay = 0; + + return (void *)x; +} + +void dist_tilde_setup(void) +{ + //post("dist~ v0.1"); + dist_class = class_new(gensym("dist~"), (t_newmethod)dist_new, + (t_method)dist_free, sizeof(t_dist), 0, A_DEFFLOAT, 0); + CLASS_MAINSIGNALIN(dist_class, t_dist, x_f); + class_addmethod(dist_class, (t_method)dist_bang, gensym("bang"), 0); + class_addmethod(dist_class, (t_method)dist_dsp, gensym("dsp"), 0); + class_addmethod(dist_class, (t_method)dist_gain, gensym("gain"), A_FLOAT, 0); + +} + diff --git a/modules/dwt.c b/modules/dwt.c new file mode 100644 index 0000000..caa75ff --- /dev/null +++ b/modules/dwt.c @@ -0,0 +1,893 @@ +/* + * dwt.c - code for discrete wavelet transform + * (symmetric interpolating biorthogonal wavelets using the lifting transform) + * 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 MAXORDER 64 + +typedef enum{DWT,IDWT,DWT16,IDWT16} t_dwttype; + +typedef struct dwtctl +{ + t_float c_update[MAXORDER]; + t_float c_predict[MAXORDER]; + t_int c_nupdate; + t_int c_npredict; + t_int c_levels; + t_int c_fakein; + t_float c_fakeval; + t_int c_mask; + char c_name[16]; + t_int *c_clutter; + t_int *c_unclutter; + t_int c_permute; + t_dwttype c_type; +} t_dwtctl; + +typedef struct dwt +{ + t_object x_obj; + t_float x_f; + t_dwtctl x_ctl; +} t_dwt; + + +static void dwt_even(t_dwt *x, t_floatarg f) +{ + int k = (int)f; + int i, j; + float *p = x->x_ctl.c_predict; + float *u = x->x_ctl.c_update; + float l, xi, xj; + + if ((k>0) && (k<MAXORDER/2)) + { + for (i=0; i<k; i++){ + l = 1; + xi = 1+2*i; + for (j=0; j<k; j++) + { + xj = 1+2*j; + if (i != j) l /= (1 - ((xi*xi) / (xj*xj))); + } + l *= .5; + + p[k-i-1] = l; + p[k+i] = l; + u[k-i-1] = l/2; + u[k+i] = l/2; + } + + x->x_ctl.c_npredict = 2*k; + x->x_ctl.c_nupdate = 2*k; + } +} + +static void dwt_wavelet(t_dwt *x, t_floatarg f) +{ + int k = (int)f; + t_float *p = x->x_ctl.c_predict; + t_float *u = x->x_ctl.c_update; + t_int *np = &x->x_ctl.c_npredict; + t_int *nu = &x->x_ctl.c_nupdate; + + switch(k) + { + default: + case 1: /* haar */ + *np = *nu = 2; /* actual order is one */ + p[0] = 1; + p[1] = 0; + u[0] = 0; + u[1] = .5; + break; + + case 2: /* hat */ + case 3: + *np = *nu = 2; + p[0] = .5; + p[1] = .5; + u[0] = .25; + u[1] = .25; + break; + + case 4: /* N = 4, N~ = 4 */ + case 5: + *np = *nu = 4; + p[0] = -0.0625; + p[1] = 0.5625; + p[2] = 0.5625; + p[3] = -0.0625; + u[0] = -0.03125; + u[1] = 0.28125; + u[2] = 0.28125; + u[3] = -0.03125; + break; + + case 6: + case 7: + *np = *nu = 6; + p[0] = 0.01171875000000; + p[1] = -0.09765625000000; + p[2] = 0.58593750000000; + p[3] = 0.58593750000000; + p[4] = -0.09765625000000; + p[5] = 0.01171875000000; + u[0] = 0.00585937500000; + u[1] = -0.04882812500000; + u[2] = 0.29296875000000; + u[3] = 0.29296875000000; + u[4] = -0.04882812500000; + u[5] = 0.00585937500000; + break; + } +} + +static inline void dwt_perform_permutation(t_float *S, int n, t_int *f) +{ + t_int k,l; + t_float swap; + for(k=0; k<n; k++) + { + l = f[k]; + while (l<k) l = f[l]; + swap = S[k]; + S[k] = S[l]; + S[l] = swap; + } +} + +static void dwt_permutation(t_dwt *x, t_int n){ + + t_dwtctl *ctl = &x->x_ctl; + t_int k, L=0, l, start, power; + t_int nsave = n; + + while(nsave>>=1) L++; + + if (ctl->c_clutter) free(ctl->c_clutter); + if (ctl->c_unclutter) free(ctl->c_unclutter); + + ctl->c_clutter = (t_int *)malloc(n*sizeof(t_int)); + ctl->c_unclutter = (t_int *)malloc(n*sizeof(t_int)); + + + for(l = L, start = n/2, power=1; l>0; l--, start /=2, power *=2) + { + for(k=0; k<start; k++) + { + ctl->c_unclutter[start+k] = (1 + 2*k) * power; + } + } + ctl->c_unclutter[0] = 0; + + for(k=0; k<n; k++) + ctl->c_clutter[ctl->c_unclutter[k]] = k; + + return; + + /* debug */ + for(k=0; k<n; k++) + printf("clutter[%d] = %d\n", k, ctl->c_clutter[k]); + for(k=0; k<n; k++) + printf("unclutter[%d] = %d\n", k, ctl->c_unclutter[k]); + + exit(1); +} + + + +static void idwt_coef(t_dwt *x, t_floatarg index, t_floatarg value) +{ + x->x_ctl.c_fakein = (int)index; + x->x_ctl.c_fakeval = value; + +} + +static void dwt_print(t_dwt *x) +{ + int i; + + printf("%s: predict: [ ", x->x_ctl.c_name); + for (i=0; i<x->x_ctl.c_npredict; i++) printf("%f ", x->x_ctl.c_predict[i]); + printf("], "); + + printf("update: [ "); + for (i=0; i<x->x_ctl.c_nupdate; i++) printf("%f ", x->x_ctl.c_update[i]); + printf("]\n"); + + + +} + + +static void dwt_filter(t_dwt *x, t_symbol *s, int argc, t_atom *argv) +{ + int invalid_argument = 0; + int i; + + char *name = x->x_ctl.c_name; + + float *pfilter = x->x_ctl.c_predict; + float *ufilter = x->x_ctl.c_update; + float *mask = NULL; + + int *length = NULL; + float sum = 0; + + if (s == gensym("predict")) + { + mask = pfilter; + length = &(x->x_ctl.c_npredict); + } + else if (s == gensym("update")) + { + mask = ufilter; + length = &(x->x_ctl.c_nupdate); + } + else if (s == gensym("mask")) + { + mask = NULL; + } + else + { + return; + } + + if (argc >= MAXORDER) post("%s: error, maximum order exceeded.",name); + else if ((x->x_ctl.c_type == DWT16 || x->x_ctl.c_type == IDWT16 ) && (argc != 16)) + post("%s: error, need to have 16 coefficients.",name); + else if (argc == 0) post("%s: no arguments given.",name); + else if (argc & 1) post("%s: error, only an even number of coefficients is allowed.", name); + else + { + for (i=0; i<argc; i++){ + if (argv[i].a_type != A_FLOAT ) + { + invalid_argument = 1; + break; + } + } + + if (invalid_argument) post("%s: invalid argument, must be a number.", name); + else + { + if (mask) /* one of update / predict */ + { + for (i=0; i<argc; i++) mask[i] = argv[i].a_w.w_float; + *length = argc; + } + else /* both + normalization */ + { + for (i=0; i<argc; i++) sum += argv[i].a_w.w_float; + for (i=0; i<argc; i++) + { + pfilter[i] = argv[i].a_w.w_float / sum; + ufilter[i] = argv[i].a_w.w_float / (sum*2); + } + x->x_ctl.c_npredict = argc; + x->x_ctl.c_nupdate = argc; + } + } + + } + +} + + + +static inline void dwtloop(float *vector, + int source, + int dest, + int increment, + int backup, + int numcoef, + int mask, + float *filter, + int filtlength, + float sign) +{ + + int k,m; + float acc; + + for (k = 0; k < numcoef; k++) + { + acc = 0; + for (m = 0; m < filtlength; m++) + { + + acc += filter[m] * vector[source]; + source += increment; + source &= mask; + } + vector[dest] += sign * acc; + dest += increment; + source -= backup; + source &= mask; + } + +} + +static inline void dwtloop16(float *vector, + int source, + int dest, + int increment, + int backup, + int numcoef, + int mask, + float *filter, + int filtlength, /* ignored, set to 16 */ + float sign) +{ + + int k,m; + float acc; + + for (k = 0; k < numcoef; k++) + { + acc = 0; + + acc += filter[0] * vector[source]; + source += increment; + source &= mask; + + acc += filter[1] * vector[source]; + source += increment; + source &= mask; + + acc += filter[2] * vector[source]; + source += increment; + source &= mask; + + acc += filter[3] * vector[source]; + source += increment; + source &= mask; + + acc += filter[4] * vector[source]; + source += increment; + source &= mask; + + acc += filter[5] * vector[source]; + source += increment; + source &= mask; + + acc += filter[6] * vector[source]; + source += increment; + source &= mask; + + acc += filter[7] * vector[source]; + source += increment; + source &= mask; + + acc += filter[8] * vector[source]; + source += increment; + source &= mask; + + acc += filter[9] * vector[source]; + source += increment; + source &= mask; + + acc += filter[10] * vector[source]; + source += increment; + source &= mask; + + acc += filter[11] * vector[source]; + source += increment; + source &= mask; + + acc += filter[12] * vector[source]; + source += increment; + source &= mask; + + acc += filter[13] * vector[source]; + source += increment; + source &= mask; + + acc += filter[14] * vector[source]; + source += increment; + source &= mask; + + acc += filter[15] * vector[source]; + source += increment; + source &= mask; + + vector[dest] += sign * acc; + dest += increment; + source -= backup; + source &= mask; + } + +} + + + + + +static t_int *dwt_perform(t_int *w) +{ + + + t_float *in = (float *)(w[3]); + t_float *out = (float *)(w[4]); + t_dwtctl *ctl = (t_dwtctl *)(w[1]); + + + t_int n = (t_int)(w[2]); + + int i; + + int numcoef = n/2; + /* int source_u = ((1 - ctl->c_nupdate)/2 - 1); + * int source_p = ((1 - ctl->c_npredict)/2); + */ + int source_u = ((2 - ctl->c_nupdate) - 1); + int source_p = ((2 - ctl->c_npredict)); + int increment = 2; + int dest = 1; + int backup_u = (ctl->c_nupdate-1)*2; + int backup_p = (ctl->c_npredict-1)*2; + + /* copy input to output */ + if (in != out) + for (i=0; i<n; i++) out[i]=in[i]; + + + /* fake input */ + /* for (i=0; i<n; i++) out[i]=0; out[n/8]=1;*/ + + + + /* backward transform */ + + + /* iterate over all levels */ + for (i=0; i < ctl->c_levels; i++){ + + + /* foreward predict */ + dwtloop(out, (source_p & (n-1)), dest, increment, backup_p, numcoef, n-1, ctl->c_predict, ctl->c_npredict, -1); + + + /* foreward update */ + dwtloop(out, (source_u & (n-1)), 0, increment, backup_u, numcoef, n-1, ctl->c_update, ctl->c_nupdate, +1); + + + /* update control parameters */ + numcoef /= 2; + source_p *= 2; + source_u *= 2; + backup_p *= 2; + backup_u *= 2; + increment *= 2; + dest *= 2; + } + + if (ctl->c_permute) + dwt_perform_permutation(out, n, ctl->c_unclutter); + + + return (w+5); +} + + + + +static t_int *idwt_perform(t_int *w) +{ + + + t_float *in = (float *)(w[3]); + t_float *out = (float *)(w[4]); + t_dwtctl *ctl = (t_dwtctl *)(w[1]); + + + t_int n = (t_int)(w[2]); + + int i; + + int numcoef = 1; + int source_u = ((2 - ctl->c_nupdate) - 1) * (n/2); + int source_p = ((2 - ctl->c_npredict)) * (n/2); + int increment = n; + int dest = n/2; + int backup_u = (ctl->c_nupdate-1)*n; + int backup_p = (ctl->c_npredict-1)*n; + int fake_in = ctl->c_fakein; + float fake_val = ctl->c_fakeval; + + /* copy input to output */ + if (in != out) + for (i=0; i<n; i++) out[i]=in[i]; + + + /* fake input */ + + if ((fake_in >= 0) && (fake_in<n)){ + for (i=0; i<n; i++) out[i]=0; + out[fake_in]=fake_val; + } + + + if (ctl->c_permute) + dwt_perform_permutation(out, n, ctl->c_clutter); + + + /* backward transform */ + + + /* iterate over all levels */ + for (i=0; i < ctl->c_levels; i++){ + + /* backward update */ + dwtloop(out, (source_u & (n-1)), 0, increment, backup_u, numcoef, n-1, ctl->c_update, ctl->c_nupdate, -1); + + + /* backward predict */ + dwtloop(out, (source_p & (n-1)), dest, increment, backup_p, numcoef, n-1, ctl->c_predict, ctl->c_npredict, +1); + + /* update control parameters */ + numcoef *= 2; + source_p /= 2; + source_u /= 2; + backup_p /= 2; + backup_u /= 2; + increment /= 2; + dest /= 2; + } + + + + return (w+5); +} + +static t_int *dwt16_perform(t_int *w) +{ + + + t_float *in = (float *)(w[3]); + t_float *out = (float *)(w[4]); + t_dwtctl *ctl = (t_dwtctl *)(w[1]); + + + t_int n = (t_int)(w[2]); + + int i; + + int numcoef = n/2; + /* int source_u = ((1 - ctl->c_nupdate)/2 - 1); + * int source_p = ((1 - ctl->c_npredict)/2); + */ + int source_u = ((2 - ctl->c_nupdate) - 1); + int source_p = ((2 - ctl->c_npredict)); + int increment = 2; + int dest = 1; + int backup_u = (ctl->c_nupdate-1)*2; + int backup_p = (ctl->c_npredict-1)*2; + + /* copy input to output */ + if (in != out) + for (i=0; i<n; i++) out[i]=in[i]; + + + /* fake input */ + /* for (i=0; i<n; i++) out[i]=0; out[n/8]=1;*/ + + + + /* backward transform */ + + + /* iterate over all levels */ + for (i=0; i < ctl->c_levels; i++){ + + + /* foreward predict */ + dwtloop16(out, (source_p & (n-1)), dest, increment, backup_p, numcoef, n-1, ctl->c_predict, 16, -1); + + + /* foreward update */ + dwtloop16(out, (source_u & (n-1)), 0, increment, backup_u, numcoef, n-1, ctl->c_update, 16, +1); + + + /* update control parameters */ + numcoef /= 2; + source_p *= 2; + source_u *= 2; + backup_p *= 2; + backup_u *= 2; + increment *= 2; + dest *= 2; + } + + if (ctl->c_permute) + dwt_perform_permutation(out, n, ctl->c_unclutter); + + + return (w+5); +} + + + + +static t_int *idwt16_perform(t_int *w) +{ + + + t_float *in = (float *)(w[3]); + t_float *out = (float *)(w[4]); + t_dwtctl *ctl = (t_dwtctl *)(w[1]); + + + t_int n = (t_int)(w[2]); + + int i; + + int numcoef = 1; + int source_u = ((2 - ctl->c_nupdate) - 1) * (n/2); + int source_p = ((2 - ctl->c_npredict)) * (n/2); + int increment = n; + int dest = n/2; + int backup_u = (ctl->c_nupdate-1)*n; + int backup_p = (ctl->c_npredict-1)*n; + int fake_in = ctl->c_fakein; + float fake_val = ctl->c_fakeval; + + /* copy input to output */ + if (in != out) + for (i=0; i<n; i++) out[i]=in[i]; + + + /* fake input */ + + if ((fake_in >= 0) && (fake_in<n)){ + for (i=0; i<n; i++) out[i]=0; + out[fake_in]=fake_val; + } + + + if (ctl->c_permute) + dwt_perform_permutation(out, n, ctl->c_clutter); + + + /* backward transform */ + + + /* iterate over all levels */ + for (i=0; i < ctl->c_levels; i++){ + + /* backward update */ + dwtloop16(out, (source_u & (n-1)), 0, increment, backup_u, numcoef, n-1, ctl->c_update, 16, -1); + + + /* backward predict */ + dwtloop16(out, (source_p & (n-1)), dest, increment, backup_p, numcoef, n-1, ctl->c_predict, 16, +1); + + /* update control parameters */ + numcoef *= 2; + source_p /= 2; + source_u /= 2; + backup_p /= 2; + backup_u /= 2; + increment /= 2; + dest /= 2; + } + + + + return (w+5); +} + + + +static void dwt_dsp(t_dwt *x, t_signal **sp) +{ + + int n = sp[0]->s_n; + int ln = 0; + + dwt_permutation(x, n); + + x->x_ctl.c_mask = n-1; + while (n >>= 1) ln++; + x->x_ctl.c_levels = ln; + + switch(x->x_ctl.c_type){ + case DWT: + dsp_add(dwt_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + break; + case IDWT: + dsp_add(idwt_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + break; + case DWT16: + dsp_add(dwt16_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + break; + case IDWT16: + dsp_add(idwt16_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + break; + + + } +} + + +void dwt_free(t_dwt *x) +{ + + if (x->x_ctl.c_clutter) free(x->x_ctl.c_clutter); + if (x->x_ctl.c_unclutter) free(x->x_ctl.c_unclutter); + + +} + +t_class *dwt_class, *idwt_class, *dwt16_class, *idwt16_class; + + +static void dwt_reset(t_dwt *x) +{ + bzero(x->x_ctl.c_update, 16*sizeof(t_float)); + bzero(x->x_ctl.c_predict, 16*sizeof(t_float)); + + x->x_ctl.c_update[7] = .25; + x->x_ctl.c_update[8] = .25; + x->x_ctl.c_nupdate = 16; + + x->x_ctl.c_predict[7] = .5; + x->x_ctl.c_predict[8] = .5; + x->x_ctl.c_npredict = 16; + + x->x_ctl.c_fakein = -1; + x->x_ctl.c_fakeval = 0; + +} + + +static void *dwt_new_common(t_floatarg permute) +{ + t_dwt *x = (t_dwt *)pd_new(dwt_class); + int i; + + outlet_new(&x->x_obj, gensym("signal")); + + /* init data */ + dwt_reset(x); + + x->x_ctl.c_clutter = NULL; + x->x_ctl.c_unclutter = NULL; + x->x_ctl.c_permute = (t_int) permute; + + return (void *)x; + + +} + +static void *dwt_new(t_floatarg permute) +{ + t_dwt *x = dwt_new_common(permute); + sprintf(x->x_ctl.c_name,"dwt"); + x->x_ctl.c_type = DWT; + return (void *)x; +} + + +static void *idwt_new(t_floatarg permute) +{ + t_dwt *x = dwt_new_common(permute); + sprintf(x->x_ctl.c_name,"idwt"); + x->x_ctl.c_type = IDWT; + return (void *)x; +} + +static void *dwt16_new(t_floatarg permute) +{ + t_dwt *x = dwt_new_common(permute); + sprintf(x->x_ctl.c_name,"dwt16"); + x->x_ctl.c_type = DWT16; + return (void *)x; +} + + +static void *idwt16_new(t_floatarg permute) +{ + t_dwt *x = dwt_new_common(permute); + sprintf(x->x_ctl.c_name,"idwt16"); + x->x_ctl.c_type = IDWT16; + return (void *)x; +} + + +void dwt_tilde_setup(void) +{ + //post("dwt~ v0.1"); + + + dwt_class = class_new(gensym("dwt~"), (t_newmethod)dwt_new, + (t_method)dwt_free, sizeof(t_dwt), 0, A_DEFFLOAT, 0); + CLASS_MAINSIGNALIN(dwt_class, t_dwt, x_f); + class_addmethod(dwt_class, (t_method)dwt_print, gensym("print"), 0); + class_addmethod(dwt_class, (t_method)dwt_reset, gensym("reset"), 0); + class_addmethod(dwt_class, (t_method)dwt_dsp, gensym("dsp"), 0); + + class_addmethod(dwt_class, (t_method)dwt_filter, gensym("predict"), A_GIMME, 0); + class_addmethod(dwt_class, (t_method)dwt_filter, gensym("update"), A_GIMME, 0); + class_addmethod(dwt_class, (t_method)dwt_filter, gensym("mask"), A_GIMME, 0); + + class_addmethod(dwt_class, (t_method)dwt_even, gensym("even"), A_DEFFLOAT, 0); + class_addmethod(dwt_class, (t_method)idwt_coef, gensym("coef"), A_DEFFLOAT, A_DEFFLOAT, 0); + + + + /*class_addmethod(dwt_class, (t_method)dwt_wavelet, gensym("wavelet"), A_DEFFLOAT, 0); */ + + + idwt_class = class_new(gensym("idwt~"), (t_newmethod)idwt_new, + (t_method)dwt_free, sizeof(t_dwt), 0, A_DEFFLOAT, 0); + + CLASS_MAINSIGNALIN(idwt_class, t_dwt, x_f); + class_addmethod(idwt_class, (t_method)dwt_print, gensym("print"), 0); + class_addmethod(idwt_class, (t_method)dwt_dsp, gensym("dsp"), 0); + + class_addmethod(idwt_class, (t_method)dwt_filter, gensym("predict"), A_GIMME, 0); + class_addmethod(idwt_class, (t_method)dwt_filter, gensym("update"), A_GIMME, 0); + class_addmethod(idwt_class, (t_method)dwt_filter, gensym("mask"), A_GIMME, 0); + + class_addmethod(idwt_class, (t_method)idwt_coef, gensym("coef"), A_DEFFLOAT, A_DEFFLOAT, 0); + + class_addmethod(idwt_class, (t_method)dwt_even, gensym("even"), A_DEFFLOAT, 0); + + + + dwt16_class = class_new(gensym("dwt16~"), (t_newmethod)dwt16_new, + (t_method)dwt_free, sizeof(t_dwt), 0, A_DEFFLOAT, 0); + CLASS_MAINSIGNALIN(dwt16_class, t_dwt, x_f); + class_addmethod(dwt16_class, (t_method)dwt_print, gensym("print"), 0); + class_addmethod(dwt16_class, (t_method)dwt_reset, gensym("reset"), 0); + class_addmethod(dwt16_class, (t_method)dwt_dsp, gensym("dsp"), 0); + + class_addmethod(dwt16_class, (t_method)dwt_filter, gensym("predict"), A_GIMME, 0); + class_addmethod(dwt16_class, (t_method)dwt_filter, gensym("update"), A_GIMME, 0); + class_addmethod(dwt16_class, (t_method)dwt_filter, gensym("mask"), A_GIMME, 0); + + + + + idwt16_class = class_new(gensym("idwt16~"), (t_newmethod)idwt16_new, + (t_method)dwt_free, sizeof(t_dwt), 0, A_DEFFLOAT, 0); + + CLASS_MAINSIGNALIN(idwt16_class, t_dwt, x_f); + class_addmethod(idwt16_class, (t_method)dwt_print, gensym("print"), 0); + class_addmethod(idwt16_class, (t_method)dwt_dsp, gensym("dsp"), 0); + + class_addmethod(idwt16_class, (t_method)dwt_filter, gensym("predict"), A_GIMME, 0); + class_addmethod(idwt16_class, (t_method)dwt_filter, gensym("update"), A_GIMME, 0); + class_addmethod(idwt16_class, (t_method)dwt_filter, gensym("mask"), A_GIMME, 0); + + class_addmethod(idwt16_class, (t_method)idwt_coef, gensym("coef"), A_DEFFLOAT, A_DEFFLOAT, 0); + + + + +} + diff --git a/modules/dynwav.c b/modules/dynwav.c new file mode 100644 index 0000000..0ff75f3 --- /dev/null +++ b/modules/dynwav.c @@ -0,0 +1,318 @@ +/* + * dynwav.c - dynamic wavetable oscillator + * 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 MAXORDER 1024 + +typedef struct dynwavctl +{ + t_float *c_buf1; /* current */ + t_float *c_buf2; /* old */ + t_int c_order; + +} t_dynwavctl; + +typedef struct dynwav +{ + t_object x_obj; + t_float x_f; + t_dynwavctl x_ctl; +} t_dynwav; + + +static t_int *dynwav_perform(t_int *w) +{ + + + t_float *wave = (float *)(w[3]); + t_float *freq = (float *)(w[4]); + t_float *out = (float *)(w[5]); + t_dynwavctl *ctl = (t_dynwavctl *)(w[1]); + t_int n = (t_int)(w[2]); + + t_float *buf, *dbuf, *swap; + + int i; + int mask = n-1; + + + /* swap buffer pointers */ + swap = ctl->c_buf1; /* this is the last one stored */ + buf = ctl->c_buf1 = ctl->c_buf2; /* put oldest in newest to overwrite */ + dbuf = ctl->c_buf2 = swap; /* put last one in oldest */ + + + if (buf && dbuf) + { + + /* store input wavetable in buffer */ + memcpy(buf, wave, n*sizeof(t_float)); + + + for (i = 0; i < n; i++) + { + float findex = *freq++ * (t_float)n; + int index = findex; + float frac, a, b, c, d, cminusb, q, r; + int ia, ib, ic, id; + + frac = findex - index; + + ia = (index-1) & mask; + ib = (index ) & mask; + ic = (index+1) & mask; + id = (index+2) & mask; + + q = i+1; + q /= n; + + r = n-1-i; + r /= n; + + /* get 4 points, wrap index */ + a = q * buf[ia] + r * dbuf[ia]; + b = q * buf[ib] + r * dbuf[ib]; + c = q * buf[ic] + r * dbuf[ic]; + d = q * buf[id] + r * dbuf[id]; + + cminusb = c-b; + *out++ = b + frac * (cminusb - 0.5f * (frac-1.) * + ((a - d + 3.0f * cminusb) * frac + + (b - a - cminusb))); + } + + } + return (w+6); +} + +static t_int *dynwav_perform_8point(t_int *w) /* werkt nog nie tegoei */ +{ + + + t_float *wave = (float *)(w[3]); + t_float *freq = (float *)(w[4]); + t_float *out = (float *)(w[5]); + t_dynwavctl *ctl = (t_dynwavctl *)(w[1]); + t_int n = (t_int)(w[2]); + + t_float *buf, *dbuf, *swap; + + int i; + int mask = n-1; + + + /* swap buffer pointers */ + swap = ctl->c_buf1; /* this is the last one stored */ + buf = ctl->c_buf1 = ctl->c_buf2; /* put oldest in newest to overwrite */ + dbuf = ctl->c_buf2 = swap; /* put last one in oldest */ + + + if (buf && dbuf) + { + + /* const float N1 = 1 / ( 2 * (1-(1/9)) * (1-(1/25)) * (1-(1/49)) ); + ** const float N2 = 1 / ( (1-(9)) * 2 * (1-(9/25)) * (1-(9/49)) ); + ** const float N3 = 1 / ( (1-(25)) * (1-(25/9)) * 2 * (1-(25/49)) ); + ** const float N4 = 1 / ( (1-(49)) * (1-(49/9)) * (1-(49/25)) * 2 ); + */ + + const float N1 = 0.59814453125; + const float N2 = -0.11962890625; + const float N3 = 0.02392578125; + const float N4 = -0.00244140625; + + + /* store input wavetable in buffer */ + memcpy(buf, wave, n*sizeof(t_float)); + + + for (i = 0; i < n; i++) + { + float findex = *freq++ * (t_float)n; + int index = findex; + float frac, q, r, fm, fp, fe, fo; + float x1, x2, x3, x4; + float g1, g2, g3, g4; + float gg, g2g3g4, g1g3g4, g1g2g4, g1g2g3; + float acc; + int im, ip; + + frac = 2 *(findex - index) - 1; + + x1 = frac; + x2 = frac/3; + x3 = frac/5; + x4 = frac/7; + + g1 = 1 - x1*x1; + g2 = 1 - x2*x2; + g3 = 1 - x3*x3; + g4 = 1 - x4*x4; + + gg = g3 * g4; + g2g3g4 = g2 * gg; /* 1 */ + g1g3g4 = g1 * gg; /* 2 */ + gg = g1 * g2; + g1g2g4 = g4 * gg; /* 3 */ + g1g2g3 = g3 * gg; /* 4 */ + + + /* triangle interpolation between current and past wavetable*/ + q = i+1; + q /= n; + + r = n-1-i; + r /= n; + + + /* 1, -1*/ + im = (index ) & mask; + ip = (index+1) & mask; + fm = q * buf[im] + r * dbuf[im]; + fp = q * buf[ip] + r * dbuf[ip]; + fe = fp + fm; + fo = fp - fm; + + acc = N1 * g2g3g4 * (fe + x1*fo); + + /* 2, -2 */ + im = (index-1) & mask; + ip = (index+2) & mask; + fm = q * buf[im] + r * dbuf[im]; + fp = q * buf[ip] + r * dbuf[ip]; + fe = fp + fm; + fo = fp - fm; + + acc += N2 * g1g3g4 * (fe + x2*fo); + + /* 3, -3 */ + im = (index-2) & mask; + ip = (index+3) & mask; + fm = q * buf[im] + r * dbuf[im]; + fp = q * buf[ip] + r * dbuf[ip]; + fe = fp + fm; + fo = fp - fm; + + acc += N3 * g1g2g4 * (fe + x3*fo); + + /* 4, -4 */ + im = (index-3) & mask; + ip = (index+4) & mask; + fm = q * buf[im] + r * dbuf[im]; + fp = q * buf[ip] + r * dbuf[ip]; + fe = fp + fm; + fo = fp - fm; + + acc += N4 * g1g2g3 * (fe + x4*fo); + + + *out++ = acc; + + } + + } + return (w+6); +} + + +static void dynwav_dsp(t_dynwav *x, t_signal **sp) +{ + int n = sp[0]->s_n; + int k; + + if (x->x_ctl.c_order != n) + { + if (x->x_ctl.c_buf1) free (x->x_ctl.c_buf1); + if (x->x_ctl.c_buf2) free (x->x_ctl.c_buf2); + + x->x_ctl.c_buf1 = (t_float *)malloc(n*sizeof(t_float)); + x->x_ctl.c_buf2 = (t_float *)malloc(n*sizeof(t_float)); + + for(k=0; k<n; k++) + { + x->x_ctl.c_buf1[k] = 0; + x->x_ctl.c_buf2[k] = 0; + } + + x->x_ctl.c_order = n; + } + + + dsp_add(dynwav_perform_8point, 5, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); + + +} +static void dynwav_free(t_dynwav *x) +{ + + if (x->x_ctl.c_buf1) free (x->x_ctl.c_buf1); + if (x->x_ctl.c_buf2) free (x->x_ctl.c_buf2); + +} + +t_class *dynwav_class; + +static void *dynwav_new(t_floatarg order) +{ + t_dynwav *x = (t_dynwav *)pd_new(dynwav_class); + int iorder = (int)order; + int i, n=64, k; + + /* in 2 */ + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal")); + + /* out 1 */ + outlet_new(&x->x_obj, gensym("signal")); + + + + /* init data */ + x->x_ctl.c_buf1 = (t_float *)malloc(n*sizeof(t_float)); + x->x_ctl.c_buf2 = (t_float *)malloc(n*sizeof(t_float)); + + for(k=0; k<n; k++) + { + x->x_ctl.c_buf1[k] = 0; + x->x_ctl.c_buf2[k] = 0; + } + + x->x_ctl.c_order = n; + + return (void *)x; +} + +void dynwav_tilde_setup(void) +{ + //post("dynwav~ v0.1"); + dynwav_class = class_new(gensym("dynwav~"), (t_newmethod)dynwav_new, + (t_method)dynwav_free, sizeof(t_dynwav), 0, A_DEFFLOAT, 0); + CLASS_MAINSIGNALIN(dynwav_class, t_dynwav, x_f); + class_addmethod(dynwav_class, (t_method)dynwav_dsp, gensym("dsp"), 0); + + +} + diff --git a/modules/ead.c b/modules/ead.c new file mode 100644 index 0000000..8b93faa --- /dev/null +++ b/modules/ead.c @@ -0,0 +1,153 @@ +/* + * ead.c - exponential attack decay envelope + * 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 "extlib_util.h" + +/* pointer to */ +t_class *ead_class; + + +/* state data fpr attack/decay dsp plugin */ +typedef struct eadctl +{ + t_float c_attack; + t_float c_decay; + t_float c_state; + t_float c_target; +} t_eadctl; + + +/* object data structure */ +typedef struct ead +{ + t_object x_obj; + t_eadctl x_ctl; +} t_ead; + + + +static void ead_attack(t_ead *x, t_floatarg f) +{ + x->x_ctl.c_attack = milliseconds_2_one_minus_realpole(f); +} + +static void ead_decay(t_ead *x, t_floatarg f) +{ + x->x_ctl.c_decay = milliseconds_2_one_minus_realpole(f); +} + +static void ead_start(t_ead *x) +{ + x->x_ctl.c_target = 1; +} + + +/* dsp callback function, not a method */ +static t_int *ead_perform(t_int *w) +{ + + /* interprete arguments */ + t_float *out = (float *)(w[3]); + t_eadctl *ctl = (t_eadctl *)(w[1]); + 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; + + + /* A/D code */ + + if (target == 1) + /* attack phase */ + { + for (i = 0; i < n; i++) + { + *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_state = state; + + return (w+4); /* pd quirk: pointer for sequencer */ +} + + +static void ead_dsp(t_ead *x, t_signal **sp) +{ + dsp_add(ead_perform, 3, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec); +} + +/* destructor */ +static void ead_free(void) +{ + +} + + + +/* constructor */ +static void *ead_new(t_floatarg attack, t_floatarg decay, t_floatarg sustain, t_floatarg release) +{ + /* create instance */ + t_ead *x = (t_ead *)pd_new(ead_class); + /* create new inlets, convert incoming message float to attack/decay */ + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("attack")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("decay")); + /* create a dsp outlet */ + outlet_new(&x->x_obj, gensym("signal")); + + /* initialize */ + x->x_ctl.c_state = 0; + x->x_ctl.c_target = 0; + ead_attack(x, attack); + ead_decay(x, decay); + + /* return instance */ + return (void *)x; +} + +void ead_tilde_setup(void) +{ + //post("ead~ v0.1"); + + ead_class = class_new(gensym("ead~"), (t_newmethod)ead_new, + (t_method)ead_free, sizeof(t_ead), 0, A_DEFFLOAT, A_DEFFLOAT, 0); + + + class_addmethod(ead_class, (t_method)ead_start, gensym("start"), 0); + class_addmethod(ead_class, (t_method)ead_start, gensym("bang"), 0); + class_addmethod(ead_class, (t_method)ead_dsp, gensym("dsp"), 0); + class_addmethod(ead_class, (t_method)ead_attack, gensym("attack"), A_FLOAT, 0); + class_addmethod(ead_class, (t_method)ead_decay, gensym("decay"), A_FLOAT, 0); +} + diff --git a/modules/eadsr.c b/modules/eadsr.c new file mode 100644 index 0000000..0e0b9db --- /dev/null +++ b/modules/eadsr.c @@ -0,0 +1,171 @@ +/* + * eadsr.c - exponential attack decay sustain release envelope + * 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 "extlib_util.h" + +typedef struct eadsrctl +{ + t_float c_attack; + t_float c_decay; + t_float c_sustain; + t_float c_release; + t_float c_state; + t_float c_target; +} t_eadsrctl; + +typedef struct eadsr +{ + t_object x_obj; + t_float x_sr; + t_eadsrctl x_ctl; +} t_eadsr; + +void eadsr_attack(t_eadsr *x, t_floatarg f) +{ + x->x_ctl.c_attack = milliseconds_2_one_minus_realpole(f); +} + +void eadsr_decay(t_eadsr *x, t_floatarg f) +{ + x->x_ctl.c_decay = milliseconds_2_one_minus_realpole(f); +} + +void eadsr_sustain(t_eadsr *x, t_floatarg f) +{ + if (f>ENVELOPE_MAX) f = ENVELOPE_MAX; + if (f<ENVELOPE_MIN) f = ENVELOPE_MIN; + + x->x_ctl.c_sustain = f; +} + +void eadsr_release(t_eadsr *x, t_floatarg f) +{ + x->x_ctl.c_release = milliseconds_2_one_minus_realpole(f); + +} + +void eadsr_start(t_eadsr *x) +{ + x->x_ctl.c_target = 1; + +} + +void eadsr_stop(t_eadsr *x) +{ + x->x_ctl.c_target = 0; + +} + +static t_int *eadsr_perform(t_int *w) +{ + t_float *out = (float *)(w[3]); + t_eadsrctl *ctl = (t_eadsrctl *)(w[1]); + t_float attack = ctl->c_attack; + t_float decay = ctl->c_decay; + t_float sustain = ctl->c_sustain; + t_float release = ctl->c_release; + t_float state = ctl->c_state; + t_float target = ctl->c_target; + t_int n = (t_int)(w[2]); + + t_int i; + + + if (target == 1) + /* attack phase */ + { + for (i = 0; i < n; i++) + { + *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; + } + + else + /* decay phase */ + for (i = 0; i < n; i++) + { + *out++ = state; + state -= decay*(state-sustain); + } + + ctl->c_state = state; + return (w+4); +} + +static void eadsr_dsp(t_eadsr *x, t_signal **sp) +{ + x->x_sr = sp[0]->s_sr; + dsp_add(eadsr_perform, 3, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec); + +} +void eadsr_free(void) +{ + +} + +t_class *eadsr_class; + +void *eadsr_new(t_floatarg attack, t_floatarg decay, t_floatarg sustain, t_floatarg release) +{ + t_eadsr *x = (t_eadsr *)pd_new(eadsr_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("attack")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("decay")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("sustain")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("release")); + outlet_new(&x->x_obj, gensym("signal")); + + x->x_ctl.c_state = 0; + x->x_ctl.c_target = 0; + eadsr_attack(x, attack); + eadsr_decay(x, decay); + eadsr_sustain(x, sustain); + eadsr_release(x, release); + + + return (void *)x; +} + +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_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); + class_addmethod(eadsr_class, (t_method)eadsr_dsp, gensym("dsp"), 0); + class_addmethod(eadsr_class, (t_method)eadsr_attack, gensym("attack"), A_FLOAT, 0); + class_addmethod(eadsr_class, (t_method)eadsr_decay, gensym("decay"), A_FLOAT, 0); + class_addmethod(eadsr_class, (t_method)eadsr_sustain, gensym("sustain"), A_FLOAT, 0); + class_addmethod(eadsr_class, (t_method)eadsr_release, gensym("release"), A_FLOAT, 0); + + +} + diff --git a/modules/ear.c b/modules/ear.c new file mode 100644 index 0000000..efe9b3f --- /dev/null +++ b/modules/ear.c @@ -0,0 +1,134 @@ +/* + * ear.c - exponential attack release envelope + * 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 "extlib_util.h" + +typedef struct earctl +{ + t_float c_attack; + t_float c_release; + t_float c_state; + t_float c_target; +} t_earctl; + +typedef struct ear +{ + t_object x_obj; + t_float x_sr; + t_earctl x_ctl; +} t_ear; + +void ear_attack(t_ear *x, t_floatarg f) +{ + x->x_ctl.c_attack = milliseconds_2_one_minus_realpole(f); +} + +void ear_release(t_ear *x, t_floatarg f) +{ + x->x_ctl.c_release = milliseconds_2_one_minus_realpole(f); +} + +void ear_start(t_ear *x) +{ + x->x_ctl.c_target = 1; + +} + +void ear_stop(t_ear *x) +{ + x->x_ctl.c_target = 0; + +} + +static t_int *ear_perform(t_int *w) +{ + t_float *out = (float *)(w[3]); + t_earctl *ctl = (t_earctl *)(w[1]); + t_float attack = ctl->c_attack; + t_float release = ctl->c_release; + t_float state = ctl->c_state; + t_float target = ctl->c_target; + t_int n = (t_int)(w[2]); + + t_int i; + + if (target) /* attack phase */ + for (i = 0; i < n; i++) + { + *out++ = state; + state += attack*(1 - state); + } + else /* release phase */ + for (i = 0; i < n; i++) + { + *out++ = state; + state -= release*state; + } + + ctl->c_state = state; + return (w+4); +} + +static void ear_dsp(t_ear *x, t_signal **sp) +{ + x->x_sr = sp[0]->s_sr; + dsp_add(ear_perform, 3, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec); + +} +void ear_free(void) +{ + +} + + +t_class *ear_class; /* attack - release */ + +void *ear_new(t_floatarg attack, t_floatarg release) +{ + t_ear *x = (t_ear *)pd_new(ear_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("attack")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("release")); + outlet_new(&x->x_obj, gensym("signal")); + + ear_attack(x,attack); + ear_release(x,release); + x->x_ctl.c_state = 0; + x->x_ctl.c_target = 0; + + return (void *)x; +} + + +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_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); + class_addmethod(ear_class, (t_method)ear_dsp, gensym("dsp"), 0); + class_addmethod(ear_class, + (t_method)ear_attack, gensym("attack"), A_FLOAT, 0); + class_addmethod(ear_class, + (t_method)ear_release, gensym("release"), A_FLOAT, 0); + + +} + diff --git a/modules/ffpoly.c b/modules/ffpoly.c new file mode 100644 index 0000000..023f29d --- /dev/null +++ b/modules/ffpoly.c @@ -0,0 +1,173 @@ +/* + * ffpoly.c - compute a finite field polynomial + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * 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 <stdlib.h> + + + + +typedef struct ffpoly_struct +{ + t_object x_obj; + t_float x_f; + + t_outlet *x_outlet; + t_int *x_coef; + t_int x_poly_order; + t_int x_field_order; + + t_int x_lastpackedcoef; + + + +} t_ffpoly; + + + + +static void ffpoly_compute(t_ffpoly *x, t_floatarg fcoef) +{ + int in = (int)fcoef; + int fo = x->x_field_order; + int po = x->x_poly_order; + int* c = x->x_coef; + int i, out; + + in %= fo; + if (in < 0) in += fo; + + out = c[po]; + for (i=po-1; i>=0; i--){ + out *= in; + out += c[i]; + out %= fo; + } + + + outlet_float(x->x_outlet, (float)out); +} + + +/* this sets all coefficients given one float */ +static void ffpoly_coefficients(t_ffpoly *x, t_floatarg fcoef) +{ + int coef = (int)fcoef; + int i; + if (coef < 0) coef = -coef; + + x->x_lastpackedcoef = coef; + + for (i=0; i<x->x_poly_order + 1; i++){ + x->x_coef[i] = coef % x->x_field_order; + coef = coef / x->x_field_order; + } + + +} + +/* this sets one coefficient */ +static void ffpoly_coef(t_ffpoly *x, t_floatarg index, t_floatarg val) +{ + int i = (int)index; + int v = (int)val; + if (i<0) return; + if (i>x->x_poly_order) return; + + v %= x->x_field_order; + if (v<0) v += x->x_field_order; + + x->x_coef[i] = v; + + +} + +static void ffpoly_fieldorder(t_ffpoly *x, t_floatarg ffieldorder) +{ + int i; + int order = (int)ffieldorder; + if (order < 2) order = 2; + x->x_field_order = order; + + for (i=0; i<x->x_poly_order+1; i++) + x->x_coef[i] %= x->x_field_order; + + //ffpoly_coefficients(x, x->x_lastpackedcoef); +} + +static void ffpoly_free(t_ffpoly *x) +{ + free (x->x_coef); +} + +t_class *ffpoly_class; + + + +static void *ffpoly_new(t_floatarg fpolyorder, t_floatarg ffieldorder) +{ + t_int polyorder = (int)fpolyorder; + t_int fieldorder = (int)ffieldorder; + + t_ffpoly *x = (t_ffpoly *)pd_new(ffpoly_class); + + if (polyorder < 1) polyorder = 1; + if (fieldorder < 2) fieldorder = 2; + + x->x_poly_order = polyorder; + x->x_field_order = fieldorder; + + x->x_coef = (int *)malloc((x->x_poly_order + 1) * sizeof(int)); + + /* set poly to f(x) = x */ + ffpoly_coefficients(x, x->x_field_order); + + x->x_outlet = outlet_new(&x->x_obj, &s_float); + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void ffpoly_setup(void) +{ + + + ffpoly_class = class_new(gensym("ffpoly"), (t_newmethod)ffpoly_new, + (t_method)ffpoly_free, sizeof(t_ffpoly), 0, A_DEFFLOAT, A_DEFFLOAT, A_NULL); + + class_addmethod(ffpoly_class, (t_method)ffpoly_coefficients, gensym("coefficients"), A_FLOAT, A_NULL); + + class_addmethod(ffpoly_class, (t_method)ffpoly_coef, gensym("coef"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(ffpoly_class, (t_method)ffpoly_fieldorder, gensym("order"), A_FLOAT, A_NULL); + class_addfloat(ffpoly_class, (t_method)ffpoly_compute); + + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/fwarp.c b/modules/fwarp.c new file mode 100644 index 0000000..28fe024 --- /dev/null +++ b/modules/fwarp.c @@ -0,0 +1,61 @@ +/* + * fwarp.c - converts a frequency to a "standard" tangent warped freq + * 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 SEQL 16 + + +typedef struct fwarp +{ + t_object t_ob; + t_outlet *x_out; +} t_fwarp; + +static void fwarp_float(t_fwarp *x, t_floatarg f) +{ + float twopi = 2.0f * M_PI; + float sr = sys_getsr(); + f /= sr; + f = tan(twopi * f) / twopi; + outlet_float(x->x_out, f * sr); +} + +static void fwarp_free(void) +{ +} + +t_class *fwarp_class; + +static void *fwarp_new(void) +{ + t_fwarp *x = (t_fwarp *)pd_new(fwarp_class); + x->x_out = outlet_new(&x->t_ob, gensym("float")); + return (void *)x; +} + +void fwarp_setup(void) +{ + fwarp_class = class_new(gensym("fwarp"), (t_newmethod)fwarp_new, + (t_method)fwarp_free, sizeof(t_fwarp), 0, 0); + class_addfloat(fwarp_class, fwarp_float); +} + diff --git a/modules/lattice.c b/modules/lattice.c new file mode 100644 index 0000000..9403393 --- /dev/null +++ b/modules/lattice.c @@ -0,0 +1,143 @@ +/* + * lattice.c - a lattice filter for pd + * 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 maxorder 1024 + +typedef struct latticesegment +{ + t_float delay; // delay element + t_float rc; // reflection coefficient +} t_latticesegment; + +typedef struct latticectl +{ + t_latticesegment c_segment[maxorder]; // array of lattice segment data + t_int c_segments; +} t_latticectl; + +typedef struct lattice +{ + t_object x_obj; + t_float x_f; + t_latticectl x_ctl; +} t_lattice; + + + +static t_int *lattice_perform(t_int *w) +{ + + + t_float *in = (float *)(w[3]); + t_float *out = (float *)(w[4]); + t_latticectl *ctl = (t_latticectl *)(w[1]); + t_int i,j; + t_int n = (t_int)(w[2]); + t_float x,rc,d; + + t_latticesegment* seg = ctl->c_segment; + t_int segments = ctl->c_segments; + for (i=0; i<n; i++) + { + x = *in++; + // section 0 + rc = seg[0].rc; + x += seg[0].delay * rc; + + // section 1 to segments-1 + for (j=1; j < segments; j++) + { + rc = seg[j].rc; + d = seg[j].delay; + x += d * rc; + seg[j-1].delay = d - rc * x; + } + // stub + seg[segments-1].delay = x; + + *out++ = x; + } + + return (w+5); +} + +static void lattice_dsp(t_lattice *x, t_signal **sp) +{ + dsp_add(lattice_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + +} +static void lattice_free(void) +{ + +} + +t_class *lattice_class; + +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; + x->x_ctl.c_segment[seg].rc = refco; + } +} + +static void lattice_reset(t_lattice *x) +{ + t_float* buf = (t_float *)x->x_ctl.c_segment; + t_int n = x->x_ctl.c_segments; + t_int i; + for (i=0; i<n; i++) buf[i]=0; +} + +static void *lattice_new(t_floatarg segments) +{ + t_lattice *x = (t_lattice *)pd_new(lattice_class); + t_int seg = (t_int)segments; + + outlet_new(&x->x_obj, gensym("signal")); + + if (seg < 1) seg = 1; + if (seg > maxorder) seg = maxorder; + + x->x_ctl.c_segments = seg; + + lattice_reset(x); + + return (void *)x; +} + +void lattice_tilde_setup(void) +{ + //post("lattice~ v0.1"); + lattice_class = class_new(gensym("lattice~"), (t_newmethod)lattice_new, + (t_method)lattice_free, sizeof(t_lattice), 0, A_DEFFLOAT, 0); + CLASS_MAINSIGNALIN(lattice_class, t_lattice, x_f); + class_addmethod(lattice_class, (t_method)lattice_dsp, gensym("dsp"), 0); + class_addmethod(lattice_class, (t_method)lattice_reset, gensym("reset"), 0); + class_addmethod(lattice_class, (t_method)lattice_rc, gensym("rc"), A_FLOAT, A_FLOAT, 0); + +} + diff --git a/modules/matrix.c b/modules/matrix.c new file mode 100644 index 0000000..6fd55b7 --- /dev/null +++ b/modules/matrix.c @@ -0,0 +1,154 @@ +/* + * matrix.c - applies a matrix transform to a signal block + * intended for spectral processing, dynwav + * + * 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 MAXORDER 1024 + +typedef struct matrixctl +{ + t_float *c_A; /* matrix */ + t_float *c_x; /* vector */ + t_int c_order; + +} t_matrixctl; + +typedef struct matrix +{ + t_object x_obj; + t_float x_f; + t_matrixctl x_ctl; +} t_matrix; + +static void matrix_load(t_matrix *x, t_symbol *s) +{ + FILE *matrix; + + if(s && s->s_name) + { + post("matrix: loading %s",s->s_name); + if(matrix = fopen(s->s_name, "r")) + { + int n = x->x_ctl.c_order; + fread(x->x_ctl.c_A, sizeof(float), n*n, matrix); + } + else post("matrix: error, cant open file."); + } +} + + +static t_int *matrix_perform(t_int *w) +{ + + + t_float *in = (float *)(w[3]); + t_float *out = (float *)(w[4]); + t_matrixctl *ctl = (t_matrixctl *)(w[1]); + t_int n = (t_int)(w[2]); + + t_int i,j; + t_float *A = ctl->c_A; + t_float *x = ctl->c_x; + + if (in == out) /* store input if ness. */ + { + memcpy(x, in, sizeof(t_float)*n); + in = x; + } + bzero(out, sizeof(t_float)*n); /* init output */ + + for (j=0; j<n; j++) + for (i=0; i<n; i++) + out[i] += A[i+j*n] * in[j]; + + return (w+5); +} + +static void matrix_dsp(t_matrix *x, t_signal **sp) +{ + int n = sp[0]->s_n; + int k,i; + + if (x->x_ctl.c_order != n) + { + if (x->x_ctl.c_A) free (x->x_ctl.c_A); + + x->x_ctl.c_A = (t_float *)calloc(n*n,sizeof(t_float)); + x->x_ctl.c_x = (t_float *)calloc(n,sizeof(t_float)); + x->x_ctl.c_order = n; + } + + for (i=0;i<n;i++) x->x_ctl.c_A[i] = 1; + + dsp_add(matrix_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + + +} +static void matrix_free(t_matrix *x) +{ + + if (x->x_ctl.c_A) free (x->x_ctl.c_A); + if (x->x_ctl.c_x) free (x->x_ctl.c_x); + +} + +t_class *matrix_class; + +static void *matrix_new(t_floatarg order) +{ + t_matrix *x = (t_matrix *)pd_new(matrix_class); + int iorder = (int)order; + int i, n=64, k; + + + /* out 1 */ + outlet_new(&x->x_obj, gensym("signal")); + + + + /* init data */ + + x->x_ctl.c_A = (t_float *)calloc(n*n,sizeof(t_float)); + x->x_ctl.c_x = (t_float *)calloc(n,sizeof(t_float)); + + + for (i=0;i<n;i++) x->x_ctl.c_A[i] = 1; + x->x_ctl.c_order = n; + + return (void *)x; +} + +void matrix_tilde_setup(void) +{ + //post("matrix~ v0.1"); + matrix_class = class_new(gensym("matrix~"), (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); + class_addmethod(matrix_class, (t_method)matrix_load, gensym("load"), A_SYMBOL,0); + + +} + diff --git a/modules/permut.c b/modules/permut.c new file mode 100644 index 0000000..bc143d2 --- /dev/null +++ b/modules/permut.c @@ -0,0 +1,177 @@ +/* + * permut.c - applies a (random) permutation on a signal block + * intended for spectral processing, dynwav + * + * 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> + + + +typedef struct permutctl +{ + char c_type; + int *c_permutationtable; + int c_blocksize; +} t_permutctl; + +typedef struct permut +{ + t_object x_obj; + t_float x_f; + t_permutctl x_ctl; +} t_permut; + + +static inline void permut_perform_permutation(t_float *S, int n, t_int *f) +{ + t_int k,l; + t_float swap; + for(k=0; k<n; k++) + { + l = f[k]; + while (l<k) l = f[l]; + swap = S[k]; + S[k] = S[l]; + S[l] = swap; + } +} + + +static void permut_random(t_permut *x, t_floatarg seed) +{ + int i,j; + int N = x->x_ctl.c_blocksize; + int mask = N-1; + int *p = x->x_ctl.c_permutationtable; + int r, last = 0; + + srand(* ((unsigned int *)(&seed))); + + if(p) + { + p[0] = rand() & mask; + for (i=1;i<N;i++) + { + r = rand() & mask; + j = 0; + while(j<i) + { + if (p[j] == r) + { + r = (r + 1) & mask; + j = 0; + } + else j++; + } + p[i] = r; + + } + } +} + +static void permut_bang(t_permut *x) +{ + unsigned int r = rand(); + permut_random(x, *((float *)(&r))); +} + +static void permut_resize_table(t_permut *x, int size) +{ + if (x->x_ctl.c_blocksize != size) + { + if (x->x_ctl.c_permutationtable) + free(x->x_ctl.c_permutationtable); + x->x_ctl.c_permutationtable = (int *)malloc(sizeof(int)*size); + x->x_ctl.c_blocksize = size; + + /* make sure it's initialized */ + permut_bang(x); + + + } +} + + + + +static t_int *permut_perform(t_int *w) +{ + + + t_float *in = (float *)(w[3]); + t_float *out = (float *)(w[4]); + t_permutctl *ctl = (t_permutctl *)(w[1]); + t_int i; + t_int n = (t_int)(w[2]); + t_float x,y; + t_int *p = ctl->c_permutationtable; + + + if (in != out) + for (i=0; i<n; i++) out[i] = in[i]; + + + permut_perform_permutation(out, n, p); + + return (w+5); +} + +static void permut_dsp(t_permut *x, t_signal **sp) +{ + permut_resize_table(x, sp[0]->s_n); + dsp_add(permut_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + +} + +static void permut_free(t_permut *x) +{ + if (x->x_ctl.c_permutationtable) free(x->x_ctl.c_permutationtable); + +} + +t_class *permut_class; + +static void *permut_new(void) +{ + t_permut *x = (t_permut *)pd_new(permut_class); + outlet_new(&x->x_obj, gensym("signal")); + + x->x_ctl.c_permutationtable = 0; + x->x_ctl.c_blocksize = 0; + permut_resize_table(x, 64); + permut_random(x, 0); + + return (void *)x; +} + +void permut_tilde_setup(void) +{ + //post("permut~ v0.1"); + permut_class = class_new(gensym("permut~"), (t_newmethod)permut_new, + (t_method)permut_free, sizeof(t_permut), 0, A_DEFFLOAT, 0); + CLASS_MAINSIGNALIN(permut_class, t_permut, x_f); + class_addmethod(permut_class, (t_method)permut_random, gensym("random"), A_FLOAT, 0); + class_addmethod(permut_class, (t_method)permut_bang, gensym("bang"), 0); + class_addmethod(permut_class, (t_method)permut_dsp, gensym("dsp"), 0); + +} + diff --git a/modules/qmult.c b/modules/qmult.c new file mode 100644 index 0000000..94766e1 --- /dev/null +++ b/modules/qmult.c @@ -0,0 +1,165 @@ +/* + * qmult.c - quaternion multiplication dsp object + * 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> + + +typedef struct qmultctl +{ + t_float *c_inputleft[4]; + t_float *c_inputright[4]; + t_float *c_output[4]; +} t_qmultctl; + +typedef struct qmult +{ + t_object x_obj; + t_float x_f; + t_qmultctl x_ctl; +} t_qmult; + + +static t_int *qmult_perform(t_int *word) +{ + + + + t_qmultctl *ctl = (t_qmultctl *)(word[1]); + t_int n = (t_int)(word[2]); + t_int i; + + t_float *in0l = ctl->c_inputleft[0]; + t_float *in1l = ctl->c_inputleft[1]; + t_float *in2l = ctl->c_inputleft[2]; + t_float *in3l = ctl->c_inputleft[3]; + + t_float *in0r = ctl->c_inputright[0]; + t_float *in1r = ctl->c_inputright[1]; + t_float *in2r = ctl->c_inputright[2]; + t_float *in3r = ctl->c_inputright[3]; + + t_float *out0 = ctl->c_output[0]; + t_float *out1 = ctl->c_output[1]; + t_float *out2 = ctl->c_output[2]; + t_float *out3 = ctl->c_output[3]; + + t_float wl, xl, yl, zl; + t_float wr, xr, yr, zr; + t_float w, x, y, z; + + for (i=0;i<n;i++) + { + + /* read input quaternions */ + wl = *in0l++; + xl = *in1l++; + yl = *in2l++; + zl = *in3l++; + + wr = *in0r++; + xr = *in1r++; + yr = *in2r++; + zr = *in3r++; + + + /* multiply quaternions */ + w = wl * wr; + x = wl * xr; + y = wl * yr; + z = wl * zr; + + w -= xl * xr; + x += xl * wr; + y -= xl * zr; + z += xl * yr; + + w -= yl * yr; + x += yl * zr; + y += yl * wr; + z -= yl * xr; + + w -= zl * zr; + x -= zl * yr; + y += zl * xr; + z += zl * wr; + + + + /* write output quaternion */ + *out0++ = w; + *out1++ = x; + *out2++ = y; + *out3++ = z; + } + + + return (word+3); +} + + + +static void qmult_dsp(t_qmult *x, t_signal **sp) +{ + + int i; + for (i=0;i<4;i++) + { + x->x_ctl.c_inputleft[i] = sp[i]->s_vec; + x->x_ctl.c_inputright[i] = sp[i+4]->s_vec; + x->x_ctl.c_output[i] = sp[i+8]->s_vec; + } + + dsp_add(qmult_perform, 2, &x->x_ctl, sp[0]->s_n); + + +} + + +static void qmult_free(t_qmult *x) +{ + +} + +t_class *qmult_class; + +static void *qmult_new(t_floatarg channels) +{ + int i; + t_qmult *x = (t_qmult *)pd_new(qmult_class); + + for (i=1;i<8;i++) inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal")); + for (i=0;i<4;i++) outlet_new(&x->x_obj, gensym("signal")); + + return (void *)x; +} + +void qmult_tilde_setup(void) +{ + //post("qmult~ v0.1"); + qmult_class = class_new(gensym("qmult~"), (t_newmethod)qmult_new, + (t_method)qmult_free, sizeof(t_qmult), 0, 0); + CLASS_MAINSIGNALIN(qmult_class, t_qmult, x_f); + class_addmethod(qmult_class, (t_method)qmult_dsp, gensym("dsp"), 0); + +} + diff --git a/modules/qnorm.c b/modules/qnorm.c new file mode 100644 index 0000000..e826b1b --- /dev/null +++ b/modules/qnorm.c @@ -0,0 +1,137 @@ +/* + * qnorm.c - quaternion normalization dsp object + * 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> + + +typedef struct qnormctl +{ + t_float *c_input[4]; + t_float *c_output[4]; +} t_qnormctl; + +typedef struct qnorm +{ + t_object x_obj; + t_float x_f; + t_qnormctl x_ctl; +} t_qnorm; + + +static t_int *qnorm_perform(t_int *word) +{ + + + + t_qnormctl *ctl = (t_qnormctl *)(word[1]); + t_int n = (t_int)(word[2]); + t_int i; + + t_float *in0 = ctl->c_input[0]; + t_float *in1 = ctl->c_input[1]; + t_float *in2 = ctl->c_input[2]; + t_float *in3 = ctl->c_input[3]; + + t_float *out0 = ctl->c_output[0]; + t_float *out1 = ctl->c_output[1]; + t_float *out2 = ctl->c_output[2]; + t_float *out3 = ctl->c_output[3]; + + t_float w, x, y, z; + t_float norm; + t_float inorm; + + for (i=0;i<n;i++) + { + + /* read input */ + w = *in0++; + x = *in1++; + y = *in2++; + z = *in3++; + + /* transform */ + norm = w * w; + norm += x * x; + norm += y * y; + norm += z * z; + + inorm = (norm == 0.0f) ? (0.0f) : (1.0f / sqrt(norm)); + + /* write output */ + *out0++ = w * inorm; + *out1++ = x * inorm; + *out2++ = y * inorm; + *out3++ = z * inorm; + } + + + return (word+3); +} + + + +static void qnorm_dsp(t_qnorm *x, t_signal **sp) +{ + + int i; + for (i=0;i<4;i++) + { + x->x_ctl.c_input[i] = sp[i]->s_vec; + x->x_ctl.c_output[i] = sp[i+4]->s_vec; + } + + dsp_add(qnorm_perform, 2, &x->x_ctl, sp[0]->s_n); + + +} + + +static void qnorm_free(t_qnorm *x) +{ + +} + +t_class *qnorm_class; + +static void *qnorm_new(t_floatarg channels) +{ + int i; + t_qnorm *x = (t_qnorm *)pd_new(qnorm_class); + + for (i=1;i<4;i++) inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal")); + for (i=0;i<4;i++) outlet_new(&x->x_obj, gensym("signal")); + + return (void *)x; +} + +void qnorm_tilde_setup(void) +{ + //post("qnorm~ v0.1"); + qnorm_class = class_new(gensym("qnorm~"), (t_newmethod)qnorm_new, + (t_method)qnorm_free, sizeof(t_qnorm), 0, 0); + CLASS_MAINSIGNALIN(qnorm_class, t_qnorm, x_f); + class_addmethod(qnorm_class, (t_method)qnorm_dsp, gensym("dsp"), 0); + +} + diff --git a/modules/ramp.c b/modules/ramp.c new file mode 100644 index 0000000..ad13582 --- /dev/null +++ b/modules/ramp.c @@ -0,0 +1,118 @@ +/* + * ramp.c - retriggerable counter for dsp signals + * 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> + + +typedef struct rampctl +{ + t_float c_offset; + t_float c_looppoint; +} t_rampctl; + +typedef struct ramp +{ + 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; + +} + + +void ramp_bang(t_ramp *x) +{ + 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; + + + + x = ctl->c_offset; + + for (i = 0; i < n; i++) + { + *out++ = (float)x++; + } + + ctl->c_offset = x; /* save state */ + + + return (w+4); +} + +static void ramp_dsp(t_ramp *x, t_signal **sp) +{ + dsp_add(ramp_perform, 3, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec); + +} +void ramp_free(void) +{ + +} + +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")); + + ramp_bang(x); + 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_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/ratio.c b/modules/ratio.c new file mode 100644 index 0000000..777f2b9 --- /dev/null +++ b/modules/ratio.c @@ -0,0 +1,66 @@ +/* + * ratio.c - multiplies by 2^k such that output is between 1 and 2 + * 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" + +#define SEQL 16 + +typedef struct{ +} t_ratio_data; + +typedef struct ratio +{ + t_object t_ob; + t_outlet *x_out; + t_ratio_data x_c; +} t_ratio; + +static void ratio_float(t_ratio *x, t_floatarg f) +{ + f = (f<0)?(-f):(f); + if (f) + { + while (f < 1.0f) f *= 2.0f; + while (f >= 2.0f) f *= 0.5f; + } + outlet_float(x->x_out, f); + +} + +static void ratio_free(void) +{ +} + +t_class *ratio_class; + +static void *ratio_new(void) +{ + t_ratio *x = (t_ratio *)pd_new(ratio_class); + x->x_out = outlet_new(&x->t_ob, gensym("float")); + return (void *)x; +} + +void ratio_setup(void) +{ + ratio_class = class_new(gensym("ratio"), (t_newmethod)ratio_new, + (t_method)ratio_free, sizeof(t_ratio), 0, 0); + class_addfloat(ratio_class, ratio_float); +} + diff --git a/modules/statwav.c b/modules/statwav.c new file mode 100644 index 0000000..52c6a0b --- /dev/null +++ b/modules/statwav.c @@ -0,0 +1,149 @@ +/* + * dynwav.c - static wavetable oscillator (scale + tabread) + * 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> + +static t_class *statwav_tilde_class; + +typedef struct _statwav_tilde +{ + t_object x_obj; + int x_npoints; + float *x_vec; + t_symbol *x_arrayname; + float x_f; +} t_statwav_tilde; + +static void *statwav_tilde_new(t_symbol *s) +{ + t_statwav_tilde *x = (t_statwav_tilde *)pd_new(statwav_tilde_class); + x->x_arrayname = s; + x->x_vec = 0; + outlet_new(&x->x_obj, gensym("signal")); + x->x_f = 0; + return (x); +} + +static t_int *statwav_tilde_perform(t_int *w) +{ + t_statwav_tilde *x = (t_statwav_tilde *)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + float maxindex; + int imaxindex; + float *buf = x->x_vec, *fp; + int i; + + maxindex = x->x_npoints; + imaxindex = x->x_npoints; + + if (!buf) goto zero; + + + for (i = 0; i < n; i++) + { + float phase = *in++; + float modphase = phase - (int)phase; + float findex = modphase * maxindex; + int index = findex; + int ia, ib, ic, id; + float frac, a, b, c, d, cminusb; + static int count; + + + frac = findex - index; + ia = (imaxindex+index-1) % imaxindex; + ib = index; + ic = (index+1) % imaxindex; + id = (index+2) % imaxindex; + + a = buf[ia]; + b = buf[ib]; + c = buf[ic]; + d = buf[id]; + /* if (!i && !(count++ & 1023)) + post("fp = %lx, shit = %lx, b = %f", fp, buf->b_shit, b); */ + cminusb = c-b; + + *out++ = b + frac * ( + cminusb - 0.5f * (frac-1.) * ( + (a - d + 3.0f * cminusb) * frac + (b - a - cminusb) + ) + ); + } + + return (w+5); + zero: + while (n--) *out++ = 0; + + return (w+5); +} + +static void statwav_tilde_set(t_statwav_tilde *x, t_symbol *s) +{ + t_garray *a; + + x->x_arrayname = s; + if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) + { + if (*s->s_name) + error("statwav~: %s: no such array", x->x_arrayname->s_name); + x->x_vec = 0; + } + else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec)) + { + error("%s: bad template for statwav~", x->x_arrayname->s_name); + x->x_vec = 0; + } + else garray_usedindsp(a); +} + +static void statwav_tilde_dsp(t_statwav_tilde *x, t_signal **sp) +{ + statwav_tilde_set(x, x->x_arrayname); + + dsp_add(statwav_tilde_perform, 4, x, + sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); + +} + +static void statwav_tilde_free(t_statwav_tilde *x) +{ +} + +void statwav_tilde_setup(void) +{ + //post("statwav~ v0.1"); + statwav_tilde_class = class_new(gensym("statwav~"), + (t_newmethod)statwav_tilde_new, (t_method)statwav_tilde_free, + sizeof(t_statwav_tilde), 0, A_DEFSYM, 0); + CLASS_MAINSIGNALIN(statwav_tilde_class, t_statwav_tilde, x_f); + class_addmethod(statwav_tilde_class, (t_method)statwav_tilde_dsp, + gensym("dsp"), 0); + class_addmethod(statwav_tilde_class, (t_method)statwav_tilde_set, + gensym("set"), A_SYMBOL, 0); +} + diff --git a/modules/tabreadmix.c b/modules/tabreadmix.c new file mode 100644 index 0000000..91181c5 --- /dev/null +++ b/modules/tabreadmix.c @@ -0,0 +1,271 @@ +/* + * tabreadmix.c - an overlap add tabread~ clone + * 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 "extlib_util.h" + +/******************** tabreadmix~ ***********************/ + +static t_class *tabreadmix_tilde_class; + +typedef struct _tabreadmix_tilde +{ + t_object x_obj; + int x_npoints; + float *x_vec; + t_symbol *x_arrayname; + float x_f; + + /* file position vars */ + int x_currpos; + int x_prevpos; + + /* cross fader state vars */ + int x_xfade_size; + int x_xfade_phase; + float x_xfade_cos; + float x_xfade_sin; + float x_xfade_state_c; + float x_xfade_state_s; + +} t_tabreadmix_tilde; + + + +inline void tabreadmix_tilde_wrapindices(t_tabreadmix_tilde *x) +{ + int max; + + /* modulo */ + x->x_currpos %= x->x_npoints; + x->x_prevpos %= x->x_npoints; + + /* make sure 0<=..<x->x_npoints */ + //if (x->x_currpos < 0) x->x_currpos += x->x_npoints; + //if (x->x_prevpos < 0) x->x_prevpos += x->x_npoints; + x->x_currpos += (x->x_currpos < 0) * x->x_npoints; + x->x_prevpos += (x->x_prevpos < 0) * x->x_npoints; + +} + + + +#define min(x,y) ((x)<(y)?(x):(y)) + +static t_int *tabreadmix_tilde_perform(t_int *w) +{ + t_tabreadmix_tilde *x = (t_tabreadmix_tilde *)(w[1]); + t_float *pos = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + int maxxindex; + float *buf = x->x_vec; + int i; + float currgain, prevgain; + float c,s; + int chunk; + int leftover; + int newpos = (int)*pos; + + maxxindex = x->x_npoints; + if (!buf) goto zero; + if (maxxindex <= 0) goto zero; + + + while (n){ + + /* process as much data as possible */ + leftover = x->x_xfade_size - x->x_xfade_phase; + chunk = min(n, leftover); + + for (i = 0; i < chunk; i++){ + /* compute crossfade gains from oscillator state */ + currgain = 0.5f - x->x_xfade_state_c; + prevgain = 0.5f + x->x_xfade_state_c; + + /* check indices & wrap */ + tabreadmix_tilde_wrapindices(x); + + /* mix and write */ + newpos = (int)(*pos++); + *out++ = currgain * buf[x->x_currpos++] + prevgain * buf[x->x_prevpos++]; + + /* advance oscillator */ + c = x->x_xfade_state_c * x->x_xfade_cos - x->x_xfade_state_s * x->x_xfade_sin; + s = x->x_xfade_state_c * x->x_xfade_sin + x->x_xfade_state_s * x->x_xfade_cos; + x->x_xfade_state_c = c; + x->x_xfade_state_s = s; + } + + /* update indices */ + x->x_xfade_phase += chunk; + n -= chunk; + //pos += chunk; + + /* check if prev chunk is finished */ + if (x->x_xfade_size == x->x_xfade_phase){ + x->x_prevpos = x->x_currpos; + x->x_currpos = newpos; + x->x_xfade_state_c = 0.5f; + x->x_xfade_state_s = 0.0f; + x->x_xfade_phase = 0; + } + + } + + /* return if we ran out of data */ + return (w+5); + + + zero: + while (n--) *out++ = 0; + return (w+5); +} + + +static void tabreadmix_tilde_blocksize(t_tabreadmix_tilde *x, t_float size) +{ + double prev_phase; + int max; + float fmax = (float)x->x_npoints * 0.5f; + + if (size < 1.0) size = 1.0; + + prev_phase = (double)x->x_xfade_phase; + prev_phase *= size; + prev_phase /= (double)x->x_xfade_size; + + + /* preserve the crossfader state */ + x->x_xfade_phase = (int)prev_phase; + x->x_xfade_size = (int)size; + + + x->x_xfade_cos = cos(M_PI / (float)x->x_xfade_size); + x->x_xfade_sin = sin(M_PI / (float)x->x_xfade_size); + + + /* make sure indices are inside array */ + if (x->x_npoints == 0){ + x->x_currpos = 0; + x->x_prevpos = 0; + } + + //else tabreadmix_tilde_wrapindices(x); + + + +} + +void tabreadmix_tilde_pitch(t_tabreadmix_tilde *x, t_float f) +{ + if (f < 1) f = 1; + + tabreadmix_tilde_blocksize(x, sys_getsr() / f); +} + +void tabreadmix_tilde_chunks(t_tabreadmix_tilde *x, t_float f) +{ + if (f < 1.0f) f = 1.0f; + tabreadmix_tilde_blocksize(x, (float)x->x_npoints / f); +} + +void tabreadmix_tilde_bang(t_tabreadmix_tilde *x, t_float f) +{ + //trigger a chunk reset on next dsp call + x->x_xfade_phase = x->x_xfade_size; +} + +void tabreadmix_tilde_set(t_tabreadmix_tilde *x, t_symbol *s) +{ + t_garray *a; + + x->x_arrayname = s; + if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) + { + if (*s->s_name) + error("tabreadmix~: %s: no such array", x->x_arrayname->s_name); + x->x_vec = 0; + } + else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec)) + { + error("%s: bad template for tabreadmix~", x->x_arrayname->s_name); + x->x_vec = 0; + } + else garray_usedindsp(a); + + /* make sure indices are inside array */ + if (x->x_npoints == 0){ + x->x_currpos = 0; + x->x_prevpos = 0; + } + + //else tabreadmix_tilde_wrapindices(x); + +} + +static void tabreadmix_tilde_dsp(t_tabreadmix_tilde *x, t_signal **sp) +{ + tabreadmix_tilde_set(x, x->x_arrayname); + + dsp_add(tabreadmix_tilde_perform, 4, x, + sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); + +} + +static void tabreadmix_tilde_free(t_tabreadmix_tilde *x) +{ +} + +static void *tabreadmix_tilde_new(t_symbol *s) +{ + t_tabreadmix_tilde *x = (t_tabreadmix_tilde *)pd_new(tabreadmix_tilde_class); + x->x_arrayname = s; + x->x_vec = 0; + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("blocksize")); + outlet_new(&x->x_obj, gensym("signal")); + x->x_f = 0; + x->x_xfade_phase = 0; + x->x_xfade_size = 1024; + x->x_currpos = 0; + x->x_prevpos = 0; + x->x_xfade_state_c = 0.5f; + x->x_xfade_state_s = 0.0f; + tabreadmix_tilde_blocksize(x, 1024); + return (x); +} + +void tabreadmix_tilde_setup(void) +{ + tabreadmix_tilde_class = class_new(gensym("tabreadmix~"), + (t_newmethod)tabreadmix_tilde_new, (t_method)tabreadmix_tilde_free, + sizeof(t_tabreadmix_tilde), 0, A_DEFSYM, 0); + CLASS_MAINSIGNALIN(tabreadmix_tilde_class, t_tabreadmix_tilde, x_f); + class_addmethod(tabreadmix_tilde_class, (t_method)tabreadmix_tilde_dsp, + gensym("dsp"), 0); + class_addmethod(tabreadmix_tilde_class, (t_method)tabreadmix_tilde_set, + gensym("set"), A_SYMBOL, 0); + class_addmethod(tabreadmix_tilde_class, (t_method)tabreadmix_tilde_blocksize, + gensym("blocksize"), A_FLOAT, 0); + class_addmethod(tabreadmix_tilde_class, (t_method)tabreadmix_tilde_pitch, + gensym("pitch"), A_FLOAT, 0); + class_addmethod(tabreadmix_tilde_class, (t_method)tabreadmix_tilde_chunks, + gensym("chunks"), A_FLOAT, 0); + class_addmethod(tabreadmix_tilde_class, (t_method)tabreadmix_tilde_bang, + gensym("bang"), 0); +} diff --git a/modules/xfm.c b/modules/xfm.c new file mode 100644 index 0000000..63c79ab --- /dev/null +++ b/modules/xfm.c @@ -0,0 +1,271 @@ +/* + * xfm.c - cross frequency modulation object + * 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. + */ + + +/* +coupled fm. osc state equations: + +phasor for system i = + + [ 1 -phi ] +(1+phi^2)^(1/2) * [ phi 1 ] + + +with phi = 2*pi*(freq_base + freq_mod * out_other) / sr + + +ideal phasor would be + +[ cos(phi) - sin(phi) ] +[ sin(phi) cos(phi) ] + + +this means frequencies are warped: + +2*pi*f_real = atan(2*pi*f) + +some (possible) enhancements: + + add an integrator to get phase modulation + + undo the frequency warping + +*/ + +#include "m_pd.h" +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define SINSAMPLES 512 +#define MYPI 3.1415927 + + +#define DISTORTED 0 +#define NORMALIZED 1 + + +typedef struct xfmctl +{ + //t_float c_sintab[SINSAMPLES + 1]; + t_float c_x1, c_y1; /* state osc 1 */ + t_float c_x2, c_y2; /* state osc 2 */ + t_int c_type; /* type of algo */ + +} t_xfmctl; + +typedef struct xfm +{ + t_object x_obj; + t_float x_f; + t_xfmctl x_ctl; +} t_xfm; + +void xfm_type(t_xfm *x, t_float f) +{ + int t = (int)f; + + if (t == DISTORTED) x->x_ctl.c_type = t; + if (t == NORMALIZED) x->x_ctl.c_type = t; + +} + + +static inline t_float xfm_sat(t_float x) +{ + const float max = 1; + const float min = -1; + + x = (x > max) ? (max) : (x); + x = (x < min) ? (min) : (x); + + return(x); +} + +static t_int *xfm_perform(t_int *w) +{ + + + t_float *inA = (float *)(w[3]); + t_float *inB = (float *)(w[4]); + t_float *fbA = (float *)(w[5]); + t_float *fbB = (float *)(w[6]); + t_float *outA = (float *)(w[7]); + t_float *outB = (float *)(w[8]); + t_xfmctl *ctl = (t_xfmctl *)(w[1]); + t_int n = (t_int)(w[2]); + //t_float *tab = ctl->c_sintab; + + t_float x1 = ctl->c_x1, y1 = ctl->c_y1, z1, dx1, dy1, inv_norm1; + t_float x2 = ctl->c_x2, y2 = ctl->c_y2, z2, dx2, dy2, inv_norm2; + + t_float scale = 2 * M_PI / sys_getsr(); + + t_int i; + + switch(ctl->c_type){ + default: + case DISTORTED: + + /* this is a 4 degree of freedom hyperchaotic system */ + /* two coupled saturated unstable oscillators */ + + for (i=0; i<n; i++){ + /* osc 1 */ + z1 = scale * (x2 * (*fbA++) + (*inA++)); + + dx1 = x1 - z1*y1; + dy1 = y1 + z1*x1; + + x1 = xfm_sat(dx1); + y1 = xfm_sat(dy1); + + /* osc 2*/ + z2 = scale * (x1 * (*fbB++) + (*inB++)); + + dx2 = x2 - z2*y2; + dy2 = y2 + z2*x2; + + x2 = xfm_sat(dx2); + y2 = xfm_sat(dy2); + + /* output */ + (*outA++) = x1; + (*outB++) = x2; + + } + break; + + case NORMALIZED: + + /* this is a an effective 2 degree of freedom quasiperiodic system */ + /* two coupled stable oscillators */ + + for (i=0; i<n; i++){ + + /* osc 1 */ + z1 = scale * (x2 * (*fbA++) + (*inA++)); + + dx1 = x1 - z1*y1; + dy1 = y1 + z1*x1; + inv_norm1 = 1.0f / hypot(dx1, dy1); + + + /* osc 2*/ + z2 = scale * (x1 * (*fbB++) + (*inB++)); + + dx2 = x2 - z2*y2; + dy2 = y2 + z2*x2; + inv_norm2 = 1.0f / hypot(dx2, dy2); + + /* renormalize */ + x1 = dx1 * inv_norm1; + y1 = dy1 * inv_norm1; + x2 = dx2 * inv_norm2; + y2 = dy2 * inv_norm2; + + /* output */ + (*outA++) = x1; + (*outB++) = x2; + } + break; + } + + ctl->c_x1 = x1; + ctl->c_y1 = y1; + ctl->c_x2 = x2; + ctl->c_y2 = y2; + + return (w+9); +} + +static void xfm_dsp(t_xfm *x, t_signal **sp) +{ + int n = sp[0]->s_n; + int k; + + + dsp_add(xfm_perform, + 8, + &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); + + +} +static void xfm_free(t_xfm *x) +{ + + +} + + + + +static void xfm_reset(t_xfm *x) +{ + x->x_ctl.c_x1 = 1; + x->x_ctl.c_y1 = 0; + x->x_ctl.c_x2 = 1; + x->x_ctl.c_y2 = 0; + +} + + +t_class *xfm_class; + +static void *xfm_new(t_floatarg algotype) +{ + t_xfm *x = (t_xfm *)pd_new(xfm_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")); + + + + /* init data */ + xfm_reset(x); + xfm_type(x, algotype); + + return (void *)x; +} + +void xfm_tilde_setup(void) +{ + //post("xfm~ v0.1"); + xfm_class = class_new(gensym("xfm~"), (t_newmethod)xfm_new, + (t_method)xfm_free, sizeof(t_xfm), 0, A_DEFFLOAT, 0); + CLASS_MAINSIGNALIN(xfm_class, t_xfm, x_f); + class_addmethod(xfm_class, (t_method)xfm_type, gensym("type"), A_FLOAT, 0); + class_addmethod(xfm_class, (t_method)xfm_dsp, gensym("dsp"), 0); + class_addmethod(xfm_class, (t_method)xfm_reset, gensym("reset"), 0); + + +} + |