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