Chris@366
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@366
|
2 /*
|
Chris@366
|
3 Constant-Q library
|
Chris@366
|
4 Copyright (c) 2013-2014 Queen Mary, University of London
|
Chris@366
|
5
|
Chris@366
|
6 Permission is hereby granted, free of charge, to any person
|
Chris@366
|
7 obtaining a copy of this software and associated documentation
|
Chris@366
|
8 files (the "Software"), to deal in the Software without
|
Chris@366
|
9 restriction, including without limitation the rights to use, copy,
|
Chris@366
|
10 modify, merge, publish, distribute, sublicense, and/or sell copies
|
Chris@366
|
11 of the Software, and to permit persons to whom the Software is
|
Chris@366
|
12 furnished to do so, subject to the following conditions:
|
Chris@366
|
13
|
Chris@366
|
14 The above copyright notice and this permission notice shall be
|
Chris@366
|
15 included in all copies or substantial portions of the Software.
|
Chris@366
|
16
|
Chris@366
|
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
Chris@366
|
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
Chris@366
|
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
Chris@366
|
20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
Chris@366
|
21 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
Chris@366
|
22 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
Chris@366
|
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
Chris@366
|
24
|
Chris@366
|
25 Except as contained in this notice, the names of the Centre for
|
Chris@366
|
26 Digital Music; Queen Mary, University of London; and Chris Cannam
|
Chris@366
|
27 shall not be used in advertising or otherwise to promote the sale,
|
Chris@366
|
28 use or other dealings in this Software without prior written
|
Chris@366
|
29 authorization.
|
Chris@366
|
30 */
|
Chris@366
|
31
|
Chris@366
|
32 #include "FFT.h"
|
Chris@366
|
33
|
Chris@366
|
34 #include "MathUtilities.h"
|
Chris@366
|
35
|
Chris@366
|
36 #include "kiss_fft.h"
|
Chris@366
|
37 #include "kiss_fftr.h"
|
Chris@366
|
38
|
Chris@366
|
39 #include <cmath>
|
Chris@366
|
40
|
Chris@366
|
41 #include <iostream>
|
Chris@366
|
42
|
Chris@366
|
43 #include <stdexcept>
|
Chris@366
|
44
|
Chris@366
|
45 class FFT::D
|
Chris@366
|
46 {
|
Chris@366
|
47 public:
|
Chris@366
|
48 D(int n) : m_n(n) {
|
Chris@366
|
49 m_planf = kiss_fft_alloc(m_n, 0, NULL, NULL);
|
Chris@366
|
50 m_plani = kiss_fft_alloc(m_n, 1, NULL, NULL);
|
Chris@366
|
51 m_kin = new kiss_fft_cpx[m_n];
|
Chris@366
|
52 m_kout = new kiss_fft_cpx[m_n];
|
Chris@366
|
53 }
|
Chris@366
|
54
|
Chris@366
|
55 ~D() {
|
Chris@366
|
56 kiss_fft_free(m_planf);
|
Chris@366
|
57 kiss_fft_free(m_plani);
|
Chris@366
|
58 delete[] m_kin;
|
Chris@366
|
59 delete[] m_kout;
|
Chris@366
|
60 }
|
Chris@366
|
61
|
Chris@366
|
62 void process(bool inverse,
|
Chris@366
|
63 const double *ri,
|
Chris@366
|
64 const double *ii,
|
Chris@366
|
65 double *ro,
|
Chris@366
|
66 double *io) {
|
Chris@366
|
67
|
Chris@366
|
68 for (int i = 0; i < m_n; ++i) {
|
Chris@366
|
69 m_kin[i].r = ri[i];
|
Chris@366
|
70 m_kin[i].i = (ii ? ii[i] : 0.0);
|
Chris@366
|
71 }
|
Chris@366
|
72
|
Chris@366
|
73 if (!inverse) {
|
Chris@366
|
74
|
Chris@366
|
75 kiss_fft(m_planf, m_kin, m_kout);
|
Chris@366
|
76
|
Chris@366
|
77 for (int i = 0; i < m_n; ++i) {
|
Chris@366
|
78 ro[i] = m_kout[i].r;
|
Chris@366
|
79 io[i] = m_kout[i].i;
|
Chris@366
|
80 }
|
Chris@366
|
81
|
Chris@366
|
82 } else {
|
Chris@366
|
83
|
Chris@366
|
84 kiss_fft(m_plani, m_kin, m_kout);
|
Chris@366
|
85
|
Chris@366
|
86 double scale = 1.0 / m_n;
|
Chris@366
|
87
|
Chris@366
|
88 for (int i = 0; i < m_n; ++i) {
|
Chris@366
|
89 ro[i] = m_kout[i].r * scale;
|
Chris@366
|
90 io[i] = m_kout[i].i * scale;
|
Chris@366
|
91 }
|
Chris@366
|
92 }
|
Chris@366
|
93 }
|
Chris@366
|
94
|
Chris@366
|
95 private:
|
Chris@366
|
96 int m_n;
|
Chris@366
|
97 kiss_fft_cfg m_planf;
|
Chris@366
|
98 kiss_fft_cfg m_plani;
|
Chris@366
|
99 kiss_fft_cpx *m_kin;
|
Chris@366
|
100 kiss_fft_cpx *m_kout;
|
Chris@366
|
101 };
|
Chris@366
|
102
|
Chris@366
|
103 FFT::FFT(int n) :
|
Chris@366
|
104 m_d(new D(n))
|
Chris@366
|
105 {
|
Chris@366
|
106 }
|
Chris@366
|
107
|
Chris@366
|
108 FFT::~FFT()
|
Chris@366
|
109 {
|
Chris@366
|
110 delete m_d;
|
Chris@366
|
111 }
|
Chris@366
|
112
|
Chris@366
|
113 void
|
Chris@366
|
114 FFT::process(bool inverse,
|
Chris@366
|
115 const double *p_lpRealIn, const double *p_lpImagIn,
|
Chris@366
|
116 double *p_lpRealOut, double *p_lpImagOut)
|
Chris@366
|
117 {
|
Chris@366
|
118 m_d->process(inverse,
|
Chris@366
|
119 p_lpRealIn, p_lpImagIn,
|
Chris@366
|
120 p_lpRealOut, p_lpImagOut);
|
Chris@366
|
121 }
|
Chris@366
|
122
|
Chris@366
|
123 class FFTReal::D
|
Chris@366
|
124 {
|
Chris@366
|
125 public:
|
Chris@366
|
126 D(int n) : m_n(n) {
|
Chris@366
|
127 if (n % 2) {
|
Chris@366
|
128 throw std::invalid_argument
|
Chris@366
|
129 ("nsamples must be even in FFTReal constructor");
|
Chris@366
|
130 }
|
Chris@366
|
131 m_planf = kiss_fftr_alloc(m_n, 0, NULL, NULL);
|
Chris@366
|
132 m_plani = kiss_fftr_alloc(m_n, 1, NULL, NULL);
|
Chris@366
|
133 m_c = new kiss_fft_cpx[m_n];
|
Chris@366
|
134 }
|
Chris@366
|
135
|
Chris@366
|
136 ~D() {
|
Chris@366
|
137 kiss_fftr_free(m_planf);
|
Chris@366
|
138 kiss_fftr_free(m_plani);
|
Chris@366
|
139 delete[] m_c;
|
Chris@366
|
140 }
|
Chris@366
|
141
|
Chris@366
|
142 void forward(const double *ri, double *ro, double *io) {
|
Chris@366
|
143
|
Chris@366
|
144 kiss_fftr(m_planf, ri, m_c);
|
Chris@366
|
145
|
Chris@366
|
146 for (int i = 0; i <= m_n/2; ++i) {
|
Chris@366
|
147 ro[i] = m_c[i].r;
|
Chris@366
|
148 io[i] = m_c[i].i;
|
Chris@366
|
149 }
|
Chris@366
|
150
|
Chris@366
|
151 for (int i = 0; i + 1 < m_n/2; ++i) {
|
Chris@366
|
152 ro[m_n - i - 1] = ro[i + 1];
|
Chris@366
|
153 io[m_n - i - 1] = -io[i + 1];
|
Chris@366
|
154 }
|
Chris@366
|
155 }
|
Chris@366
|
156
|
Chris@366
|
157 void forwardMagnitude(const double *ri, double *mo) {
|
Chris@366
|
158
|
Chris@366
|
159 double *io = new double[m_n];
|
Chris@366
|
160
|
Chris@366
|
161 forward(ri, mo, io);
|
Chris@366
|
162
|
Chris@366
|
163 for (int i = 0; i < m_n; ++i) {
|
Chris@366
|
164 mo[i] = sqrt(mo[i] * mo[i] + io[i] * io[i]);
|
Chris@366
|
165 }
|
Chris@366
|
166
|
Chris@366
|
167 delete[] io;
|
Chris@366
|
168 }
|
Chris@366
|
169
|
Chris@366
|
170 void inverse(const double *ri, const double *ii, double *ro) {
|
Chris@366
|
171
|
Chris@366
|
172 // kiss_fftr.h says
|
Chris@366
|
173 // "input freqdata has nfft/2+1 complex points"
|
Chris@366
|
174
|
Chris@366
|
175 for (int i = 0; i < m_n/2 + 1; ++i) {
|
Chris@366
|
176 m_c[i].r = ri[i];
|
Chris@366
|
177 m_c[i].i = ii[i];
|
Chris@366
|
178 }
|
Chris@366
|
179
|
Chris@366
|
180 kiss_fftri(m_plani, m_c, ro);
|
Chris@366
|
181
|
Chris@366
|
182 double scale = 1.0 / m_n;
|
Chris@366
|
183
|
Chris@366
|
184 for (int i = 0; i < m_n; ++i) {
|
Chris@366
|
185 ro[i] *= scale;
|
Chris@366
|
186 }
|
Chris@366
|
187 }
|
Chris@366
|
188
|
Chris@366
|
189 private:
|
Chris@366
|
190 int m_n;
|
Chris@366
|
191 kiss_fftr_cfg m_planf;
|
Chris@366
|
192 kiss_fftr_cfg m_plani;
|
Chris@366
|
193 kiss_fft_cpx *m_c;
|
Chris@366
|
194 };
|
Chris@366
|
195
|
Chris@366
|
196 FFTReal::FFTReal(int n) :
|
Chris@366
|
197 m_d(new D(n))
|
Chris@366
|
198 {
|
Chris@366
|
199 }
|
Chris@366
|
200
|
Chris@366
|
201 FFTReal::~FFTReal()
|
Chris@366
|
202 {
|
Chris@366
|
203 delete m_d;
|
Chris@366
|
204 }
|
Chris@366
|
205
|
Chris@366
|
206 void
|
Chris@366
|
207 FFTReal::forward(const double *ri, double *ro, double *io)
|
Chris@366
|
208 {
|
Chris@366
|
209 m_d->forward(ri, ro, io);
|
Chris@366
|
210 }
|
Chris@366
|
211
|
Chris@366
|
212 void
|
Chris@366
|
213 FFTReal::forwardMagnitude(const double *ri, double *mo)
|
Chris@366
|
214 {
|
Chris@366
|
215 m_d->forwardMagnitude(ri, mo);
|
Chris@366
|
216 }
|
Chris@366
|
217
|
Chris@366
|
218 void
|
Chris@366
|
219 FFTReal::inverse(const double *ri, const double *ii, double *ro)
|
Chris@366
|
220 {
|
Chris@366
|
221 m_d->inverse(ri, ii, ro);
|
Chris@366
|
222 }
|
Chris@366
|
223
|
Chris@366
|
224
|
Chris@366
|
225
|