Max 5 API Reference
00001 /** 00002 @file 00003 lores - A low pass controllable with freq and res 00004 00005 updated 3/22/09 ajm: new API 00006 00007 @ingroup examples 00008 */ 00009 00010 #include "ext.h" 00011 #include "ext_obex.h" 00012 #include "z_dsp.h" 00013 #include <math.h> 00014 00015 #define SMOOTHING_VERSION 0 00016 00017 void *lores_class; 00018 00019 typedef struct _lores 00020 { 00021 t_pxobject l_obj; 00022 float l_freq; // stored cutoff frequency in Hz 00023 float l_r; // stored resonance (0-1) 00024 float l_a1; // computed coefficient 00025 float l_a2; // computer coefficient 00026 float l_a1p; // previous computed coefficient 00027 float l_a2p; // previous computer coefficient 00028 float l_ym1; // previous output sample 00029 float l_ym2; // previous to previous output sample 00030 float l_fqterm; // computed frequency term 00031 float l_resterm; // computer resonance term 00032 float l_2pidsr; // stored value of 2 pi over the sampling rate 00033 short l_rcon; // is a signal connected to the resonance inlet 00034 short l_fcon; // is a signal connected to the frequency inlet 00035 } t_lores; 00036 00037 void lores_dsp(t_lores *x, t_signal **sp, short *count); 00038 t_int *lores_perform(t_int *w); 00039 t_int *lores_perform_unroll(t_int *w); 00040 t_int *lores_perform_unroll_smooth(t_int *w); 00041 void lores_int(t_lores *x, long n); 00042 void lores_float(t_lores *x, double f); 00043 void lores_calc(t_lores *x); 00044 void lores_clear(t_lores *x); 00045 void lores_assist(t_lores *x, void *b, long m, long a, char *s); 00046 void *lores_new(double freq, double reso); 00047 00048 int main(void) 00049 { 00050 t_class *c; 00051 00052 c = class_new("lores~",(method)lores_new, (method)dsp_free, 00053 (short)sizeof(t_lores), 0L, A_DEFFLOAT, A_DEFFLOAT, 0); 00054 class_addmethod(c, (method)lores_dsp, "dsp", A_CANT, 0); 00055 class_addmethod(c, (method)lores_assist, "assist", A_CANT, 0); 00056 class_addmethod(c, (method)lores_clear, "clear", 0); 00057 class_addmethod(c, (method)lores_int, "int", A_LONG, 0); 00058 class_addmethod(c, (method)lores_float, "float", A_FLOAT, 0); 00059 class_dspinit(c); 00060 class_register(CLASS_BOX, c); 00061 lores_class = c; 00062 00063 return 0; 00064 } 00065 00066 void lores_dsp(t_lores *x, t_signal **sp, short *count) 00067 { 00068 x->l_2pidsr = (2. * PI) / sp[0]->s_sr; 00069 lores_calc(x); 00070 x->l_a1p = x->l_a1; // store prev coefs 00071 x->l_a2p = x->l_a2; 00072 x->l_fcon = count[1]; // signal connected to the frequency inlet? 00073 x->l_rcon = count[2]; // signal connected to the resonance inlet? 00074 lores_clear(x); 00075 00076 if (sp[0]->s_n >= 4) { 00077 #if SMOOTHING_VERSION 00078 dsp_add(lores_perform_unroll_smooth, 6, sp[0]->s_vec, sp[3]->s_vec, x, sp[1]->s_vec, sp[2]->s_vec, (sp[0]->s_n/4)); 00079 #else 00080 dsp_add(lores_perform_unroll, 6, sp[0]->s_vec, sp[3]->s_vec, x, sp[1]->s_vec, sp[2]->s_vec, (sp[0]->s_n/4)); 00081 #endif 00082 } 00083 else 00084 dsp_add(lores_perform, 6, sp[0]->s_vec, sp[3]->s_vec, x, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); 00085 } 00086 00087 t_int *lores_perform(t_int *w) 00088 { 00089 // assign from parameters 00090 t_float *in = (t_float *)(w[1]); 00091 t_float *out = (t_float *)(w[2]); 00092 t_lores *x = (t_lores *)(w[3]); 00093 t_float freq = x->l_fcon? *(float *)(w[4]) : x->l_freq; 00094 t_float resonance = x->l_rcon? *(float *)(w[5]) : x->l_r; 00095 int n = (int)(w[6]); 00096 float a1 = x->l_a1,a2 = x->l_a2, ym1 = x->l_ym1, ym2 = x->l_ym2; 00097 float val,scale,temp,resterm; 00098 00099 if (x->l_obj.z_disabled) 00100 goto out; 00101 00102 // constrain resonance value 00103 00104 if (resonance >= 1.) 00105 resonance = 1. - 1E-20; 00106 else if (resonance < 0.) 00107 resonance = 0.; 00108 00109 // do we need to recompute coefficients? 00110 00111 if (freq != x->l_freq || resonance != x->l_r) { 00112 if (resonance != x->l_r) 00113 resterm = x->l_resterm = exp(resonance * 0.125) * .882497; 00114 else 00115 resterm = x->l_resterm; 00116 if (freq != x->l_freq) 00117 x->l_fqterm = cos(x->l_2pidsr * freq); 00118 x->l_a1 = a1 = -2. * resterm * x->l_fqterm; 00119 x->l_a2 = a2 = resterm * resterm; 00120 x->l_r = resonance; 00121 x->l_freq = freq; 00122 } 00123 00124 scale = 1. + a1 + a2; 00125 00126 // DSP loop 00127 00128 while (n--) { 00129 val = *in++; 00130 temp = ym1; 00131 ym1 = scale * val - a1 * ym1 - a2 * ym2; 00132 #ifdef DENORM_WANT_FIX 00133 if (IS_DENORM_NAN_FLOAT(ym1)) ym1 = temp = 0; 00134 #endif 00135 ym2 = temp; 00136 *out++ = ym1; 00137 } 00138 x->l_ym1 = ym1; 00139 x->l_ym2 = ym2; 00140 out: 00141 return (w+7); 00142 } 00143 00144 t_int *lores_perform_unroll(t_int *w) 00145 { 00146 // assign from parameters 00147 t_float *in = (t_float *)(w[1]); 00148 t_float *out = (t_float *)(w[2]); 00149 t_lores *x = (t_lores *)(w[3]); 00150 t_float freq = x->l_fcon? *(float *)(w[4]) : x->l_freq; 00151 t_float resonance = x->l_rcon? *(float *)(w[5]) : x->l_r; 00152 int n = (int)(w[6]); // n=VS/4+1 00153 float a1 = x->l_a1,a2 = x->l_a2; 00154 00155 float yna = x->l_ym2, ynb = x->l_ym1; 00156 float val,scale,resterm; 00157 00158 if (x->l_obj.z_disabled) 00159 goto out; 00160 00161 // constrain resonance value 00162 00163 if (resonance >= 1.) 00164 resonance = 1. - 1E-20; 00165 else if (resonance < 0.) 00166 resonance = 0.; 00167 00168 // do we need to recompute coefficients? 00169 00170 if (freq != x->l_freq || resonance != x->l_r) { 00171 if (resonance != x->l_r) 00172 resterm = x->l_resterm = exp(resonance * 0.125) * .882497; 00173 else 00174 resterm = x->l_resterm; 00175 if (freq != x->l_freq) 00176 x->l_fqterm = cos(x->l_2pidsr * freq); 00177 x->l_a1 = a1 = -2. * resterm * x->l_fqterm; 00178 x->l_a2 = a2 = resterm * resterm; 00179 x->l_r = resonance; 00180 x->l_freq = freq; 00181 } 00182 00183 scale = 1. + a1 + a2; 00184 00185 while (n--) { //n=VS/4 00186 *out++ = yna = scale * (val = *in++) - a1 * ynb - a2 * yna; 00187 #ifdef DENORM_WANT_FIX 00188 if (IS_DENORM_NAN_FLOAT(yna)) yna = ynb = *out = 0; 00189 #endif 00190 *out++ = ynb = scale * (val = *in++) - a1 * yna - a2 * ynb; 00191 #ifdef DENORM_WANT_FIX 00192 if (IS_DENORM_NAN_FLOAT(ynb)) yna = ynb = *out = 0; 00193 #endif 00194 *out++ = yna = scale * (val = *in++) - a1 * ynb - a2 * yna; 00195 #ifdef DENORM_WANT_FIX 00196 if (IS_DENORM_NAN_FLOAT(yna)) yna = ynb = *out = 0; 00197 #endif 00198 *out++ = ynb = scale * (val = *in++) - a1 * yna - a2 * ynb; 00199 #ifdef DENORM_WANT_FIX 00200 if (IS_DENORM_NAN_FLOAT(ynb)) yna = ynb = *out = 0; 00201 #endif 00202 } 00203 x->l_ym1 = ynb; 00204 x->l_ym2 = yna; 00205 out: 00206 return (w+7); 00207 } 00208 00209 t_int *lores_perform_unroll_smooth(t_int *w) 00210 { 00211 // assign from parameters 00212 t_float *in = (t_float *)(w[1]); 00213 t_float *out = (t_float *)(w[2]); 00214 t_lores *x = (t_lores *)(w[3]); 00215 t_float freq = x->l_fcon? *(float *)(w[4]) : x->l_freq; 00216 t_float resonance = x->l_rcon? *(float *)(w[5]) : x->l_r; 00217 int n = (int)(w[6]); // vs/4 00218 float a1 = x->l_a1,a2 = x->l_a2; 00219 00220 float yna = x->l_ym2, ynb = x->l_ym1; 00221 float val,scale, scalep, scalei,resterm; 00222 00223 float mult, a1i, a2i; 00224 00225 if (x->l_obj.z_disabled) 00226 goto out; 00227 00228 // constrain resonance value 00229 00230 if (resonance >= 1.) 00231 resonance = 1. - 1E-20; 00232 else if (resonance < 0.) 00233 resonance = 0.; 00234 00235 // do we need to recompute coefficients? 00236 00237 if (freq != x->l_freq || resonance != x->l_r) { 00238 if (resonance != x->l_r) 00239 resterm = x->l_resterm = exp(resonance * 0.125) * .882497; 00240 else 00241 resterm = x->l_resterm; 00242 if (freq != x->l_freq) 00243 x->l_fqterm = cos(x->l_2pidsr * freq); 00244 x->l_a1 = a1 = -2. * resterm * x->l_fqterm; 00245 x->l_a2 = a2 = resterm * resterm; 00246 x->l_r = resonance; 00247 x->l_freq = freq; 00248 } 00249 00250 a1 = x->l_a1p; 00251 a2 = x->l_a2p; 00252 00253 scalep = 1. + a1 + a2; 00254 scale = 1. + x->l_a1 + x->l_a2; 00255 00256 mult = 0.25/n; // 0.25 because n = vs/4 00257 a1i = (x->l_a1-a1) * mult; 00258 a2i = (x->l_a2-a2) * mult; 00259 scalei = (scale-scalep) * mult; 00260 00261 while (n--) { //n=VS/4 00262 scale+=scalei; a1+=a1i; a2+=a2i; 00263 *out++ = yna = scale * (val = *in++) - a1 * ynb - a2 * yna; 00264 #ifdef DENORM_WANT_FIX 00265 if (IS_DENORM_NAN_FLOAT(yna)) yna = ynb = *out = 0; 00266 #endif 00267 scale+=scalei; a1+=a1i; a2+=a2i; 00268 *out++ = ynb = scale * (val = *in++) - a1 * yna - a2 * ynb; 00269 #ifdef DENORM_WANT_FIX 00270 if (IS_DENORM_NAN_FLOAT(ynb)) yna = ynb = *out = 0; 00271 #endif 00272 scale+=scalei; a1+=a1i; a2+=a2i; 00273 *out++ = yna = scale * (val = *in++) - a1 * ynb - a2 * yna; 00274 #ifdef DENORM_WANT_FIX 00275 if (IS_DENORM_NAN_FLOAT(yna)) yna = ynb = *out = 0; 00276 #endif 00277 scale+=scalei; a1+=a1i; a2+=a2i; 00278 *out++ = ynb = scale * (val = *in++) - a1 * yna - a2 * ynb; 00279 #ifdef DENORM_WANT_FIX 00280 if (IS_DENORM_NAN_FLOAT(ynb)) yna = ynb = *out = 0; 00281 #endif 00282 } 00283 x->l_ym1 = ynb; 00284 x->l_ym2 = yna; 00285 00286 // store prev coefs 00287 x->l_a1p = x->l_a1; 00288 x->l_a2p = x->l_a2; 00289 00290 out: 00291 return (w+7); 00292 } 00293 00294 void lores_int(t_lores *x, long n) 00295 { 00296 lores_float(x,(double)n); 00297 } 00298 00299 void lores_float(t_lores *x, double f) 00300 { 00301 long in = proxy_getinlet((t_object *)x); 00302 00303 if (in == 1) { 00304 x->l_freq = f; 00305 lores_calc(x); 00306 } else if (in == 2) { 00307 x->l_r = f >= 1.0 ? 1 - 1E-20 : f; 00308 lores_calc(x); 00309 } 00310 } 00311 00312 void lores_clear(t_lores *x) 00313 { 00314 x->l_ym1 = x->l_ym2 = 0.; // clear sample memory to recover from blowup 00315 } 00316 00317 void lores_calc(t_lores *x) 00318 { 00319 float resterm; 00320 00321 // calculate filter coefficients from frequency and resonance 00322 00323 resterm = exp(x->l_r * 0.125) * 0.882497; 00324 x->l_fqterm = cos(x->l_2pidsr * x->l_freq); 00325 x->l_a1 = -2. * resterm * x->l_fqterm; 00326 x->l_a2 = resterm * resterm; 00327 x->l_resterm = resterm; 00328 } 00329 00330 void lores_assist(t_lores *x, void *b, long m, long a, char *s) 00331 { 00332 if (m == 2) 00333 sprintf(s,"(signal) Output"); 00334 else { 00335 switch (a) { 00336 case 0: sprintf(s,"(signal) Input"); break; 00337 case 1: sprintf(s,"(signal/float) Cutoff Frequency"); break; 00338 case 2: sprintf(s,"(signal/float) Resonance Control (0-1)"); break; 00339 } 00340 } 00341 } 00342 00343 void *lores_new(double val, double reso) 00344 { 00345 t_lores *x = object_alloc(lores_class); 00346 dsp_setup((t_pxobject *)x,3); 00347 00348 // three signal inlets 00349 00350 x->l_freq = val; 00351 x->l_r = reso >= 1.0 ? 1. - 1E-20 : reso; 00352 x->l_2pidsr = (2. * PI) / sys_getsr(); 00353 lores_calc(x); 00354 00355 x->l_a1p = x->l_a1; 00356 x->l_a2p = x->l_a2; 00357 00358 // one signal outlet 00359 00360 outlet_new((t_object *)x, "signal"); 00361 00362 return (x); 00363 }
Copyright © 2008, Cycling '74