annotate dsp/transforms/FFT.cpp @ 129:6ec45e85ed81 kissfft

Drop in kissfft to replace the "old" fft, and add tests for newly-supported sizes
author Chris Cannam
date Tue, 15 Oct 2013 11:38:18 +0100
parents f6ccde089491
children a586888bc06c
rev   line source
cannam@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@0 2
cannam@0 3 /*
cannam@0 4 QM DSP Library
cannam@0 5
cannam@0 6 Centre for Digital Music, Queen Mary, University of London.
cannam@0 7 This file is based on Don Cross's public domain FFT implementation.
cannam@0 8 */
cannam@0 9
cannam@0 10 #include "FFT.h"
cannam@55 11
cannam@55 12 #include "maths/MathUtilities.h"
cannam@55 13
Chris@129 14 #include "kiss_fft.h"
Chris@129 15 #include "kiss_fftr.h"
Chris@129 16
cannam@0 17 #include <cmath>
cannam@0 18
cannam@55 19 #include <iostream>
cannam@55 20
Chris@129 21 #include <stdexcept>
Chris@129 22
Chris@129 23 class FFT::D
Chris@129 24 {
Chris@129 25 public:
Chris@129 26 D(int n) : m_n(n) {
Chris@129 27 m_planf = kiss_fft_alloc(m_n, 0, NULL, NULL);
Chris@129 28 m_plani = kiss_fft_alloc(m_n, 1, NULL, NULL);
Chris@129 29 m_kin = new kiss_fft_cpx[m_n];
Chris@129 30 m_kout = new kiss_fft_cpx[m_n];
Chris@129 31 }
Chris@129 32
Chris@129 33 ~D() {
Chris@129 34 kiss_fft_free(m_planf);
Chris@129 35 kiss_fft_free(m_plani);
Chris@129 36 delete[] m_kin;
Chris@129 37 delete[] m_kout;
Chris@129 38 }
Chris@129 39
Chris@129 40 void process(bool inverse,
Chris@129 41 const double *ri,
Chris@129 42 const double *ii,
Chris@129 43 double *ro,
Chris@129 44 double *io) {
Chris@129 45
Chris@129 46 for (int i = 0; i < m_n; ++i) {
Chris@129 47 m_kin[i].r = ri[i];
Chris@129 48 m_kin[i].i = (ii ? ii[i] : 0.0);
Chris@129 49 }
Chris@129 50
Chris@129 51 if (!inverse) {
Chris@129 52
Chris@129 53 kiss_fft(m_planf, m_kin, m_kout);
Chris@129 54
Chris@129 55 for (int i = 0; i < m_n; ++i) {
Chris@129 56 ro[i] = m_kout[i].r;
Chris@129 57 io[i] = m_kout[i].i;
Chris@129 58 }
Chris@129 59
Chris@129 60 } else {
Chris@129 61
Chris@129 62 kiss_fft(m_plani, m_kin, m_kout);
Chris@129 63
Chris@129 64 double scale = 1.0 / m_n;
Chris@129 65
Chris@129 66 for (int i = 0; i < m_n; ++i) {
Chris@129 67 ro[i] = m_kout[i].r * scale;
Chris@129 68 io[i] = m_kout[i].i * scale;
Chris@129 69 }
Chris@129 70 }
Chris@129 71 }
Chris@129 72
Chris@129 73 private:
Chris@129 74 int m_n;
Chris@129 75 kiss_fft_cfg m_planf;
Chris@129 76 kiss_fft_cfg m_plani;
Chris@129 77 kiss_fft_cpx *m_kin;
Chris@129 78 kiss_fft_cpx *m_kout;
Chris@129 79 };
Chris@129 80
Chris@114 81 FFT::FFT(int n) :
Chris@129 82 m_d(new D(n))
cannam@0 83 {
cannam@0 84 }
cannam@0 85
cannam@0 86 FFT::~FFT()
cannam@0 87 {
Chris@129 88 delete m_d;
cannam@0 89 }
cannam@0 90
Chris@129 91 void
Chris@129 92 FFT::process(bool inverse,
Chris@129 93 const double *p_lpRealIn, const double *p_lpImagIn,
Chris@129 94 double *p_lpRealOut, double *p_lpImagOut)
Chris@129 95 {
Chris@129 96 m_d->process(inverse,
Chris@129 97 p_lpRealIn, p_lpImagIn,
Chris@129 98 p_lpRealOut, p_lpImagOut);
Chris@129 99 }
Chris@129 100
Chris@129 101 class FFTReal::D
Chris@129 102 {
Chris@129 103 public:
Chris@129 104 D(int n) : m_n(n) {
Chris@129 105 if (n % 2) {
Chris@129 106 throw std::invalid_argument
Chris@129 107 ("nsamples must be even in FFTReal constructor");
Chris@129 108 }
Chris@129 109 m_planf = kiss_fftr_alloc(m_n, 0, NULL, NULL);
Chris@129 110 m_plani = kiss_fftr_alloc(m_n, 1, NULL, NULL);
Chris@129 111 m_c = new kiss_fft_cpx[m_n];
Chris@129 112 }
Chris@129 113
Chris@129 114 ~D() {
Chris@129 115 kiss_fftr_free(m_planf);
Chris@129 116 kiss_fftr_free(m_plani);
Chris@129 117 delete[] m_c;
Chris@129 118 }
Chris@129 119
Chris@129 120 void forward(const double *ri, double *ro, double *io) {
Chris@129 121
Chris@129 122 kiss_fftr(m_planf, ri, m_c);
Chris@129 123
Chris@129 124 for (int i = 0; i <= m_n/2; ++i) {
Chris@129 125 ro[i] = m_c[i].r;
Chris@129 126 io[i] = m_c[i].i;
Chris@129 127 }
Chris@129 128
Chris@129 129 for (int i = 0; i + 1 < m_n/2; ++i) {
Chris@129 130 ro[m_n - i - 1] = ro[i + 1];
Chris@129 131 io[m_n - i - 1] = -io[i + 1];
Chris@129 132 }
Chris@129 133 }
Chris@129 134
Chris@129 135 void inverse(const double *ri, const double *ii, double *ro) {
Chris@129 136
Chris@129 137 for (int i = 0; i < m_n; ++i) {
Chris@129 138 m_c[i].r = ri[i];
Chris@129 139 m_c[i].i = ii[i];
Chris@129 140 }
Chris@129 141
Chris@129 142 kiss_fftri(m_plani, m_c, ro);
Chris@129 143
Chris@129 144 double scale = 1.0 / m_n;
Chris@129 145
Chris@129 146 for (int i = 0; i < m_n; ++i) {
Chris@129 147 ro[i] *= scale;
Chris@129 148 }
Chris@129 149 }
Chris@129 150
Chris@129 151 private:
Chris@129 152 int m_n;
Chris@129 153 kiss_fftr_cfg m_planf;
Chris@129 154 kiss_fftr_cfg m_plani;
Chris@129 155 kiss_fft_cpx *m_c;
Chris@129 156 };
Chris@129 157
Chris@114 158 FFTReal::FFTReal(int n) :
Chris@129 159 m_d(new D(n))
cannam@0 160 {
cannam@64 161 }
cannam@0 162
cannam@64 163 FFTReal::~FFTReal()
cannam@64 164 {
Chris@129 165 delete m_d;
cannam@64 166 }
cannam@64 167
cannam@64 168 void
Chris@129 169 FFTReal::forward(const double *ri, double *ro, double *io)
cannam@64 170 {
Chris@129 171 m_d->forward(ri, ro, io);
cannam@64 172 }
cannam@64 173
Chris@114 174 void
Chris@129 175 FFTReal::inverse(const double *ri, const double *ii, double *ro)
Chris@114 176 {
Chris@129 177 m_d->inverse(ri, ii, ro);
Chris@114 178 }
Chris@114 179
cannam@64 180
Chris@129 181