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