annotate data/model/test/TestWaveformOversampler.h @ 1552:05c3fbaec8ea

Introduce RelativelyFineZoomConstraint, which encodes more-or-less the scheme that was already used for the horizontal thumbwheel in the pane (which overrode the layers' own zoom constraints unless they said they couldn't support any other)
author Chris Cannam
date Wed, 10 Oct 2018 14:32:34 +0100
parents a53bf95f0bea
children 074b860a7828
rev   line source
Chris@1537 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@1537 2
Chris@1537 3 /*
Chris@1537 4 Sonic Visualiser
Chris@1537 5 An audio file viewer and annotation editor.
Chris@1537 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1537 7
Chris@1537 8 This program is free software; you can redistribute it and/or
Chris@1537 9 modify it under the terms of the GNU General Public License as
Chris@1537 10 published by the Free Software Foundation; either version 2 of the
Chris@1537 11 License, or (at your option) any later version. See the file
Chris@1537 12 COPYING included with this distribution for more information.
Chris@1537 13 */
Chris@1537 14
Chris@1537 15 #ifndef TEST_WAVEFORM_OVERSAMPLER_H
Chris@1537 16 #define TEST_WAVEFORM_OVERSAMPLER_H
Chris@1537 17
Chris@1537 18 #include "../WaveformOversampler.h"
Chris@1537 19 #include "../WritableWaveFileModel.h"
Chris@1537 20
Chris@1537 21 #include "../../../base/BaseTypes.h"
Chris@1537 22
Chris@1537 23 #include <QObject>
Chris@1537 24 #include <QtTest>
Chris@1537 25
Chris@1537 26 class TestWaveformOversampler : public QObject
Chris@1537 27 {
Chris@1537 28 Q_OBJECT
Chris@1537 29
Chris@1537 30 public:
Chris@1537 31 TestWaveformOversampler() {
Chris@1537 32 m_source = floatvec_t(5000, 0.f);
Chris@1537 33 m_source[0] = 1.f;
Chris@1537 34 m_source[2500] = 0.5f;
Chris@1537 35 m_source[2501] = -0.5f;
Chris@1537 36 m_source[4999] = -1.f;
Chris@1540 37 for (int i = 3000; i < 3900; ++i) {
Chris@1540 38 m_source[i] = float(sin(double(i - 3000) * M_PI / 50.0));
Chris@1537 39 }
Chris@1537 40 m_sourceModel = new WritableWaveFileModel(8000, 1);
Chris@1537 41 const float *d = m_source.data();
Chris@1537 42 QVERIFY(m_sourceModel->addSamples(&d, m_source.size()));
Chris@1537 43 m_sourceModel->writeComplete();
Chris@1537 44 }
Chris@1537 45
Chris@1537 46 ~TestWaveformOversampler() {
Chris@1537 47 delete m_sourceModel;
Chris@1537 48 }
Chris@1537 49
Chris@1537 50 private:
Chris@1537 51 floatvec_t m_source;
Chris@1537 52 WritableWaveFileModel *m_sourceModel;
Chris@1537 53
Chris@1537 54 void compareStrided(floatvec_t obtained, floatvec_t expected, int stride) {
Chris@1537 55 QCOMPARE(obtained.size(), expected.size() * stride);
Chris@1537 56 float threshold = 1e-10f;
Chris@1537 57 for (int i = 0; in_range_for(expected, i); ++i) {
Chris@1537 58 if (fabsf(obtained[i * stride] - expected[i]) > threshold) {
Chris@1539 59 std::cerr << "At position " << i * stride << ": "
Chris@1539 60 << obtained[i * stride] << " != " << expected[i]
Chris@1539 61 << std::endl;
Chris@1537 62 QCOMPARE(obtained, expected);
Chris@1537 63 }
Chris@1537 64 }
Chris@1537 65 }
Chris@1537 66
Chris@1537 67 void compareVecs(floatvec_t obtained, floatvec_t expected) {
Chris@1537 68 compareStrided(obtained, expected, 1);
Chris@1537 69 }
Chris@1537 70
Chris@1537 71 floatvec_t get(sv_frame_t sourceStartFrame,
Chris@1537 72 sv_frame_t sourceFrameCount,
Chris@1538 73 int oversampleBy) {
Chris@1537 74 return WaveformOversampler::getOversampledData
Chris@1537 75 (m_sourceModel, 0,
Chris@1537 76 sourceStartFrame, sourceFrameCount, oversampleBy);
Chris@1537 77 }
Chris@1537 78
Chris@1537 79 void testVerbatim(sv_frame_t sourceStartFrame,
Chris@1537 80 sv_frame_t sourceFrameCount,
Chris@1537 81 int oversampleBy,
Chris@1537 82 floatvec_t expected) {
Chris@1537 83 floatvec_t output =
Chris@1537 84 get(sourceStartFrame, sourceFrameCount, oversampleBy);
Chris@1537 85 compareVecs(output, expected);
Chris@1537 86 }
Chris@1537 87
Chris@1537 88 void testStrided(sv_frame_t sourceStartFrame,
Chris@1537 89 sv_frame_t sourceFrameCount,
Chris@1537 90 int oversampleBy,
Chris@1537 91 floatvec_t expected) {
Chris@1537 92 // check only the values that are expected to be precisely the
Chris@1537 93 // original samples
Chris@1537 94 floatvec_t output =
Chris@1537 95 get(sourceStartFrame, sourceFrameCount, oversampleBy);
Chris@1537 96 compareStrided(output, expected, oversampleBy);
Chris@1537 97 }
Chris@1537 98
Chris@1537 99 floatvec_t sourceSubset(sv_frame_t start, sv_frame_t length) {
Chris@1537 100 return floatvec_t(m_source.begin() + start,
Chris@1537 101 m_source.begin() + start + length);
Chris@1537 102 }
Chris@1537 103
Chris@1537 104 private slots:
Chris@1537 105 void testWholeVerbatim() {
Chris@1537 106 testVerbatim(0, 5000, 1, m_source);
Chris@1537 107 }
Chris@1537 108
Chris@1537 109 void testSubsetsVerbatim() {
Chris@1537 110 testVerbatim(0, 500, 1, sourceSubset(0, 500));
Chris@1537 111 testVerbatim(4500, 500, 1, sourceSubset(4500, 500));
Chris@1537 112 testVerbatim(2000, 1000, 1, sourceSubset(2000, 1000));
Chris@1537 113 }
Chris@1537 114
Chris@1537 115 void testOverlapsVerbatim() {
Chris@1537 116 // overlapping the start -> result should be zero-padded to
Chris@1537 117 // preserve start frame
Chris@1537 118 floatvec_t expected = sourceSubset(0, 400);
Chris@1537 119 expected.insert(expected.begin(), 100, 0.f);
Chris@1537 120 testVerbatim(-100, 500, 1, expected);
Chris@1537 121
Chris@1537 122 // overlapping the end -> result should be truncated to
Chris@1537 123 // preserve source length
Chris@1537 124 expected = sourceSubset(4600, 400);
Chris@1537 125 testVerbatim(4600, 500, 1, expected);
Chris@1537 126 }
Chris@1537 127
Chris@1537 128 void testWhole2x() {
Chris@1537 129 testStrided(0, 5000, 2, m_source);
Chris@1537 130
Chris@1537 131 // check for windowed sinc values between the original samples
Chris@1537 132 floatvec_t output = get(0, 5000, 2);
Chris@1537 133 QVERIFY(output[1] - 0.6358 < 0.0001);
Chris@1537 134 QVERIFY(output[3] + 0.2099 < 0.0001);
Chris@1537 135 }
Chris@1537 136
Chris@1537 137 void testWhole3x() {
Chris@1537 138 testStrided(0, 5000, 3, m_source);
Chris@1537 139
Chris@1537 140 // check for windowed sinc values between the original samples
Chris@1537 141 floatvec_t output = get(0, 5000, 3);
Chris@1537 142 QVERIFY(output[1] > 0.7);
Chris@1537 143 QVERIFY(output[2] > 0.4);
Chris@1537 144 QVERIFY(output[4] < -0.1);
Chris@1537 145 QVERIFY(output[5] < -0.1);
Chris@1537 146 }
Chris@1537 147
Chris@1537 148 void testWhole4x() {
Chris@1537 149 testStrided(0, 5000, 4, m_source);
Chris@1537 150
Chris@1537 151 // check for windowed sinc values between the original samples
Chris@1537 152 floatvec_t output = get(0, 5000, 4);
Chris@1537 153 QVERIFY(output[1] - 0.9000 < 0.0001);
Chris@1537 154 QVERIFY(output[2] - 0.6358 < 0.0001);
Chris@1537 155 QVERIFY(output[3] - 0.2993 < 0.0001);
Chris@1537 156 QVERIFY(output[5] + 0.1787 < 0.0001);
Chris@1537 157 QVERIFY(output[6] + 0.2099 < 0.0001);
Chris@1537 158 QVERIFY(output[7] + 0.1267 < 0.0001);
Chris@1537 159
Chris@1537 160 // alternate values at 2n should equal all values at n
Chris@1537 161 output = get(0, 5000, 4);
Chris@1537 162 floatvec_t half = get(0, 5000, 2);
Chris@1537 163 compareStrided(output, half, 2);
Chris@1537 164 }
Chris@1537 165
Chris@1537 166 void testWhole8x() {
Chris@1537 167 testStrided(0, 5000, 8, m_source);
Chris@1537 168
Chris@1537 169 // alternate values at 2n should equal all values at n
Chris@1537 170 floatvec_t output = get(0, 5000, 8);
Chris@1537 171 floatvec_t half = get(0, 5000, 4);
Chris@1537 172 compareStrided(output, half, 2);
Chris@1537 173 }
Chris@1537 174
Chris@1537 175 void testWhole10x() {
Chris@1537 176 testStrided(0, 5000, 10, m_source);
Chris@1537 177
Chris@1537 178 // alternate values at 2n should equal all values at n
Chris@1537 179 floatvec_t output = get(0, 5000, 10);
Chris@1537 180 floatvec_t half = get(0, 5000, 5);
Chris@1537 181 compareStrided(output, half, 2);
Chris@1537 182 }
Chris@1537 183
Chris@1537 184 void testWhole16x() {
Chris@1537 185 testStrided(0, 5000, 16, m_source);
Chris@1537 186
Chris@1537 187 // alternate values at 2n should equal all values at n
Chris@1537 188 floatvec_t output = get(0, 5000, 16);
Chris@1537 189 floatvec_t half = get(0, 5000, 8);
Chris@1537 190 compareStrided(output, half, 2);
Chris@1537 191 }
Chris@1537 192
Chris@1537 193 void testSubsets4x() {
Chris@1537 194 testStrided(0, 500, 4, sourceSubset(0, 500));
Chris@1537 195 testStrided(4500, 500, 4, sourceSubset(4500, 500));
Chris@1537 196 testStrided(2000, 1000, 4, sourceSubset(2000, 1000));
Chris@1538 197
Chris@1538 198 // check for windowed sinc values between the original
Chris@1538 199 // samples, even when the original sample that was the source
Chris@1538 200 // of this sinc kernel is not within the requested range
Chris@1538 201 floatvec_t output = get(1, 10, 4);
Chris@1540 202 QVERIFY(output[0] < 0.0001);
Chris@1538 203 QVERIFY(output[1] + 0.1787 < 0.0001);
Chris@1538 204 QVERIFY(output[2] + 0.2099 < 0.0001);
Chris@1538 205 QVERIFY(output[3] + 0.1267 < 0.0001);
Chris@1540 206
Chris@1540 207 // and again at the end
Chris@1540 208 output = get(4989, 10, 4);
Chris@1540 209 QVERIFY(output[39] + 0.9000 < 0.0001);
Chris@1540 210 QVERIFY(output[38] + 0.6358 < 0.0001);
Chris@1540 211 QVERIFY(output[37] + 0.2993 < 0.0001);
Chris@1540 212 QVERIFY(output[35] - 0.1787 < 0.0001);
Chris@1540 213 QVERIFY(output[34] - 0.2099 < 0.0001);
Chris@1540 214 QVERIFY(output[33] - 0.1267 < 0.0001);
Chris@1537 215 }
Chris@1537 216
Chris@1537 217 void testOverlaps4x() {
Chris@1537 218 // overlapping the start -> result should be zero-padded to
Chris@1537 219 // preserve start frame
Chris@1537 220 floatvec_t expected = sourceSubset(0, 400);
Chris@1537 221 expected.insert(expected.begin(), 100, 0.f);
Chris@1537 222 testStrided(-100, 500, 4, expected);
Chris@1537 223
Chris@1537 224 // overlapping the end -> result should be truncated to
Chris@1537 225 // preserve source length
Chris@1537 226 expected = sourceSubset(4600, 400);
Chris@1537 227 testStrided(4600, 500, 4, expected);
Chris@1537 228 }
Chris@1537 229
Chris@1537 230 void testSubsets15x() {
Chris@1537 231 testStrided(0, 500, 15, sourceSubset(0, 500));
Chris@1537 232 testStrided(4500, 500, 15, sourceSubset(4500, 500));
Chris@1537 233 testStrided(2000, 1000, 15, sourceSubset(2000, 1000));
Chris@1537 234 }
Chris@1537 235
Chris@1537 236 void testOverlaps15x() {
Chris@1537 237 // overlapping the start -> result should be zero-padded to
Chris@1537 238 // preserve start frame
Chris@1537 239 floatvec_t expected = sourceSubset(0, 400);
Chris@1537 240 expected.insert(expected.begin(), 100, 0.f);
Chris@1537 241 testStrided(-100, 500, 15, expected);
Chris@1537 242
Chris@1537 243 // overlapping the end -> result should be truncated to
Chris@1537 244 // preserve source length
Chris@1537 245 expected = sourceSubset(4600, 400);
Chris@1537 246 testStrided(4600, 500, 15, expected);
Chris@1537 247 }
Chris@1537 248 };
Chris@1537 249
Chris@1537 250
Chris@1537 251 #endif