# HG changeset patch # User Chris Cannam # Date 1479393200 0 # Node ID dd190086db7384b1633274f56873015095543ecd # Parent e2e66bfd4a8840053523ba12279b45ea1053c7f0 Tests and fixes for distribute(). Although this version of interpolated distribution passes these tests, it isn't right visually -- the expected values in the tests are offset. To be continued. diff -r e2e66bfd4a88 -r dd190086db73 base/ColumnOp.h --- a/base/ColumnOp.h Thu Nov 17 11:56:54 2016 +0000 +++ b/base/ColumnOp.h Thu Nov 17 14:33:20 2016 +0000 @@ -18,10 +18,7 @@ #include "BaseTypes.h" -#include #include -#include -#include /** * Display normalization types for columns in e.g. grid plots. @@ -58,24 +55,17 @@ * Scale the given column using the given gain multiplier. */ static Column applyGain(const Column &in, double gain) { - - if (gain == 1.0) { - return in; - } + if (gain == 1.0) return in; Column out; out.reserve(in.size()); - for (auto v: in) { - out.push_back(float(v * gain)); - } + for (auto v: in) out.push_back(float(v * gain)); return out; } /** * Scale an FFT output downward by half the FFT size. */ - static Column fftScale(const Column &in, int fftSize) { - return applyGain(in, 2.0 / fftSize); - } + static Column fftScale(const Column &in, int fftSize); /** * Determine whether an index points to a local peak. @@ -103,59 +93,18 @@ * Return a column containing only the local peak values (all * others zero). */ - static Column peakPick(const Column &in) { - - std::vector out(in.size(), 0.f); - for (int i = 0; in_range_for(in, i); ++i) { - if (isPeak(in, i)) { - out[i] = in[i]; - } - } - - return out; - } + static Column peakPick(const Column &in); /** * Return a column normalized from the input column according to * the given normalization scheme. + * + * Note that the sum or max (as appropriate) used for + * normalisation will be calculated from the absolute values of + * the column elements, should any of them be negative. */ - static Column normalize(const Column &in, ColumnNormalization n) { - - if (n == ColumnNormalization::None || in.empty()) { - return in; - } - - float scale = 1.f; - - if (n == ColumnNormalization::Sum1) { - - float sum = 0.f; - - for (auto v: in) { - sum += v; - } - - if (sum != 0.f) { - scale = 1.f / sum; - } - } else { - - float max = *max_element(in.begin(), in.end()); - - if (n == ColumnNormalization::Max1) { - if (max != 0.f) { - scale = 1.f / max; - } - } else if (n == ColumnNormalization::Hybrid) { - if (max > 0.f) { - scale = log10f(max + 1.f) / max; - } - } - } - - return applyGain(in, scale); - } - + static Column normalize(const Column &in, ColumnNormalization n); + /** * Distribute the given column into a target vector of a different * size, optionally using linear interpolation. The binfory vector @@ -169,63 +118,7 @@ int h, const std::vector &binfory, int minbin, - bool interpolate) { - - std::vector out(h, 0.f); - int bins = int(in.size()); - - for (int y = 0; y < h; ++y) { - - double sy0 = binfory[y] - minbin; - double sy1 = sy0 + 1; - if (y+1 < h) { - sy1 = binfory[y+1] - minbin; - } - - std::cerr << "y = " << y << " of " << h << ", sy0 = " << sy0 << ", sy1 = " << sy1 << std::endl; - - if (interpolate && fabs(sy1 - sy0) < 1.0) { - - double centre = (sy0 + sy1) / 2; - double dist = (centre - 0.5) - rint(centre - 0.5); - int bin = int(centre); - - int other = (dist < 0 ? (bin-1) : (bin+1)); - - if (bin < 0) bin = 0; - if (bin >= bins) bin = bins-1; - - if (other < 0 || other >= bins) { - other = bin; - } - - double prop = 1.0 - fabs(dist); - - double v0 = in[bin]; - double v1 = in[other]; - - out[y] = float(prop * v0 + (1.0 - prop) * v1); - - } else { // not interpolating this one - - int by0 = int(sy0 + 0.0001); - int by1 = int(sy1 + 0.0001); - if (by1 < by0 + 1) by1 = by0 + 1; - if (by1 >= bins) by1 = bins - 1; - - for (int bin = by0; bin <= by1; ++bin) { - - float value = in[bin]; - - if (bin == by0 || value > out[y]) { - out[y] = value; - } - } - } - } - - return out; - } + bool interpolate); }; diff -r e2e66bfd4a88 -r dd190086db73 base/test/TestColumnOp.h --- a/base/test/TestColumnOp.h Thu Nov 17 11:56:54 2016 +0000 +++ b/base/test/TestColumnOp.h Thu Nov 17 14:33:20 2016 +0000 @@ -31,7 +31,18 @@ typedef ColumnOp C; typedef ColumnOp::Column Column; - + typedef vector BinMapping; + + template + void report(vector v) { + cerr << "Vector is: [ "; + for (int i = 0; i < int(v.size()); ++i) { + if (i > 0) cerr << ", "; + cerr << v[i]; + } + cerr << " ]\n"; + } + private slots: void applyGain() { QCOMPARE(C::applyGain({}, 1.0), Column()); @@ -129,18 +140,35 @@ QCOMPARE(C::normalize(c, ColumnNormalization::None), c); } + void normalize_none_mixedSign() { + Column c { 1, 2, -3, -4 }; + QCOMPARE(C::normalize(c, ColumnNormalization::None), c); + } + void normalize_sum1() { Column c { 1, 2, 4, 3 }; QCOMPARE(C::normalize(c, ColumnNormalization::Sum1), Column({ 0.1, 0.2, 0.4, 0.3 })); } + void normalize_sum1_mixedSign() { + Column c { 1, 2, -4, -3 }; + QCOMPARE(C::normalize(c, ColumnNormalization::Sum1), + Column({ 0.1, 0.2, -0.4, -0.3 })); + } + void normalize_max1() { Column c { 4, 3, 2, 1 }; QCOMPARE(C::normalize(c, ColumnNormalization::Max1), Column({ 1.0, 0.75, 0.5, 0.25 })); } + void normalize_max1_mixedSign() { + Column c { -4, -3, 2, 1 }; + QCOMPARE(C::normalize(c, ColumnNormalization::Max1), + Column({ -1.0, -0.75, 0.5, 0.25 })); + } + void normalize_hybrid() { // with max == 99, log10(max+1) == 2 so scale factor will be 2/99 Column c { 22, 44, 99, 66 }; @@ -148,6 +176,68 @@ Column({ 44.0/99.0, 88.0/99.0, 2.0, 132.0/99.0 })); } + void normalize_hybrid_mixedSign() { + // with max == 99, log10(max+1) == 2 so scale factor will be 2/99 + Column c { 22, 44, -99, -66 }; + QCOMPARE(C::normalize(c, ColumnNormalization::Hybrid), + Column({ 44.0/99.0, 88.0/99.0, -2.0, -132.0/99.0 })); + } + + void distribute_simple() { + Column in { 1, 2, 3 }; + BinMapping binfory { 0.0, 0.5, 1.0, 1.5, 2.0, 2.5 }; + Column expected { 1, 1, 2, 2, 3, 3 }; + Column actual(C::distribute(in, 6, binfory, 0, false)); + report(actual); + QCOMPARE(actual, expected); + } + + void distribute_simple_interpolated() { + Column in { 1, 2, 3 }; + BinMapping binfory { 0.0, 0.5, 1.0, 1.5, 2.0, 2.5 }; + Column expected { 1, 1.5, 2, 2.5, 3, 3 }; + Column actual(C::distribute(in, 6, binfory, 0, true)); + report(actual); + QCOMPARE(actual, expected); + } + + void distribute_nonlinear() { + Column in { 1, 2, 3 }; + BinMapping binfory { 0.0, 0.2, 0.5, 1.0, 2.0, 2.5 }; + Column expected { 1, 1, 1, 2, 3, 3 }; + Column actual(C::distribute(in, 6, binfory, 0, false)); + report(actual); + QCOMPARE(actual, expected); + } + + void distribute_nonlinear_interpolated() { + Column in { 1, 2, 3 }; + BinMapping binfory { 0.0, 0.2, 0.5, 1.0, 2.0, 2.5 }; + Column expected { 1, 1.2, 1.5, 2, 3, 3 }; + Column actual(C::distribute(in, 6, binfory, 0, true)); + report(actual); + QCOMPARE(actual, expected); + } + + void distribute_shrinking() { + Column in { 4, 1, 2, 3, 5, 6 }; + BinMapping binfory { 0.0, 2.0, 4.0 }; + Column expected { 4, 3, 6 }; + Column actual(C::distribute(in, 3, binfory, 0, false)); + report(actual); + QCOMPARE(actual, expected); + } + + void distribute_shrinking_interpolated() { + // should be same as distribute_shrinking, we don't + // interpolate when resizing down + Column in { 4, 1, 2, 3, 5, 6 }; + BinMapping binfory { 0.0, 2.0, 4.0 }; + Column expected { 4, 3, 6 }; + Column actual(C::distribute(in, 3, binfory, 0, true)); + report(actual); + QCOMPARE(actual, expected); + } }; diff -r e2e66bfd4a88 -r dd190086db73 files.pri --- a/files.pri Thu Nov 17 11:56:54 2016 +0000 +++ b/files.pri Thu Nov 17 14:33:20 2016 +0000 @@ -143,6 +143,7 @@ SVCORE_SOURCES = \ base/AudioLevel.cpp \ base/Clipboard.cpp \ + base/ColumnOp.cpp \ base/Command.cpp \ base/Debug.cpp \ base/Exceptions.cpp \