Chris@366: #ifndef KISSFFT_CLASS_HH Chris@366: #define KISSFFT_CLASS_HH Chris@366: #include Chris@366: #include Chris@366: Chris@366: namespace kissfft_utils { Chris@366: Chris@366: template Chris@366: struct traits Chris@366: { Chris@366: typedef T_scalar scalar_type; Chris@366: typedef std::complex cpx_type; Chris@366: void fill_twiddles( std::complex * dst ,int nfft,bool inverse) Chris@366: { Chris@366: T_scalar phinc = (inverse?2:-2)* acos( (T_scalar) -1) / nfft; Chris@366: for (int i=0;i(0,i*phinc) ); Chris@366: } Chris@366: Chris@366: void prepare( Chris@366: std::vector< std::complex > & dst, Chris@366: int nfft,bool inverse, Chris@366: std::vector & stageRadix, Chris@366: std::vector & stageRemainder ) Chris@366: { Chris@366: _twiddles.resize(nfft); Chris@366: fill_twiddles( &_twiddles[0],nfft,inverse); Chris@366: dst = _twiddles; Chris@366: Chris@366: //factorize Chris@366: //start factoring out 4's, then 2's, then 3,5,7,9,... Chris@366: int n= nfft; Chris@366: int p=4; Chris@366: do { Chris@366: while (n % p) { Chris@366: switch (p) { Chris@366: case 4: p = 2; break; Chris@366: case 2: p = 3; break; Chris@366: default: p += 2; break; Chris@366: } Chris@366: if (p*p>n) Chris@366: p=n;// no more factors Chris@366: } Chris@366: n /= p; Chris@366: stageRadix.push_back(p); Chris@366: stageRemainder.push_back(n); Chris@366: }while(n>1); Chris@366: } Chris@366: std::vector _twiddles; Chris@366: Chris@366: Chris@366: const cpx_type twiddle(int i) { return _twiddles[i]; } Chris@366: }; Chris@366: Chris@366: } Chris@366: Chris@366: template Chris@366: > Chris@366: class kissfft Chris@366: { Chris@366: public: Chris@366: typedef T_traits traits_type; Chris@366: typedef typename traits_type::scalar_type scalar_type; Chris@366: typedef typename traits_type::cpx_type cpx_type; Chris@366: Chris@366: kissfft(int nfft,bool inverse,const traits_type & traits=traits_type() ) Chris@366: :_nfft(nfft),_inverse(inverse),_traits(traits) Chris@366: { Chris@366: _traits.prepare(_twiddles, _nfft,_inverse ,_stageRadix, _stageRemainder); Chris@366: } Chris@366: Chris@366: void transform(const cpx_type * src , cpx_type * dst) Chris@366: { Chris@366: kf_work(0, dst, src, 1,1); Chris@366: } Chris@366: Chris@366: private: Chris@366: void kf_work( int stage,cpx_type * Fout, const cpx_type * f, size_t fstride,size_t in_stride) Chris@366: { Chris@366: int p = _stageRadix[stage]; Chris@366: int m = _stageRemainder[stage]; Chris@366: cpx_type * Fout_beg = Fout; Chris@366: cpx_type * Fout_end = Fout + p*m; Chris@366: Chris@366: if (m==1) { Chris@366: do{ Chris@366: *Fout = *f; Chris@366: f += fstride*in_stride; Chris@366: }while(++Fout != Fout_end ); Chris@366: }else{ Chris@366: do{ Chris@366: // recursive call: Chris@366: // DFT of size m*p performed by doing Chris@366: // p instances of smaller DFTs of size m, Chris@366: // each one takes a decimated version of the input Chris@366: kf_work(stage+1, Fout , f, fstride*p,in_stride); Chris@366: f += fstride*in_stride; Chris@366: }while( (Fout += m) != Fout_end ); Chris@366: } Chris@366: Chris@366: Fout=Fout_beg; Chris@366: Chris@366: // recombine the p smaller DFTs Chris@366: switch (p) { Chris@366: case 2: kf_bfly2(Fout,fstride,m); break; Chris@366: case 3: kf_bfly3(Fout,fstride,m); break; Chris@366: case 4: kf_bfly4(Fout,fstride,m); break; Chris@366: case 5: kf_bfly5(Fout,fstride,m); break; Chris@366: default: kf_bfly_generic(Fout,fstride,m,p); break; Chris@366: } Chris@366: } Chris@366: Chris@366: // these were #define macros in the original kiss_fft Chris@366: void C_ADD( cpx_type & c,const cpx_type & a,const cpx_type & b) { c=a+b;} Chris@366: void C_MUL( cpx_type & c,const cpx_type & a,const cpx_type & b) { c=a*b;} Chris@366: void C_SUB( cpx_type & c,const cpx_type & a,const cpx_type & b) { c=a-b;} Chris@366: void C_ADDTO( cpx_type & c,const cpx_type & a) { c+=a;} Chris@366: void C_FIXDIV( cpx_type & ,int ) {} // NO-OP for float types Chris@366: scalar_type S_MUL( const scalar_type & a,const scalar_type & b) { return a*b;} Chris@366: scalar_type HALF_OF( const scalar_type & a) { return a*.5;} Chris@366: void C_MULBYSCALAR(cpx_type & c,const scalar_type & a) {c*=a;} Chris@366: Chris@366: void kf_bfly2( cpx_type * Fout, const size_t fstride, int m) Chris@366: { Chris@366: for (int k=0;kreal() - HALF_OF(scratch[3].real() ) , Fout->imag() - HALF_OF(scratch[3].imag() ) ); Chris@366: Chris@366: C_MULBYSCALAR( scratch[0] , epi3.imag() ); Chris@366: Chris@366: C_ADDTO(*Fout,scratch[3]); Chris@366: Chris@366: Fout[m2] = cpx_type( Fout[m].real() + scratch[0].imag() , Fout[m].imag() - scratch[0].real() ); Chris@366: Chris@366: C_ADDTO( Fout[m] , cpx_type( -scratch[0].imag(),scratch[0].real() ) ); Chris@366: ++Fout; Chris@366: }while(--k); Chris@366: } Chris@366: Chris@366: void kf_bfly5( cpx_type * Fout, const size_t fstride, const size_t m) Chris@366: { Chris@366: cpx_type *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; Chris@366: size_t u; Chris@366: cpx_type scratch[13]; Chris@366: cpx_type * twiddles = &_twiddles[0]; Chris@366: cpx_type *tw; Chris@366: cpx_type ya,yb; Chris@366: ya = twiddles[fstride*m]; Chris@366: yb = twiddles[fstride*2*m]; Chris@366: Chris@366: Fout0=Fout; Chris@366: Fout1=Fout0+m; Chris@366: Fout2=Fout0+2*m; Chris@366: Fout3=Fout0+3*m; Chris@366: Fout4=Fout0+4*m; Chris@366: Chris@366: tw=twiddles; Chris@366: for ( u=0; u=Norig) twidx-=Norig; Chris@366: C_MUL(t,scratchbuf[q] , twiddles[twidx] ); Chris@366: C_ADDTO( Fout[ k ] ,t); Chris@366: } Chris@366: k += m; Chris@366: } Chris@366: } Chris@366: } Chris@366: Chris@366: int _nfft; Chris@366: bool _inverse; Chris@366: std::vector _twiddles; Chris@366: std::vector _stageRadix; Chris@366: std::vector _stageRemainder; Chris@366: traits_type _traits; Chris@366: }; Chris@366: #endif