Chris@211: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@211: Chris@211: /* Chris@211: QM DSP Library Chris@211: Chris@211: Centre for Digital Music, Queen Mary, University of London. Chris@211: */ Chris@211: Chris@211: #include "FFT.h" Chris@211: Chris@211: #include "maths/MathUtilities.h" Chris@211: Chris@211: #include "kiss_fft.h" Chris@211: #include "kiss_fftr.h" Chris@211: Chris@211: #include Chris@211: Chris@211: #include Chris@211: Chris@211: #include Chris@211: Chris@211: class FFT::D Chris@211: { Chris@211: public: Chris@211: D(int n) : m_n(n) { Chris@211: m_planf = kiss_fft_alloc(m_n, 0, NULL, NULL); Chris@211: m_plani = kiss_fft_alloc(m_n, 1, NULL, NULL); Chris@211: m_kin = new kiss_fft_cpx[m_n]; Chris@211: m_kout = new kiss_fft_cpx[m_n]; Chris@211: } Chris@211: Chris@211: ~D() { Chris@211: kiss_fft_free(m_planf); Chris@211: kiss_fft_free(m_plani); Chris@211: delete[] m_kin; Chris@211: delete[] m_kout; Chris@211: } Chris@211: Chris@211: void process(bool inverse, Chris@211: const double *ri, Chris@211: const double *ii, Chris@211: double *ro, Chris@211: double *io) { Chris@211: Chris@211: for (int i = 0; i < m_n; ++i) { Chris@211: m_kin[i].r = ri[i]; Chris@211: m_kin[i].i = (ii ? ii[i] : 0.0); Chris@211: } Chris@211: Chris@211: if (!inverse) { Chris@211: Chris@211: kiss_fft(m_planf, m_kin, m_kout); Chris@211: Chris@211: for (int i = 0; i < m_n; ++i) { Chris@211: ro[i] = m_kout[i].r; Chris@211: io[i] = m_kout[i].i; Chris@211: } Chris@211: Chris@211: } else { Chris@211: Chris@211: kiss_fft(m_plani, m_kin, m_kout); Chris@211: Chris@211: double scale = 1.0 / m_n; Chris@211: Chris@211: for (int i = 0; i < m_n; ++i) { Chris@211: ro[i] = m_kout[i].r * scale; Chris@211: io[i] = m_kout[i].i * scale; Chris@211: } Chris@211: } Chris@211: } Chris@211: Chris@211: private: Chris@211: int m_n; Chris@211: kiss_fft_cfg m_planf; Chris@211: kiss_fft_cfg m_plani; Chris@211: kiss_fft_cpx *m_kin; Chris@211: kiss_fft_cpx *m_kout; Chris@211: }; Chris@211: Chris@211: FFT::FFT(int n) : Chris@211: m_d(new D(n)) Chris@211: { Chris@211: } Chris@211: Chris@211: FFT::~FFT() Chris@211: { Chris@211: delete m_d; Chris@211: } Chris@211: Chris@211: void Chris@211: FFT::process(bool inverse, Chris@211: const double *p_lpRealIn, const double *p_lpImagIn, Chris@211: double *p_lpRealOut, double *p_lpImagOut) Chris@211: { Chris@211: m_d->process(inverse, Chris@211: p_lpRealIn, p_lpImagIn, Chris@211: p_lpRealOut, p_lpImagOut); Chris@211: } Chris@211: Chris@211: class FFTReal::D Chris@211: { Chris@211: public: Chris@211: D(int n) : m_n(n) { Chris@211: if (n % 2) { Chris@211: throw std::invalid_argument Chris@211: ("nsamples must be even in FFTReal constructor"); Chris@211: } Chris@211: m_planf = kiss_fftr_alloc(m_n, 0, NULL, NULL); Chris@211: m_plani = kiss_fftr_alloc(m_n, 1, NULL, NULL); Chris@211: m_c = new kiss_fft_cpx[m_n]; Chris@211: } Chris@211: Chris@211: ~D() { Chris@211: kiss_fftr_free(m_planf); Chris@211: kiss_fftr_free(m_plani); Chris@211: delete[] m_c; Chris@211: } Chris@211: Chris@211: void forward(const double *ri, double *ro, double *io) { Chris@211: Chris@211: kiss_fftr(m_planf, ri, m_c); Chris@211: Chris@211: for (int i = 0; i <= m_n/2; ++i) { Chris@211: ro[i] = m_c[i].r; Chris@211: io[i] = m_c[i].i; Chris@211: } Chris@211: Chris@211: for (int i = 0; i + 1 < m_n/2; ++i) { Chris@211: ro[m_n - i - 1] = ro[i + 1]; Chris@211: io[m_n - i - 1] = -io[i + 1]; Chris@211: } Chris@211: } Chris@211: Chris@211: void forwardMagnitude(const double *ri, double *mo) { Chris@211: Chris@211: double *io = new double[m_n]; Chris@211: Chris@211: forward(ri, mo, io); Chris@211: Chris@211: for (int i = 0; i < m_n; ++i) { Chris@211: mo[i] = sqrt(mo[i] * mo[i] + io[i] * io[i]); Chris@211: } Chris@211: Chris@211: delete[] io; Chris@211: } Chris@211: Chris@211: void inverse(const double *ri, const double *ii, double *ro) { Chris@211: Chris@211: // kiss_fftr.h says Chris@211: // "input freqdata has nfft/2+1 complex points" Chris@211: Chris@211: for (int i = 0; i < m_n/2 + 1; ++i) { Chris@211: m_c[i].r = ri[i]; Chris@211: m_c[i].i = ii[i]; Chris@211: } Chris@211: Chris@211: kiss_fftri(m_plani, m_c, ro); Chris@211: Chris@211: double scale = 1.0 / m_n; Chris@211: Chris@211: for (int i = 0; i < m_n; ++i) { Chris@211: ro[i] *= scale; Chris@211: } Chris@211: } Chris@211: Chris@211: private: Chris@211: int m_n; Chris@211: kiss_fftr_cfg m_planf; Chris@211: kiss_fftr_cfg m_plani; Chris@211: kiss_fft_cpx *m_c; Chris@211: }; Chris@211: Chris@211: FFTReal::FFTReal(int n) : Chris@211: m_d(new D(n)) Chris@211: { Chris@211: } Chris@211: Chris@211: FFTReal::~FFTReal() Chris@211: { Chris@211: delete m_d; Chris@211: } Chris@211: Chris@211: void Chris@211: FFTReal::forward(const double *ri, double *ro, double *io) Chris@211: { Chris@211: m_d->forward(ri, ro, io); Chris@211: } Chris@211: Chris@211: void Chris@211: FFTReal::forwardMagnitude(const double *ri, double *mo) Chris@211: { Chris@211: m_d->forwardMagnitude(ri, mo); Chris@211: } Chris@211: Chris@211: void Chris@211: FFTReal::inverse(const double *ri, const double *ii, double *ro) Chris@211: { Chris@211: m_d->inverse(ri, ii, ro); Chris@211: } Chris@211: Chris@211: Chris@211: