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