# HG changeset patch # User Chris Cannam # Date 1602605891 -3600 # Tue Oct 13 17:18:11 2020 +0100 # Branch simplewavread # Node ID e75864a82092fb1786fad06ba6d4ca3871fc26b7 # Parent 7f9df1a483ec9661d47dc5dea7dcc262efdbb71d Support float wav, skip extended fmt chunk diff --git a/Makefile b/Makefile --- a/Makefile +++ b/Makefile @@ -38,4 +38,3 @@ # no routinely user-modifiable parts include build/Makefile.inc - diff --git a/build/Makefile.inc b/build/Makefile.inc --- a/build/Makefile.inc +++ b/build/Makefile.inc @@ -29,10 +29,12 @@ src/AudioReadStreamFactory.o: ./bqaudiostream/Exceptions.h src/AudioReadStreamFactory.o: src/WavFileReadStream.cpp src/AudioReadStreamFactory.o: src/OggVorbisReadStream.cpp +src/AudioReadStreamFactory.o: src/MiniMP3ReadStream.cpp src/AudioReadStreamFactory.o: src/MediaFoundationReadStream.cpp +src/AudioReadStreamFactory.o: src/SimpleWavFileReadStream.cpp +src/AudioReadStreamFactory.o: src/SimpleWavFileReadStream.h src/AudioReadStreamFactory.o: src/CoreAudioReadStream.cpp src/AudioReadStreamFactory.o: src/OpusReadStream.cpp -src/AudioReadStreamFactory.o: src/MiniMP3ReadStream.cpp src/AudioWriteStreamFactory.o: ./bqaudiostream/AudioWriteStreamFactory.h src/AudioWriteStreamFactory.o: ./bqaudiostream/AudioWriteStream.h src/AudioWriteStreamFactory.o: ./bqaudiostream/Exceptions.h @@ -42,13 +44,14 @@ src/AudioWriteStreamFactory.o: src/SimpleWavFileWriteStream.h src/AudioWriteStreamFactory.o: src/CoreAudioWriteStream.cpp src/AudioWriteStreamFactory.o: src/CoreAudioWriteStream.h -src/Exceptions.o: ./bqaudiostream/Exceptions.h +src/AudioStreamExceptions.o: ./bqaudiostream/Exceptions.h +src/CoreAudioReadStream.o: ./bqaudiostream/AudioReadStream.h +src/CoreAudioWriteStream.o: ./bqaudiostream/AudioWriteStream.h src/MediaFoundationReadStream.o: ./bqaudiostream/AudioReadStream.h -src/WavFileWriteStream.o: ./bqaudiostream/AudioWriteStream.h +src/MiniMP3ReadStream.o: ./bqaudiostream/AudioReadStream.h +src/OggVorbisReadStream.o: ./bqaudiostream/AudioReadStream.h +src/OpusReadStream.o: ./bqaudiostream/AudioReadStream.h +src/SimpleWavFileReadStream.o: ./bqaudiostream/AudioReadStream.h src/SimpleWavFileWriteStream.o: ./bqaudiostream/AudioWriteStream.h src/WavFileReadStream.o: ./bqaudiostream/AudioReadStream.h -src/CoreAudioWriteStream.o: ./bqaudiostream/AudioWriteStream.h -src/CoreAudioReadStream.o: ./bqaudiostream/AudioReadStream.h -src/OggVorbisReadStream.o: ./bqaudiostream/AudioReadStream.h -src/OpusReadStream.o: ./bqaudiostream/AudioReadStream.h -src/MiniMP3ReadStream.o: ./bqaudiostream/AudioReadStream.h +src/WavFileWriteStream.o: ./bqaudiostream/AudioWriteStream.h diff --git a/src/SimpleWavFileReadStream.cpp b/src/SimpleWavFileReadStream.cpp --- a/src/SimpleWavFileReadStream.cpp +++ b/src/SimpleWavFileReadStream.cpp @@ -61,13 +61,13 @@ m_bitDepth(0), m_startPos(0), m_index(0), - m_file(nullptr) + m_file(0) { m_file = new ifstream(filename.c_str(), ios::in | std::ios::binary); if (!*m_file) { delete m_file; - m_file = nullptr; + m_file = 0; throw FileNotFound(m_path); } @@ -92,14 +92,14 @@ uint32_t totalSize = readExpectedChunkSize("RIFF"); readExpectedTag("WAVE"); uint32_t fmtSize = readExpectedChunkSize("fmt "); - if (fmtSize != 16) { + if (fmtSize < 16) { cout << "fmtSize = " << fmtSize << endl; - throw InvalidFileFormat(m_path, "unexpected format chunk size"); + throw InvalidFileFormat(m_path, "unexpectedly short format chunk"); } uint32_t audioFormat = readMandatoryNumber(2); - if (audioFormat != 1) { - throw InvalidFileFormat(m_path, "PCM formats only supported by this reader"); + if (audioFormat != 1 && audioFormat != 3) { + throw InvalidFileFormat(m_path, "only PCM and float WAV formats are supported by this reader"); } uint32_t channels = readMandatoryNumber(2); @@ -107,23 +107,42 @@ uint32_t byteRate = readMandatoryNumber(4); uint32_t bytesPerSample = readMandatoryNumber(2); uint32_t bitsPerSample = readMandatoryNumber(2); - + if (bitsPerSample != 8 && bitsPerSample != 16 && - bitsPerSample != 24) { + bitsPerSample != 24 && + bitsPerSample != 32) { throw InvalidFileFormat(m_path, "unsupported bit depth"); } + if (bitsPerSample == 32) { + if (audioFormat == 1) { + throw InvalidFileFormat(m_path, "32-bit samples are only supported in float format, not PCM"); + } else { + char *buf = (char *)malloc(sizeof(float)); + *(float *)buf = -0.f; + m_floatSwap = (buf[0] != '\0'); + } + } + m_channelCount = channels; m_sampleRate = sampleRate; m_bitDepth = bitsPerSample; - cerr << "bit depth = " << m_bitDepth << endl; + // we don't use these + (void)totalSize; + (void)byteRate; + (void)bytesPerSample; + + // and we ignore extended format chunk data + if (fmtSize > 16) { + m_file->ignore(fmtSize - 16); + } while (true) { string tag = readTag(); if (tag == "") { - throw InvalidFileFormat(m_path, "tag expected"); + throw InvalidFileFormat(m_path, "tag expected after fmt chunk"); } uint32_t chunkSize = readChunkSizeAfterTag(); if (tag == "data") { @@ -135,11 +154,6 @@ } } } - - // we don't use these - (void)totalSize; - (void)byteRate; - (void)bytesPerSample; } uint32_t @@ -203,6 +217,7 @@ case 8: frames[got] = convertSample8(buf); break; case 16: frames[got] = convertSample16(buf); break; case 24: frames[got] = convertSample24(buf); break; + case 32: frames[got] = convertSampleFloat(buf); break; } ++got; } @@ -238,10 +253,26 @@ return float(i) / 2147483647.f; } +float +SimpleWavFileReadStream::convertSampleFloat(const vector &v) +{ + if (!m_floatSwap) { + const uint8_t *buf = v.data(); + return *(const float *)buf; + } else { + vector vv(4); + for (int i = 0; i < 4; ++i) { + vv[i] = v[3-i]; + } + const uint8_t *buf = vv.data(); + return *(const float *)buf; + } +} + int SimpleWavFileReadStream::getBytes(int n, vector &v) { - if (!m_file) return {}; + if (!m_file) return 0; for (int i = 0; i < n; ++i) { char c; @@ -271,5 +302,4 @@ } - #endif diff --git a/src/SimpleWavFileReadStream.h b/src/SimpleWavFileReadStream.h --- a/src/SimpleWavFileReadStream.h +++ b/src/SimpleWavFileReadStream.h @@ -70,6 +70,7 @@ int m_channels; int m_rate; int m_bitDepth; + bool m_floatSwap; size_t m_startPos; size_t m_index; @@ -85,7 +86,8 @@ float convertSample8(const vector &); float convertSample16(const vector &); float convertSample24(const vector &); - + float convertSampleFloat(const vector &); + int getBytes(int n, std::vector &); static uint32_t le2int(const std::vector &le); }; diff --git a/test/TestAudioStreamRead.h b/test/TestAudioStreamRead.h --- a/test/TestAudioStreamRead.h +++ b/test/TestAudioStreamRead.h @@ -60,7 +60,7 @@ { QFETCH(QString, audiofile); - cerr << "\n\n*** audiofile = " << audiofile.toLocal8Bit().data() << "\n\n" << endl; +// cerr << "\n\n*** audiofile = " << audiofile.toLocal8Bit().data() << "\n\n" << endl; try { diff --git a/test/TestWavReadWrite.h b/test/TestWavReadWrite.h --- a/test/TestWavReadWrite.h +++ b/test/TestWavReadWrite.h @@ -18,17 +18,17 @@ static const float DB_FLOOR = -1000.0; -static float to_dB(float ratio) +static float to_dBV(float ratio) { if (ratio == 0.0) return DB_FLOOR; - float dB = 10 * log10f(ratio); + float dB = 20 * log10f(ratio); return dB; } -static float from_dB(float dB) +static float from_dBV(float dB) { if (dB == DB_FLOOR) return 0.0; - float m = powf(10.0, dB / 10.0); + float m = powf(10.0, dB / 20.0); return m; } @@ -123,8 +123,8 @@ QVERIFY(ws); - float error = from_dB(-10); - float warning = from_dB(-25); + float error = from_dBV(-10); + float warning = from_dBV(-25); float maxdiff = 0.f; float mda = 0.f, mdb = 0.f; int maxdiffindex = -1; @@ -157,14 +157,14 @@ QString message = QString("Max diff is %1 (%2 dB) at index %3 (a = %4, b = %5) [error threshold %6 (%7 dB), warning threshold %8 (%9 dB)]") .arg(maxdiff) - .arg(to_dB(maxdiff)) + .arg(to_dBV(maxdiff)) .arg(maxdiffindex) .arg(mda) .arg(mdb) .arg(error) - .arg(to_dB(error)) + .arg(to_dBV(error)) .arg(warning) - .arg(to_dB(warning)); + .arg(to_dBV(warning)); QVERIFY2(maxdiff < error, message.toLocal8Bit().data());