Mercurial > hg > svcore
changeset 1359:1c9bbbb6116a 3.0-integration
Use W64 instead of WAV for decoded files; use Ogg reader in preference to WAV one for Ogg files (WAV reader works, via libsndfile, but doesn't load metadata); fix Ogg reader to use QFile open instead of non-Win32-compatible API; add more encoder tests, audio writer test, midi reader test
line wrap: on
line diff
--- a/base/TempWriteFile.cpp Mon Jan 09 18:51:42 2017 +0000 +++ b/base/TempWriteFile.cpp Tue Jan 10 10:58:25 2017 +0000 @@ -27,7 +27,7 @@ temp.setAutoRemove(false); temp.open(); // creates the file and opens it atomically if (temp.error()) { - cerr << "TempWriteFile: Failed to create temporary file in directory of " << m_target << ": " << temp.errorString() << endl; + SVCERR << "TempWriteFile: Failed to create temporary file in directory of " << m_target << ": " << temp.errorString() << endl; throw FileOperationFailed(temp.fileName(), "creation"); } @@ -54,13 +54,17 @@ { if (m_temp == "") return; - QDir dir(QFileInfo(m_temp).dir()); - // According to http://doc.trolltech.com/4.4/qdir.html#rename - // some systems fail, if renaming over an existing file. - // Therefore, delete first the existing file. - if (dir.exists(m_target)) dir.remove(m_target); - if (!dir.rename(m_temp, m_target)) { - cerr << "TempWriteFile: Failed to rename temporary file " << m_temp << " to target " << m_target << endl; + QFile tempFile(m_temp); + QFile targetFile(m_target); + + if (targetFile.exists()) { + if (!targetFile.remove()) { + SVCERR << "TempWriteFile: WARNING: Failed to remove existing target file " << m_target << " prior to moving temporary file " << m_temp << " to it" << endl; + } + } + + if (!tempFile.rename(m_target)) { + SVCERR << "TempWriteFile: Failed to rename temporary file " << m_temp << " to target " << m_target << endl; throw FileOperationFailed(m_temp, "rename"); }
--- a/base/TempWriteFile.h Mon Jan 09 18:51:42 2017 +0000 +++ b/base/TempWriteFile.h Tue Jan 10 10:58:25 2017 +0000 @@ -12,8 +12,8 @@ COPYING included with this distribution for more information. */ -#ifndef _TEMP_WRITE_FILE_H_ -#define _TEMP_WRITE_FILE_H_ +#ifndef SV_TEMP_WRITE_FILE_H +#define SV_TEMP_WRITE_FILE_H #include <QTemporaryFile> @@ -23,7 +23,6 @@ * use when saving a file over an existing one, to avoid clobbering * the original before the save is complete. */ - class TempWriteFile { public:
--- a/data/fileio/AudioFileReaderFactory.cpp Mon Jan 09 18:51:42 2017 +0000 +++ b/data/fileio/AudioFileReaderFactory.cpp Tue Jan 10 10:58:25 2017 +0000 @@ -126,6 +126,27 @@ SVDEBUG << "AudioFileReaderFactory: Source not officially handled by any reader, trying again with each reader in turn" << endl; } + +#ifdef HAVE_OGGZ +#ifdef HAVE_FISHSOUND + // If we have the "real" Ogg reader, use that first. Otherwise + // the WavFileReader will likely accept Ogg files (as + // libsndfile supports them) but it has no ability to return + // file metadata, so we get a slightly less useful result. + if (anyReader || OggVorbisFileReader::supports(source)) { + + reader = new OggVorbisFileReader + (source, decodeMode, cacheMode, targetRate, normalised, reporter); + + if (reader->isOK()) { + SVDEBUG << "AudioFileReaderFactory: Ogg file reader is OK, returning it" << endl; + return reader; + } else { + delete reader; + } + } +#endif +#endif if (anyReader || WavFileReader::supports(source)) { @@ -157,23 +178,6 @@ delete reader; } } - -#ifdef HAVE_OGGZ -#ifdef HAVE_FISHSOUND - if (anyReader || OggVorbisFileReader::supports(source)) { - - reader = new OggVorbisFileReader - (source, decodeMode, cacheMode, targetRate, normalised, reporter); - - if (reader->isOK()) { - SVDEBUG << "AudioFileReaderFactory: Ogg file reader is OK, returning it" << endl; - return reader; - } else { - delete reader; - } - } -#endif -#endif #ifdef HAVE_MAD if (anyReader || MP3FileReader::supports(source)) {
--- a/data/fileio/CodedAudioFileReader.cpp Mon Jan 09 18:51:42 2017 +0000 +++ b/data/fileio/CodedAudioFileReader.cpp Tue Jan 10 10:58:25 2017 +0000 @@ -164,7 +164,7 @@ try { QDir dir(TempDirectory::getInstance()->getPath()); - m_cacheFileName = dir.filePath(QString("decoded_%1.wav") + m_cacheFileName = dir.filePath(QString("decoded_%1.w64") .arg((intptr_t)this)); SF_INFO fileInfo; @@ -196,10 +196,15 @@ // tests.) // // So: now we write floats. - fileInfo.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT; - - m_cacheFileWritePtr = sf_open(m_cacheFileName.toLocal8Bit(), - SFM_WRITE, &fileInfo); + fileInfo.format = SF_FORMAT_W64 | SF_FORMAT_FLOAT; + +#ifdef Q_OS_WIN + m_cacheFileWritePtr = sf_wchar_open + ((LPCWSTR)m_cacheFileName.utf16(), SFM_WRITE, &m_fileInfo); +#else + m_cacheFileWritePtr = sf_open + (m_cacheFileName.toLocal8Bit(), SFM_WRITE, &fileInfo); +#endif if (m_cacheFileWritePtr) {
--- a/data/fileio/CodedAudioFileReader.h Mon Jan 09 18:51:42 2017 +0000 +++ b/data/fileio/CodedAudioFileReader.h Tue Jan 10 10:58:25 2017 +0000 @@ -13,15 +13,21 @@ COPYING included with this distribution for more information. */ -#ifndef _CODED_AUDIO_FILE_READER_H_ -#define _CODED_AUDIO_FILE_READER_H_ +#ifndef SV_CODED_AUDIO_FILE_READER_H +#define SV_CODED_AUDIO_FILE_READER_H #include "AudioFileReader.h" -#include <sndfile.h> #include <QMutex> #include <QReadWriteLock> +#ifdef Q_OS_WIN +#include <windows.h> +#define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1 +#endif + +#include <sndfile.h> + class WavFileReader; class Serialiser;
--- a/data/fileio/MIDIFileReader.h Mon Jan 09 18:51:42 2017 +0000 +++ b/data/fileio/MIDIFileReader.h Tue Jan 10 10:58:25 2017 +0000 @@ -12,15 +12,14 @@ COPYING included with this distribution for more information. */ - /* This is a modified version of a source file from the Rosegarden MIDI and audio sequencer and notation editor. This file copyright 2000-2006 Richard Bown and Chris Cannam. */ -#ifndef _MIDI_FILE_READER_H_ -#define _MIDI_FILE_READER_H_ +#ifndef SV_MIDI_FILE_READER_H +#define SV_MIDI_FILE_READER_H #include "DataFileReader.h" #include "base/RealTime.h" @@ -61,7 +60,7 @@ public: MIDIFileReader(QString path, - MIDIFileImportPreferenceAcquirer *pref, + MIDIFileImportPreferenceAcquirer *pref, // may be null sv_samplerate_t mainModelSampleRate); virtual ~MIDIFileReader();
--- a/data/fileio/OggVorbisFileReader.cpp Mon Jan 09 18:51:42 2017 +0000 +++ b/data/fileio/OggVorbisFileReader.cpp Tue Jan 10 10:58:25 2017 +0000 @@ -40,6 +40,10 @@ CodedAudioFileReader(mode, targetRate, normalised), m_source(source), m_path(source.getLocalFilename()), + m_qfile(0), + m_ffile(0), + m_oggz(0), + m_fishSound(0), m_reporter(reporter), m_fileSize(0), m_bytesRead(0), @@ -60,11 +64,35 @@ Profiler profiler("OggVorbisFileReader::OggVorbisFileReader"); - QFileInfo info(m_path); - m_fileSize = info.size(); + // These shenanigans are to avoid using oggz_open(..) with a local + // codepage on Windows (make sure proper filename encoding is used) + + m_qfile = new QFile(m_path); + if (!m_qfile->open(QIODevice::ReadOnly)) { + m_error = QString("Failed to open file %1 for reading.").arg(m_path); + SVDEBUG << "OggVorbisFileReader: " << m_error << endl; + delete m_qfile; + m_qfile = 0; + return; + } + + m_fileSize = m_qfile->size(); - if (!(m_oggz = oggz_open(m_path.toLocal8Bit().data(), OGGZ_READ))) { + m_ffile = fdopen(dup(m_qfile->handle()), "r"); + if (!m_ffile) { + m_error = QString("Failed to open file pointer for file %1").arg(m_path); + SVDEBUG << "OggVorbisFileReader: " << m_error << endl; + delete m_qfile; + m_qfile = 0; + return; + } + + if (!(m_oggz = oggz_open_stdio(m_ffile, OGGZ_READ))) { m_error = QString("File %1 is not an OGG file.").arg(m_path); + fclose(m_ffile); + m_ffile = 0; + delete m_qfile; + m_qfile = 0; return; } @@ -114,6 +142,11 @@ m_decodeThread->wait(); delete m_decodeThread; } + if (m_qfile) { + // don't fclose m_ffile; oggz_close did that + delete m_qfile; + m_qfile = 0; + } } void @@ -134,8 +167,14 @@ fish_sound_delete(m_reader->m_fishSound); m_reader->m_fishSound = 0; + oggz_close(m_reader->m_oggz); m_reader->m_oggz = 0; + + // don't fclose m_ffile; oggz_close did that + + delete m_reader->m_qfile; + m_reader->m_qfile = 0; if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache(); m_reader->m_completion = 100;
--- a/data/fileio/OggVorbisFileReader.h Mon Jan 09 18:51:42 2017 +0000 +++ b/data/fileio/OggVorbisFileReader.h Tue Jan 10 10:58:25 2017 +0000 @@ -13,8 +13,8 @@ COPYING included with this distribution for more information. */ -#ifndef _OGG_VORBIS_FILE_READER_H_ -#define _OGG_VORBIS_FILE_READER_H_ +#ifndef SV_OGG_VORBIS_FILE_READER_H +#define SV_OGG_VORBIS_FILE_READER_H #ifdef HAVE_OGGZ #ifdef HAVE_FISHSOUND @@ -25,6 +25,8 @@ #include <oggz/oggz.h> #include <fishsound/fishsound.h> +#include <cstdio> + #include <set> class ProgressReporter; @@ -71,6 +73,8 @@ QString m_maker; TagMap m_tags; + QFile *m_qfile; + FILE *m_ffile; OGGZ *m_oggz; FishSound *m_fishSound; ProgressReporter *m_reporter;
--- a/data/fileio/test/AudioFileReaderTest.h Mon Jan 09 18:51:42 2017 +0000 +++ b/data/fileio/test/AudioFileReaderTest.h Tue Jan 10 10:58:25 2017 +0000 @@ -47,7 +47,7 @@ base = "svcore/data/fileio/test"; } testDirBase = base; - audioDir = base + "/testfiles"; + audioDir = base + "/audio"; diffDir = base + "/diffs"; } @@ -389,7 +389,7 @@ diffFile += ".wav"; diffFile = QDir(diffDir).filePath(diffFile); WavFileWriter diffWriter(diffFile, readRate, channels, - WavFileWriter::WriteToTarget); //!!! NB WriteToTemporary not working, why? + WavFileWriter::WriteToTemporary); QVERIFY(diffWriter.isOK()); vector<vector<float>> diffs(channels);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/fileio/test/AudioFileWriterTest.h Tue Jan 10 10:58:25 2017 +0000 @@ -0,0 +1,135 @@ +/* -*- 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 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_WRITER_H +#define TEST_AUDIO_FILE_WRITER_H + +#include "../AudioFileReaderFactory.h" +#include "../AudioFileReader.h" +#include "../WavFileWriter.h" + +#include "AudioTestData.h" + +#include "bqvec/VectorOps.h" +#include "bqvec/Allocators.h" + +#include <cmath> + +#include <QObject> +#include <QtTest> +#include <QDir> + +#include <iostream> + +using namespace std; +using namespace breakfastquay; + +class AudioFileWriterTest : public QObject +{ + Q_OBJECT + +private: + QString testDirBase; + QString outDir; + + static const int rate = 44100; + +public: + AudioFileWriterTest(QString base) { + if (base == "") { + base = "svcore/data/fileio/test"; + } + testDirBase = base; + outDir = base + "/outfiles"; + } + + const char *strOf(QString s) { + return strdup(s.toLocal8Bit().data()); + } + + QString testName(bool direct, int channels) { + return QString("%1 %2 %3") + .arg(channels) + .arg(channels > 1 ? "channels" : "channel") + .arg(direct ? "direct" : "via temporary"); + } + +private slots: + void init() + { + if (!QDir(outDir).exists() && !QDir().mkpath(outDir)) { + cerr << "ERROR: Audio out directory \"" << outDir << "\" does not exist and could not be created" << endl; + QVERIFY2(QDir(outDir).exists(), "Audio out directory not found and could not be created"); + } + } + + void write_data() + { + QTest::addColumn<bool>("direct"); + QTest::addColumn<int>("channels"); + for (int direct = 0; direct <= 1; ++direct) { + for (int channels = 1; channels < 8; ++channels) { + if (channels == 1 || channels == 2 || + channels == 5 || channels == 8) { + QString desc = testName(direct, channels); + QTest::newRow(strOf(desc)) << (bool)direct << channels; + } + } + } + } + + void write() + { + QFETCH(bool, direct); + QFETCH(int, channels); + + QString outfile = QString("%1/out-%2ch-%3.wav") + .arg(outDir).arg(channels).arg(direct ? "direct" : "via-temporary"); + + WavFileWriter writer(outfile, + rate, + channels, + direct ? + WavFileWriter::WriteToTarget : + WavFileWriter::WriteToTemporary); + QVERIFY(writer.isOK()); + + AudioTestData data(rate, channels); + data.generate(); + + sv_frame_t frameCount = data.getFrameCount(); + float *interleaved = data.getInterleavedData(); + float **nonInterleaved = allocate_channels<float>(channels, frameCount); + v_deinterleave(nonInterleaved, interleaved, channels, int(frameCount)); + bool ok = writer.writeSamples(nonInterleaved, frameCount); + deallocate_channels(nonInterleaved, channels); + QVERIFY(ok); + + ok = writer.close(); + QVERIFY(ok); + + AudioFileReaderFactory::Parameters params; + AudioFileReader *rereader = + AudioFileReaderFactory::createReader(outfile, params); + QVERIFY(rereader != nullptr); + + floatvec_t readFrames = rereader->getInterleavedFrames(0, frameCount); + floatvec_t expected(interleaved, interleaved + frameCount * channels); + QCOMPARE(readFrames, expected); + + delete rereader; + } +}; + +#endif
--- a/data/fileio/test/EncodingTest.h Mon Jan 09 18:51:42 2017 +0000 +++ b/data/fileio/test/EncodingTest.h Tue Jan 10 10:58:25 2017 +0000 @@ -20,6 +20,7 @@ #include "../AudioFileReaderFactory.h" #include "../AudioFileReader.h" +#include "../WavFileWriter.h" #include <cmath> @@ -36,6 +37,7 @@ const char utf8_name_tsprk[] = "T\303\253mple of Sp\303\266rks"; const char utf8_name_sprkt[] = "\343\202\271\343\203\235\343\203\274\343\202\257\343\201\256\345\257\272\351\231\242"; +// Mapping between filename and expected title metadata field static const char *mapping[][2] = { { "id3v2-iso-8859-1", utf8_name_cdp_1 }, { "id3v2-ucs-2", utf8_name_cdp_2 }, @@ -51,6 +53,7 @@ private: QString testDirBase; QString encodingDir; + QString outDir; public: EncodingTest(QString base) { @@ -59,6 +62,7 @@ } testDirBase = base; encodingDir = base + "/encodings"; + outDir = base + "/outfiles"; } private: @@ -66,6 +70,14 @@ return strdup(s.toLocal8Bit().data()); } + void addAudioFiles() { + QTest::addColumn<QString>("audiofile"); + QStringList files = QDir(encodingDir).entryList(QDir::Files); + foreach (QString filename, files) { + QTest::newRow(strOf(filename)) << filename; + } + } + private slots: void init() { @@ -73,19 +85,40 @@ cerr << "ERROR: Audio encoding file directory \"" << encodingDir << "\" does not exist" << endl; QVERIFY2(QDir(encodingDir).exists(), "Audio encoding file directory not found"); } - } - - void read_data() - { - QTest::addColumn<QString>("audiofile"); - QStringList files = QDir(encodingDir).entryList(QDir::Files); - foreach (QString filename, files) { - QTest::newRow(strOf(filename)) << filename; + if (!QDir(outDir).exists() && !QDir().mkpath(outDir)) { + cerr << "ERROR: Audio out directory \"" << outDir << "\" does not exist and could not be created" << endl; + QVERIFY2(QDir(outDir).exists(), "Audio out directory not found and could not be created"); } } - void read() - { + void readAudio_data() { + addAudioFiles(); + } + + void readAudio() { + + // Ensure that we can open all the files + + QFETCH(QString, audiofile); + + AudioFileReaderFactory::Parameters params; + AudioFileReader *reader = + AudioFileReaderFactory::createReader + (encodingDir + "/" + audiofile, params); + + QVERIFY(reader != nullptr); + } + + void readMetadata_data() { + addAudioFiles(); + } + + void readMetadata() { + + // All files other than WAVs should have title metadata; check + // that the title matches whatever is in our mapping structure + // defined at the top + QFETCH(QString, audiofile); AudioFileReaderFactory::Parameters params; @@ -99,8 +132,10 @@ QString file = fileAndExt[0]; QString extension = fileAndExt[1]; - if (extension == "mp3") { + if (extension != "wav") { + auto blah = reader->getInterleavedFrames(0, 10); + QString title = reader->getTitle(); QVERIFY(title != QString()); @@ -128,12 +163,83 @@ } if (!found) { + // Note that this can happen legitimately on Windows, + // where (for annoying VCS-related reasons) the test + // files may have a different filename encoding from + // the expected UTF-16. We check this properly in + // readWriteAudio below, by saving out the file to a + // name matching the metadata cerr << "Couldn't find filename \"" << file << "\" in title mapping array" << endl; QSKIP("Couldn't find filename in title mapping array"); } } } + + void readWriteAudio_data() { + addAudioFiles(); + } + + void readWriteAudio() + { + // For those files that have title metadata (i.e. all of them + // except the WAVs), read the title metadata and write a wav + // file (of arbitrary content) whose name matches that. Then + // check that we can re-read it. This is intended to exercise + // systems on which the original test filename is miscoded (as + // can happen on Windows). + + QFETCH(QString, audiofile); + + QStringList fileAndExt = audiofile.split("."); + QString file = fileAndExt[0]; + QString extension = fileAndExt[1]; + + if (extension == "wav") { + return; + } + + AudioFileReaderFactory::Parameters params; + AudioFileReader *reader = + AudioFileReaderFactory::createReader + (encodingDir + "/" + audiofile, params); + QVERIFY(reader != nullptr); + + QString title = reader->getTitle(); + QVERIFY(title != QString()); + + for (int useTemporary = 0; useTemporary <= 1; ++useTemporary) { + + QString outfile = outDir + "/" + file + ".wav"; + WavFileWriter writer(outfile, + reader->getSampleRate(), + 1, + useTemporary ? + WavFileWriter::WriteToTemporary : + WavFileWriter::WriteToTarget); + + QVERIFY(writer.isOK()); + + floatvec_t data { 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0 }; + const float *samples = data.data(); + bool ok = writer.writeSamples(&samples, 8); + QVERIFY(ok); + + ok = writer.close(); + QVERIFY(ok); + + AudioFileReader *rereader = + AudioFileReaderFactory::createReader(outfile, params); + QVERIFY(rereader != nullptr); + + floatvec_t readFrames = rereader->getInterleavedFrames(0, 8); + QCOMPARE(readFrames, data); + + delete rereader; + } + + delete reader; + } }; #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/fileio/test/MIDIFileReaderTest.h Tue Jan 10 10:58:25 2017 +0000 @@ -0,0 +1,88 @@ +/* -*- 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_MIDI_FILE_READER_H +#define TEST_MIDI_FILE_READER_H + +#include "../MIDIFileReader.h" + +#include <cmath> + +#include <QObject> +#include <QtTest> +#include <QDir> + +#include "base/Debug.h" + +#include <iostream> + +using namespace std; + +class MIDIFileReaderTest : public QObject +{ + Q_OBJECT + +private: + QString testDirBase; + QString midiDir; + + const char *strOf(QString s) { + return strdup(s.toLocal8Bit().data()); + } + +public: + MIDIFileReaderTest(QString base) { + if (base == "") { + base = "svcore/data/fileio/test"; + } + testDirBase = base; + midiDir = base + "/midi"; + } + +private slots: + void init() + { + if (!QDir(midiDir).exists()) { + cerr << "ERROR: MIDI file directory \"" << midiDir << "\" does not exist" << endl; + QVERIFY2(QDir(midiDir).exists(), "MIDI file directory not found"); + } + } + + void read_data() + { + QTest::addColumn<QString>("filename"); + QStringList files = QDir(midiDir).entryList(QDir::Files); + foreach (QString filename, files) { + QTest::newRow(strOf(filename)) << filename; + } + } + + void read() + { + QFETCH(QString, filename); + QString path = midiDir + "/" + filename; + MIDIFileReader reader(path, nullptr, 44100); + Model *m = reader.load(); + if (!m) { + cerr << "MIDI load failed for path: \"" << path << "\"" << endl; + } + QVERIFY(m != nullptr); + //!!! Ah, now here we could do something a bit more informative + } + +}; + +#endif +
--- a/data/fileio/test/files.pri Mon Jan 09 18:51:42 2017 +0000 +++ b/data/fileio/test/files.pri Tue Jan 10 10:58:25 2017 +0000 @@ -1,8 +1,10 @@ TEST_HEADERS += \ AudioFileReaderTest.h \ + AudioFileWriterTest.h \ AudioTestData.h \ - EncodingTest.h + EncodingTest.h \ + MIDIFileReaderTest.h TEST_SOURCES += \ svcore-data-fileio-test.cpp
--- a/data/fileio/test/svcore-data-fileio-test.cpp Mon Jan 09 18:51:42 2017 +0000 +++ b/data/fileio/test/svcore-data-fileio-test.cpp Tue Jan 10 10:58:25 2017 +0000 @@ -13,7 +13,9 @@ */ #include "AudioFileReaderTest.h" +#include "AudioFileWriterTest.h" #include "EncodingTest.h" +#include "MIDIFileReaderTest.h" #include <QtTest> @@ -51,11 +53,23 @@ } { + AudioFileWriterTest t(testDir); + if (QTest::qExec(&t, argc, argv) == 0) ++good; + else ++bad; + } + + { EncodingTest t(testDir); if (QTest::qExec(&t, argc, argv) == 0) ++good; else ++bad; } + { + MIDIFileReaderTest t(testDir); + if (QTest::qExec(&t, argc, argv) == 0) ++good; + else ++bad; + } + if (bad > 0) { cerr << "\n********* " << bad << " test suite(s) failed!\n" << endl; return 1;
--- a/plugin/plugins/SamplePlayer.cpp Mon Jan 09 18:51:42 2017 +0000 +++ b/plugin/plugins/SamplePlayer.cpp Tue Jan 10 10:58:25 2017 +0000 @@ -29,6 +29,11 @@ #include <QDir> #include <QFileInfo> +#ifdef Q_OS_WIN +#include <windows.h> +#define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1 +#endif + #include <sndfile.h> #include <samplerate.h> #include <iostream> @@ -395,7 +400,11 @@ size_t i; info.format = 0; +#ifdef Q_OS_WIN + file = sf_wchar_open((LPCWSTR)path.utf16(), SFM_READ, &m_fileInfo); +#else file = sf_open(path.toLocal8Bit().data(), SFM_READ, &info); +#endif if (!file) { cerr << "SamplePlayer::loadSampleData: Failed to open file " << path << ": "