annotate base/test/TestColumnOp.h @ 1391:2c0e04062a99

Write aggregate models to .sv file when saving document. They still are not reloaded, but I think this is far as I'm prepared to go for 3.0.
author Chris Cannam
date Mon, 27 Feb 2017 16:52:47 +0000
parents bd1eb56df8d5
children 9ef1cc26024c
rev   line source
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@1265 142 QCOMPARE(C::normalize({}, ColumnNormalization::Hybrid), Column());
Chris@1265 143 }
Chris@1265 144
Chris@1265 145 void normalize_none() {
Chris@1265 146 Column c { 1, 2, 3, 4 };
Chris@1265 147 QCOMPARE(C::normalize(c, ColumnNormalization::None), c);
Chris@1265 148 }
Chris@1265 149
Chris@1266 150 void normalize_none_mixedSign() {
Chris@1266 151 Column c { 1, 2, -3, -4 };
Chris@1266 152 QCOMPARE(C::normalize(c, ColumnNormalization::None), c);
Chris@1266 153 }
Chris@1266 154
Chris@1265 155 void normalize_sum1() {
Chris@1265 156 Column c { 1, 2, 4, 3 };
Chris@1265 157 QCOMPARE(C::normalize(c, ColumnNormalization::Sum1),
Chris@1380 158 Column({ 0.1f, 0.2f, 0.4f, 0.3f }));
Chris@1265 159 }
Chris@1265 160
Chris@1266 161 void normalize_sum1_mixedSign() {
Chris@1266 162 Column c { 1, 2, -4, -3 };
Chris@1266 163 QCOMPARE(C::normalize(c, ColumnNormalization::Sum1),
Chris@1380 164 Column({ 0.1f, 0.2f, -0.4f, -0.3f }));
Chris@1266 165 }
Chris@1266 166
Chris@1265 167 void normalize_max1() {
Chris@1265 168 Column c { 4, 3, 2, 1 };
Chris@1265 169 QCOMPARE(C::normalize(c, ColumnNormalization::Max1),
Chris@1380 170 Column({ 1.0f, 0.75f, 0.5f, 0.25f }));
Chris@1265 171 }
Chris@1265 172
Chris@1266 173 void normalize_max1_mixedSign() {
Chris@1266 174 Column c { -4, -3, 2, 1 };
Chris@1266 175 QCOMPARE(C::normalize(c, ColumnNormalization::Max1),
Chris@1380 176 Column({ -1.0f, -0.75f, 0.5f, 0.25f }));
Chris@1266 177 }
Chris@1266 178
Chris@1265 179 void normalize_hybrid() {
Chris@1265 180 // with max == 99, log10(max+1) == 2 so scale factor will be 2/99
Chris@1265 181 Column c { 22, 44, 99, 66 };
Chris@1265 182 QCOMPARE(C::normalize(c, ColumnNormalization::Hybrid),
Chris@1380 183 Column({ 44.0f/99.0f, 88.0f/99.0f, 2.0f, 132.0f/99.0f }));
Chris@1265 184 }
Chris@1265 185
Chris@1266 186 void normalize_hybrid_mixedSign() {
Chris@1266 187 // with max == 99, log10(max+1) == 2 so scale factor will be 2/99
Chris@1266 188 Column c { 22, 44, -99, -66 };
Chris@1266 189 QCOMPARE(C::normalize(c, ColumnNormalization::Hybrid),
Chris@1380 190 Column({ 44.0f/99.0f, 88.0f/99.0f, -2.0f, -132.0f/99.0f }));
Chris@1266 191 }
Chris@1266 192
Chris@1266 193 void distribute_simple() {
Chris@1266 194 Column in { 1, 2, 3 };
Chris@1380 195 BinMapping binfory { 0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 2.5f };
Chris@1266 196 Column expected { 1, 1, 2, 2, 3, 3 };
Chris@1266 197 Column actual(C::distribute(in, 6, binfory, 0, false));
Chris@1266 198 report(actual);
Chris@1266 199 QCOMPARE(actual, expected);
Chris@1266 200 }
Chris@1266 201
Chris@1266 202 void distribute_simple_interpolated() {
Chris@1266 203 Column in { 1, 2, 3 };
Chris@1380 204 BinMapping binfory { 0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 2.5f };
Chris@1267 205 // There is a 0.5-bin offset from the distribution you might
Chris@1267 206 // expect, because this corresponds visually to the way that
Chris@1267 207 // bin values are duplicated upwards in simple_distribution.
Chris@1267 208 // It means that switching between interpolated and
Chris@1267 209 // non-interpolated views retains the visual position of each
Chris@1267 210 // bin peak as somewhere in the middle of the scale area for
Chris@1267 211 // that bin.
Chris@1380 212 Column expected { 1, 1, 1.5f, 2, 2.5f, 3 };
Chris@1266 213 Column actual(C::distribute(in, 6, binfory, 0, true));
Chris@1266 214 report(actual);
Chris@1266 215 QCOMPARE(actual, expected);
Chris@1266 216 }
Chris@1266 217
Chris@1266 218 void distribute_nonlinear() {
Chris@1266 219 Column in { 1, 2, 3 };
Chris@1380 220 BinMapping binfory { 0.0f, 0.2f, 0.5f, 1.0f, 2.0f, 2.5f };
Chris@1266 221 Column expected { 1, 1, 1, 2, 3, 3 };
Chris@1266 222 Column actual(C::distribute(in, 6, binfory, 0, false));
Chris@1266 223 report(actual);
Chris@1266 224 QCOMPARE(actual, expected);
Chris@1266 225 }
Chris@1266 226
Chris@1266 227 void distribute_nonlinear_interpolated() {
Chris@1267 228 // See distribute_simple_interpolated
Chris@1266 229 Column in { 1, 2, 3 };
Chris@1380 230 BinMapping binfory { 0.0f, 0.2f, 0.5f, 1.0f, 2.0f, 2.5f };
Chris@1267 231 Column expected { 1, 1, 1, 1.5, 2.5, 3 };
Chris@1266 232 Column actual(C::distribute(in, 6, binfory, 0, true));
Chris@1266 233 report(actual);
Chris@1266 234 QCOMPARE(actual, expected);
Chris@1266 235 }
Chris@1266 236
Chris@1266 237 void distribute_shrinking() {
Chris@1266 238 Column in { 4, 1, 2, 3, 5, 6 };
Chris@1380 239 BinMapping binfory { 0.0f, 2.0f, 4.0f };
Chris@1266 240 Column expected { 4, 3, 6 };
Chris@1266 241 Column actual(C::distribute(in, 3, binfory, 0, false));
Chris@1266 242 report(actual);
Chris@1266 243 QCOMPARE(actual, expected);
Chris@1266 244 }
Chris@1266 245
Chris@1266 246 void distribute_shrinking_interpolated() {
Chris@1266 247 // should be same as distribute_shrinking, we don't
Chris@1266 248 // interpolate when resizing down
Chris@1266 249 Column in { 4, 1, 2, 3, 5, 6 };
Chris@1380 250 BinMapping binfory { 0.0f, 2.0f, 4.0f };
Chris@1266 251 Column expected { 4, 3, 6 };
Chris@1266 252 Column actual(C::distribute(in, 3, binfory, 0, true));
Chris@1266 253 report(actual);
Chris@1266 254 QCOMPARE(actual, expected);
Chris@1266 255 }
Chris@1265 256
Chris@1304 257 void distribute_nonlinear_someshrinking_interpolated() {
Chris@1304 258 // But we *should* interpolate if the mapping involves
Chris@1304 259 // shrinking some bins but expanding others. See
Chris@1304 260 // distribute_simple_interpolated for note on 0.5 offset
Chris@1304 261 Column in { 4, 1, 2, 3, 5, 6 };
Chris@1380 262 BinMapping binfory { 0.0f, 3.0f, 4.0f, 4.5f };
Chris@1380 263 Column expected { 4.0f, 2.5f, 4.0f, 5.0f };
Chris@1304 264 Column actual(C::distribute(in, 4, binfory, 0, true));
Chris@1304 265 report(actual);
Chris@1304 266 QCOMPARE(actual, expected);
Chris@1380 267 binfory = BinMapping { 0.5f, 1.0f, 2.0f, 5.0f };
Chris@1380 268 expected = { 4.0f, 2.5f, 1.5f, 5.5f };
Chris@1304 269 actual = (C::distribute(in, 4, binfory, 0, true));
Chris@1304 270 report(actual);
Chris@1304 271 QCOMPARE(actual, expected);
Chris@1304 272 }
Chris@1265 273 };
Chris@1265 274
Chris@1265 275 #endif
Chris@1265 276