Chris@1086: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@1086: Chris@1086: /* Chris@1086: Sonic Visualiser Chris@1086: An audio file viewer and annotation editor. Chris@1086: Centre for Digital Music, Queen Mary, University of London. Chris@1086: Chris@1086: This program is free software; you can redistribute it and/or Chris@1086: modify it under the terms of the GNU General Public License as Chris@1086: published by the Free Software Foundation; either version 2 of the Chris@1086: License, or (at your option) any later version. See the file Chris@1086: COPYING included with this distribution for more information. Chris@1086: */ Chris@1086: Chris@1086: #ifndef TEST_FFT_MODEL_H Chris@1086: #define TEST_FFT_MODEL_H Chris@1086: Chris@1086: #include "../FFTModel.h" Chris@1086: Chris@1086: #include "MockWaveModel.h" Chris@1086: Chris@1086: #include "Compares.h" Chris@1086: Chris@1086: #include Chris@1086: #include Chris@1086: #include Chris@1086: Chris@1086: #include Chris@1088: #include Chris@1086: Chris@1086: using namespace std; Chris@1086: Chris@1086: class TestFFTModel : public QObject Chris@1086: { Chris@1086: Q_OBJECT Chris@1086: Chris@1088: private: Chris@1088: void test(DenseTimeValueModel *model, Chris@1088: WindowType window, int windowSize, int windowIncrement, int fftSize, Chris@1088: int columnNo, vector>> expectedValues, Chris@1088: int expectedWidth) { Chris@1088: for (int ch = 0; in_range_for(expectedValues, ch); ++ch) { Chris@1088: for (int polar = 0; polar <= 1; ++polar) { Chris@1088: FFTModel fftm(model, ch, window, windowSize, windowIncrement, Chris@1088: fftSize, bool(polar)); Chris@1088: QCOMPARE(fftm.getWidth(), expectedWidth); Chris@1088: int hs1 = fftSize/2 + 1; Chris@1088: QCOMPARE(fftm.getHeight(), hs1); Chris@1088: vector reals(hs1 + 1, 0.f); Chris@1088: vector imags(hs1 + 1, 0.f); Chris@1088: reals[hs1] = 999.f; // overrun guards Chris@1088: imags[hs1] = 999.f; Chris@1088: fftm.getValuesAt(columnNo, &reals[0], &imags[0]); Chris@1088: for (int i = 0; i < hs1; ++i) { Chris@1088: float eRe = expectedValues[ch][i].real(); Chris@1088: float eIm = expectedValues[ch][i].imag(); Chris@1088: if (reals[i] != eRe || imags[i] != eIm) { Chris@1088: cerr << "ERROR: output is not as expected for column " Chris@1088: << i << " in channel " << ch << " (polar store = " Chris@1088: << polar << ")" << endl; Chris@1088: cerr << "expected : "; Chris@1088: for (int j = 0; j < hs1; ++j) { Chris@1088: cerr << expectedValues[ch][j] << " "; Chris@1088: } Chris@1088: cerr << "\nactual : "; Chris@1088: for (int j = 0; j < hs1; ++j) { Chris@1088: cerr << complex(reals[j], imags[j]) << " "; Chris@1088: } Chris@1088: cerr << endl; Chris@1088: } Chris@1088: QCOMPARE(reals[i], eRe); Chris@1088: QCOMPARE(imags[i], eIm); Chris@1088: } Chris@1088: QCOMPARE(reals[hs1], 999.f); Chris@1088: QCOMPARE(imags[hs1], 999.f); Chris@1088: } Chris@1088: } Chris@1088: } Chris@1088: Chris@1086: private slots: Chris@1086: Chris@1088: // NB. FFTModel columns are centred on the sample frame, and in Chris@1088: // particular this means column 0 is centred at sample 0 (i.e. it Chris@1088: // contains only half the window-size worth of real samples, the Chris@1088: // others are 0-valued from before the origin). Generally in Chris@1088: // these tests we are padding our signal with half a window of Chris@1088: // zeros, in order that the result for column 0 is all zeros Chris@1088: // (rather than something with a step in it that is harder to Chris@1088: // reason about the FFT of) and the results for subsequent columns Chris@1088: // are those of our expected signal. Chris@1088: Chris@1088: void dc_simple_rect() { Chris@1088: MockWaveModel mwm({ DC }, 16, 4); Chris@1088: test(&mwm, RectangularWindow, 8, 8, 8, 0, Chris@1088: { { {}, {}, {}, {}, {} } }, 4); Chris@1088: test(&mwm, RectangularWindow, 8, 8, 8, 1, Chris@1088: { { { 4.f, 0.f }, {}, {}, {}, {} } }, 4); Chris@1088: test(&mwm, RectangularWindow, 8, 8, 8, 2, Chris@1088: { { { 4.f, 0.f }, {}, {}, {}, {} } }, 4); Chris@1088: test(&mwm, RectangularWindow, 8, 8, 8, 3, Chris@1088: { { { }, {}, {}, {}, {} } }, 4); Chris@1088: } Chris@1088: Chris@1088: void dc_simple_hann() { Chris@1088: // The Hann window function is a simple sinusoid with period Chris@1088: // equal to twice the window size, and it halves the DC energy Chris@1088: MockWaveModel mwm({ DC }, 16, 4); Chris@1088: test(&mwm, HanningWindow, 8, 8, 8, 0, Chris@1088: { { {}, {}, {}, {}, {} } }, 4); Chris@1088: test(&mwm, HanningWindow, 8, 8, 8, 1, Chris@1088: { { { 4.f, 0.f }, { 2.f, 0.f }, {}, {}, {} } }, 4); Chris@1088: test(&mwm, HanningWindow, 8, 8, 8, 2, Chris@1088: { { { 4.f, 0.f }, { 2.f, 0.f }, {}, {}, {} } }, 4); Chris@1088: test(&mwm, HanningWindow, 8, 8, 8, 3, Chris@1088: { { { }, {}, {}, {}, {} } }, 4); Chris@1086: } Chris@1086: Chris@1086: }; Chris@1086: Chris@1086: #endif