#include "m_pd.h" #include "math.h" #include "stdlib.h" #ifdef NT #pragma warning( disable : 4244 ) #pragma warning( disable : 4305 ) #endif /* ------------------------ KarplusStrong~ ----------------------------- */ /* Essa implementacao foi feita sobre um template do tutorial sobre externals para Pd do Johannes Zmoelnig (http://pdstatic.iem.at/externals-HOWTO/) e varios comentarios do exemplo original foram mantidos, sobre as estruturas gerais de um external em Pure Data. Apenas os comentarios em Portugues sao especificos do metodo de Karplus-Strong. */ /* tilde object to take absolute value. */ static t_class *KarplusStrong_class; typedef struct _KarplusStrong { t_object x_obj; /* obligatory header */ t_float x_f; /* place to hold inlet's value if it's set by message */ t_int N; /* tamanho do buffer de recirculacao (igual comprimento de onda) */ t_float buf[4410]; /* buffer para filtragens sucessivas */ t_int i; /* indice no buffer */ t_float f_ant; /* ultimo valor de saida do buffer (para filtro) */ } t_KarplusStrong; void KarplusStrong_bang(t_KarplusStrong *x) { int i; for (i=0;iN;i++) { x->buf[i] = (2.0*rand())/RAND_MAX-1; } } void KarplusStrong_ft2(t_KarplusStrong *x, t_floatarg f) { int i; /* A frequencia tem que ser pelo menos 20Hz (o buffer tem no maximo 4410 posicoes) */ if (f<20) f=20; /* Calcula o tamanho do buffer (para a frequencia f) */ x->N = 44100/f; /* o mesmo que round(44100/f-0.5) */ /* inicializa buffer */ for (i=0;iN;i++) x->buf[i] = 0; } /* this is the actual performance routine which acts on the samples. It's called with a single pointer "w" which is our location in the DSP call list. We return a new "w" which will point to the next item after us. Meanwhile, w[0] is just a pointer to dsp-perform itself (no use to us), w[1] and w[2] are the input and output vector locations, and w[3] is the number of points to calculate. */ static t_int *KarplusStrong_perform(t_int *w) { t_float *in = (t_float *)(w[1]); t_float *out = (t_float *)(w[2]); int n = (int)(w[3]); t_KarplusStrong *x = (t_KarplusStrong *)(w[4]); while (n--) { float f = x->buf[x->i]; /* aplica filtro passa baixa */ *out = 0.499*f+0.499*x->f_ant; x->f_ant = f; x->buf[x->i] = *out; x->i++; if (x->i>=x->N) x->i=0; out++; } return (w+5); } /* called to start DSP. Here we call Pd back to add our perform routine to a linear callback list which Pd in turn calls to grind out the samples. */ static void KarplusStrong_dsp(t_KarplusStrong *x, t_signal **sp) { dsp_add(KarplusStrong_perform, 4, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n, x); } static void *KarplusStrong_new(void) { int i; t_KarplusStrong *x = (t_KarplusStrong *)pd_new(KarplusStrong_class); inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft2")); outlet_new(&x->x_obj, gensym("signal")); x->x_f = x->i = x->f_ant = x->N = 0; for (i=0;i<4410;i++) x->buf[i]=0; return (x); } /* this routine, which must have exactly this name (with the "~" replaced by "_tilde) is called when the code is first loaded, and tells Pd how to build the "class". */ void KarplusStrong_tilde_setup(void) { KarplusStrong_class = class_new(gensym("KarplusStrong~"), (t_newmethod)KarplusStrong_new, 0, sizeof(t_KarplusStrong), 0, A_DEFFLOAT, 0); /* this is magic to declare that the leftmost, "main" inlet takes signals; other signal inlets are done differently...*/ CLASS_MAINSIGNALIN(KarplusStrong_class, t_KarplusStrong, x_f); /* here we tell Pd about the "dsp" method, which is called back when DSP is turned on. */ class_addmethod(KarplusStrong_class, (t_method)KarplusStrong_dsp, gensym("dsp"), 0); class_addbang(KarplusStrong_class, (t_method)KarplusStrong_bang); class_addmethod(KarplusStrong_class, (t_method)KarplusStrong_ft2, gensym("ft2"), A_FLOAT, 0); }