Mercurial > hg > svcore
changeset 756:02390a4c2abe
Toward audio read tests
line wrap: on
line diff
--- a/base/Resampler.cpp Thu Mar 07 17:18:08 2013 +0000 +++ b/base/Resampler.cpp Fri Mar 08 16:14:21 2013 +0000 @@ -143,6 +143,10 @@ //!!! check err, respond appropriately + if (data.input_frames_used != incount) { + std::cerr << "Resampler: NOTE: input_frames_used == " << data.input_frames_used << " (while incount = " << incount << ")" << std::endl; + } + return data.output_frames_gen; }
--- a/data/fileio/AudioFileReaderFactory.cpp Thu Mar 07 17:18:08 2013 +0000 +++ b/data/fileio/AudioFileReaderFactory.cpp Fri Mar 08 16:14:21 2013 +0000 @@ -311,7 +311,7 @@ if (reader) { if (reader->isOK()) { - std::cerr << "AudioFileReaderFactory: Reader is OK" << std::endl; + SVDEBUG << "AudioFileReaderFactory: Reader is OK" << endl; return reader; } std::cerr << "AudioFileReaderFactory: Preferred reader for "
--- a/data/fileio/CodedAudioFileReader.cpp Thu Mar 07 17:18:08 2013 +0000 +++ b/data/fileio/CodedAudioFileReader.cpp Fri Mar 08 16:14:21 2013 +0000 @@ -82,7 +82,7 @@ void CodedAudioFileReader::endSerialised() { - std::cerr << "CodedAudioFileReader(" << this << ")::endSerialised: id = " << (m_serialiser ? m_serialiser->getId().toStdString() : "(none)") << std::endl; + SVDEBUG << "CodedAudioFileReader(" << this << ")::endSerialised: id = " << (m_serialiser ? m_serialiser->getId().toStdString() : "(none)") << endl; delete m_serialiser; m_serialiser = 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/fileio/test/AudioFileReaderTest.h Fri Mar 08 16:14:21 2013 +0000 @@ -0,0 +1,119 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2013 Chris Cannam. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef TEST_AUDIO_FILE_READER_H +#define TEST_AUDIO_FILE_READER_H + +#include "../AudioFileReaderFactory.h" +#include "../AudioFileReader.h" + +#include "AudioTestData.h" + +#include <cmath> + +#include <QObject> +#include <QtTest> +#include <QDir> + +#include <iostream> + +using namespace std; + +static QString audioDir = "testfiles"; + +class AudioFileReaderTest : public QObject +{ + Q_OBJECT + + const char *strOf(QString s) { + return strdup(s.toLocal8Bit().data()); + } + +private slots: + void init() + { + if (!QDir(audioDir).exists()) { + cerr << "ERROR: Audio test file directory \"" << audioDir << "\" does not exist" << endl; + QVERIFY2(QDir(audioDir).exists(), "Audio test file directory not found"); + } + } + + void read_data() + { + QTest::addColumn<QString>("audiofile"); + QStringList files = QDir(audioDir).entryList(QDir::Files); + foreach (QString filename, files) { + QTest::newRow(strOf(filename)) << filename; + } + } + + void read() + { + QFETCH(QString, audiofile); + + AudioFileReader *reader = + AudioFileReaderFactory::createReader + (audioDir + "/" + audiofile, 48000); + + if (!reader) { + QSKIP(strOf(QString("File format for \"%1\" not supported, skipping").arg(audiofile)), SkipSingle); + } + + int channels = reader->getChannelCount(); + AudioTestData tdata(48000, channels); + + float *reference = tdata.getInterleavedData(); + int refsize = tdata.getFrameCount() * channels; + + vector<float> test; + + // The reader should give us exactly the expected number of + // frames -- so we ask for one more, just to check we don't + // get it! + reader->getInterleavedFrames + (0, tdata.getFrameCount() + 1, test); + int read = test.size() / channels; + + // need to resolve questions about frame count at end of + // resampled file before we can do this +//!!! QCOMPARE(read, tdata.getFrameCount()); + + float limit = 0.011; + + for (int c = 0; c < channels; ++c) { + float maxdiff = 0.f; + int maxAt = 0; + float totdiff = 0.f; + for (int i = 0; i < read; ++i) { + float diff = fabsf(test[i * channels + c] - + reference[i * channels + c]); + totdiff += diff; + if (diff > maxdiff) { + maxdiff = diff; + maxAt = i; + } + } + float meandiff = totdiff / read; +// cerr << "meandiff on channel " << c << ": " << meandiff << endl; +// cerr << "maxdiff on channel " << c << ": " << maxdiff << " at " << maxAt << endl; + if (maxdiff >= limit) { + cerr << "ERROR: for audiofile " << audiofile << ": maxdiff = " << maxdiff << " at frame " << maxAt << " of " << read << " on channel " << c << " (mean diff = " << meandiff << ")" << endl; + QVERIFY(maxdiff < limit); + } + } + } +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/fileio/test/AudioTestData.h Fri Mar 08 16:14:21 2013 +0000 @@ -0,0 +1,120 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2013 Chris Cannam. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef AUDIO_TEST_DATA_H +#define AUDIO_TEST_DATA_H + +#include <cmath> + +/** + * Class that generates a single fixed test pattern to a given sample + * rate and number of channels. + * + * The test pattern is two seconds long and consists of: + * + * -- in channel 0, a 600Hz sinusoid with peak amplitude 1.0 + * + * -- in channel 1, four triangular forms with peaks at +1.0, -1.0, + * +1.0, -1.0 respectively, of 10ms width, starting at 0.0, 0.5, + * 1.0 and 1.5 seconds; silence elsewhere + * + * -- in subsequent channels, a flat DC offset at +(channelNo / 20.0) + */ +class AudioTestData +{ +public: + AudioTestData(float rate, int channels) : + m_channelCount(channels), + m_duration(2.0), + m_sampleRate(rate), + m_sinFreq(600.0), + m_pulseFreq(2) + { + m_frameCount = lrint(m_duration * m_sampleRate); + m_data = new float[m_frameCount * m_channelCount]; + m_pulseWidth = 0.01 * m_sampleRate; + generate(); + } + + ~AudioTestData() { + delete[] m_data; + } + + void generate() { + + float hpw = m_pulseWidth / 2.0; + + for (int i = 0; i < m_frameCount; ++i) { + for (int c = 0; c < m_channelCount; ++c) { + + float s = 0.f; + + if (c == 0) { + + float phase = (i * m_sinFreq * 2.f * M_PI) / m_sampleRate; + s = sinf(phase); + + } else if (c == 1) { + + int pulseNo = int((i * m_pulseFreq) / m_sampleRate); + int index = (i * m_pulseFreq) - (m_sampleRate * pulseNo); + if (index < m_pulseWidth) { + s = 1.0 - fabsf(hpw - index) / hpw; + if (pulseNo % 2) s = -s; + } + + } else { + + s = c / 20.0; + } + + m_data[i * m_channelCount + c] = s; + } + } + } + + float *getInterleavedData() const { + return m_data; + } + + int getFrameCount() const { + return m_frameCount; + } + + int getChannelCount() const { + return m_channelCount; + } + + float getSampleRate () const { + return m_sampleRate; + } + + float getDuration() const { // seconds + return m_duration; + } + +private: + float *m_data; + int m_frameCount; + int m_channelCount; + float m_duration; + float m_sampleRate; + float m_sinFreq; + float m_pulseFreq; + float m_pulseWidth; +}; + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/fileio/test/main.cpp Fri Mar 08 16:14:21 2013 +0000 @@ -0,0 +1,32 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ +/* Copyright Chris Cannam - All Rights Reserved */ + +#include "AudioFileReaderTest.h" + +#include <QtTest> + +#include <iostream> + +int main(int argc, char *argv[]) +{ + int good = 0, bad = 0; + + QCoreApplication app(argc, argv); + app.setOrganizationName("Sonic Visualiser"); + app.setApplicationName("test-fileio"); + + { + AudioFileReaderTest t; + if (QTest::qExec(&t, argc, argv) == 0) ++good; + else ++bad; + } + + if (bad > 0) { + std::cerr << "\n********* " << bad << " test suite(s) failed!\n" << std::endl; + return 1; + } else { + std::cerr << "All tests passed" << std::endl; + return 0; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/fileio/test/test.pro Fri Mar 08 16:14:21 2013 +0000 @@ -0,0 +1,40 @@ + +TEMPLATE = app + +LIBS += -L../../.. -lsvcore + +include(../../../config.pri) + +CONFIG += qt thread warn_on stl rtti exceptions console +QT += network xml testlib +QT -= gui + +TARGET = svcore-test + +DEPENDPATH += ../../.. +INCLUDEPATH += ../../.. +OBJECTS_DIR = o +MOC_DIR = o + +HEADERS += AudioFileReaderTest.h \ + AudioTestData.h +SOURCES += main.cpp + +win* { +PRE_TARGETDEPS += ../../../svcore.lib +} +!win* { +PRE_TARGETDEPS += ../../../libsvcore.a +} + +!win32 { + !macx* { + QMAKE_POST_LINK=./$${TARGET} + } + macx* { + QMAKE_POST_LINK=./$${TARGET}.app/Contents/MacOS/$${TARGET} + } +} + +win32:QMAKE_POST_LINK=.$${TARGET}.exe +