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