Chris@1537
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@1537
|
2
|
Chris@1537
|
3 /*
|
Chris@1537
|
4 Sonic Visualiser
|
Chris@1537
|
5 An audio file viewer and annotation editor.
|
Chris@1537
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@1537
|
7
|
Chris@1537
|
8 This program is free software; you can redistribute it and/or
|
Chris@1537
|
9 modify it under the terms of the GNU General Public License as
|
Chris@1537
|
10 published by the Free Software Foundation; either version 2 of the
|
Chris@1537
|
11 License, or (at your option) any later version. See the file
|
Chris@1537
|
12 COPYING included with this distribution for more information.
|
Chris@1537
|
13 */
|
Chris@1537
|
14
|
Chris@1537
|
15 #ifndef TEST_WAVEFORM_OVERSAMPLER_H
|
Chris@1537
|
16 #define TEST_WAVEFORM_OVERSAMPLER_H
|
Chris@1537
|
17
|
Chris@1537
|
18 #include "../WaveformOversampler.h"
|
Chris@1537
|
19 #include "../WritableWaveFileModel.h"
|
Chris@1537
|
20
|
Chris@1537
|
21 #include "../../../base/BaseTypes.h"
|
Chris@1537
|
22
|
Chris@1537
|
23 #include <QObject>
|
Chris@1537
|
24 #include <QtTest>
|
Chris@1537
|
25
|
Chris@1537
|
26 class TestWaveformOversampler : public QObject
|
Chris@1537
|
27 {
|
Chris@1537
|
28 Q_OBJECT
|
Chris@1537
|
29
|
Chris@1537
|
30 public:
|
Chris@1537
|
31 TestWaveformOversampler() {
|
Chris@1537
|
32 m_source = floatvec_t(5000, 0.f);
|
Chris@1537
|
33 m_source[0] = 1.f;
|
Chris@1537
|
34 m_source[2500] = 0.5f;
|
Chris@1537
|
35 m_source[2501] = -0.5f;
|
Chris@1537
|
36 m_source[4999] = -1.f;
|
Chris@1540
|
37 for (int i = 3000; i < 3900; ++i) {
|
Chris@1540
|
38 m_source[i] = float(sin(double(i - 3000) * M_PI / 50.0));
|
Chris@1537
|
39 }
|
Chris@1537
|
40 m_sourceModel = new WritableWaveFileModel(8000, 1);
|
Chris@1537
|
41 const float *d = m_source.data();
|
Chris@1537
|
42 QVERIFY(m_sourceModel->addSamples(&d, m_source.size()));
|
Chris@1537
|
43 m_sourceModel->writeComplete();
|
Chris@1537
|
44 }
|
Chris@1537
|
45
|
Chris@1537
|
46 ~TestWaveformOversampler() {
|
Chris@1537
|
47 delete m_sourceModel;
|
Chris@1537
|
48 }
|
Chris@1537
|
49
|
Chris@1537
|
50 private:
|
Chris@1537
|
51 floatvec_t m_source;
|
Chris@1537
|
52 WritableWaveFileModel *m_sourceModel;
|
Chris@1537
|
53
|
Chris@1537
|
54 void compareStrided(floatvec_t obtained, floatvec_t expected, int stride) {
|
Chris@1537
|
55 QCOMPARE(obtained.size(), expected.size() * stride);
|
Chris@1537
|
56 float threshold = 1e-10f;
|
Chris@1537
|
57 for (int i = 0; in_range_for(expected, i); ++i) {
|
Chris@1537
|
58 if (fabsf(obtained[i * stride] - expected[i]) > threshold) {
|
Chris@1539
|
59 std::cerr << "At position " << i * stride << ": "
|
Chris@1539
|
60 << obtained[i * stride] << " != " << expected[i]
|
Chris@1539
|
61 << std::endl;
|
Chris@1537
|
62 QCOMPARE(obtained, expected);
|
Chris@1537
|
63 }
|
Chris@1537
|
64 }
|
Chris@1537
|
65 }
|
Chris@1537
|
66
|
Chris@1537
|
67 void compareVecs(floatvec_t obtained, floatvec_t expected) {
|
Chris@1537
|
68 compareStrided(obtained, expected, 1);
|
Chris@1537
|
69 }
|
Chris@1537
|
70
|
Chris@1537
|
71 floatvec_t get(sv_frame_t sourceStartFrame,
|
Chris@1537
|
72 sv_frame_t sourceFrameCount,
|
Chris@1538
|
73 int oversampleBy) {
|
Chris@1537
|
74 return WaveformOversampler::getOversampledData
|
Chris@1745
|
75 (*m_sourceModel, 0,
|
Chris@1537
|
76 sourceStartFrame, sourceFrameCount, oversampleBy);
|
Chris@1537
|
77 }
|
Chris@1537
|
78
|
Chris@1537
|
79 void testVerbatim(sv_frame_t sourceStartFrame,
|
Chris@1537
|
80 sv_frame_t sourceFrameCount,
|
Chris@1537
|
81 int oversampleBy,
|
Chris@1537
|
82 floatvec_t expected) {
|
Chris@1537
|
83 floatvec_t output =
|
Chris@1537
|
84 get(sourceStartFrame, sourceFrameCount, oversampleBy);
|
Chris@1537
|
85 compareVecs(output, expected);
|
Chris@1537
|
86 }
|
Chris@1537
|
87
|
Chris@1537
|
88 void testStrided(sv_frame_t sourceStartFrame,
|
Chris@1537
|
89 sv_frame_t sourceFrameCount,
|
Chris@1537
|
90 int oversampleBy,
|
Chris@1537
|
91 floatvec_t expected) {
|
Chris@1537
|
92 // check only the values that are expected to be precisely the
|
Chris@1537
|
93 // original samples
|
Chris@1537
|
94 floatvec_t output =
|
Chris@1537
|
95 get(sourceStartFrame, sourceFrameCount, oversampleBy);
|
Chris@1537
|
96 compareStrided(output, expected, oversampleBy);
|
Chris@1537
|
97 }
|
Chris@1537
|
98
|
Chris@1537
|
99 floatvec_t sourceSubset(sv_frame_t start, sv_frame_t length) {
|
Chris@1537
|
100 return floatvec_t(m_source.begin() + start,
|
Chris@1537
|
101 m_source.begin() + start + length);
|
Chris@1537
|
102 }
|
Chris@1537
|
103
|
Chris@1537
|
104 private slots:
|
Chris@1537
|
105 void testWholeVerbatim() {
|
Chris@1537
|
106 testVerbatim(0, 5000, 1, m_source);
|
Chris@1537
|
107 }
|
Chris@1537
|
108
|
Chris@1537
|
109 void testSubsetsVerbatim() {
|
Chris@1537
|
110 testVerbatim(0, 500, 1, sourceSubset(0, 500));
|
Chris@1537
|
111 testVerbatim(4500, 500, 1, sourceSubset(4500, 500));
|
Chris@1537
|
112 testVerbatim(2000, 1000, 1, sourceSubset(2000, 1000));
|
Chris@1537
|
113 }
|
Chris@1537
|
114
|
Chris@1537
|
115 void testOverlapsVerbatim() {
|
Chris@1537
|
116 // overlapping the start -> result should be zero-padded to
|
Chris@1537
|
117 // preserve start frame
|
Chris@1537
|
118 floatvec_t expected = sourceSubset(0, 400);
|
Chris@1537
|
119 expected.insert(expected.begin(), 100, 0.f);
|
Chris@1537
|
120 testVerbatim(-100, 500, 1, expected);
|
Chris@1537
|
121
|
Chris@1537
|
122 // overlapping the end -> result should be truncated to
|
Chris@1537
|
123 // preserve source length
|
Chris@1537
|
124 expected = sourceSubset(4600, 400);
|
Chris@1537
|
125 testVerbatim(4600, 500, 1, expected);
|
Chris@1537
|
126 }
|
Chris@1537
|
127
|
Chris@1537
|
128 void testWhole2x() {
|
Chris@1537
|
129 testStrided(0, 5000, 2, m_source);
|
Chris@1537
|
130
|
Chris@1537
|
131 // check for windowed sinc values between the original samples
|
Chris@1537
|
132 floatvec_t output = get(0, 5000, 2);
|
Chris@1537
|
133 QVERIFY(output[1] - 0.6358 < 0.0001);
|
Chris@1537
|
134 QVERIFY(output[3] + 0.2099 < 0.0001);
|
Chris@1537
|
135 }
|
Chris@1537
|
136
|
Chris@1537
|
137 void testWhole3x() {
|
Chris@1537
|
138 testStrided(0, 5000, 3, m_source);
|
Chris@1537
|
139
|
Chris@1537
|
140 // check for windowed sinc values between the original samples
|
Chris@1537
|
141 floatvec_t output = get(0, 5000, 3);
|
Chris@1537
|
142 QVERIFY(output[1] > 0.7);
|
Chris@1537
|
143 QVERIFY(output[2] > 0.4);
|
Chris@1537
|
144 QVERIFY(output[4] < -0.1);
|
Chris@1537
|
145 QVERIFY(output[5] < -0.1);
|
Chris@1537
|
146 }
|
Chris@1537
|
147
|
Chris@1537
|
148 void testWhole4x() {
|
Chris@1537
|
149 testStrided(0, 5000, 4, m_source);
|
Chris@1537
|
150
|
Chris@1537
|
151 // check for windowed sinc values between the original samples
|
Chris@1537
|
152 floatvec_t output = get(0, 5000, 4);
|
Chris@1537
|
153 QVERIFY(output[1] - 0.9000 < 0.0001);
|
Chris@1537
|
154 QVERIFY(output[2] - 0.6358 < 0.0001);
|
Chris@1537
|
155 QVERIFY(output[3] - 0.2993 < 0.0001);
|
Chris@1537
|
156 QVERIFY(output[5] + 0.1787 < 0.0001);
|
Chris@1537
|
157 QVERIFY(output[6] + 0.2099 < 0.0001);
|
Chris@1537
|
158 QVERIFY(output[7] + 0.1267 < 0.0001);
|
Chris@1537
|
159
|
Chris@1537
|
160 // alternate values at 2n should equal all values at n
|
Chris@1537
|
161 output = get(0, 5000, 4);
|
Chris@1537
|
162 floatvec_t half = get(0, 5000, 2);
|
Chris@1537
|
163 compareStrided(output, half, 2);
|
Chris@1537
|
164 }
|
Chris@1537
|
165
|
Chris@1537
|
166 void testWhole8x() {
|
Chris@1537
|
167 testStrided(0, 5000, 8, m_source);
|
Chris@1537
|
168
|
Chris@1537
|
169 // alternate values at 2n should equal all values at n
|
Chris@1537
|
170 floatvec_t output = get(0, 5000, 8);
|
Chris@1537
|
171 floatvec_t half = get(0, 5000, 4);
|
Chris@1537
|
172 compareStrided(output, half, 2);
|
Chris@1537
|
173 }
|
Chris@1537
|
174
|
Chris@1537
|
175 void testWhole10x() {
|
Chris@1537
|
176 testStrided(0, 5000, 10, m_source);
|
Chris@1537
|
177
|
Chris@1537
|
178 // alternate values at 2n should equal all values at n
|
Chris@1537
|
179 floatvec_t output = get(0, 5000, 10);
|
Chris@1537
|
180 floatvec_t half = get(0, 5000, 5);
|
Chris@1537
|
181 compareStrided(output, half, 2);
|
Chris@1537
|
182 }
|
Chris@1537
|
183
|
Chris@1537
|
184 void testWhole16x() {
|
Chris@1537
|
185 testStrided(0, 5000, 16, m_source);
|
Chris@1537
|
186
|
Chris@1537
|
187 // alternate values at 2n should equal all values at n
|
Chris@1537
|
188 floatvec_t output = get(0, 5000, 16);
|
Chris@1537
|
189 floatvec_t half = get(0, 5000, 8);
|
Chris@1537
|
190 compareStrided(output, half, 2);
|
Chris@1537
|
191 }
|
Chris@1537
|
192
|
Chris@1537
|
193 void testSubsets4x() {
|
Chris@1537
|
194 testStrided(0, 500, 4, sourceSubset(0, 500));
|
Chris@1537
|
195 testStrided(4500, 500, 4, sourceSubset(4500, 500));
|
Chris@1537
|
196 testStrided(2000, 1000, 4, sourceSubset(2000, 1000));
|
Chris@1538
|
197
|
Chris@1538
|
198 // check for windowed sinc values between the original
|
Chris@1538
|
199 // samples, even when the original sample that was the source
|
Chris@1538
|
200 // of this sinc kernel is not within the requested range
|
Chris@1538
|
201 floatvec_t output = get(1, 10, 4);
|
Chris@1540
|
202 QVERIFY(output[0] < 0.0001);
|
Chris@1538
|
203 QVERIFY(output[1] + 0.1787 < 0.0001);
|
Chris@1538
|
204 QVERIFY(output[2] + 0.2099 < 0.0001);
|
Chris@1538
|
205 QVERIFY(output[3] + 0.1267 < 0.0001);
|
Chris@1540
|
206
|
Chris@1540
|
207 // and again at the end
|
Chris@1540
|
208 output = get(4989, 10, 4);
|
Chris@1540
|
209 QVERIFY(output[39] + 0.9000 < 0.0001);
|
Chris@1540
|
210 QVERIFY(output[38] + 0.6358 < 0.0001);
|
Chris@1540
|
211 QVERIFY(output[37] + 0.2993 < 0.0001);
|
Chris@1540
|
212 QVERIFY(output[35] - 0.1787 < 0.0001);
|
Chris@1540
|
213 QVERIFY(output[34] - 0.2099 < 0.0001);
|
Chris@1540
|
214 QVERIFY(output[33] - 0.1267 < 0.0001);
|
Chris@1537
|
215 }
|
Chris@1537
|
216
|
Chris@1537
|
217 void testOverlaps4x() {
|
Chris@1537
|
218 // overlapping the start -> result should be zero-padded to
|
Chris@1537
|
219 // preserve start frame
|
Chris@1537
|
220 floatvec_t expected = sourceSubset(0, 400);
|
Chris@1537
|
221 expected.insert(expected.begin(), 100, 0.f);
|
Chris@1537
|
222 testStrided(-100, 500, 4, expected);
|
Chris@1537
|
223
|
Chris@1537
|
224 // overlapping the end -> result should be truncated to
|
Chris@1537
|
225 // preserve source length
|
Chris@1537
|
226 expected = sourceSubset(4600, 400);
|
Chris@1537
|
227 testStrided(4600, 500, 4, expected);
|
Chris@1537
|
228 }
|
Chris@1537
|
229
|
Chris@1537
|
230 void testSubsets15x() {
|
Chris@1537
|
231 testStrided(0, 500, 15, sourceSubset(0, 500));
|
Chris@1537
|
232 testStrided(4500, 500, 15, sourceSubset(4500, 500));
|
Chris@1537
|
233 testStrided(2000, 1000, 15, sourceSubset(2000, 1000));
|
Chris@1537
|
234 }
|
Chris@1537
|
235
|
Chris@1537
|
236 void testOverlaps15x() {
|
Chris@1537
|
237 // overlapping the start -> result should be zero-padded to
|
Chris@1537
|
238 // preserve start frame
|
Chris@1537
|
239 floatvec_t expected = sourceSubset(0, 400);
|
Chris@1537
|
240 expected.insert(expected.begin(), 100, 0.f);
|
Chris@1537
|
241 testStrided(-100, 500, 15, expected);
|
Chris@1537
|
242
|
Chris@1537
|
243 // overlapping the end -> result should be truncated to
|
Chris@1537
|
244 // preserve source length
|
Chris@1537
|
245 expected = sourceSubset(4600, 400);
|
Chris@1537
|
246 testStrided(4600, 500, 15, expected);
|
Chris@1537
|
247 }
|
Chris@1537
|
248 };
|
Chris@1537
|
249
|
Chris@1537
|
250
|
Chris@1537
|
251 #endif
|