Chris@1265: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@1265: Chris@1265: /* Chris@1265: Sonic Visualiser Chris@1265: An audio file viewer and annotation editor. Chris@1265: Centre for Digital Music, Queen Mary, University of London. Chris@1265: Chris@1265: This program is free software; you can redistribute it and/or Chris@1265: modify it under the terms of the GNU General Public License as Chris@1265: published by the Free Software Foundation; either version 2 of the Chris@1265: License, or (at your option) any later version. See the file Chris@1265: COPYING included with this distribution for more information. Chris@1265: */ Chris@1265: Chris@1265: #ifndef TEST_COLUMN_OP_H Chris@1265: #define TEST_COLUMN_OP_H Chris@1265: Chris@1265: #include "../ColumnOp.h" Chris@1265: Chris@1265: #include Chris@1265: #include Chris@1265: #include Chris@1265: Chris@1265: #include Chris@1265: Chris@1304: //#define REPORT 1 Chris@1304: Chris@1265: using namespace std; Chris@1265: Chris@1265: class TestColumnOp : public QObject Chris@1265: { Chris@1265: Q_OBJECT Chris@1265: Chris@1265: typedef ColumnOp C; Chris@1265: typedef ColumnOp::Column Column; Chris@1266: typedef vector BinMapping; Chris@1266: Chris@1269: #ifdef REPORT Chris@1266: template Chris@1266: void report(vector v) { Chris@1266: cerr << "Vector is: [ "; Chris@1266: for (int i = 0; i < int(v.size()); ++i) { Chris@1266: if (i > 0) cerr << ", "; Chris@1266: cerr << v[i]; Chris@1266: } Chris@1266: cerr << " ]\n"; Chris@1266: } Chris@1269: #else Chris@1269: template Chris@1269: void report(vector ) { } Chris@1269: #endif Chris@1266: Chris@1265: private slots: Chris@1265: void applyGain() { Chris@1265: QCOMPARE(C::applyGain({}, 1.0), Column()); Chris@1265: Column c { 1, 2, 3, -4, 5, 6 }; Chris@1265: Column actual(C::applyGain(c, 1.5)); Chris@1380: Column expected { 1.5f, 3, 4.5f, -6, 7.5f, 9 }; Chris@1265: QCOMPARE(actual, expected); Chris@1265: actual = C::applyGain(c, 1.0); Chris@1265: QCOMPARE(actual, c); Chris@1265: actual = C::applyGain(c, 0.0); Chris@1265: expected = { 0, 0, 0, 0, 0, 0 }; Chris@1265: QCOMPARE(actual, expected); Chris@1265: } Chris@1265: Chris@1265: void fftScale() { Chris@1265: QCOMPARE(C::fftScale({}, 2.0), Column()); Chris@1265: Column c { 1, 2, 3, -4, 5 }; Chris@1265: Column actual(C::fftScale(c, 8)); Chris@1380: Column expected { 0.25f, 0.5f, 0.75f, -1, 1.25f }; Chris@1265: QCOMPARE(actual, expected); Chris@1265: } Chris@1265: Chris@1265: void isPeak_null() { Chris@1265: QVERIFY(!C::isPeak({}, 0)); Chris@1265: QVERIFY(!C::isPeak({}, 1)); Chris@1265: QVERIFY(!C::isPeak({}, -1)); Chris@1265: } Chris@1265: Chris@1265: void isPeak_obvious() { Chris@1380: Column c { 0.4f, 0.5f, 0.3f }; Chris@1265: QVERIFY(!C::isPeak(c, 0)); Chris@1265: QVERIFY(C::isPeak(c, 1)); Chris@1265: QVERIFY(!C::isPeak(c, 2)); Chris@1265: } Chris@1265: Chris@1265: void isPeak_edges() { Chris@1380: Column c { 0.5f, 0.4f, 0.3f }; Chris@1265: QVERIFY(C::isPeak(c, 0)); Chris@1265: QVERIFY(!C::isPeak(c, 1)); Chris@1265: QVERIFY(!C::isPeak(c, 2)); Chris@1265: QVERIFY(!C::isPeak(c, 3)); Chris@1265: QVERIFY(!C::isPeak(c, -1)); Chris@1380: c = { 1.4f, 1.5f }; Chris@1265: QVERIFY(!C::isPeak(c, 0)); Chris@1265: QVERIFY(C::isPeak(c, 1)); Chris@1265: } Chris@1265: Chris@1265: void isPeak_flat() { Chris@1380: Column c { 0.0f, 0.0f, 0.0f }; Chris@1265: QVERIFY(C::isPeak(c, 0)); Chris@1265: QVERIFY(!C::isPeak(c, 1)); Chris@1265: QVERIFY(!C::isPeak(c, 2)); Chris@1265: } Chris@1265: Chris@1265: void isPeak_mixedSign() { Chris@1380: Column c { 0.4f, -0.5f, -0.3f, -0.6f, 0.1f, -0.3f }; Chris@1265: QVERIFY(C::isPeak(c, 0)); Chris@1265: QVERIFY(!C::isPeak(c, 1)); Chris@1265: QVERIFY(C::isPeak(c, 2)); Chris@1265: QVERIFY(!C::isPeak(c, 3)); Chris@1265: QVERIFY(C::isPeak(c, 4)); Chris@1265: QVERIFY(!C::isPeak(c, 5)); Chris@1265: } Chris@1265: Chris@1265: void isPeak_duplicate() { Chris@1380: Column c({ 0.5f, 0.5f, 0.4f, 0.4f }); Chris@1265: QVERIFY(C::isPeak(c, 0)); Chris@1265: QVERIFY(!C::isPeak(c, 1)); Chris@1265: QVERIFY(!C::isPeak(c, 2)); Chris@1265: QVERIFY(!C::isPeak(c, 3)); Chris@1380: c = { 0.4f, 0.4f, 0.5f, 0.5f }; Chris@1265: QVERIFY(C::isPeak(c, 0)); // counterintuitive but necessary Chris@1265: QVERIFY(!C::isPeak(c, 1)); Chris@1265: QVERIFY(C::isPeak(c, 2)); Chris@1265: QVERIFY(!C::isPeak(c, 3)); Chris@1265: } Chris@1265: Chris@1265: void peakPick() { Chris@1265: QCOMPARE(C::peakPick({}), Column()); Chris@1380: Column c({ 0.5f, 0.5f, 0.4f, 0.4f }); Chris@1380: QCOMPARE(C::peakPick(c), Column({ 0.5f, 0.0f, 0.0f, 0.0f })); Chris@1380: c = Column({ 0.4f, -0.5f, -0.3f, -0.6f, 0.1f, -0.3f }); Chris@1380: QCOMPARE(C::peakPick(c), Column({ 0.4f, 0.0f, -0.3f, 0.0f, 0.1f, 0.0f })); Chris@1265: } Chris@1265: Chris@1265: void normalize_null() { Chris@1265: QCOMPARE(C::normalize({}, ColumnNormalization::None), Column()); Chris@1265: QCOMPARE(C::normalize({}, ColumnNormalization::Sum1), Column()); Chris@1265: QCOMPARE(C::normalize({}, ColumnNormalization::Max1), Column()); Chris@1394: QCOMPARE(C::normalize({}, ColumnNormalization::Range01), Column()); Chris@1265: QCOMPARE(C::normalize({}, ColumnNormalization::Hybrid), Column()); Chris@1265: } Chris@1265: Chris@1265: void normalize_none() { Chris@1265: Column c { 1, 2, 3, 4 }; Chris@1265: QCOMPARE(C::normalize(c, ColumnNormalization::None), c); Chris@1265: } Chris@1265: Chris@1266: void normalize_none_mixedSign() { Chris@1266: Column c { 1, 2, -3, -4 }; Chris@1266: QCOMPARE(C::normalize(c, ColumnNormalization::None), c); Chris@1266: } Chris@1266: Chris@1265: void normalize_sum1() { Chris@1265: Column c { 1, 2, 4, 3 }; Chris@1265: QCOMPARE(C::normalize(c, ColumnNormalization::Sum1), Chris@1380: Column({ 0.1f, 0.2f, 0.4f, 0.3f })); Chris@1265: } Chris@1265: Chris@1266: void normalize_sum1_mixedSign() { Chris@1266: Column c { 1, 2, -4, -3 }; Chris@1266: QCOMPARE(C::normalize(c, ColumnNormalization::Sum1), Chris@1380: Column({ 0.1f, 0.2f, -0.4f, -0.3f })); Chris@1266: } Chris@1266: Chris@1265: void normalize_max1() { Chris@1265: Column c { 4, 3, 2, 1 }; Chris@1265: QCOMPARE(C::normalize(c, ColumnNormalization::Max1), Chris@1380: Column({ 1.0f, 0.75f, 0.5f, 0.25f })); Chris@1265: } Chris@1265: Chris@1266: void normalize_max1_mixedSign() { Chris@1266: Column c { -4, -3, 2, 1 }; Chris@1266: QCOMPARE(C::normalize(c, ColumnNormalization::Max1), Chris@1380: Column({ -1.0f, -0.75f, 0.5f, 0.25f })); Chris@1266: } Chris@1266: Chris@1394: void normalize_range01() { Chris@1394: Column c { 4, 3, 2, 1 }; Chris@1394: QCOMPARE(C::normalize(c, ColumnNormalization::Range01), Chris@1394: Column({ 1.0f, 2.f/3.f, 1.f/3.f, 0.0f })); Chris@1394: } Chris@1394: Chris@1394: void normalize_range01_mixedSign() { Chris@1394: Column c { -2, -3, 2, 1 }; Chris@1394: QCOMPARE(C::normalize(c, ColumnNormalization::Range01), Chris@1394: Column({ 0.2f, 0.0f, 1.0f, 0.8f })); Chris@1394: } Chris@1394: Chris@1265: void normalize_hybrid() { Chris@1265: // with max == 99, log10(max+1) == 2 so scale factor will be 2/99 Chris@1265: Column c { 22, 44, 99, 66 }; Chris@1265: QCOMPARE(C::normalize(c, ColumnNormalization::Hybrid), Chris@1380: Column({ 44.0f/99.0f, 88.0f/99.0f, 2.0f, 132.0f/99.0f })); Chris@1265: } Chris@1265: Chris@1266: void normalize_hybrid_mixedSign() { Chris@1266: // with max == 99, log10(max+1) == 2 so scale factor will be 2/99 Chris@1266: Column c { 22, 44, -99, -66 }; Chris@1266: QCOMPARE(C::normalize(c, ColumnNormalization::Hybrid), Chris@1380: Column({ 44.0f/99.0f, 88.0f/99.0f, -2.0f, -132.0f/99.0f })); Chris@1266: } Chris@1266: Chris@1266: void distribute_simple() { Chris@1266: Column in { 1, 2, 3 }; Chris@1380: BinMapping binfory { 0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 2.5f }; Chris@1266: Column expected { 1, 1, 2, 2, 3, 3 }; Chris@1266: Column actual(C::distribute(in, 6, binfory, 0, false)); Chris@1266: report(actual); Chris@1266: QCOMPARE(actual, expected); Chris@1266: } Chris@1266: Chris@1266: void distribute_simple_interpolated() { Chris@1266: Column in { 1, 2, 3 }; Chris@1380: BinMapping binfory { 0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 2.5f }; Chris@1267: // There is a 0.5-bin offset from the distribution you might Chris@1267: // expect, because this corresponds visually to the way that Chris@1267: // bin values are duplicated upwards in simple_distribution. Chris@1267: // It means that switching between interpolated and Chris@1267: // non-interpolated views retains the visual position of each Chris@1267: // bin peak as somewhere in the middle of the scale area for Chris@1267: // that bin. Chris@1380: Column expected { 1, 1, 1.5f, 2, 2.5f, 3 }; Chris@1266: Column actual(C::distribute(in, 6, binfory, 0, true)); Chris@1266: report(actual); Chris@1266: QCOMPARE(actual, expected); Chris@1266: } Chris@1266: Chris@1266: void distribute_nonlinear() { Chris@1266: Column in { 1, 2, 3 }; Chris@1380: BinMapping binfory { 0.0f, 0.2f, 0.5f, 1.0f, 2.0f, 2.5f }; Chris@1266: Column expected { 1, 1, 1, 2, 3, 3 }; Chris@1266: Column actual(C::distribute(in, 6, binfory, 0, false)); Chris@1266: report(actual); Chris@1266: QCOMPARE(actual, expected); Chris@1266: } Chris@1266: Chris@1266: void distribute_nonlinear_interpolated() { Chris@1267: // See distribute_simple_interpolated Chris@1266: Column in { 1, 2, 3 }; Chris@1380: BinMapping binfory { 0.0f, 0.2f, 0.5f, 1.0f, 2.0f, 2.5f }; Chris@1267: Column expected { 1, 1, 1, 1.5, 2.5, 3 }; Chris@1266: Column actual(C::distribute(in, 6, binfory, 0, true)); Chris@1266: report(actual); Chris@1266: QCOMPARE(actual, expected); Chris@1266: } Chris@1266: Chris@1266: void distribute_shrinking() { Chris@1266: Column in { 4, 1, 2, 3, 5, 6 }; Chris@1380: BinMapping binfory { 0.0f, 2.0f, 4.0f }; Chris@1266: Column expected { 4, 3, 6 }; Chris@1266: Column actual(C::distribute(in, 3, binfory, 0, false)); Chris@1266: report(actual); Chris@1266: QCOMPARE(actual, expected); Chris@1266: } Chris@1266: Chris@1266: void distribute_shrinking_interpolated() { Chris@1266: // should be same as distribute_shrinking, we don't Chris@1266: // interpolate when resizing down Chris@1266: Column in { 4, 1, 2, 3, 5, 6 }; Chris@1380: BinMapping binfory { 0.0f, 2.0f, 4.0f }; Chris@1266: Column expected { 4, 3, 6 }; Chris@1266: Column actual(C::distribute(in, 3, binfory, 0, true)); Chris@1266: report(actual); Chris@1266: QCOMPARE(actual, expected); Chris@1266: } Chris@1265: Chris@1304: void distribute_nonlinear_someshrinking_interpolated() { Chris@1304: // But we *should* interpolate if the mapping involves Chris@1304: // shrinking some bins but expanding others. See Chris@1304: // distribute_simple_interpolated for note on 0.5 offset Chris@1304: Column in { 4, 1, 2, 3, 5, 6 }; Chris@1380: BinMapping binfory { 0.0f, 3.0f, 4.0f, 4.5f }; Chris@1380: Column expected { 4.0f, 2.5f, 4.0f, 5.0f }; Chris@1304: Column actual(C::distribute(in, 4, binfory, 0, true)); Chris@1304: report(actual); Chris@1304: QCOMPARE(actual, expected); Chris@1380: binfory = BinMapping { 0.5f, 1.0f, 2.0f, 5.0f }; Chris@1380: expected = { 4.0f, 2.5f, 1.5f, 5.5f }; Chris@1304: actual = (C::distribute(in, 4, binfory, 0, true)); Chris@1304: report(actual); Chris@1304: QCOMPARE(actual, expected); Chris@1304: } Chris@1265: }; Chris@1265: Chris@1265: #endif Chris@1265: