/* Copyright (c) 1997-1999 Miller Puckette. * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ #include "m_pd.h" #include "iemlib.h" #include "iem_dp.h" #define DEFDELVS_TT 64 /* LATER get this from canvas at DSP time */ #define XTRASAMPS_TT 4 #define SAMPBLK_TT 4 /* ----------------------------- delwrite~~ ----------------------------- */ typedef struct delwrite_tilde_tilde_ctl { int c_n; t_sample *c_vec; int c_phase; } t_delwrite_tilde_tilde_ctl; typedef struct _delwrite_tilde_tilde { t_object x_obj; t_symbol *x_sym; double x_deltime; t_delwrite_tilde_tilde_ctl x_cspace; int x_sortno; /* DSP sort number at which this was last put on chain */ int x_rsortno; /* DSP sort # for first delread or write in chain */ int x_vecsize; /* vector size for delread~ to use */ t_float x_f; } t_delwrite_tilde_tilde; //extern static int delread_zero; static t_class *delwrite_tilde_tilde_class; static void delwrite_tilde_tilde_updatesr (t_delwrite_tilde_tilde *x, t_float sr) /* added by Mathieu Bouchard */ { int nsamps = (int)(x->x_deltime * (double)sr * (double)(0.001)); if (nsamps < 1) nsamps = 1; nsamps += ((- nsamps) & (SAMPBLK_TT - 1)); nsamps += DEFDELVS_TT; if(x->x_cspace.c_n != nsamps) { x->x_cspace.c_vec = (t_sample *)resizebytes(x->x_cspace.c_vec, (x->x_cspace.c_n + XTRASAMPS_TT) * sizeof(t_sample), (nsamps + XTRASAMPS_TT) * sizeof(t_sample)); x->x_cspace.c_n = nsamps; x->x_cspace.c_phase = XTRASAMPS_TT; } } /* routine to check that all delwrites/delreads/vds have same vecsize */ static void delwrite_tilde_tilde_checkvecsize(t_delwrite_tilde_tilde *x, int vecsize) { if (x->x_rsortno != ugen_getsortno()) { x->x_vecsize = vecsize; x->x_rsortno = ugen_getsortno(); } /* LATER this should really check sample rate and blocking, once that is supported. Probably we don't actually care about vecsize. For now just suppress this check. */ #if 0 else if (vecsize != x->x_vecsize) pd_error(x, "delread/delwrite/vd vector size mismatch"); #endif } static void *delwrite_tilde_tilde_new(t_symbol *s, t_floatarg coarse_msec, t_floatarg fine_msec) { t_delwrite_tilde_tilde *x = (t_delwrite_tilde_tilde *)pd_new(delwrite_tilde_tilde_class); if(!*s->s_name) s = gensym("delwrite~~"); pd_bind(&x->x_obj.ob_pd, s); x->x_sym = s; x->x_deltime = iem_dp_calc_sum(coarse_msec, fine_msec); x->x_cspace.c_n = 0; x->x_cspace.c_vec = (t_sample *)getbytes(XTRASAMPS_TT * sizeof(t_sample)); x->x_sortno = 0; x->x_vecsize = 0; x->x_f = 0; return (x); } static t_int *delwrite_tilde_tilde_perform(t_int *w) { t_float *in = (t_float *)(w[1]); t_delwrite_tilde_tilde_ctl *c = (t_delwrite_tilde_tilde_ctl *)(w[2]); int n = (int)(w[3]); int phase = c->c_phase, nsamps = c->c_n; t_sample *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS_TT); phase += n; while (n--) { t_sample f = *in++; if(IEM_DENORMAL(f)) f = 0; *bp++ = f; if (bp == ep) { vp[0] = ep[-4]; vp[1] = ep[-3]; vp[2] = ep[-2]; vp[3] = ep[-1]; bp = vp + XTRASAMPS_TT; phase -= nsamps; } } c->c_phase = phase; return (w+4); } static void delwrite_tilde_tilde_dsp(t_delwrite_tilde_tilde *x, t_signal **sp) { dsp_add(delwrite_tilde_tilde_perform, 3, sp[0]->s_vec, &x->x_cspace, sp[0]->s_n); x->x_sortno = ugen_getsortno(); delwrite_tilde_tilde_checkvecsize(x, sp[0]->s_n); delwrite_tilde_tilde_updatesr(x, sp[0]->s_sr); } static void delwrite_tilde_tilde_free(t_delwrite_tilde_tilde *x) { pd_unbind(&x->x_obj.ob_pd, x->x_sym); freebytes(x->x_cspace.c_vec, (x->x_cspace.c_n + XTRASAMPS_TT) * sizeof(t_sample)); } static void delwrite_tilde_tilde_setup(void) { delwrite_tilde_tilde_class = class_new(gensym("delwrite~~"), (t_newmethod)delwrite_tilde_tilde_new, (t_method)delwrite_tilde_tilde_free, sizeof(t_delwrite_tilde_tilde), 0, A_DEFSYM, A_DEFFLOAT, A_DEFFLOAT, 0); CLASS_MAINSIGNALIN(delwrite_tilde_tilde_class, t_delwrite_tilde_tilde, x_f); class_addmethod(delwrite_tilde_tilde_class, (t_method)delwrite_tilde_tilde_dsp, gensym("dsp"), 0); } /* ----------------------------- delread~~ ----------------------------- */ static t_class *delread_tilde_tilde_class; typedef struct _delread_tilde_tilde { t_object x_obj; t_symbol *x_sym; t_float x_fine; double x_deltime; /* delay in msec */ int x_delsamps; /* delay in samples */ t_float x_sr; /* samples per msec */ t_float x_n; /* vector size */ int x_zerodel; /* 0 or vecsize depending on read/write order */ } t_delread_tilde_tilde; static void delread_tilde_tilde_list(t_delread_tilde_tilde *x, t_symbol *s, int ac, t_atom *av); static void *delread_tilde_tilde_new(t_symbol *s, int ac, t_atom *av) { t_symbol *delname; t_delread_tilde_tilde *x = (t_delread_tilde_tilde *)pd_new(delread_tilde_tilde_class); if((ac > 0) && IS_A_SYMBOL(av, 0)) delname = atom_getsymbolarg(0, ac, av); else delname = &s_; x->x_sym = delname; x->x_sr = 1; x->x_n = 1; x->x_zerodel = 0; delread_tilde_tilde_list(x, &s_list, ac-1, av+1); floatinlet_new(&x->x_obj, &x->x_fine); outlet_new(&x->x_obj, &s_signal); return (x); } static void delread_tilde_tilde_list(t_delread_tilde_tilde *x, t_symbol *s, int ac, t_atom *av) { t_float coarse, fine; t_delwrite_tilde_tilde *delwriter = (t_delwrite_tilde_tilde *)pd_findbyclass(x->x_sym, delwrite_tilde_tilde_class); if((ac > 0) && (IS_A_FLOAT(av, 0))) coarse = atom_getfloatarg(0, ac, av); else coarse = 0.0; if((ac > 1) && (IS_A_FLOAT(av, 1))) fine = atom_getfloatarg(1, ac, av); else fine = 0.0; x->x_deltime = iem_dp_calc_sum(coarse, fine); if(delwriter) { int delsize = delwriter->x_cspace.c_n; x->x_delsamps = (int)(0.5 + (double)x->x_sr * x->x_deltime) + x->x_n - x->x_zerodel; if(x->x_delsamps < x->x_n) x->x_delsamps = x->x_n; else if(x->x_delsamps > delwriter->x_cspace.c_n - DEFDELVS_TT) x->x_delsamps = delwriter->x_cspace.c_n - DEFDELVS_TT; } } static void delread_tilde_tilde_double(t_delread_tilde_tilde *x, double d) { t_delwrite_tilde_tilde *delwriter = (t_delwrite_tilde_tilde *)pd_findbyclass(x->x_sym, delwrite_tilde_tilde_class); x->x_deltime = d; if(delwriter) { int delsize = delwriter->x_cspace.c_n; x->x_delsamps = (int)(0.5 + (double)x->x_sr * x->x_deltime) + x->x_n - x->x_zerodel; if(x->x_delsamps < x->x_n) x->x_delsamps = x->x_n; else if(x->x_delsamps > delwriter->x_cspace.c_n - DEFDELVS_TT) x->x_delsamps = delwriter->x_cspace.c_n - DEFDELVS_TT; } } static void delread_tilde_tilde_float(t_delread_tilde_tilde *x, t_float coarse) { t_delwrite_tilde_tilde *delwriter = (t_delwrite_tilde_tilde *)pd_findbyclass(x->x_sym, delwrite_tilde_tilde_class); x->x_deltime = iem_dp_calc_sum(coarse, x->x_fine); if(delwriter) { int delsize = delwriter->x_cspace.c_n; x->x_delsamps = (int)(0.5 + (double)x->x_sr * x->x_deltime) + x->x_n - x->x_zerodel; if(x->x_delsamps < x->x_n) x->x_delsamps = x->x_n; else if(x->x_delsamps > delwriter->x_cspace.c_n - DEFDELVS_TT) x->x_delsamps = delwriter->x_cspace.c_n - DEFDELVS_TT; } } static t_int *delread_tilde_tilde_perform(t_int *w) { t_sample *out = (t_float *)(w[1]); t_delwrite_tilde_tilde_ctl *c = (t_delwrite_tilde_tilde_ctl *)(w[2]); int delsamps = *(int *)(w[3]); int n = (int)(w[4]); int phase = c->c_phase - delsamps, nsamps = c->c_n; t_sample *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS_TT); if(phase < 0) phase += nsamps; bp = vp + phase; while(n--) { *out++ = *bp++; if(bp == ep) bp -= nsamps; } return (w+5); } static void delread_tilde_tilde_dsp(t_delread_tilde_tilde *x, t_signal **sp) { t_delwrite_tilde_tilde *delwriter = (t_delwrite_tilde_tilde *)pd_findbyclass(x->x_sym, delwrite_tilde_tilde_class); x->x_sr = sp[0]->s_sr * 0.001; x->x_n = sp[0]->s_n; if(delwriter) { delwrite_tilde_tilde_checkvecsize(delwriter, sp[0]->s_n); x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ? 0 : delwriter->x_vecsize); delread_tilde_tilde_double(x, x->x_deltime); dsp_add(delread_tilde_tilde_perform, 4, sp[0]->s_vec, &delwriter->x_cspace, &x->x_delsamps, sp[0]->s_n); } else if (*x->x_sym->s_name) error("delread~~: %s: no such delwrite~~",x->x_sym->s_name); } static void delread_tilde_tilde_setup(void) { delread_tilde_tilde_class = class_new(gensym("delread~~"), (t_newmethod)delread_tilde_tilde_new, 0, sizeof(t_delread_tilde_tilde), 0, A_GIMME, 0); class_addmethod(delread_tilde_tilde_class, (t_method)delread_tilde_tilde_dsp, gensym("dsp"), 0); class_addfloat(delread_tilde_tilde_class, (t_method)delread_tilde_tilde_float); } /* ----------------------------- vd~~ ----------------------------- */ static t_class *vd_tilde_tilde_class; typedef struct _vd_tilde_tilde { t_object x_obj; t_symbol *x_sym; t_float x_sr; /* samples per msec */ int x_zerodel; /* 0 or vecsize depending on read/write order */ t_float x_f; } t_vd_tilde_tilde; static void *vd_tilde_tilde_new(t_symbol *s) { t_vd_tilde_tilde *x = (t_vd_tilde_tilde *)pd_new(vd_tilde_tilde_class); if(!*s->s_name) s = gensym("vd~~"); x->x_sym = s; x->x_sr = 1; x->x_zerodel = 0; inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); outlet_new(&x->x_obj, &s_signal); x->x_f = 0; return (x); } static t_int *vd_tilde_tilde_perform(t_int *w) { t_sample *cin = (t_sample *)(w[1]); t_sample *fin = (t_sample *)(w[2]); t_sample *out = (t_sample *)(w[3]); t_delwrite_tilde_tilde_ctl *ctl = (t_delwrite_tilde_tilde_ctl *)(w[4]); t_vd_tilde_tilde *x = (t_vd_tilde_tilde *)(w[5]); int n = (int)(w[6]); int nsamps = ctl->c_n; double limit = (double)nsamps - (double)n - 1.0; t_sample fn = n-1; t_sample *vp = ctl->c_vec, *bp, *wp = vp + ctl->c_phase; t_sample zerodel = x->x_zerodel; while (n--) { double delsamps = (double)x->x_sr * iem_dp_calc_sum(*cin++, *fin++) - (double)zerodel; t_sample frac; int idelsamps; t_sample a, b, c, d, cminusb; if(delsamps < 1.00001) delsamps = 1.00001; if(delsamps > limit) delsamps = limit; delsamps += (double)fn; fn = fn - 1.0f; idelsamps = (int)delsamps; frac = (t_sample)(delsamps - (double)idelsamps); bp = wp - idelsamps; if(bp < vp + 4) bp += nsamps; d = bp[-3]; c = bp[-2]; b = bp[-1]; a = bp[0]; cminusb = c - b; *out++ = b + frac * ( cminusb - 0.1666667f * (1.-frac) * ( (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b) ) ); } return (w+7); } static void vd_tilde_tilde_dsp(t_vd_tilde_tilde *x, t_signal **sp) { t_delwrite_tilde_tilde *delwriter = (t_delwrite_tilde_tilde *)pd_findbyclass(x->x_sym, delwrite_tilde_tilde_class); x->x_sr = sp[0]->s_sr * 0.001; if(delwriter) { delwrite_tilde_tilde_checkvecsize(delwriter, sp[0]->s_n); x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ? 0 : delwriter->x_vecsize); dsp_add(vd_tilde_tilde_perform, 6, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, &delwriter->x_cspace, x, sp[0]->s_n); } else error("vd~~: %s: no such delwrite~~", x->x_sym->s_name); } static void vd_tilde_tilde_setup(void) { vd_tilde_tilde_class = class_new(gensym("vd~~"), (t_newmethod)vd_tilde_tilde_new, 0, sizeof(t_vd_tilde_tilde), 0, A_DEFSYM, 0); class_addmethod(vd_tilde_tilde_class, (t_method)vd_tilde_tilde_dsp, gensym("dsp"), 0); CLASS_MAINSIGNALIN(vd_tilde_tilde_class, t_vd_tilde_tilde, x_f); } /********************/ void delay_tilde_tilde_setup(void) { delwrite_tilde_tilde_setup(); delread_tilde_tilde_setup(); vd_tilde_tilde_setup(); }