Chris@29
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@29
|
2
|
Chris@29
|
3 /*
|
Chris@29
|
4 bqfft
|
Chris@29
|
5
|
Chris@29
|
6 A small library wrapping various FFT implementations for some
|
Chris@29
|
7 common audio processing use cases.
|
Chris@29
|
8
|
Chris@29
|
9 Copyright 2007-2015 Particular Programs Ltd.
|
Chris@29
|
10
|
Chris@29
|
11 Permission is hereby granted, free of charge, to any person
|
Chris@29
|
12 obtaining a copy of this software and associated documentation
|
Chris@29
|
13 files (the "Software"), to deal in the Software without
|
Chris@29
|
14 restriction, including without limitation the rights to use, copy,
|
Chris@29
|
15 modify, merge, publish, distribute, sublicense, and/or sell copies
|
Chris@29
|
16 of the Software, and to permit persons to whom the Software is
|
Chris@29
|
17 furnished to do so, subject to the following conditions:
|
Chris@29
|
18
|
Chris@29
|
19 The above copyright notice and this permission notice shall be
|
Chris@29
|
20 included in all copies or substantial portions of the Software.
|
Chris@29
|
21
|
Chris@29
|
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
Chris@29
|
23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
Chris@29
|
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
Chris@29
|
25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
Chris@29
|
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
Chris@29
|
27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
Chris@29
|
28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
Chris@29
|
29
|
Chris@29
|
30 Except as contained in this notice, the names of Chris Cannam and
|
Chris@29
|
31 Particular Programs Ltd shall not be used in advertising or
|
Chris@29
|
32 otherwise to promote the sale, use or other dealings in this
|
Chris@29
|
33 Software without prior written authorization.
|
Chris@29
|
34 */
|
Chris@29
|
35
|
Chris@29
|
36 #ifndef TEST_FFT_H
|
Chris@29
|
37 #define TEST_FFT_H
|
Chris@29
|
38
|
Chris@29
|
39 #include "bqfft/FFT.h"
|
Chris@29
|
40
|
Chris@29
|
41 #include <QObject>
|
Chris@29
|
42 #include <QtTest>
|
Chris@29
|
43
|
Chris@29
|
44 #include <cstdio>
|
Chris@29
|
45
|
Chris@29
|
46 #include "Compares.h"
|
Chris@29
|
47
|
Chris@29
|
48 namespace breakfastquay {
|
Chris@29
|
49
|
Chris@29
|
50 class TestFFT : public QObject
|
Chris@29
|
51 {
|
Chris@29
|
52 Q_OBJECT
|
Chris@29
|
53
|
Chris@29
|
54 private:
|
Chris@29
|
55 void idat() {
|
Chris@29
|
56 QTest::addColumn<QString>("implementation");
|
Chris@29
|
57 std::set<std::string> impls = FFT::getImplementations();
|
Chris@29
|
58 foreach (std::string i, impls) {
|
Chris@29
|
59 QTest::newRow(i.c_str()) << i.c_str();
|
Chris@29
|
60 }
|
Chris@29
|
61 }
|
Chris@29
|
62 QString ifetch() {
|
Chris@29
|
63 QFETCH(QString, implementation);
|
Chris@29
|
64 FFT::setDefaultImplementation(implementation.toLocal8Bit().data());
|
Chris@29
|
65 return implementation;
|
Chris@29
|
66 }
|
Chris@29
|
67
|
Chris@29
|
68 bool lackSingle() {
|
Chris@29
|
69 return !(FFT(4).getSupportedPrecisions() & FFT::SinglePrecision);
|
Chris@29
|
70 }
|
Chris@29
|
71 bool lackDouble() {
|
Chris@29
|
72 return !(FFT(4).getSupportedPrecisions() & FFT::DoublePrecision);
|
Chris@29
|
73 }
|
Chris@29
|
74
|
Chris@29
|
75 private slots:
|
Chris@29
|
76
|
Chris@29
|
77 void checkD() {
|
Chris@29
|
78 QString impl = ifetch();
|
Chris@29
|
79 }
|
Chris@29
|
80
|
Chris@29
|
81 void dc() {
|
Chris@29
|
82 ifetch();
|
Chris@29
|
83 // DC-only signal. The DC bin is purely real
|
Chris@29
|
84 double in[] = { 1, 1, 1, 1 };
|
Chris@29
|
85 double re[3], im[3];
|
Chris@29
|
86 FFT(4).forward(in, re, im);
|
Chris@29
|
87 QCOMPARE(re[0], 4.0);
|
Chris@29
|
88 COMPARE_ZERO(re[1]);
|
Chris@29
|
89 COMPARE_ZERO(re[2]);
|
Chris@29
|
90 COMPARE_ALL(im, 0.0);
|
Chris@29
|
91 double back[4];
|
Chris@29
|
92 FFT(4).inverse(re, im, back);
|
Chris@29
|
93 COMPARE_SCALED(back, in, 4);
|
Chris@29
|
94 }
|
Chris@29
|
95
|
Chris@29
|
96 void sine() {
|
Chris@29
|
97 ifetch();
|
Chris@29
|
98 // Sine. Output is purely imaginary
|
Chris@29
|
99 double in[] = { 0, 1, 0, -1 };
|
Chris@29
|
100 double re[3], im[3];
|
Chris@29
|
101 FFT(4).forward(in, re, im);
|
Chris@29
|
102 COMPARE_ALL(re, 0.0);
|
Chris@29
|
103 COMPARE_ZERO(im[0]);
|
Chris@29
|
104 QCOMPARE(im[1], -2.0);
|
Chris@29
|
105 COMPARE_ZERO(im[2]);
|
Chris@29
|
106 double back[4];
|
Chris@29
|
107 FFT(4).inverse(re, im, back);
|
Chris@29
|
108 COMPARE_SCALED(back, in, 4);
|
Chris@29
|
109 }
|
Chris@29
|
110
|
Chris@29
|
111 void cosine() {
|
Chris@29
|
112 ifetch();
|
Chris@29
|
113 // Cosine. Output is purely real
|
Chris@29
|
114 double in[] = { 1, 0, -1, 0 };
|
Chris@29
|
115 double re[3], im[3];
|
Chris@29
|
116 FFT(4).forward(in, re, im);
|
Chris@29
|
117 COMPARE_ZERO(re[0]);
|
Chris@29
|
118 QCOMPARE(re[1], 2.0);
|
Chris@29
|
119 COMPARE_ZERO(re[2]);
|
Chris@29
|
120 COMPARE_ALL(im, 0.0);
|
Chris@29
|
121 double back[4];
|
Chris@29
|
122 FFT(4).inverse(re, im, back);
|
Chris@29
|
123 COMPARE_SCALED(back, in, 4);
|
Chris@29
|
124 }
|
Chris@29
|
125
|
Chris@29
|
126 void sineCosine() {
|
Chris@29
|
127 ifetch();
|
Chris@29
|
128 // Sine and cosine mixed
|
Chris@29
|
129 double in[] = { 0.5, 1, -0.5, -1 };
|
Chris@29
|
130 double re[3], im[3];
|
Chris@29
|
131 FFT(4).forward(in, re, im);
|
Chris@29
|
132 COMPARE_ZERO(re[0]);
|
Chris@29
|
133 QCOMPARE(re[1], 1.0);
|
Chris@29
|
134 COMPARE_ZERO(re[2]);
|
Chris@29
|
135 COMPARE_ZERO(im[0]);
|
Chris@29
|
136 QCOMPARE(im[1], -2.0);
|
Chris@29
|
137 COMPARE_ZERO(im[2]);
|
Chris@29
|
138 double back[4];
|
Chris@29
|
139 FFT(4).inverse(re, im, back);
|
Chris@29
|
140 COMPARE_SCALED(back, in, 4);
|
Chris@29
|
141 }
|
Chris@29
|
142
|
Chris@29
|
143 void nyquist() {
|
Chris@29
|
144 ifetch();
|
Chris@29
|
145 double in[] = { 1, -1, 1, -1 };
|
Chris@29
|
146 double re[3], im[3];
|
Chris@29
|
147 FFT(4).forward(in, re, im);
|
Chris@29
|
148 COMPARE_ZERO(re[0]);
|
Chris@29
|
149 COMPARE_ZERO(re[1]);
|
Chris@29
|
150 QCOMPARE(re[2], 4.0);
|
Chris@29
|
151 COMPARE_ALL(im, 0.0);
|
Chris@29
|
152 double back[4];
|
Chris@29
|
153 FFT(4).inverse(re, im, back);
|
Chris@29
|
154 COMPARE_SCALED(back, in, 4);
|
Chris@29
|
155 }
|
Chris@29
|
156
|
Chris@29
|
157 void interleaved() {
|
Chris@29
|
158 ifetch();
|
Chris@29
|
159 // Sine and cosine mixed, test output format
|
Chris@29
|
160 double in[] = { 0.5, 1, -0.5, -1 };
|
Chris@29
|
161 double out[6];
|
Chris@29
|
162 FFT(4).forwardInterleaved(in, out);
|
Chris@29
|
163 COMPARE_ZERO(out[0]);
|
Chris@29
|
164 COMPARE_ZERO(out[1]);
|
Chris@29
|
165 QCOMPARE(out[2], 1.0);
|
Chris@29
|
166 QCOMPARE(out[3], -2.0);
|
Chris@29
|
167 COMPARE_ZERO(out[4]);
|
Chris@29
|
168 COMPARE_ZERO(out[5]);
|
Chris@29
|
169 double back[4];
|
Chris@29
|
170 FFT(4).inverseInterleaved(out, back);
|
Chris@29
|
171 COMPARE_SCALED(back, in, 4);
|
Chris@29
|
172 }
|
Chris@29
|
173
|
Chris@29
|
174 void cosinePolar() {
|
Chris@29
|
175 ifetch();
|
Chris@29
|
176 double in[] = { 1, 0, -1, 0 };
|
Chris@29
|
177 double mag[3], phase[3];
|
Chris@29
|
178 FFT(4).forwardPolar(in, mag, phase);
|
Chris@29
|
179 COMPARE_ZERO(mag[0]);
|
Chris@29
|
180 QCOMPARE(mag[1], 2.0);
|
Chris@29
|
181 COMPARE_ZERO(mag[2]);
|
Chris@29
|
182 // No meaningful tests for phase[i] where mag[i]==0 (phase
|
Chris@29
|
183 // could legitimately be anything)
|
Chris@29
|
184 COMPARE_ZERO(phase[1]);
|
Chris@29
|
185 double back[4];
|
Chris@29
|
186 FFT(4).inversePolar(mag, phase, back);
|
Chris@29
|
187 COMPARE_SCALED(back, in, 4);
|
Chris@29
|
188 }
|
Chris@29
|
189
|
Chris@29
|
190 void sinePolar() {
|
Chris@29
|
191 ifetch();
|
Chris@29
|
192 double in[] = { 0, 1, 0, -1 };
|
Chris@29
|
193 double mag[3], phase[3];
|
Chris@29
|
194 FFT(4).forwardPolar(in, mag, phase);
|
Chris@29
|
195 COMPARE_ZERO(mag[0]);
|
Chris@29
|
196 QCOMPARE(mag[1], 2.0);
|
Chris@29
|
197 COMPARE_ZERO(mag[2]);
|
Chris@29
|
198 // No meaningful tests for phase[i] where mag[i]==0 (phase
|
Chris@29
|
199 // could legitimately be anything)
|
Chris@29
|
200 QCOMPARE(phase[1], -M_PI/2.0);
|
Chris@29
|
201 double back[4];
|
Chris@29
|
202 FFT(4).inversePolar(mag, phase, back);
|
Chris@29
|
203 COMPARE_SCALED(back, in, 4);
|
Chris@29
|
204 }
|
Chris@29
|
205
|
Chris@29
|
206 void magnitude() {
|
Chris@29
|
207 ifetch();
|
Chris@29
|
208 // Sine and cosine mixed
|
Chris@29
|
209 double in[] = { 0.5, 1, -0.5, -1 };
|
Chris@29
|
210 double out[3];
|
Chris@29
|
211 FFT(4).forwardMagnitude(in, out);
|
Chris@29
|
212 COMPARE_ZERO(out[0]);
|
Chris@29
|
213 QCOMPARE(float(out[1]), sqrtf(5.0));
|
Chris@29
|
214 COMPARE_ZERO(out[2]);
|
Chris@29
|
215 }
|
Chris@29
|
216
|
Chris@29
|
217 void dirac() {
|
Chris@29
|
218 ifetch();
|
Chris@29
|
219 double in[] = { 1, 0, 0, 0 };
|
Chris@29
|
220 double re[3], im[3];
|
Chris@29
|
221 FFT(4).forward(in, re, im);
|
Chris@29
|
222 QCOMPARE(re[0], 1.0);
|
Chris@29
|
223 QCOMPARE(re[1], 1.0);
|
Chris@29
|
224 QCOMPARE(re[2], 1.0);
|
Chris@29
|
225 COMPARE_ALL(im, 0.0);
|
Chris@29
|
226 double back[4];
|
Chris@29
|
227 FFT(4).inverse(re, im, back);
|
Chris@29
|
228 COMPARE_SCALED(back, in, 4);
|
Chris@29
|
229 }
|
Chris@29
|
230
|
Chris@29
|
231 void cepstrum() {
|
Chris@29
|
232 ifetch();
|
Chris@29
|
233 double in[] = { 1, 0, 0, 0, 1, 0, 0, 0 };
|
Chris@29
|
234 double mag[5];
|
Chris@29
|
235 FFT(8).forwardMagnitude(in, mag);
|
Chris@29
|
236 double cep[8];
|
Chris@29
|
237 FFT(8).inverseCepstral(mag, cep);
|
Chris@29
|
238 COMPARE_ZERO(cep[1]);
|
Chris@29
|
239 COMPARE_ZERO(cep[2]);
|
Chris@29
|
240 COMPARE_ZERO(cep[3]);
|
Chris@29
|
241 COMPARE_ZERO(cep[5]);
|
Chris@29
|
242 COMPARE_ZERO(cep[6]);
|
Chris@29
|
243 COMPARE_ZERO(cep[7]);
|
Chris@29
|
244 QVERIFY(fabs(-6.561181 - cep[0]/8) < 0.000001);
|
Chris@29
|
245 QVERIFY(fabs( 7.254329 - cep[4]/8) < 0.000001);
|
Chris@29
|
246 }
|
Chris@29
|
247
|
Chris@29
|
248 void forwardArrayBounds() {
|
Chris@29
|
249 ifetch();
|
Chris@29
|
250 // initialise bins to something recognisable, so we can tell
|
Chris@29
|
251 // if they haven't been written
|
Chris@29
|
252 double in[] = { 1, 1, -1, -1 };
|
Chris@29
|
253 double re[] = { 999, 999, 999, 999, 999 };
|
Chris@29
|
254 double im[] = { 999, 999, 999, 999, 999 };
|
Chris@29
|
255 FFT(4).forward(in, re+1, im+1);
|
Chris@29
|
256 // And check we haven't overrun the arrays
|
Chris@29
|
257 QCOMPARE(re[0], 999.0);
|
Chris@29
|
258 QCOMPARE(im[0], 999.0);
|
Chris@29
|
259 QCOMPARE(re[4], 999.0);
|
Chris@29
|
260 QCOMPARE(im[4], 999.0);
|
Chris@29
|
261 }
|
Chris@29
|
262
|
Chris@29
|
263 void inverseArrayBounds() {
|
Chris@29
|
264 ifetch();
|
Chris@29
|
265 // initialise bins to something recognisable, so we can tell
|
Chris@29
|
266 // if they haven't been written
|
Chris@29
|
267 double re[] = { 0, 1, 0 };
|
Chris@29
|
268 double im[] = { 0, -2, 0 };
|
Chris@29
|
269 double out[] = { 999, 999, 999, 999, 999, 999 };
|
Chris@29
|
270 FFT(4).inverse(re, im, out+1);
|
Chris@29
|
271 // And check we haven't overrun the arrays
|
Chris@29
|
272 QCOMPARE(out[0], 999.0);
|
Chris@29
|
273 QCOMPARE(out[5], 999.0);
|
Chris@29
|
274 }
|
Chris@29
|
275
|
Chris@29
|
276 void checkF() {
|
Chris@29
|
277 QString impl = ifetch();
|
Chris@29
|
278 }
|
Chris@29
|
279
|
Chris@29
|
280 void dcF() {
|
Chris@29
|
281 ifetch();
|
Chris@29
|
282 // DC-only signal. The DC bin is purely real
|
Chris@29
|
283 float in[] = { 1, 1, 1, 1 };
|
Chris@29
|
284 float re[3], im[3];
|
Chris@29
|
285 FFT(4).forward(in, re, im);
|
Chris@29
|
286 QCOMPARE(re[0], 4.0f);
|
Chris@29
|
287 COMPARE_ZERO_F(re[1]);
|
Chris@29
|
288 COMPARE_ZERO_F(re[2]);
|
Chris@29
|
289 COMPARE_ALL_F(im, 0.0f);
|
Chris@29
|
290 float back[4];
|
Chris@29
|
291 FFT(4).inverse(re, im, back);
|
Chris@29
|
292 COMPARE_SCALED_F(back, in, 4);
|
Chris@29
|
293 }
|
Chris@29
|
294
|
Chris@29
|
295 void sineF() {
|
Chris@29
|
296 ifetch();
|
Chris@29
|
297 // Sine. Output is purely imaginary
|
Chris@29
|
298 float in[] = { 0, 1, 0, -1 };
|
Chris@29
|
299 float re[3], im[3];
|
Chris@29
|
300 FFT(4).forward(in, re, im);
|
Chris@29
|
301 COMPARE_ALL_F(re, 0.0f);
|
Chris@29
|
302 COMPARE_ZERO_F(im[0]);
|
Chris@29
|
303 QCOMPARE(im[1], -2.0f);
|
Chris@29
|
304 COMPARE_ZERO_F(im[2]);
|
Chris@29
|
305 float back[4];
|
Chris@29
|
306 FFT(4).inverse(re, im, back);
|
Chris@29
|
307 COMPARE_SCALED_F(back, in, 4);
|
Chris@29
|
308 }
|
Chris@29
|
309
|
Chris@29
|
310 void cosineF() {
|
Chris@29
|
311 ifetch();
|
Chris@29
|
312 // Cosine. Output is purely real
|
Chris@29
|
313 float in[] = { 1, 0, -1, 0 };
|
Chris@29
|
314 float re[3], im[3];
|
Chris@29
|
315 FFT(4).forward(in, re, im);
|
Chris@29
|
316 COMPARE_ZERO_F(re[0]);
|
Chris@29
|
317 QCOMPARE(re[1], 2.0f);
|
Chris@29
|
318 COMPARE_ZERO_F(re[2]);
|
Chris@29
|
319 COMPARE_ALL_F(im, 0.0f);
|
Chris@29
|
320 float back[4];
|
Chris@29
|
321 FFT(4).inverse(re, im, back);
|
Chris@29
|
322 COMPARE_SCALED_F(back, in, 4);
|
Chris@29
|
323 }
|
Chris@29
|
324
|
Chris@29
|
325 void sineCosineF() {
|
Chris@29
|
326 ifetch();
|
Chris@29
|
327 // Sine and cosine mixed
|
Chris@29
|
328 float in[] = { 0.5, 1, -0.5, -1 };
|
Chris@29
|
329 float re[3], im[3];
|
Chris@29
|
330 FFT(4).forward(in, re, im);
|
Chris@29
|
331 COMPARE_ZERO_F(re[0]);
|
Chris@29
|
332 QCOMPARE(re[1], 1.0f);
|
Chris@29
|
333 COMPARE_ZERO_F(re[2]);
|
Chris@29
|
334 COMPARE_ZERO_F(im[0]);
|
Chris@29
|
335 QCOMPARE(im[1], -2.0f);
|
Chris@29
|
336 COMPARE_ZERO_F(im[2]);
|
Chris@29
|
337 float back[4];
|
Chris@29
|
338 FFT(4).inverse(re, im, back);
|
Chris@29
|
339 COMPARE_SCALED_F(back, in, 4);
|
Chris@29
|
340 }
|
Chris@29
|
341
|
Chris@29
|
342 void nyquistF() {
|
Chris@29
|
343 ifetch();
|
Chris@29
|
344 float in[] = { 1, -1, 1, -1 };
|
Chris@29
|
345 float re[3], im[3];
|
Chris@29
|
346 FFT(4).forward(in, re, im);
|
Chris@29
|
347 COMPARE_ZERO_F(re[0]);
|
Chris@29
|
348 COMPARE_ZERO_F(re[1]);
|
Chris@29
|
349 QCOMPARE(re[2], 4.0f);
|
Chris@29
|
350 COMPARE_ALL_F(im, 0.0f);
|
Chris@29
|
351 float back[4];
|
Chris@29
|
352 FFT(4).inverse(re, im, back);
|
Chris@29
|
353 COMPARE_SCALED_F(back, in, 4);
|
Chris@29
|
354 }
|
Chris@29
|
355
|
Chris@29
|
356 void interleavedF() {
|
Chris@29
|
357 ifetch();
|
Chris@29
|
358 // Sine and cosine mixed, test output format
|
Chris@29
|
359 float in[] = { 0.5, 1, -0.5, -1 };
|
Chris@29
|
360 float out[6];
|
Chris@29
|
361 FFT(4).forwardInterleaved(in, out);
|
Chris@29
|
362 COMPARE_ZERO_F(out[0]);
|
Chris@29
|
363 COMPARE_ZERO_F(out[1]);
|
Chris@29
|
364 QCOMPARE(out[2], 1.0f);
|
Chris@29
|
365 QCOMPARE(out[3], -2.0f);
|
Chris@29
|
366 COMPARE_ZERO_F(out[4]);
|
Chris@29
|
367 COMPARE_ZERO_F(out[5]);
|
Chris@29
|
368 float back[4];
|
Chris@29
|
369 FFT(4).inverseInterleaved(out, back);
|
Chris@29
|
370 COMPARE_SCALED_F(back, in, 4);
|
Chris@29
|
371 }
|
Chris@29
|
372
|
Chris@29
|
373 void cosinePolarF() {
|
Chris@29
|
374 ifetch();
|
Chris@29
|
375 float in[] = { 1, 0, -1, 0 };
|
Chris@29
|
376 float mag[3], phase[3];
|
Chris@29
|
377 FFT(4).forwardPolar(in, mag, phase);
|
Chris@29
|
378 COMPARE_ZERO_F(mag[0]);
|
Chris@29
|
379 QCOMPARE(mag[1], 2.0f);
|
Chris@29
|
380 COMPARE_ZERO_F(mag[2]);
|
Chris@29
|
381 // No meaningful tests for phase[i] where mag[i]==0 (phase
|
Chris@29
|
382 // could legitimately be anything)
|
Chris@29
|
383 COMPARE_ZERO_F(phase[1]);
|
Chris@29
|
384 float back[4];
|
Chris@29
|
385 FFT(4).inversePolar(mag, phase, back);
|
Chris@29
|
386 COMPARE_SCALED_F(back, in, 4);
|
Chris@29
|
387 }
|
Chris@29
|
388
|
Chris@29
|
389 void sinePolarF() {
|
Chris@29
|
390 ifetch();
|
Chris@29
|
391 float in[] = { 0, 1, 0, -1 };
|
Chris@29
|
392 float mag[3], phase[3];
|
Chris@29
|
393 FFT(4).forwardPolar(in, mag, phase);
|
Chris@29
|
394 COMPARE_ZERO_F(mag[0]);
|
Chris@29
|
395 QCOMPARE(mag[1], 2.0f);
|
Chris@29
|
396 COMPARE_ZERO_F(mag[2]);
|
Chris@29
|
397 // No meaningful tests for phase[i] where mag[i]==0 (phase
|
Chris@29
|
398 // could legitimately be anything)
|
Chris@29
|
399 QCOMPARE(phase[1], -float(M_PI)/2.0f);
|
Chris@29
|
400 float back[4];
|
Chris@29
|
401 FFT(4).inversePolar(mag, phase, back);
|
Chris@29
|
402 COMPARE_SCALED_F(back, in, 4);
|
Chris@29
|
403 }
|
Chris@29
|
404
|
Chris@29
|
405 void magnitudeF() {
|
Chris@29
|
406 ifetch();
|
Chris@29
|
407 // Sine and cosine mixed
|
Chris@29
|
408 float in[] = { 0.5, 1, -0.5, -1 };
|
Chris@29
|
409 float out[3];
|
Chris@29
|
410 FFT(4).forwardMagnitude(in, out);
|
Chris@29
|
411 COMPARE_ZERO_F(out[0]);
|
Chris@29
|
412 QCOMPARE(float(out[1]), sqrtf(5.0f));
|
Chris@29
|
413 COMPARE_ZERO_F(out[2]);
|
Chris@29
|
414 }
|
Chris@29
|
415
|
Chris@29
|
416 void diracF() {
|
Chris@29
|
417 ifetch();
|
Chris@29
|
418 float in[] = { 1, 0, 0, 0 };
|
Chris@29
|
419 float re[3], im[3];
|
Chris@29
|
420 FFT(4).forward(in, re, im);
|
Chris@29
|
421 QCOMPARE(re[0], 1.0f);
|
Chris@29
|
422 QCOMPARE(re[1], 1.0f);
|
Chris@29
|
423 QCOMPARE(re[2], 1.0f);
|
Chris@29
|
424 COMPARE_ALL_F(im, 0.0f);
|
Chris@29
|
425 float back[4];
|
Chris@29
|
426 FFT(4).inverse(re, im, back);
|
Chris@29
|
427 COMPARE_SCALED_F(back, in, 4);
|
Chris@29
|
428 }
|
Chris@29
|
429
|
Chris@29
|
430 void cepstrumF() {
|
Chris@29
|
431 ifetch();
|
Chris@29
|
432 float in[] = { 1, 0, 0, 0, 1, 0, 0, 0 };
|
Chris@29
|
433 float mag[5];
|
Chris@29
|
434 FFT(8).forwardMagnitude(in, mag);
|
Chris@29
|
435 float cep[8];
|
Chris@29
|
436 FFT(8).inverseCepstral(mag, cep);
|
Chris@29
|
437 COMPARE_ZERO_F(cep[1]);
|
Chris@29
|
438 COMPARE_ZERO_F(cep[2]);
|
Chris@29
|
439 COMPARE_ZERO_F(cep[3]);
|
Chris@29
|
440 COMPARE_ZERO_F(cep[5]);
|
Chris@29
|
441 COMPARE_ZERO_F(cep[6]);
|
Chris@29
|
442 COMPARE_ZERO_F(cep[7]);
|
Chris@29
|
443 QVERIFY(fabsf(-6.561181 - cep[0]/8) < 0.000001);
|
Chris@29
|
444 QVERIFY(fabsf( 7.254329 - cep[4]/8) < 0.000001);
|
Chris@29
|
445 }
|
Chris@29
|
446
|
Chris@29
|
447 void forwardArrayBoundsF() {
|
Chris@29
|
448 ifetch();
|
Chris@29
|
449 // initialise bins to something recognisable, so we can tell
|
Chris@29
|
450 // if they haven't been written
|
Chris@29
|
451 float in[] = { 1, 1, -1, -1 };
|
Chris@29
|
452 float re[] = { 999, 999, 999, 999, 999 };
|
Chris@29
|
453 float im[] = { 999, 999, 999, 999, 999 };
|
Chris@29
|
454 FFT(4).forward(in, re+1, im+1);
|
Chris@29
|
455 // And check we haven't overrun the arrays
|
Chris@29
|
456 QCOMPARE(re[0], 999.0f);
|
Chris@29
|
457 QCOMPARE(im[0], 999.0f);
|
Chris@29
|
458 QCOMPARE(re[4], 999.0f);
|
Chris@29
|
459 QCOMPARE(im[4], 999.0f);
|
Chris@29
|
460 }
|
Chris@29
|
461
|
Chris@29
|
462 void inverseArrayBoundsF() {
|
Chris@29
|
463 ifetch();
|
Chris@29
|
464 // initialise bins to something recognisable, so we can tell
|
Chris@29
|
465 // if they haven't been written
|
Chris@29
|
466 float re[] = { 0, 1, 0 };
|
Chris@29
|
467 float im[] = { 0, -2, 0 };
|
Chris@29
|
468 float out[] = { 999, 999, 999, 999, 999, 999 };
|
Chris@29
|
469 FFT(4).inverse(re, im, out+1);
|
Chris@29
|
470 // And check we haven't overrun the arrays
|
Chris@29
|
471 QCOMPARE(out[0], 999.0f);
|
Chris@29
|
472 QCOMPARE(out[5], 999.0f);
|
Chris@29
|
473 }
|
Chris@29
|
474
|
Chris@29
|
475 void checkD_data() { idat(); }
|
Chris@29
|
476 void dc_data() { idat(); }
|
Chris@29
|
477 void sine_data() { idat(); }
|
Chris@29
|
478 void cosine_data() { idat(); }
|
Chris@29
|
479 void sineCosine_data() { idat(); }
|
Chris@29
|
480 void sineCosineDC_data() { idat(); }
|
Chris@29
|
481 void nyquist_data() { idat(); }
|
Chris@29
|
482 void interleaved_data() { idat(); }
|
Chris@29
|
483 void cosinePolar_data() { idat(); }
|
Chris@29
|
484 void sinePolar_data() { idat(); }
|
Chris@29
|
485 void magnitude_data() { idat(); }
|
Chris@29
|
486 void dirac_data() { idat(); }
|
Chris@29
|
487 void cepstrum_data() { idat(); }
|
Chris@29
|
488 void forwardArrayBounds_data() { idat(); }
|
Chris@29
|
489 void inverseArrayBounds_data() { idat(); }
|
Chris@29
|
490
|
Chris@29
|
491 void checkF_data() { idat(); }
|
Chris@29
|
492 void dcF_data() { idat(); }
|
Chris@29
|
493 void sineF_data() { idat(); }
|
Chris@29
|
494 void cosineF_data() { idat(); }
|
Chris@29
|
495 void sineCosineF_data() { idat(); }
|
Chris@29
|
496 void sineCosineDCF_data() { idat(); }
|
Chris@29
|
497 void nyquistF_data() { idat(); }
|
Chris@29
|
498 void interleavedF_data() { idat(); }
|
Chris@29
|
499 void cosinePolarF_data() { idat(); }
|
Chris@29
|
500 void sinePolarF_data() { idat(); }
|
Chris@29
|
501 void magnitudeF_data() { idat(); }
|
Chris@29
|
502 void diracF_data() { idat(); }
|
Chris@29
|
503 void cepstrumF_data() { idat(); }
|
Chris@29
|
504 void forwardArrayBoundsF_data() { idat(); }
|
Chris@29
|
505 void inverseArrayBoundsF_data() { idat(); }
|
Chris@29
|
506 };
|
Chris@29
|
507
|
Chris@29
|
508 }
|
Chris@29
|
509
|
Chris@29
|
510 #endif
|