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