annotate base/test/TestColumnOp.h @ 1791:c2388289fce8 time-frequency-boxes

Rename TimeFrequencyBoxModel to simply BoxModel
author Chris Cannam
date Wed, 25 Sep 2019 09:44:02 +0100
parents 9ef1cc26024c
children 1b688ab5f1b3
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@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