/***************************************************************************** FFTRealFixLen.hpp Copyright (c) 2005 Laurent de Soras --- Legal stuff --- This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *Tab=3***********************************************************************/ #if defined (FFTRealFixLen_CURRENT_CODEHEADER) #error Recursive inclusion of FFTRealFixLen code header. #endif #define FFTRealFixLen_CURRENT_CODEHEADER #if ! defined (FFTRealFixLen_CODEHEADER_INCLUDED) #define FFTRealFixLen_CODEHEADER_INCLUDED /*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ #include "def.h" #include "FFTRealPassDirect.h" #include "FFTRealPassInverse.h" #include "FFTRealSelect.h" #include #include namespace std { } /*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ template FFTRealFixLen ::FFTRealFixLen () : _buffer (FFT_LEN) , _br_data (BR_ARR_SIZE) , _trigo_data (TRIGO_TABLE_ARR_SIZE) , _trigo_osc () { build_br_lut (); build_trigo_lut (); build_trigo_osc (); } template long FFTRealFixLen ::get_length () const { return (FFT_LEN); } // General case template void FFTRealFixLen ::do_fft (DataType f [], const DataType x []) { assert (f != 0); assert (x != 0); assert (x != f); assert (FFT_LEN_L2 >= 3); // Do the transform in several passes const DataType * cos_ptr = &_trigo_data [0]; const long * br_ptr = &_br_data [0]; FFTRealPassDirect ::process ( FFT_LEN, f, &_buffer [0], x, cos_ptr, TRIGO_TABLE_ARR_SIZE, br_ptr, &_trigo_osc [0] ); } // 4-point FFT template <> void FFTRealFixLen <2>::do_fft (DataType f [], const DataType x []) { assert (f != 0); assert (x != 0); assert (x != f); f [1] = x [0] - x [2]; f [3] = x [1] - x [3]; const DataType b_0 = x [0] + x [2]; const DataType b_2 = x [1] + x [3]; f [0] = b_0 + b_2; f [2] = b_0 - b_2; } // 2-point FFT template <> void FFTRealFixLen <1>::do_fft (DataType f [], const DataType x []) { assert (f != 0); assert (x != 0); assert (x != f); f [0] = x [0] + x [1]; f [1] = x [0] - x [1]; } // 1-point FFT template <> void FFTRealFixLen <0>::do_fft (DataType f [], const DataType x []) { assert (f != 0); assert (x != 0); f [0] = x [0]; } // General case template void FFTRealFixLen ::do_ifft (const DataType f [], DataType x []) { assert (f != 0); assert (x != 0); assert (x != f); assert (FFT_LEN_L2 >= 3); // Do the transform in several passes DataType * s_ptr = FFTRealSelect ::sel_bin (&_buffer [0], x); DataType * d_ptr = FFTRealSelect ::sel_bin (x, &_buffer [0]); const DataType * cos_ptr = &_trigo_data [0]; const long * br_ptr = &_br_data [0]; FFTRealPassInverse ::process ( FFT_LEN, d_ptr, s_ptr, f, cos_ptr, TRIGO_TABLE_ARR_SIZE, br_ptr, &_trigo_osc [0] ); } // 4-point IFFT template <> void FFTRealFixLen <2>::do_ifft (const DataType f [], DataType x []) { assert (f != 0); assert (x != 0); assert (x != f); const DataType b_0 = f [0] + f [2]; const DataType b_2 = f [0] - f [2]; x [0] = b_0 + f [1] * 2; x [2] = b_0 - f [1] * 2; x [1] = b_2 + f [3] * 2; x [3] = b_2 - f [3] * 2; } // 2-point IFFT template <> void FFTRealFixLen <1>::do_ifft (const DataType f [], DataType x []) { assert (f != 0); assert (x != 0); assert (x != f); x [0] = f [0] + f [1]; x [1] = f [0] - f [1]; } // 1-point IFFT template <> void FFTRealFixLen <0>::do_ifft (const DataType f [], DataType x []) { assert (f != 0); assert (x != 0); assert (x != f); x [0] = f [0]; } template void FFTRealFixLen ::rescale (DataType x []) const { assert (x != 0); const DataType mul = DataType (1.0 / FFT_LEN); if (FFT_LEN < 4) { long i = FFT_LEN - 1; do { x [i] *= mul; --i; } while (i >= 0); } else { assert ((FFT_LEN & 3) == 0); // Could be optimized with SIMD instruction sets (needs alignment check) long i = FFT_LEN - 4; do { x [i + 0] *= mul; x [i + 1] *= mul; x [i + 2] *= mul; x [i + 3] *= mul; i -= 4; } while (i >= 0); } } /*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ /*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ template void FFTRealFixLen ::build_br_lut () { _br_data [0] = 0; for (long cnt = 1; cnt < BR_ARR_SIZE; ++cnt) { long index = cnt << 2; long br_index = 0; int bit_cnt = FFT_LEN_L2; do { br_index <<= 1; br_index += (index & 1); index >>= 1; -- bit_cnt; } while (bit_cnt > 0); _br_data [cnt] = br_index; } } template void FFTRealFixLen ::build_trigo_lut () { const double mul = (0.5 * PI) / TRIGO_TABLE_ARR_SIZE; for (long i = 0; i < TRIGO_TABLE_ARR_SIZE; ++ i) { using namespace std; _trigo_data [i] = DataType (cos (i * mul)); } } template void FFTRealFixLen ::build_trigo_osc () { for (int i = 0; i < NBR_TRIGO_OSC; ++i) { OscType & osc = _trigo_osc [i]; const long len = static_cast (TRIGO_TABLE_ARR_SIZE) << (i + 1); const double mul = (0.5 * PI) / len; osc.set_step (mul); } } #endif // FFTRealFixLen_CODEHEADER_INCLUDED #undef FFTRealFixLen_CURRENT_CODEHEADER /*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/