Update of /cvsroot/pure-data/pd/src
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29916
Modified Files:
Tag: devel_0_37
d_fft.c
Log Message:
added support for fftw
Index: d_fft.c
===================================================================
RCS file: /cvsroot/pure-data/pd/src/d_fft.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.16.1
diff -C2 -d -r1.1.1.1 -r1.1.1.1.16.1
*** d_fft.c 29 Jul 2002 17:05:56 -0000 1.1.1.1
--- d_fft.c 2 Mar 2004 11:04:50 -0000 1.1.1.1.16.1
***************
*** 5,8 ****
--- 5,14 ----
#include "m_pd.h"
+ #ifdef USE_FFTW
+ #include "fftw3.h"
+ #include <string.h>
+ #endif
+
+ #ifndef USE_FFTW
/* ------------------------ fft~ and ifft~ -------------------------------- */
static t_class *sigfft_class, *sigifft_class;
***************
*** 41,45 ****
for (;n--; in1++, in2++)
{
! float f = *in1;
*in1 = *in2;
*in2 = f;
--- 47,51 ----
for (;n--; in1++, in2++)
{
! float f = *in1;
*in1 = *in2;
*in2 = f;
***************
*** 141,144 ****
--- 147,151 ----
}
+
static t_int *sigrfft_perform(t_int *w)
{
***************
*** 185,190 ****
--- 192,200 ----
}
+
/* ----------------------- rifft~ -------------------------------- */
+
+
static t_class *sigrifft_class;
***************
*** 245,248 ****
--- 255,702 ----
}
+ #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;
+ t_int bins;
+ fftwf_complex * incomplex;
+ fftwf_complex * outcomplex;
+
+ } 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;
+
+ //get ready for the default blocksize
+ x->bins=64;
+ x->incomplex = fftwf_malloc(sizeof(fftw_complex) * x->bins);
+ x->outcomplex = fftwf_malloc(sizeof(fftw_complex) * x->bins);
+ x->plan = fftwf_plan_dft_1d(x->bins,x->incomplex,x->outcomplex,
+ FFTW_FORWARD,FFTW_MEASURE);
+
+ return (x);
+ }
+
+ static void *sigifftw_new(void)
+ {
+ t_sigfftw *x = (t_sigfftw *)pd_new(sigifftw_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;
+
+ //get ready for the default blocksize
+ x->bins=64;
+ x->incomplex = fftwf_malloc(sizeof(fftw_complex) * x->bins);
+ x->outcomplex = fftwf_malloc(sizeof(fftw_complex) * x->bins);
+ x->plan = fftwf_plan_dft_1d(x->bins,x->incomplex,x->outcomplex,
+ FFTW_BACKWARD,FFTW_MEASURE);
+ return (x);
+ }
+
+ static void sigfftw_free(t_sigfftw * x)
+ {
+ fftwf_free(x->incomplex);
+ fftwf_free(x->outcomplex);
+ fftwf_destroy_plan(x->plan);
+
+ }
+
+ static void sigifftw_free(t_sigfftw * x)
+ {
+ fftwf_free(x->incomplex);
+ fftwf_free(x->outcomplex);
+ fftwf_destroy_plan(x->plan);
+ }
+
+ static t_int *sigfftw_perform(t_int *w)
+ {
+ t_sigfftw * x =(t_sigfftw *) w[1];
+ t_sample * in1 =(t_sample *) w[2];
+ t_sample * in2 =(t_sample *) w[3];
+ t_sample * out1 =(t_sample *) w[4];
+ t_sample * out2 =(t_sample *) w[5];
+ t_int n =(t_int) w[6];
+
+ if (n != x->bins)
+ {
+ x->bins=n;
+
+ //re-allocate fft buffers
+ fftwf_free(x->incomplex);
+ x->incomplex = fftwf_malloc(sizeof(fftwf_complex) * x->bins);
+ fftwf_free(x->outcomplex);
+ x->outcomplex = fftwf_malloc(sizeof(fftwf_complex) * x->bins);
+
+ //set plan, this might take a few seconds
+ //but you don't have to do that on the fly...
+ fftwf_destroy_plan(x->plan);
+ x->plan = fftwf_plan_dft_1d(x->bins,x->incomplex,x->outcomplex,
+ FFTW_FORWARD,FFTW_MEASURE);
+ }
+
+ t_int i=n;
+ while(i!=0)
+ {
+ --i;
+ x->incomplex[i][0]=*(in1+i);
+ x->incomplex[i][1]=*(in2+i);
+ }
+ fftwf_execute(x->plan);
+
+ i=n;
+ while(i!=0)
+ {
+ --i;
+ *(out1+i)=x->outcomplex[i][0];
+ *(out2+i)=x->outcomplex[i][1];
+ }
+
+ return (w+7);
+ }
+
+ static t_int *sigifftw_perform(t_int *w)
+ {
+ t_sigfftw * x =(t_sigfftw *) w[1];
+ t_sample * in1 =(t_sample *) w[2];
+ t_sample * in2 =(t_sample *) w[3];
+ t_sample * out1 =(t_sample *) w[4];
+ t_sample * out2 =(t_sample *) w[5];
+ t_int n =(t_int) w[6];
+
+ if (n != x->bins)
+ {
+ x->bins=n;
+
+ //re-allocate fft buffers
+ fftwf_free(x->incomplex);
+ x->incomplex = fftwf_malloc(sizeof(fftwf_complex) * x->bins);
+ fftwf_free(x->outcomplex);
+ x->outcomplex = fftwf_malloc(sizeof(fftwf_complex) * x->bins);
+
+ //set plan, this might take a few seconds
+ //but you don't have to do that on the fly...
+ fftwf_destroy_plan(x->plan);
+ x->plan = fftwf_plan_dft_1d(x->bins,x->incomplex,x->outcomplex,
+ FFTW_BACKWARD,FFTW_MEASURE);
+ }
+
+ t_int i=n;
+ while(i!=0)
+ {
+ --i;
+ x->incomplex[i][0]=*(in1+i);
+ x->incomplex[i][1]=*(in2+i);
+ }
+ fftwf_execute(x->plan);
+
+ i=n;
+ while(i!=0)
+ {
+ --i;
+ *(out1+i)=x->outcomplex[i][0];
+ *(out2+i)=x->outcomplex[i][1];
+ }
+
+ return (w+7);
+
+ }
+
+ static void sigfftw_dspx(t_sigfftw *x, t_signal **sp, t_int *(*f)(t_int *w))
+ {
+ 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;
+ dsp_add(f, 6, x, in1, in2, out1, out2, n);
+ }
+
+ static void sigfftw_dsp(t_sigfftw *x, t_signal **sp)
+ {
+ sigfftw_dspx(x, sp, sigfftw_perform);
+ }
+
+ static void sigifftw_dsp(t_sigfftw *x, t_signal **sp)
+ {
+ sigfftw_dspx(x, sp, sigifftw_perform);
+ }
+
+ 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~"), sigifftw_new,
+ (t_method) sigifftw_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; //me
+
+ fftwf_plan plan; //fftw plan
+ t_int bins; //number of bins
+ t_sample * infft; //array fftw is working on
+ t_sample * outfft; //array fftw uses to output it's values
+
+ float x_f;
+
+ } t_sigrfftw;
+
+ //constructor
+ 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;
+
+ //get ready for the default blocksize
+ x->bins=64;
+ x->infft = fftwf_malloc(sizeof(t_sample) * x->bins);
+ x->outfft = fftwf_malloc(sizeof(t_sample) * x->bins);
+ //it seems that the halfcomplex transformation is a bit faster
+ x->plan = fftwf_plan_r2r_1d(x->bins,x->infft,x->outfft,
+ FFTW_FORWARD,FFTW_MEASURE);
+
+ return (x);
+ }
+
+ //destructor
+ static void sigrfftw_free(t_sigrfftw *x)
+ {
+ fftwf_free(x->infft);
+ fftwf_free(x->outfft);
+ fftwf_destroy_plan(x->plan);
+ }
+
+ static t_int *sigrfftw_perform(t_int *w)
+ {
+ t_sigrfftw * x =(t_sigrfftw *) w[1];
+ t_sample * in1 =(t_sample *) w[2];
+ t_sample * out1 =(t_sample *) w[3];
+ t_sample * out2 =(t_sample *) w[4];
+ t_int n =(t_int) w[5];
+
+ if (n != x->bins)
+ {
+ x->bins=n;
+
+ //re-allocate fft buffers
+ fftwf_free(x->infft);
+ x->infft = fftwf_malloc(sizeof(float) * x->bins);
+ fftwf_free(x->outfft);
+ x->outfft = fftwf_malloc(sizeof(float) * x->bins);
+
+ //set plan, this might take a few seconds
+ //but you don't have to do that on the fly...
+ fftwf_destroy_plan(x->plan);
+ x->plan = fftwf_plan_r2r_1d(x->bins,x->infft,x->outfft,
+ FFTW_FORWARD,FFTW_MEASURE);
+ }
+
+ memcpy(x->infft,in1,n*sizeof(t_sample));
+ fftwf_execute(x->plan);
+ memcpy(out1,x->outfft,n/2*(sizeof(t_sample)));
+
+ t_int i = n/2;
+ while (i)
+ {
+ out2[i] = -(x->outfft[n-i]);
+ --i;
+ }
+ return (w+6);
+ }
+
+ static void sigrfftw_dsp(t_sigrfftw *x, t_signal **sp)
+ {
+ int n = sp[0]->s_n, n2 = (n>>1);
+ float *in1 = 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
+ dsp_add(sigrfftw_perform,5,x,in1,out1,out2,n);
+
+ 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; //me
+
+ fftwf_iodim iodim;
+
+ fftwf_plan plan; //fftw plan
+ t_int bins; //number of bins
+ t_sample * infft;
+ t_sample * inimag;
+ t_sample * outfft;
+
+ float x_f;
+
+ } t_sigrifftw;
+
+ //constructor
+ 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;
+
+ //get ready for the default blocksize
+ x->bins=64;
+ x->infft = fftwf_malloc(sizeof(t_sample) * (x->bins));
+ //x->inimag = fftwf_malloc(sizeof(t_sample) * (x->bins)/2);
+ x->outfft = fftwf_malloc(sizeof(t_sample) * x->bins);
+
+ // x->iodim->1;
+
+ x->plan = fftwf_plan_r2r_1d(x->bins,x->infft,x->outfft,
+ FFTW_BACKWARD,FFTW_MEASURE);
+
+
+ return (x);
+ }
+
+ //destructor
+ static void sigrifftw_free(t_sigrifftw *x)
+ {
+ fftwf_free(x->infft);
+ fftwf_free(x->inimag);
+ fftwf_free(x->outfft);
+ fftwf_destroy_plan(x->plan);
+ }
+
+ static t_int *sigrifftw_perform(t_int *w)
+ {
+ t_sigrifftw * x =(t_sigrifftw *) w[1];
+ t_sample * in1 =(t_sample *) w[2];
+ t_sample * in2 =(t_sample *) w[3];
+ t_sample * out1 =(t_sample *) w[4];
+ t_int n =(t_int) w[5];
+
+ if (n != x->bins)
+ {
+ x->bins=n;
+
+ //re-allocate fft buffers
+ fftwf_free(x->infft);
+ x->infft = fftwf_malloc(sizeof(float) * (x->bins));
+ //fftwf_free(x->inimag);
+ //x->inimag = fftwf_malloc(sizeof(float) * (x->bins)/2);
+ fftwf_free(x->outfft);
+ x->outfft = fftwf_malloc(sizeof(float) * x->bins);
+
+ //set plan, this might take a few seconds
+ //but you don't have to do that on the fly...
+ fftwf_destroy_plan(x->plan);
+ x->plan = fftwf_plan_r2r_1d(x->bins,x->infft,x->outfft,
+ FFTW_BACKWARD,FFTW_MEASURE);
+
+ //x->plan = fftwf_plan_guru_split_dft_c2r(1,iodim ,x->bins,x->infft,x->outfft,FFTW_BACKWARD,FFTW_MEASURE);
+ }
+
+ memcpy(x->infft,in1,n/2*sizeof(t_sample));
+
+ t_int i = n/2;
+ while (i!=n)
+ {
+ x->infft[i]=-in2[n-i];
+ ++i;
+ }
+
+ fftwf_execute(x->plan);
+ memcpy(out1,x->outfft,n*(sizeof(t_sample)));
+
+ return (w+6);
+ }
+
+ 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 *out1 = sp[2]->s_vec;
+
+ if (n < 4)
+ {
+ error("fft: minimum 4 points");
+ return;
+ }
+
+ else
+ dsp_add(sigrifftw_perform,5,x,in1,in2,out1,n);
+
+ }
+
+ 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
+ /* end of FFTW support */
+
+
/* ----------------------- framp~ -------------------------------- */
***************
*** 336,342 ****
void d_fft_setup(void)
{
sigfft_setup();
sigrfft_setup();
sigrifft_setup();
! sigframp_setup();
}
--- 790,804 ----
void d_fft_setup(void)
{
+ sigframp_setup();
+
+ #ifndef USE_FFTW
sigfft_setup();
sigrfft_setup();
sigrifft_setup();
! #else
! sigfftw_setup(); /* added by Tim Blechmann to support fftw */
! sigrifftw_setup();
! sigrfftw_setup();
! #endif
!
}