/* notch~.c emulation of a Butterworth type band-reject filter based on the example in Dodge and Jerse "Computer Music" */ #include "ext.h" #include "math.h" #include "z_dsp.h" #define ASSIST_RSRC 9591 // resource number for assistance strings #ifndef PI #define PI 3.14159265358979323846 #endif #ifndef TWOPI #define TWOPI 6.28318530717958647692 #endif void *notch_class; typedef struct _notch { t_pxobject n_obj; float n_CF, n_BW; // center frequency and bandwidth of notch filter float n_xnm1, n_xnm2, n_ynm1, n_ynm2; // store past samples from one perform pass to another float n_oneoversr; // reciprocal of sample rate of input signal void *n_outlet; } t_notch; void *notch_new(float CF, float BW); t_int *notch_perform(t_int *w); // if signals for both parameters t_int *notch_perform1(t_int *w); // if no signal for CF t_int *notch_perform2(t_int *w); // if no signal for BW t_int *notch_perform3(t_int *w); // if no signals for parameters void notch_int(t_notch *x, long n); void notch_float(t_notch *x, float f); void notch_dsp(t_notch *x, t_signal **sp, short *count); void notch_assist(t_notch *x, void *b, long m, long a, char *s); void notch_free(t_notch *x); void dsp_initclass(void); void main() { setup((t_messlist **)¬ch_class, (method)notch_new,(method)notch_free, (short)sizeof(t_notch), 0L, A_DEFFLOAT, A_DEFFLOAT, 0); addint((method)notch_int); addfloat((method)notch_float); addmess((method)notch_dsp, "dsp", A_CANT, 0); addmess((method)notch_assist,"assist",A_CANT,0); finder_addclass("MSP Filters","notch~"); dsp_initclass(); rescopy('STR#',9591); } void notch_assist(t_notch *x, void *b, long m, long a, char *s) { assist_string(ASSIST_RSRC,m,a,1,4,s); } void notch_int(t_notch *x, long n) { if (x->n_obj.z_in == 1) x->n_CF = (float)n; else if (x->n_obj.z_in == 2) x->n_BW = (float)n; } void notch_float(t_notch *x, float f) { if (x->n_obj.z_in == 1) x->n_CF = f; else if (x->n_obj.z_in == 2) x->n_BW = f; } void *notch_new(float CF, float BW) { t_notch *x; x = (t_notch *)newobject(notch_class); // point to this instance of notch~ dsp_setup((t_pxobject *)x,3); /* create 3 signal inlets */ outlet_new((t_object *)x,"signal"); // create 1 signal outlet x->n_CF = CF; x->n_BW = BW; x->n_xnm1 = x->n_xnm2 = x->n_ynm1 = x->n_ynm2 = 0.0; return x; } void notch_free(t_notch *x) { dsp_free((t_pxobject *)x); } void notch_dsp(t_notch *x, t_signal **sp, short *count) { x->n_oneoversr = 1. / (double)sp[0]->s_sr; if (count[1] && count[2]) { // signals connected for both parameters dsp_add(notch_perform, 6, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[0]->s_n); } else { if (count[2]) { // then !count[1], so no signal for CF dsp_add(notch_perform1, 5, x, sp[0]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[0]->s_n); } else if (count[1]) { // then !count[2], so no signal for BW dsp_add(notch_perform2, 5, x, sp[0]->s_vec, sp[1]->s_vec, sp[3]->s_vec, sp[0]->s_n); } else { // no signal for either CF or BW, so use stored float values dsp_add(notch_perform3, 4, x, sp[0]->s_vec, sp[3]->s_vec, sp[0]->s_n); } } } t_int *notch_perform(t_int *w) { // if signals for both parameters; 6 arguments t_notch *x; // pointer to this object short n; // vector size (counter variable) float *in, *out; // pointers to input and output signals float *CF, *BW; // pointers to parameter signals float oneoversr; // reciprocal of the input signal sample rate float C, D; // intermediate values for calculating filter coefficients float a0, a1, a2, b1, b2; // filter coefficients float xn, xnm1, xnm2, yn, ynm1, ynm2; // current and past sample values x = (t_notch *)(w[1]); // point to the object in = (float *)(w[2]); // point to the input signal CF = (float *)(w[3]); // point to the center frequency parameter (signal) BW = (float *)(w[4]); // point to the bandwidth parameter (signal) out = (float *)(w[5]); // point to the output signal n = (w[6]); // this is the vector size oneoversr = x->n_oneoversr; // get previously stored sample values xnm1 = x->n_xnm1; xnm2 = x->n_xnm2; ynm1 = x->n_ynm1; ynm2 = x->n_ynm2; // actual filter calculation while (n--) { // for each sample in the vector... xn = *in++; // get current input sample // calculate intermediate values, based on signal parameter inputs C = tan(PI*(*BW++)*oneoversr); D = 2.0*cos(TWOPI*(*CF++)*oneoversr); // calculate filter coefficients for this sample a0 = a2 = 1.0/(1.0+C); a1 = b1 = -1.0*a0*D; b2 = a0*(1.0-C); yn = (a0*xn) + (a1*xnm1) + (a2*xnm2) - (b1*ynm1) - (b2*ynm2); // calculate current output sample *out++ = yn; // output it // store past sample values xnm2 = xnm1; xnm1 = xn; ynm2 = ynm1; ynm1 = yn; } // store all past sample values in object, for use in next perform pass x->n_xnm1 = xnm1; x->n_xnm2 = xnm2; x->n_ynm1 = ynm1; x->n_ynm2 = ynm2; return w+7; // return pointer just beyond arguments } t_int *notch_perform1(t_int *w) { // if no signals for CF parameter; 5 arguments t_notch *x; // pointer to this object short n; // vector size (counter variable) float *in, *out; // pointers to input and output signals float *BW; // pointer to BW parameter signals float oneoversr; // reciprocal of the input signal sample rate float C, D; // intermediate values for calculating filter coefficients float a0, a1, a2, b1, b2; // filter coefficients float xn, xnm1, xnm2, yn, ynm1, ynm2; // current and past sample values x = (t_notch *)(w[1]); // point to the object in = (float *)(w[2]); // point to the input signal BW = (float *)(w[3]); // point to the bandwidth parameter (signal) out = (float *)(w[4]); // point to the output signal n = (w[5]); // this is the vector size oneoversr = x->n_oneoversr; // get previously stored sample values xnm1 = x->n_xnm1; xnm2 = x->n_xnm2; ynm1 = x->n_ynm1; ynm2 = x->n_ynm2; D = 2.0*cos(TWOPI*(x->n_CF)*oneoversr); // calculate intermediate value, based on float input for CF // actual filter calculation while (n--) { // for each sample in the vector... xn = *in++; // get current input sample C = tan(PI*(*BW++)*oneoversr); // calculate intermediate value, based on signal parameter input for BW // calculate filter coefficients for this sample a0 = a2 = 1.0/(1.0+C); a1 = b1 = -1.0*a0*D; b2 = a0*(1.0-C); yn = (a0*xn) + (a1*xnm1) + (a2*xnm2) - (b1*ynm1) - (b2*ynm2); // calculate current output sample *out++ = yn; // output it // store past sample values xnm2 = xnm1; xnm1 = xn; ynm2 = ynm1; ynm1 = yn; } // store all past sample values in object, for use in next perform pass x->n_xnm1 = xnm1; x->n_xnm2 = xnm2; x->n_ynm1 = ynm1; x->n_ynm2 = ynm2; return w+6; // return pointer just beyond arguments } t_int *notch_perform2(t_int *w) { // if no signal for BW parameter; 5 arguments t_notch *x; // pointer to this object short n; // vector size (counter variable) float *in, *out; // pointers to input and output signals float *CF; // pointer to CF parameter signal float oneoversr; // reciprocal of the input signal sample rate float C, D; // intermediate values for calculating filter coefficients float a0, a1, a2, b1, b2; // filter coefficients float xn, xnm1, xnm2, yn, ynm1, ynm2; // current and past sample values x = (t_notch *)(w[1]); // point to the object in = (float *)(w[2]); // point to the input signal CF = (float *)(w[3]); // point to the center frequency parameter (signal) out = (float *)(w[4]); // point to the output signal n = (w[5]); // this is the vector size oneoversr = x->n_oneoversr; // get previously stored sample values xnm1 = x->n_xnm1; xnm2 = x->n_xnm2; ynm1 = x->n_ynm1; ynm2 = x->n_ynm2; C = tan(PI*(x->n_BW)*oneoversr); // calculate intermediate value, based on float parameter input for BW a0 = a2 = 1.0/(1.0+C); // calculate these filter coefficients for the entire vector b2 = a0*(1.0-C); // then calculate this filter coefficient for the entire vector // actual filter calculation while (n--) { // for each sample in the vector... xn = *in++; // get current input sample // calculate this intermediate value, based on signal parameter input for center frequency D = 2.0*cos(TWOPI*(*CF++)*oneoversr); a1 = b1 = -1.0*a0*D; // calculate this filter coefficient for this sample yn = (a0*xn) + (a1*xnm1) + (a2*xnm2) - (b1*ynm1) - (b2*ynm2); // calculate current output sample *out++ = yn; // output it // store past sample values xnm2 = xnm1; xnm1 = xn; ynm2 = ynm1; ynm1 = yn; } // store all past sample values in object, for use in next perform pass x->n_xnm1 = xnm1; x->n_xnm2 = xnm2; x->n_ynm1 = ynm1; x->n_ynm2 = ynm2; return w+6; // return pointer just beyond arguments } t_int *notch_perform3(t_int *w) { // if no signals for parameters; 4 arguments t_notch *x; // pointer to this object short n; // vector size (counter variable) float *in, *out; // pointers to input and output signals float C, D; // intermediate values for calculating filter coefficients float a0, a1, a2, b1, b2; // filter coefficients float xn, xnm1, xnm2, yn, ynm1, ynm2; // current and past sample values x = (t_notch *)(w[1]); // point to the object in = (float *)(w[2]); // point to the input signal out = (float *)(w[3]); // point to the output signal n = (w[4]); // this is the vector size // calculate intermediate values, based on float parameter inputs C = tan(PI*(x->n_BW)*(x->n_oneoversr)); D = 2.0*cos(TWOPI*(x->n_CF)*(x->n_oneoversr)); // calculate filter coefficients for the entire vector a0 = a2 = 1.0/(1.0+C); a1 = b1 = -1.0*a0*D; b2 = a0*(1.0-C); // get previously stored sample values xnm1 = x->n_xnm1; xnm2 = x->n_xnm2; ynm1 = x->n_ynm1; ynm2 = x->n_ynm2; // actual filter calculation while (n--) { // for each sample in the vector... xn = *in++; // get current input sample yn = (a0*xn) + (a1*xnm1) + (a2*xnm2) - (b1*ynm1) - (b2*ynm2); // calculate current output sample *out++ = yn; // output it // store past sample values xnm2 = xnm1; xnm1 = xn; ynm2 = ynm1; ynm1 = yn; } // store all past sample values in object, for use in next perform pass x->n_xnm1 = xnm1; x->n_xnm2 = xnm2; x->n_ynm1 = ynm1; x->n_ynm2 = ynm2; return w+5; // return pointer just beyond arguments }