Index: d_fft.c =================================================================== RCS file: /cvsroot/pure-data/pd/src/d_fft.c,v retrieving revision 1.2 diff -u -w -r1.2 d_fft.c --- d_fft.c 6 Sep 2004 20:20:33 -0000 1.2 +++ d_fft.c 2 Dec 2005 05:37:43 -0000 @@ -4,6 +4,12 @@ #include "m_pd.h" +#ifdef HAVE_LIBFFTW3F +#include "fftw3.h" +#include +#endif + +#ifndef HAVE_LIBFFTW3F /* ------------------------ fft~ and ifft~ -------------------------------- */ static t_class *sigfft_class, *sigifft_class; @@ -244,6 +250,259 @@ class_sethelpsymbol(sigrifft_class, gensym("fft~")); } +#else + +/* Support for fftw3 by Tim Blechmann */ + +/* ------------------------ fft~ and ifft~ -------------------------------- */ + +static t_class *sigfftw_class, *sigifftw_class; + +typedef struct fftw +{ + t_object x_obj; + float x_f; + + fftwf_plan plan; + fftwf_iodim dim; +} t_sigfftw; + +static void *sigfftw_new(void) +{ + t_sigfftw *x = (t_sigfftw *)pd_new(sigfftw_class); + outlet_new(&x->x_obj, gensym("signal")); + outlet_new(&x->x_obj, gensym("signal")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + x->x_f = 0; + return (x); +} + +static void sigfftw_free(t_sigfftw * x) +{ + fftwf_destroy_plan(x->plan); +} + +static t_int *sigfftw_perform(t_int *w) +{ + fftwf_execute(*(fftwf_plan *)w[1]); + + return (w+2); +} + +static void sigfftw_dsp(t_sigfftw *x, t_signal **sp) +{ + int n = sp[0]->s_n; + float *in1 = sp[0]->s_vec; + float *in2 = sp[1]->s_vec; + float *out1 = sp[2]->s_vec; + float *out2 = sp[3]->s_vec; + + x->dim.n=n; + x->dim.is=1; + x->dim.os=1; + x->plan = fftwf_plan_guru_split_dft(1, &(x->dim), 0, NULL, in1, + in2, out1, out2, FFTW_MEASURE); + dsp_add(sigfftw_perform, 1, &x->plan); +} + +static void sigifftw_dsp(t_sigfftw *x, t_signal **sp) +{ + int n = sp[0]->s_n; + float *in1 = sp[0]->s_vec; + float *in2 = sp[1]->s_vec; + float *out1 = sp[2]->s_vec; + float *out2 = sp[3]->s_vec; + + x->dim.n=n; + x->dim.is=1; + x->dim.os=1; + x->plan = fftwf_plan_guru_split_dft(1, &(x->dim), 0, NULL, in2, + in1, out2, out1, FFTW_MEASURE); + dsp_add(sigfftw_perform, 1, &x->plan); +} + +static void sigfftw_setup(void) +{ + sigfftw_class = class_new(gensym("fft~"), sigfftw_new, + (t_method) sigfftw_free, + sizeof(t_sigfftw), 0, 0); + CLASS_MAINSIGNALIN(sigfftw_class, t_sigfftw, x_f); + class_addmethod(sigfftw_class, (t_method)sigfftw_dsp, + gensym("dsp"), 0); + + sigifftw_class = class_new(gensym("ifft~"), sigfftw_new, + (t_method) sigfftw_free, + sizeof(t_sigfftw), 0, 0); + CLASS_MAINSIGNALIN(sigifftw_class, t_sigfftw, x_f); + class_addmethod(sigifftw_class, (t_method)sigifftw_dsp, + gensym("dsp"), 0); + class_sethelpsymbol(sigifftw_class, gensym("fft~")); + +} + + +/* ----------------------- rfft~ --------------------------------- */ + +static t_class *sigrfftw_class; + +typedef struct rfftw +{ + t_object x_obj; + float x_f; + + fftwf_plan plan; + fftwf_iodim dim; +} t_sigrfftw; + +static void *sigrfftw_new(void) +{ + t_sigrfftw *x = (t_sigrfftw *)pd_new(sigrfftw_class); + outlet_new(&x->x_obj, gensym("signal")); + outlet_new(&x->x_obj, gensym("signal")); + x->x_f = 0; + return (x); +} + +static void sigrfftw_free(t_sigrfftw *x) +{ + fftwf_destroy_plan(x->plan); +} + +/* + * for compatibility reasons with the mayer fft, we'll have to invert + * some samples ... this is ugly, but someone might rely on that ... + */ +static void sigrfftw_invert(t_sample * s, t_int n) +{ + while (n!=0) + { + --n; + s[n]=-s[n]; + } +} + +static t_int *sigrfftw_perform(t_int *w) +{ + fftwf_execute(*(fftwf_plan*)w[1]); + sigrfftw_invert((t_sample*)w[2],(t_int)w[3]); + + return (w+4); +} + +static void sigrfftw_dsp(t_sigrfftw *x, t_signal **sp) +{ + int n = sp[0]->s_n, n2 = (n>>1); + float *in = sp[0]->s_vec; + float *out1 = sp[1]->s_vec; + float *out2 = sp[2]->s_vec; + + if (n < 4) + { + error("fft: minimum 4 points"); + return; + } + else + { + x->dim.n=n; + x->dim.is=1; + x->dim.os=1; + x->plan = fftwf_plan_guru_split_dft_r2c(1, &(x->dim), 0, NULL, + in, out1, out2, + FFTW_MEASURE); + dsp_add(sigrfftw_perform,3,&x->plan,out2+1,n2-1); + } + + dsp_add_zero(out1 + n2, n2); + dsp_add_zero(out2 + n2, n2); +} + +static void sigrfftw_setup(void) +{ + sigrfftw_class = class_new(gensym("rfft~"), sigrfftw_new, + (t_method)sigrfftw_free, + sizeof(t_sigrfftw), 0, 0); + CLASS_MAINSIGNALIN(sigrfftw_class, t_sigrfftw, x_f); + class_addmethod(sigrfftw_class, (t_method)sigrfftw_dsp, + gensym("dsp"), 0); + class_sethelpsymbol(sigrfftw_class, gensym("fft~")); +} + + +/* ----------------------- rifft~ -------------------------------- */ + +static t_class *sigrifftw_class; + +typedef struct rifftw +{ + t_object x_obj; + float x_f; + + fftwf_plan plan; + fftwf_iodim dim; +} t_sigrifftw; + +static void *sigrifftw_new(void) +{ + t_sigrifftw *x = (t_sigrifftw *)pd_new(sigrifftw_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + outlet_new(&x->x_obj, gensym("signal")); + x->x_f = 0; + return (x); +} + +static void sigrifftw_free(t_sigrifftw *x) +{ + fftwf_destroy_plan(x->plan); +} + +static t_int *sigrifftw_perform(t_int *w) +{ + sigrfftw_invert((t_sample *)w[2],w[3]); + fftwf_execute(*(fftwf_plan*)w[1]); + + return (w+4); +} + +static void sigrifftw_dsp(t_sigrifftw *x, t_signal **sp) +{ + int n = sp[0]->s_n, n2 = (n>>1); + float *in1 = sp[0]->s_vec; + float *in2 = sp[1]->s_vec; + float *out = sp[2]->s_vec; + + if (n < 4) + { + error("fft: minimum 4 points"); + return; + } + + else + { + x->dim.n=n; + x->dim.is=1; + x->dim.os=1; + x->plan = fftwf_plan_guru_split_dft_c2r(1, &(x->dim), 0, NULL, + in1, in2, out, + FFTW_MEASURE); + dsp_add(sigrifftw_perform,3,&x->plan,in2,n2); + } +} + +static void sigrifftw_setup(void) +{ + sigrifftw_class = class_new(gensym("rifft~"), sigrifftw_new, + (t_method)sigrifftw_free, + sizeof(t_sigrifftw), 0, 0); + CLASS_MAINSIGNALIN(sigrifftw_class, t_sigrifftw, x_f); + class_addmethod(sigrifftw_class, (t_method)sigrifftw_dsp, + gensym("dsp"), 0); + class_sethelpsymbol(sigrifftw_class, gensym("fft~")); +} + +#endif /* HAVE_LIBFFTW3F */ +/* end of FFTW support */ + + /* ----------------------- framp~ -------------------------------- */ static t_class *sigframp_class; @@ -335,8 +594,16 @@ void d_fft_setup(void) { + sigframp_setup(); + +#ifndef HAVE_LIBFFTW3F sigfft_setup(); sigrfft_setup(); sigrifft_setup(); - sigframp_setup(); +#else + sigfftw_setup(); /* added by Tim Blechmann to support fftw */ + sigrifftw_setup(); + sigrfftw_setup(); +#endif /* HAVE_LIBFFTW3F */ + }