/* * Copyright (c) 1997-1999 Mark Danks. * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt" in this distribution. */ /* Original code by Miller Puckette */ /* a non-interpolating reson filter, not very carefully coded... */ /* 11/29/94 modified to do interpolation - M. Danks */ #include "m_pd.h" #include #define BUFSIZE 4096 typedef struct resonctl { float c_freq; float c_samprate; float c_feedback; int c_delayinsamps; float c_fraction; int c_phase; float *c_buf; } t_resonctl; typedef struct sigreson { t_object x_obj; /* header */ t_resonctl *x_ctl; /* pointer to state */ t_resonctl x_cspace; /* garage for state when not in a chain */ } t_sigreson; /* the DSP routine -- called for every n samples of input */ static t_int *cu_reson(t_int *w) { t_float *in1 = (t_float *)(w[1]); t_float *in2 = (t_float *)(w[2]); t_float *out = (t_float *)(w[3]); t_resonctl *x = (t_resonctl *)(w[4]); int n = (int)(w[5]); long i; int writephase = x->c_phase; for (i = 0; i < n; i++) { /* note two tricks: 1. input is read before output * is written, because the routine might be called * in-place; * 2 - a seed of 1E-20 is thrown in to avoid floating * underflow which slows the calculation down. */ int readphase, phase, delayinsamps; float fraction, f, g, freq, freqtemp; float ftemp; freq = *in2++; freqtemp = (freq < 1 ? 1 : freq); ftemp = x->c_samprate/freqtemp; if (ftemp >= BUFSIZE-1) ftemp = BUFSIZE - 1.f; else if (ftemp < 1.0) ftemp = 1.f; delayinsamps = (int)ftemp; fraction = ftemp - delayinsamps; readphase = writephase - delayinsamps; phase = readphase & (BUFSIZE-1); f = x->c_buf[phase] + fraction * (x->c_buf[(phase-1)& (BUFSIZE-1)] - x->c_buf[phase]); g = *in1++; *out++ = x->c_buf[(writephase++) & (BUFSIZE-1)] = g + x->c_feedback * f + 1E-20f; } x->c_phase = writephase & (BUFSIZE-1); return (w+6); } /* sets the reson frequency */ void sigreson_float(t_sigreson *x, t_floatarg f) { float ftemp; x->x_ctl->c_freq = (f < 1 ? 1 : f); ftemp = x->x_ctl->c_samprate/x->x_ctl->c_freq; if (ftemp >= BUFSIZE - 1) ftemp = BUFSIZE - 1.f; else if (ftemp < 1.0) ftemp = 1.f; x->x_ctl->c_delayinsamps = (int)ftemp; x->x_ctl->c_fraction = ftemp - x->x_ctl->c_delayinsamps; } /* routine which FTS calls to put you on the DSP chain or take you off. */ static void sigreson_dsp(t_sigreson *x, t_signal **sp) { x->x_ctl->c_samprate = sp[0]->s_sr; sigreson_float(x, x->x_ctl->c_freq); dsp_add(cu_reson, 5, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, x->x_ctl, sp[0]->s_n); } static void sigreson_ft1(t_sigreson *x, t_floatarg f) /* sets feedback */ { if (f > .99999) f = .99999f; else if (f < -.99999) f = -.99999f; x->x_ctl->c_feedback = (float)f; } static void sigreson_ff(t_sigreson *x) /* cleanup on free */ { free(x->x_ctl->c_buf); } static t_class *sigreson_class; void *sigreson_new(t_floatarg f, t_floatarg g) { t_sigreson *x = (t_sigreson *)pd_new(sigreson_class); outlet_new(&x->x_obj, &s_signal); /* things in "cspace" are things you'll actually use at DSP time */ x->x_cspace.c_phase = 0; if (!(x->x_cspace.c_buf = (float *)malloc(BUFSIZE * sizeof(float)))) { error("buffer alloc failed"); return (0); } x->x_cspace.c_samprate = 44100.f; /* just a plausible default */ /* control block is in the garage at startup */ x->x_ctl = &x->x_cspace; sigreson_float(x, (t_float)f); /* setup params */ sigreson_ft1(x, g); /* make a "float" inlet */ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1")); return (x); } void reson_tilde_setup(void) { sigreson_class = class_new(gensym("reson~"), (t_newmethod)sigreson_new, (t_method)sigreson_ff, sizeof(t_sigreson), 0, A_DEFFLOAT, A_DEFFLOAT, 0); class_addfloat(sigreson_class, (t_method)sigreson_float); class_addmethod(sigreson_class, (t_method)sigreson_ft1, gensym("ft1"), A_FLOAT, 0); class_addmethod(sigreson_class, (t_method)nullfn, &s_signal, A_NULL); class_addmethod(sigreson_class, (t_method)sigreson_dsp, gensym("dsp"), A_NULL); }