Chris@1265
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@1265
|
2
|
Chris@1265
|
3 /*
|
Chris@1265
|
4 Sonic Visualiser
|
Chris@1265
|
5 An audio file viewer and annotation editor.
|
Chris@1265
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@1265
|
7
|
Chris@1265
|
8 This program is free software; you can redistribute it and/or
|
Chris@1265
|
9 modify it under the terms of the GNU General Public License as
|
Chris@1265
|
10 published by the Free Software Foundation; either version 2 of the
|
Chris@1265
|
11 License, or (at your option) any later version. See the file
|
Chris@1265
|
12 COPYING included with this distribution for more information.
|
Chris@1265
|
13 */
|
Chris@1265
|
14
|
Chris@1265
|
15 #ifndef TEST_COLUMN_OP_H
|
Chris@1265
|
16 #define TEST_COLUMN_OP_H
|
Chris@1265
|
17
|
Chris@1265
|
18 #include "../ColumnOp.h"
|
Chris@1265
|
19
|
Chris@1265
|
20 #include <QObject>
|
Chris@1265
|
21 #include <QtTest>
|
Chris@1265
|
22 #include <QDir>
|
Chris@1265
|
23
|
Chris@1265
|
24 #include <iostream>
|
Chris@1265
|
25
|
Chris@1304
|
26 //#define REPORT 1
|
Chris@1304
|
27
|
Chris@1265
|
28 using namespace std;
|
Chris@1265
|
29
|
Chris@1265
|
30 class TestColumnOp : public QObject
|
Chris@1265
|
31 {
|
Chris@1265
|
32 Q_OBJECT
|
Chris@1265
|
33
|
Chris@1265
|
34 typedef ColumnOp C;
|
Chris@1265
|
35 typedef ColumnOp::Column Column;
|
Chris@1266
|
36 typedef vector<double> BinMapping;
|
Chris@1266
|
37
|
Chris@1269
|
38 #ifdef REPORT
|
Chris@1266
|
39 template <typename T>
|
Chris@1266
|
40 void report(vector<T> v) {
|
Chris@1266
|
41 cerr << "Vector is: [ ";
|
Chris@1266
|
42 for (int i = 0; i < int(v.size()); ++i) {
|
Chris@1266
|
43 if (i > 0) cerr << ", ";
|
Chris@1266
|
44 cerr << v[i];
|
Chris@1266
|
45 }
|
Chris@1266
|
46 cerr << " ]\n";
|
Chris@1266
|
47 }
|
Chris@1269
|
48 #else
|
Chris@1269
|
49 template <typename T>
|
Chris@1269
|
50 void report(vector<T> ) { }
|
Chris@1269
|
51 #endif
|
Chris@1266
|
52
|
Chris@1265
|
53 private slots:
|
Chris@1265
|
54 void applyGain() {
|
Chris@1265
|
55 QCOMPARE(C::applyGain({}, 1.0), Column());
|
Chris@1265
|
56 Column c { 1, 2, 3, -4, 5, 6 };
|
Chris@1265
|
57 Column actual(C::applyGain(c, 1.5));
|
Chris@1380
|
58 Column expected { 1.5f, 3, 4.5f, -6, 7.5f, 9 };
|
Chris@1265
|
59 QCOMPARE(actual, expected);
|
Chris@1265
|
60 actual = C::applyGain(c, 1.0);
|
Chris@1265
|
61 QCOMPARE(actual, c);
|
Chris@1265
|
62 actual = C::applyGain(c, 0.0);
|
Chris@1265
|
63 expected = { 0, 0, 0, 0, 0, 0 };
|
Chris@1265
|
64 QCOMPARE(actual, expected);
|
Chris@1265
|
65 }
|
Chris@1265
|
66
|
Chris@1265
|
67 void fftScale() {
|
Chris@1265
|
68 QCOMPARE(C::fftScale({}, 2.0), Column());
|
Chris@1265
|
69 Column c { 1, 2, 3, -4, 5 };
|
Chris@1265
|
70 Column actual(C::fftScale(c, 8));
|
Chris@1380
|
71 Column expected { 0.25f, 0.5f, 0.75f, -1, 1.25f };
|
Chris@1265
|
72 QCOMPARE(actual, expected);
|
Chris@1265
|
73 }
|
Chris@1265
|
74
|
Chris@1265
|
75 void isPeak_null() {
|
Chris@1265
|
76 QVERIFY(!C::isPeak({}, 0));
|
Chris@1265
|
77 QVERIFY(!C::isPeak({}, 1));
|
Chris@1265
|
78 QVERIFY(!C::isPeak({}, -1));
|
Chris@1265
|
79 }
|
Chris@1265
|
80
|
Chris@1265
|
81 void isPeak_obvious() {
|
Chris@1380
|
82 Column c { 0.4f, 0.5f, 0.3f };
|
Chris@1265
|
83 QVERIFY(!C::isPeak(c, 0));
|
Chris@1265
|
84 QVERIFY(C::isPeak(c, 1));
|
Chris@1265
|
85 QVERIFY(!C::isPeak(c, 2));
|
Chris@1265
|
86 }
|
Chris@1265
|
87
|
Chris@1265
|
88 void isPeak_edges() {
|
Chris@1380
|
89 Column c { 0.5f, 0.4f, 0.3f };
|
Chris@1265
|
90 QVERIFY(C::isPeak(c, 0));
|
Chris@1265
|
91 QVERIFY(!C::isPeak(c, 1));
|
Chris@1265
|
92 QVERIFY(!C::isPeak(c, 2));
|
Chris@1265
|
93 QVERIFY(!C::isPeak(c, 3));
|
Chris@1265
|
94 QVERIFY(!C::isPeak(c, -1));
|
Chris@1380
|
95 c = { 1.4f, 1.5f };
|
Chris@1265
|
96 QVERIFY(!C::isPeak(c, 0));
|
Chris@1265
|
97 QVERIFY(C::isPeak(c, 1));
|
Chris@1265
|
98 }
|
Chris@1265
|
99
|
Chris@1265
|
100 void isPeak_flat() {
|
Chris@1380
|
101 Column c { 0.0f, 0.0f, 0.0f };
|
Chris@1265
|
102 QVERIFY(C::isPeak(c, 0));
|
Chris@1265
|
103 QVERIFY(!C::isPeak(c, 1));
|
Chris@1265
|
104 QVERIFY(!C::isPeak(c, 2));
|
Chris@1265
|
105 }
|
Chris@1265
|
106
|
Chris@1265
|
107 void isPeak_mixedSign() {
|
Chris@1380
|
108 Column c { 0.4f, -0.5f, -0.3f, -0.6f, 0.1f, -0.3f };
|
Chris@1265
|
109 QVERIFY(C::isPeak(c, 0));
|
Chris@1265
|
110 QVERIFY(!C::isPeak(c, 1));
|
Chris@1265
|
111 QVERIFY(C::isPeak(c, 2));
|
Chris@1265
|
112 QVERIFY(!C::isPeak(c, 3));
|
Chris@1265
|
113 QVERIFY(C::isPeak(c, 4));
|
Chris@1265
|
114 QVERIFY(!C::isPeak(c, 5));
|
Chris@1265
|
115 }
|
Chris@1265
|
116
|
Chris@1265
|
117 void isPeak_duplicate() {
|
Chris@1380
|
118 Column c({ 0.5f, 0.5f, 0.4f, 0.4f });
|
Chris@1265
|
119 QVERIFY(C::isPeak(c, 0));
|
Chris@1265
|
120 QVERIFY(!C::isPeak(c, 1));
|
Chris@1265
|
121 QVERIFY(!C::isPeak(c, 2));
|
Chris@1265
|
122 QVERIFY(!C::isPeak(c, 3));
|
Chris@1380
|
123 c = { 0.4f, 0.4f, 0.5f, 0.5f };
|
Chris@1265
|
124 QVERIFY(C::isPeak(c, 0)); // counterintuitive but necessary
|
Chris@1265
|
125 QVERIFY(!C::isPeak(c, 1));
|
Chris@1265
|
126 QVERIFY(C::isPeak(c, 2));
|
Chris@1265
|
127 QVERIFY(!C::isPeak(c, 3));
|
Chris@1265
|
128 }
|
Chris@1265
|
129
|
Chris@1265
|
130 void peakPick() {
|
Chris@1265
|
131 QCOMPARE(C::peakPick({}), Column());
|
Chris@1380
|
132 Column c({ 0.5f, 0.5f, 0.4f, 0.4f });
|
Chris@1380
|
133 QCOMPARE(C::peakPick(c), Column({ 0.5f, 0.0f, 0.0f, 0.0f }));
|
Chris@1380
|
134 c = Column({ 0.4f, -0.5f, -0.3f, -0.6f, 0.1f, -0.3f });
|
Chris@1380
|
135 QCOMPARE(C::peakPick(c), Column({ 0.4f, 0.0f, -0.3f, 0.0f, 0.1f, 0.0f }));
|
Chris@1265
|
136 }
|
Chris@1265
|
137
|
Chris@1265
|
138 void normalize_null() {
|
Chris@1265
|
139 QCOMPARE(C::normalize({}, ColumnNormalization::None), Column());
|
Chris@1265
|
140 QCOMPARE(C::normalize({}, ColumnNormalization::Sum1), Column());
|
Chris@1265
|
141 QCOMPARE(C::normalize({}, ColumnNormalization::Max1), Column());
|
Chris@1394
|
142 QCOMPARE(C::normalize({}, ColumnNormalization::Range01), Column());
|
Chris@1265
|
143 QCOMPARE(C::normalize({}, ColumnNormalization::Hybrid), Column());
|
Chris@1265
|
144 }
|
Chris@1265
|
145
|
Chris@1265
|
146 void normalize_none() {
|
Chris@1265
|
147 Column c { 1, 2, 3, 4 };
|
Chris@1265
|
148 QCOMPARE(C::normalize(c, ColumnNormalization::None), c);
|
Chris@1265
|
149 }
|
Chris@1265
|
150
|
Chris@1266
|
151 void normalize_none_mixedSign() {
|
Chris@1266
|
152 Column c { 1, 2, -3, -4 };
|
Chris@1266
|
153 QCOMPARE(C::normalize(c, ColumnNormalization::None), c);
|
Chris@1266
|
154 }
|
Chris@1266
|
155
|
Chris@1265
|
156 void normalize_sum1() {
|
Chris@1265
|
157 Column c { 1, 2, 4, 3 };
|
Chris@1265
|
158 QCOMPARE(C::normalize(c, ColumnNormalization::Sum1),
|
Chris@1380
|
159 Column({ 0.1f, 0.2f, 0.4f, 0.3f }));
|
Chris@1265
|
160 }
|
Chris@1265
|
161
|
Chris@1266
|
162 void normalize_sum1_mixedSign() {
|
Chris@1266
|
163 Column c { 1, 2, -4, -3 };
|
Chris@1266
|
164 QCOMPARE(C::normalize(c, ColumnNormalization::Sum1),
|
Chris@1380
|
165 Column({ 0.1f, 0.2f, -0.4f, -0.3f }));
|
Chris@1266
|
166 }
|
Chris@1266
|
167
|
Chris@1265
|
168 void normalize_max1() {
|
Chris@1265
|
169 Column c { 4, 3, 2, 1 };
|
Chris@1265
|
170 QCOMPARE(C::normalize(c, ColumnNormalization::Max1),
|
Chris@1380
|
171 Column({ 1.0f, 0.75f, 0.5f, 0.25f }));
|
Chris@1265
|
172 }
|
Chris@1265
|
173
|
Chris@1266
|
174 void normalize_max1_mixedSign() {
|
Chris@1266
|
175 Column c { -4, -3, 2, 1 };
|
Chris@1266
|
176 QCOMPARE(C::normalize(c, ColumnNormalization::Max1),
|
Chris@1380
|
177 Column({ -1.0f, -0.75f, 0.5f, 0.25f }));
|
Chris@1266
|
178 }
|
Chris@1266
|
179
|
Chris@1394
|
180 void normalize_range01() {
|
Chris@1394
|
181 Column c { 4, 3, 2, 1 };
|
Chris@1394
|
182 QCOMPARE(C::normalize(c, ColumnNormalization::Range01),
|
Chris@1394
|
183 Column({ 1.0f, 2.f/3.f, 1.f/3.f, 0.0f }));
|
Chris@1394
|
184 }
|
Chris@1394
|
185
|
Chris@1394
|
186 void normalize_range01_mixedSign() {
|
Chris@1394
|
187 Column c { -2, -3, 2, 1 };
|
Chris@1394
|
188 QCOMPARE(C::normalize(c, ColumnNormalization::Range01),
|
Chris@1394
|
189 Column({ 0.2f, 0.0f, 1.0f, 0.8f }));
|
Chris@1394
|
190 }
|
Chris@1394
|
191
|
Chris@1265
|
192 void normalize_hybrid() {
|
Chris@1265
|
193 // with max == 99, log10(max+1) == 2 so scale factor will be 2/99
|
Chris@1265
|
194 Column c { 22, 44, 99, 66 };
|
Chris@1265
|
195 QCOMPARE(C::normalize(c, ColumnNormalization::Hybrid),
|
Chris@1380
|
196 Column({ 44.0f/99.0f, 88.0f/99.0f, 2.0f, 132.0f/99.0f }));
|
Chris@1265
|
197 }
|
Chris@1265
|
198
|
Chris@1266
|
199 void normalize_hybrid_mixedSign() {
|
Chris@1266
|
200 // with max == 99, log10(max+1) == 2 so scale factor will be 2/99
|
Chris@1266
|
201 Column c { 22, 44, -99, -66 };
|
Chris@1266
|
202 QCOMPARE(C::normalize(c, ColumnNormalization::Hybrid),
|
Chris@1380
|
203 Column({ 44.0f/99.0f, 88.0f/99.0f, -2.0f, -132.0f/99.0f }));
|
Chris@1266
|
204 }
|
Chris@1266
|
205
|
Chris@1266
|
206 void distribute_simple() {
|
Chris@1266
|
207 Column in { 1, 2, 3 };
|
Chris@1380
|
208 BinMapping binfory { 0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 2.5f };
|
Chris@1266
|
209 Column expected { 1, 1, 2, 2, 3, 3 };
|
Chris@1266
|
210 Column actual(C::distribute(in, 6, binfory, 0, false));
|
Chris@1266
|
211 report(actual);
|
Chris@1266
|
212 QCOMPARE(actual, expected);
|
Chris@1266
|
213 }
|
Chris@1266
|
214
|
Chris@1266
|
215 void distribute_simple_interpolated() {
|
Chris@1266
|
216 Column in { 1, 2, 3 };
|
Chris@1380
|
217 BinMapping binfory { 0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 2.5f };
|
Chris@1267
|
218 // There is a 0.5-bin offset from the distribution you might
|
Chris@1267
|
219 // expect, because this corresponds visually to the way that
|
Chris@1267
|
220 // bin values are duplicated upwards in simple_distribution.
|
Chris@1267
|
221 // It means that switching between interpolated and
|
Chris@1267
|
222 // non-interpolated views retains the visual position of each
|
Chris@1267
|
223 // bin peak as somewhere in the middle of the scale area for
|
Chris@1267
|
224 // that bin.
|
Chris@1380
|
225 Column expected { 1, 1, 1.5f, 2, 2.5f, 3 };
|
Chris@1266
|
226 Column actual(C::distribute(in, 6, binfory, 0, true));
|
Chris@1266
|
227 report(actual);
|
Chris@1266
|
228 QCOMPARE(actual, expected);
|
Chris@1266
|
229 }
|
Chris@1266
|
230
|
Chris@1266
|
231 void distribute_nonlinear() {
|
Chris@1266
|
232 Column in { 1, 2, 3 };
|
Chris@1380
|
233 BinMapping binfory { 0.0f, 0.2f, 0.5f, 1.0f, 2.0f, 2.5f };
|
Chris@1266
|
234 Column expected { 1, 1, 1, 2, 3, 3 };
|
Chris@1266
|
235 Column actual(C::distribute(in, 6, binfory, 0, false));
|
Chris@1266
|
236 report(actual);
|
Chris@1266
|
237 QCOMPARE(actual, expected);
|
Chris@1266
|
238 }
|
Chris@1266
|
239
|
Chris@1266
|
240 void distribute_nonlinear_interpolated() {
|
Chris@1267
|
241 // See distribute_simple_interpolated
|
Chris@1266
|
242 Column in { 1, 2, 3 };
|
Chris@1380
|
243 BinMapping binfory { 0.0f, 0.2f, 0.5f, 1.0f, 2.0f, 2.5f };
|
Chris@1267
|
244 Column expected { 1, 1, 1, 1.5, 2.5, 3 };
|
Chris@1266
|
245 Column actual(C::distribute(in, 6, binfory, 0, true));
|
Chris@1266
|
246 report(actual);
|
Chris@1266
|
247 QCOMPARE(actual, expected);
|
Chris@1266
|
248 }
|
Chris@1266
|
249
|
Chris@1266
|
250 void distribute_shrinking() {
|
Chris@1266
|
251 Column in { 4, 1, 2, 3, 5, 6 };
|
Chris@1380
|
252 BinMapping binfory { 0.0f, 2.0f, 4.0f };
|
Chris@1266
|
253 Column expected { 4, 3, 6 };
|
Chris@1266
|
254 Column actual(C::distribute(in, 3, binfory, 0, false));
|
Chris@1266
|
255 report(actual);
|
Chris@1266
|
256 QCOMPARE(actual, expected);
|
Chris@1266
|
257 }
|
Chris@1266
|
258
|
Chris@1266
|
259 void distribute_shrinking_interpolated() {
|
Chris@1266
|
260 // should be same as distribute_shrinking, we don't
|
Chris@1266
|
261 // interpolate when resizing down
|
Chris@1266
|
262 Column in { 4, 1, 2, 3, 5, 6 };
|
Chris@1380
|
263 BinMapping binfory { 0.0f, 2.0f, 4.0f };
|
Chris@1266
|
264 Column expected { 4, 3, 6 };
|
Chris@1266
|
265 Column actual(C::distribute(in, 3, binfory, 0, true));
|
Chris@1266
|
266 report(actual);
|
Chris@1266
|
267 QCOMPARE(actual, expected);
|
Chris@1266
|
268 }
|
Chris@1265
|
269
|
Chris@1304
|
270 void distribute_nonlinear_someshrinking_interpolated() {
|
Chris@1304
|
271 // But we *should* interpolate if the mapping involves
|
Chris@1304
|
272 // shrinking some bins but expanding others. See
|
Chris@1304
|
273 // distribute_simple_interpolated for note on 0.5 offset
|
Chris@1304
|
274 Column in { 4, 1, 2, 3, 5, 6 };
|
Chris@1380
|
275 BinMapping binfory { 0.0f, 3.0f, 4.0f, 4.5f };
|
Chris@1380
|
276 Column expected { 4.0f, 2.5f, 4.0f, 5.0f };
|
Chris@1304
|
277 Column actual(C::distribute(in, 4, binfory, 0, true));
|
Chris@1304
|
278 report(actual);
|
Chris@1304
|
279 QCOMPARE(actual, expected);
|
Chris@1380
|
280 binfory = BinMapping { 0.5f, 1.0f, 2.0f, 5.0f };
|
Chris@1380
|
281 expected = { 4.0f, 2.5f, 1.5f, 5.5f };
|
Chris@1304
|
282 actual = (C::distribute(in, 4, binfory, 0, true));
|
Chris@1304
|
283 report(actual);
|
Chris@1304
|
284 QCOMPARE(actual, expected);
|
Chris@1304
|
285 }
|
Chris@1265
|
286 };
|
Chris@1265
|
287
|
Chris@1265
|
288 #endif
|
Chris@1265
|
289
|