From fc54dba3d7ff15d99d9e86fea7d5cb593dd86106 Mon Sep 17 00:00:00 2001 From: Tyson Grant Nottingham Date: Thu, 28 Sep 2017 17:00:58 -0700 Subject: [PATCH] Added support for extensible format PCM wave files. --- src/SFML/Audio/SoundFileReaderWav.cpp | 55 ++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/src/SFML/Audio/SoundFileReaderWav.cpp b/src/SFML/Audio/SoundFileReaderWav.cpp index 6f4a77792..b49909e81 100644 --- a/src/SFML/Audio/SoundFileReaderWav.cpp +++ b/src/SFML/Audio/SoundFileReaderWav.cpp @@ -31,6 +31,7 @@ #include #include #include +#include namespace @@ -88,6 +89,14 @@ namespace } const sf::Uint64 mainChunkSize = 12; + + const sf::Uint16 waveFormatPcm = 1; + + const sf::Uint16 waveFormatExtensible= 65534; + + const char* waveSubformatPcm = + "\x01\x00\x00\x00\x00\x00\x10\x00" + "\x80\x00\x00\xAA\x00\x38\x9B\x71"; } namespace sf @@ -226,6 +235,9 @@ bool SoundFileReaderWav::parseHeader(Info& info) Uint32 subChunkSize = 0; if (!decode(*m_stream, subChunkSize)) return false; + Int64 subChunkStart = m_stream->tell(); + if (subChunkStart == -1) + return false; // Check which chunk it is if ((subChunkId[0] == 'f') && (subChunkId[1] == 'm') && (subChunkId[2] == 't') && (subChunkId[3] == ' ')) @@ -236,7 +248,7 @@ bool SoundFileReaderWav::parseHeader(Info& info) Uint16 format = 0; if (!decode(*m_stream, format)) return false; - if (format != 1) // PCM + if ((format != waveFormatPcm) && (format != waveFormatExtensible)) return false; // Channel count @@ -272,12 +284,45 @@ bool SoundFileReaderWav::parseHeader(Info& info) } m_bytesPerSample = bitsPerSample / 8; - // Skip potential extra information (should not exist for PCM) - if (subChunkSize > 16) + if (format == waveFormatExtensible) { - if (m_stream->seek(m_stream->tell() + subChunkSize - 16) == -1) + // Extension size + Uint16 extensionSize = 0; + if (!decode(*m_stream, extensionSize)) return false; + + // Valid bits per sample + Uint16 validBitsPerSample = 0; + if (!decode(*m_stream, validBitsPerSample)) + return false; + + // Channel mask + Uint32 channelMask = 0; + if (!decode(*m_stream, channelMask)) + return false; + + // Subformat + char subformat[16]; + if (m_stream->read(subformat, sizeof(subformat)) != sizeof(subformat)) + return false; + + if (std::memcmp(subformat, waveSubformatPcm, sizeof(subformat)) != 0) + { + err() << "Unsupported format: extensible format with non-PCM subformat" << std::endl; + return false; + } + + if (validBitsPerSample != bitsPerSample) + { + err() << "Unsupported format: sample size (" << validBitsPerSample << " bits) and " + "sample container size (" << bitsPerSample << " bits) differ" << std::endl; + return false; + } } + + // Skip potential extra information + if (m_stream->seek(subChunkStart + subChunkSize) == -1) + return false; } else if ((subChunkId[0] == 'd') && (subChunkId[1] == 'a') && (subChunkId[2] == 't') && (subChunkId[3] == 'a')) { @@ -287,7 +332,7 @@ bool SoundFileReaderWav::parseHeader(Info& info) info.sampleCount = subChunkSize / m_bytesPerSample; // Store the start and end position of samples in the file - m_dataStart = m_stream->tell(); + m_dataStart = subChunkStart; m_dataEnd = m_dataStart + info.sampleCount * m_bytesPerSample; dataChunkFound = true;