annotate data/model/test/TestWaveformOversampler.h @ 1855:db489a1ece9b

Pull out text-document check; it's useful elsewhere
author Chris Cannam
date Mon, 11 May 2020 17:27:18 +0100
parents 074b860a7828
children
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@1745 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