Chris@1537: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@1537: Chris@1537: /* Chris@1537: Sonic Visualiser Chris@1537: An audio file viewer and annotation editor. Chris@1537: Centre for Digital Music, Queen Mary, University of London. Chris@1537: Chris@1537: This program is free software; you can redistribute it and/or Chris@1537: modify it under the terms of the GNU General Public License as Chris@1537: published by the Free Software Foundation; either version 2 of the Chris@1537: License, or (at your option) any later version. See the file Chris@1537: COPYING included with this distribution for more information. Chris@1537: */ Chris@1537: Chris@1537: #ifndef TEST_WAVEFORM_OVERSAMPLER_H Chris@1537: #define TEST_WAVEFORM_OVERSAMPLER_H Chris@1537: Chris@1537: #include "../WaveformOversampler.h" Chris@1537: #include "../WritableWaveFileModel.h" Chris@1537: Chris@1537: #include "../../../base/BaseTypes.h" Chris@1537: Chris@1537: #include Chris@1537: #include Chris@1537: Chris@1537: class TestWaveformOversampler : public QObject Chris@1537: { Chris@1537: Q_OBJECT Chris@1537: Chris@1537: public: Chris@1537: TestWaveformOversampler() { Chris@1537: m_source = floatvec_t(5000, 0.f); Chris@1537: m_source[0] = 1.f; Chris@1537: m_source[2500] = 0.5f; Chris@1537: m_source[2501] = -0.5f; Chris@1537: m_source[4999] = -1.f; Chris@1540: for (int i = 3000; i < 3900; ++i) { Chris@1540: m_source[i] = float(sin(double(i - 3000) * M_PI / 50.0)); Chris@1537: } Chris@1537: m_sourceModel = new WritableWaveFileModel(8000, 1); Chris@1537: const float *d = m_source.data(); Chris@1537: QVERIFY(m_sourceModel->addSamples(&d, m_source.size())); Chris@1537: m_sourceModel->writeComplete(); Chris@1537: } Chris@1537: Chris@1537: ~TestWaveformOversampler() { Chris@1537: delete m_sourceModel; Chris@1537: } Chris@1537: Chris@1537: private: Chris@1537: floatvec_t m_source; Chris@1537: WritableWaveFileModel *m_sourceModel; Chris@1537: Chris@1537: void compareStrided(floatvec_t obtained, floatvec_t expected, int stride) { Chris@1537: QCOMPARE(obtained.size(), expected.size() * stride); Chris@1537: float threshold = 1e-10f; Chris@1537: for (int i = 0; in_range_for(expected, i); ++i) { Chris@1537: if (fabsf(obtained[i * stride] - expected[i]) > threshold) { Chris@1539: std::cerr << "At position " << i * stride << ": " Chris@1539: << obtained[i * stride] << " != " << expected[i] Chris@1539: << std::endl; Chris@1537: QCOMPARE(obtained, expected); Chris@1537: } Chris@1537: } Chris@1537: } Chris@1537: Chris@1537: void compareVecs(floatvec_t obtained, floatvec_t expected) { Chris@1537: compareStrided(obtained, expected, 1); Chris@1537: } Chris@1537: Chris@1537: floatvec_t get(sv_frame_t sourceStartFrame, Chris@1537: sv_frame_t sourceFrameCount, Chris@1538: int oversampleBy) { Chris@1537: return WaveformOversampler::getOversampledData Chris@1745: (*m_sourceModel, 0, Chris@1537: sourceStartFrame, sourceFrameCount, oversampleBy); Chris@1537: } Chris@1537: Chris@1537: void testVerbatim(sv_frame_t sourceStartFrame, Chris@1537: sv_frame_t sourceFrameCount, Chris@1537: int oversampleBy, Chris@1537: floatvec_t expected) { Chris@1537: floatvec_t output = Chris@1537: get(sourceStartFrame, sourceFrameCount, oversampleBy); Chris@1537: compareVecs(output, expected); Chris@1537: } Chris@1537: Chris@1537: void testStrided(sv_frame_t sourceStartFrame, Chris@1537: sv_frame_t sourceFrameCount, Chris@1537: int oversampleBy, Chris@1537: floatvec_t expected) { Chris@1537: // check only the values that are expected to be precisely the Chris@1537: // original samples Chris@1537: floatvec_t output = Chris@1537: get(sourceStartFrame, sourceFrameCount, oversampleBy); Chris@1537: compareStrided(output, expected, oversampleBy); Chris@1537: } Chris@1537: Chris@1537: floatvec_t sourceSubset(sv_frame_t start, sv_frame_t length) { Chris@1537: return floatvec_t(m_source.begin() + start, Chris@1537: m_source.begin() + start + length); Chris@1537: } Chris@1537: Chris@1537: private slots: Chris@1537: void testWholeVerbatim() { Chris@1537: testVerbatim(0, 5000, 1, m_source); Chris@1537: } Chris@1537: Chris@1537: void testSubsetsVerbatim() { Chris@1537: testVerbatim(0, 500, 1, sourceSubset(0, 500)); Chris@1537: testVerbatim(4500, 500, 1, sourceSubset(4500, 500)); Chris@1537: testVerbatim(2000, 1000, 1, sourceSubset(2000, 1000)); Chris@1537: } Chris@1537: Chris@1537: void testOverlapsVerbatim() { Chris@1537: // overlapping the start -> result should be zero-padded to Chris@1537: // preserve start frame Chris@1537: floatvec_t expected = sourceSubset(0, 400); Chris@1537: expected.insert(expected.begin(), 100, 0.f); Chris@1537: testVerbatim(-100, 500, 1, expected); Chris@1537: Chris@1537: // overlapping the end -> result should be truncated to Chris@1537: // preserve source length Chris@1537: expected = sourceSubset(4600, 400); Chris@1537: testVerbatim(4600, 500, 1, expected); Chris@1537: } Chris@1537: Chris@1537: void testWhole2x() { Chris@1537: testStrided(0, 5000, 2, m_source); Chris@1537: Chris@1537: // check for windowed sinc values between the original samples Chris@1537: floatvec_t output = get(0, 5000, 2); Chris@1537: QVERIFY(output[1] - 0.6358 < 0.0001); Chris@1537: QVERIFY(output[3] + 0.2099 < 0.0001); Chris@1537: } Chris@1537: Chris@1537: void testWhole3x() { Chris@1537: testStrided(0, 5000, 3, m_source); Chris@1537: Chris@1537: // check for windowed sinc values between the original samples Chris@1537: floatvec_t output = get(0, 5000, 3); Chris@1537: QVERIFY(output[1] > 0.7); Chris@1537: QVERIFY(output[2] > 0.4); Chris@1537: QVERIFY(output[4] < -0.1); Chris@1537: QVERIFY(output[5] < -0.1); Chris@1537: } Chris@1537: Chris@1537: void testWhole4x() { Chris@1537: testStrided(0, 5000, 4, m_source); Chris@1537: Chris@1537: // check for windowed sinc values between the original samples Chris@1537: floatvec_t output = get(0, 5000, 4); Chris@1537: QVERIFY(output[1] - 0.9000 < 0.0001); Chris@1537: QVERIFY(output[2] - 0.6358 < 0.0001); Chris@1537: QVERIFY(output[3] - 0.2993 < 0.0001); Chris@1537: QVERIFY(output[5] + 0.1787 < 0.0001); Chris@1537: QVERIFY(output[6] + 0.2099 < 0.0001); Chris@1537: QVERIFY(output[7] + 0.1267 < 0.0001); Chris@1537: Chris@1537: // alternate values at 2n should equal all values at n Chris@1537: output = get(0, 5000, 4); Chris@1537: floatvec_t half = get(0, 5000, 2); Chris@1537: compareStrided(output, half, 2); Chris@1537: } Chris@1537: Chris@1537: void testWhole8x() { Chris@1537: testStrided(0, 5000, 8, m_source); Chris@1537: Chris@1537: // alternate values at 2n should equal all values at n Chris@1537: floatvec_t output = get(0, 5000, 8); Chris@1537: floatvec_t half = get(0, 5000, 4); Chris@1537: compareStrided(output, half, 2); Chris@1537: } Chris@1537: Chris@1537: void testWhole10x() { Chris@1537: testStrided(0, 5000, 10, m_source); Chris@1537: Chris@1537: // alternate values at 2n should equal all values at n Chris@1537: floatvec_t output = get(0, 5000, 10); Chris@1537: floatvec_t half = get(0, 5000, 5); Chris@1537: compareStrided(output, half, 2); Chris@1537: } Chris@1537: Chris@1537: void testWhole16x() { Chris@1537: testStrided(0, 5000, 16, m_source); Chris@1537: Chris@1537: // alternate values at 2n should equal all values at n Chris@1537: floatvec_t output = get(0, 5000, 16); Chris@1537: floatvec_t half = get(0, 5000, 8); Chris@1537: compareStrided(output, half, 2); Chris@1537: } Chris@1537: Chris@1537: void testSubsets4x() { Chris@1537: testStrided(0, 500, 4, sourceSubset(0, 500)); Chris@1537: testStrided(4500, 500, 4, sourceSubset(4500, 500)); Chris@1537: testStrided(2000, 1000, 4, sourceSubset(2000, 1000)); Chris@1538: Chris@1538: // check for windowed sinc values between the original Chris@1538: // samples, even when the original sample that was the source Chris@1538: // of this sinc kernel is not within the requested range Chris@1538: floatvec_t output = get(1, 10, 4); Chris@1540: QVERIFY(output[0] < 0.0001); Chris@1538: QVERIFY(output[1] + 0.1787 < 0.0001); Chris@1538: QVERIFY(output[2] + 0.2099 < 0.0001); Chris@1538: QVERIFY(output[3] + 0.1267 < 0.0001); Chris@1540: Chris@1540: // and again at the end Chris@1540: output = get(4989, 10, 4); Chris@1540: QVERIFY(output[39] + 0.9000 < 0.0001); Chris@1540: QVERIFY(output[38] + 0.6358 < 0.0001); Chris@1540: QVERIFY(output[37] + 0.2993 < 0.0001); Chris@1540: QVERIFY(output[35] - 0.1787 < 0.0001); Chris@1540: QVERIFY(output[34] - 0.2099 < 0.0001); Chris@1540: QVERIFY(output[33] - 0.1267 < 0.0001); Chris@1537: } Chris@1537: Chris@1537: void testOverlaps4x() { Chris@1537: // overlapping the start -> result should be zero-padded to Chris@1537: // preserve start frame Chris@1537: floatvec_t expected = sourceSubset(0, 400); Chris@1537: expected.insert(expected.begin(), 100, 0.f); Chris@1537: testStrided(-100, 500, 4, expected); Chris@1537: Chris@1537: // overlapping the end -> result should be truncated to Chris@1537: // preserve source length Chris@1537: expected = sourceSubset(4600, 400); Chris@1537: testStrided(4600, 500, 4, expected); Chris@1537: } Chris@1537: Chris@1537: void testSubsets15x() { Chris@1537: testStrided(0, 500, 15, sourceSubset(0, 500)); Chris@1537: testStrided(4500, 500, 15, sourceSubset(4500, 500)); Chris@1537: testStrided(2000, 1000, 15, sourceSubset(2000, 1000)); Chris@1537: } Chris@1537: Chris@1537: void testOverlaps15x() { Chris@1537: // overlapping the start -> result should be zero-padded to Chris@1537: // preserve start frame Chris@1537: floatvec_t expected = sourceSubset(0, 400); Chris@1537: expected.insert(expected.begin(), 100, 0.f); Chris@1537: testStrided(-100, 500, 15, expected); Chris@1537: Chris@1537: // overlapping the end -> result should be truncated to Chris@1537: // preserve source length Chris@1537: expected = sourceSubset(4600, 400); Chris@1537: testStrided(4600, 500, 15, expected); Chris@1537: } Chris@1537: }; Chris@1537: Chris@1537: Chris@1537: #endif