comparison data/model/test/TestWaveformOversampler.h @ 1537:c5092ca1c6e5 zoom

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