Chris@1086
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@1086
|
2
|
Chris@1086
|
3 /*
|
Chris@1086
|
4 Sonic Visualiser
|
Chris@1086
|
5 An audio file viewer and annotation editor.
|
Chris@1086
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@1086
|
7
|
Chris@1086
|
8 This program is free software; you can redistribute it and/or
|
Chris@1086
|
9 modify it under the terms of the GNU General Public License as
|
Chris@1086
|
10 published by the Free Software Foundation; either version 2 of the
|
Chris@1086
|
11 License, or (at your option) any later version. See the file
|
Chris@1086
|
12 COPYING included with this distribution for more information.
|
Chris@1086
|
13 */
|
Chris@1086
|
14
|
Chris@1086
|
15 #ifndef TEST_FFT_MODEL_H
|
Chris@1086
|
16 #define TEST_FFT_MODEL_H
|
Chris@1086
|
17
|
Chris@1086
|
18 #include "../FFTModel.h"
|
Chris@1086
|
19
|
Chris@1086
|
20 #include "MockWaveModel.h"
|
Chris@1086
|
21
|
Chris@1086
|
22 #include "Compares.h"
|
Chris@1086
|
23
|
Chris@1086
|
24 #include <QObject>
|
Chris@1086
|
25 #include <QtTest>
|
Chris@1086
|
26 #include <QDir>
|
Chris@1086
|
27
|
Chris@1086
|
28 #include <iostream>
|
Chris@1088
|
29 #include <complex>
|
Chris@1086
|
30
|
Chris@1086
|
31 using namespace std;
|
Chris@1086
|
32
|
Chris@1086
|
33 class TestFFTModel : public QObject
|
Chris@1086
|
34 {
|
Chris@1086
|
35 Q_OBJECT
|
Chris@1086
|
36
|
Chris@1088
|
37 private:
|
Chris@1088
|
38 void test(DenseTimeValueModel *model,
|
Chris@1088
|
39 WindowType window, int windowSize, int windowIncrement, int fftSize,
|
Chris@1088
|
40 int columnNo, vector<vector<complex<float>>> expectedValues,
|
Chris@1088
|
41 int expectedWidth) {
|
Chris@1088
|
42 for (int ch = 0; in_range_for(expectedValues, ch); ++ch) {
|
Chris@1088
|
43 for (int polar = 0; polar <= 1; ++polar) {
|
Chris@1088
|
44 FFTModel fftm(model, ch, window, windowSize, windowIncrement,
|
Chris@1088
|
45 fftSize, bool(polar));
|
Chris@1088
|
46 QCOMPARE(fftm.getWidth(), expectedWidth);
|
Chris@1088
|
47 int hs1 = fftSize/2 + 1;
|
Chris@1088
|
48 QCOMPARE(fftm.getHeight(), hs1);
|
Chris@1088
|
49 vector<float> reals(hs1 + 1, 0.f);
|
Chris@1088
|
50 vector<float> imags(hs1 + 1, 0.f);
|
Chris@1088
|
51 reals[hs1] = 999.f; // overrun guards
|
Chris@1088
|
52 imags[hs1] = 999.f;
|
Chris@1088
|
53 fftm.getValuesAt(columnNo, &reals[0], &imags[0]);
|
Chris@1088
|
54 for (int i = 0; i < hs1; ++i) {
|
Chris@1088
|
55 float eRe = expectedValues[ch][i].real();
|
Chris@1088
|
56 float eIm = expectedValues[ch][i].imag();
|
Chris@1088
|
57 if (reals[i] != eRe || imags[i] != eIm) {
|
Chris@1088
|
58 cerr << "ERROR: output is not as expected for column "
|
Chris@1088
|
59 << i << " in channel " << ch << " (polar store = "
|
Chris@1088
|
60 << polar << ")" << endl;
|
Chris@1088
|
61 cerr << "expected : ";
|
Chris@1088
|
62 for (int j = 0; j < hs1; ++j) {
|
Chris@1088
|
63 cerr << expectedValues[ch][j] << " ";
|
Chris@1088
|
64 }
|
Chris@1088
|
65 cerr << "\nactual : ";
|
Chris@1088
|
66 for (int j = 0; j < hs1; ++j) {
|
Chris@1088
|
67 cerr << complex<float>(reals[j], imags[j]) << " ";
|
Chris@1088
|
68 }
|
Chris@1088
|
69 cerr << endl;
|
Chris@1088
|
70 }
|
Chris@1088
|
71 QCOMPARE(reals[i], eRe);
|
Chris@1088
|
72 QCOMPARE(imags[i], eIm);
|
Chris@1088
|
73 }
|
Chris@1088
|
74 QCOMPARE(reals[hs1], 999.f);
|
Chris@1088
|
75 QCOMPARE(imags[hs1], 999.f);
|
Chris@1088
|
76 }
|
Chris@1088
|
77 }
|
Chris@1088
|
78 }
|
Chris@1088
|
79
|
Chris@1086
|
80 private slots:
|
Chris@1086
|
81
|
Chris@1088
|
82 // NB. FFTModel columns are centred on the sample frame, and in
|
Chris@1088
|
83 // particular this means column 0 is centred at sample 0 (i.e. it
|
Chris@1088
|
84 // contains only half the window-size worth of real samples, the
|
Chris@1088
|
85 // others are 0-valued from before the origin). Generally in
|
Chris@1088
|
86 // these tests we are padding our signal with half a window of
|
Chris@1088
|
87 // zeros, in order that the result for column 0 is all zeros
|
Chris@1088
|
88 // (rather than something with a step in it that is harder to
|
Chris@1088
|
89 // reason about the FFT of) and the results for subsequent columns
|
Chris@1088
|
90 // are those of our expected signal.
|
Chris@1088
|
91
|
Chris@1088
|
92 void dc_simple_rect() {
|
Chris@1088
|
93 MockWaveModel mwm({ DC }, 16, 4);
|
Chris@1088
|
94 test(&mwm, RectangularWindow, 8, 8, 8, 0,
|
Chris@1088
|
95 { { {}, {}, {}, {}, {} } }, 4);
|
Chris@1088
|
96 test(&mwm, RectangularWindow, 8, 8, 8, 1,
|
Chris@1088
|
97 { { { 4.f, 0.f }, {}, {}, {}, {} } }, 4);
|
Chris@1088
|
98 test(&mwm, RectangularWindow, 8, 8, 8, 2,
|
Chris@1088
|
99 { { { 4.f, 0.f }, {}, {}, {}, {} } }, 4);
|
Chris@1088
|
100 test(&mwm, RectangularWindow, 8, 8, 8, 3,
|
Chris@1088
|
101 { { { }, {}, {}, {}, {} } }, 4);
|
Chris@1088
|
102 }
|
Chris@1088
|
103
|
Chris@1088
|
104 void dc_simple_hann() {
|
Chris@1088
|
105 // The Hann window function is a simple sinusoid with period
|
Chris@1088
|
106 // equal to twice the window size, and it halves the DC energy
|
Chris@1088
|
107 MockWaveModel mwm({ DC }, 16, 4);
|
Chris@1088
|
108 test(&mwm, HanningWindow, 8, 8, 8, 0,
|
Chris@1088
|
109 { { {}, {}, {}, {}, {} } }, 4);
|
Chris@1088
|
110 test(&mwm, HanningWindow, 8, 8, 8, 1,
|
Chris@1088
|
111 { { { 4.f, 0.f }, { 2.f, 0.f }, {}, {}, {} } }, 4);
|
Chris@1088
|
112 test(&mwm, HanningWindow, 8, 8, 8, 2,
|
Chris@1088
|
113 { { { 4.f, 0.f }, { 2.f, 0.f }, {}, {}, {} } }, 4);
|
Chris@1088
|
114 test(&mwm, HanningWindow, 8, 8, 8, 3,
|
Chris@1088
|
115 { { { }, {}, {}, {}, {} } }, 4);
|
Chris@1086
|
116 }
|
Chris@1086
|
117
|
Chris@1086
|
118 };
|
Chris@1086
|
119
|
Chris@1086
|
120 #endif
|