diff options
author | James Cowgill <james410@cowgill.org.uk> | 2015-05-08 21:14:39 +0100 |
---|---|---|
committer | James Cowgill <james410@cowgill.org.uk> | 2015-05-08 21:14:39 +0100 |
commit | ebd1b636e5bf0f8fa6d210690582757e8b47f141 (patch) | |
tree | 02dc3aacf1c6f351154432247be0b4347fb14330 /src/SFML/Audio/SoundFileReaderWav.cpp | |
parent | fa21c65d0c764705cfc377bf0d0de08fac26874e (diff) |
Imported Upstream version 2.3+dfsg
Diffstat (limited to 'src/SFML/Audio/SoundFileReaderWav.cpp')
-rw-r--r-- | src/SFML/Audio/SoundFileReaderWav.cpp | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/src/SFML/Audio/SoundFileReaderWav.cpp b/src/SFML/Audio/SoundFileReaderWav.cpp new file mode 100644 index 0000000..730f841 --- /dev/null +++ b/src/SFML/Audio/SoundFileReaderWav.cpp @@ -0,0 +1,285 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include <SFML/Audio/SoundFileReaderWav.hpp> +#include <SFML/System/InputStream.hpp> +#include <SFML/System/Err.hpp> +#include <algorithm> +#include <cctype> +#include <cassert> + + +namespace +{ + // The following functions read integers as little endian and + // return them in the host byte order + + bool decode(sf::InputStream& stream, sf::Uint8& value) + { + return stream.read(&value, sizeof(value)) == sizeof(value); + } + + bool decode(sf::InputStream& stream, sf::Int16& value) + { + unsigned char bytes[sizeof(value)]; + if (stream.read(bytes, sizeof(bytes)) != sizeof(bytes)) + return false; + + value = bytes[0] | (bytes[1] << 8); + + return true; + } + + bool decode(sf::InputStream& stream, sf::Uint16& value) + { + unsigned char bytes[sizeof(value)]; + if (stream.read(bytes, sizeof(bytes)) != sizeof(bytes)) + return false; + + value = bytes[0] | (bytes[1] << 8); + + return true; + } + + bool decode(sf::InputStream& stream, sf::Int32& value) + { + unsigned char bytes[sizeof(value)]; + if (stream.read(bytes, sizeof(bytes)) != sizeof(bytes)) + return false; + + value = bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24); + + return true; + } + + bool decode(sf::InputStream& stream, sf::Uint32& value) + { + unsigned char bytes[sizeof(value)]; + if (stream.read(bytes, sizeof(bytes)) != sizeof(bytes)) + return false; + + value = bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24); + + return true; + } + + const sf::Uint64 mainChunkSize = 12; +} + +namespace sf +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +bool SoundFileReaderWav::check(InputStream& stream) +{ + char header[mainChunkSize]; + if (stream.read(header, sizeof(header)) < static_cast<Int64>(sizeof(header))) + return false; + + return (header[0] == 'R') && (header[1] == 'I') && (header[2] == 'F') && (header[3] == 'F') + && (header[8] == 'W') && (header[9] == 'A') && (header[10] == 'V') && (header[11] == 'E'); +} + + +//////////////////////////////////////////////////////////// +SoundFileReaderWav::SoundFileReaderWav() : +m_stream (NULL), +m_bytesPerSample(0), +m_dataStart (0) +{ +} + + +//////////////////////////////////////////////////////////// +bool SoundFileReaderWav::open(InputStream& stream, Info& info) +{ + m_stream = &stream; + + if (!parseHeader(info)) + { + err() << "Failed to open WAV sound file (invalid or unsupported file)" << std::endl; + return false; + } + + return true; +} + + +//////////////////////////////////////////////////////////// +void SoundFileReaderWav::seek(Uint64 sampleOffset) +{ + assert(m_stream); + + m_stream->seek(m_dataStart + sampleOffset * m_bytesPerSample); +} + + +//////////////////////////////////////////////////////////// +Uint64 SoundFileReaderWav::read(Int16* samples, Uint64 maxCount) +{ + assert(m_stream); + + Uint64 count = 0; + while (count < maxCount) + { + switch (m_bytesPerSample) + { + case 1: + { + Uint8 sample = 0; + if (decode(*m_stream, sample)) + *samples++ = (static_cast<Int16>(sample) - 128) << 8; + else + return count; + break; + } + + case 2: + { + Int16 sample = 0; + if (decode(*m_stream, sample)) + *samples++ = sample; + else + return count; + break; + } + + case 4: + { + Int32 sample = 0; + if (decode(*m_stream, sample)) + *samples++ = sample >> 16; + else + return count; + break; + } + } + + ++count; + } + + return count; +} + + +//////////////////////////////////////////////////////////// +bool SoundFileReaderWav::parseHeader(Info& info) +{ + assert(m_stream); + + // If we are here, it means that the first part of the header + // (the format) has already been checked + char mainChunk[mainChunkSize]; + if (m_stream->read(mainChunk, sizeof(mainChunk)) != sizeof(mainChunk)) + return false; + + // Parse all the sub-chunks + bool dataChunkFound = false; + while (!dataChunkFound) + { + // Parse the sub-chunk id and size + char subChunkId[4]; + if (m_stream->read(subChunkId, sizeof(subChunkId)) != sizeof(subChunkId)) + return false; + Uint32 subChunkSize = 0; + if (!decode(*m_stream, subChunkSize)) + return false; + + // Check which chunk it is + if ((subChunkId[0] == 'f') && (subChunkId[1] == 'm') && (subChunkId[2] == 't') && (subChunkId[3] == ' ')) + { + // "fmt" chunk + + // Audio format + Uint16 format = 0; + if (!decode(*m_stream, format)) + return false; + if (format != 1) // PCM + return false; + + // Channel count + Uint16 channelCount = 0; + if (!decode(*m_stream, channelCount)) + return false; + info.channelCount = channelCount; + + // Sample rate + Uint32 sampleRate = 0; + if (!decode(*m_stream, sampleRate)) + return false; + info.sampleRate = sampleRate; + + // Byte rate + Uint32 byteRate = 0; + if (!decode(*m_stream, byteRate)) + return false; + + // Block align + Uint16 blockAlign = 0; + if (!decode(*m_stream, blockAlign)) + return false; + + // Bits per sample + Uint16 bitsPerSample = 0; + if (!decode(*m_stream, bitsPerSample)) + return false; + m_bytesPerSample = bitsPerSample / 8; + + // Skip potential extra information (should not exist for PCM) + if (subChunkSize > 16) + { + if (m_stream->seek(m_stream->tell() + subChunkSize - 16) == -1) + return false; + } + } + else if ((subChunkId[0] == 'd') && (subChunkId[1] == 'a') && (subChunkId[2] == 't') && (subChunkId[3] == 'a')) + { + // "data" chunk + + // Compute the total number of samples + info.sampleCount = subChunkSize / m_bytesPerSample; + + // Store the starting position of samples in the file + m_dataStart = m_stream->tell(); + + dataChunkFound = true; + } + else + { + // unknown chunk, skip it + if (m_stream->seek(m_stream->tell() + subChunkSize) == -1) + return false; + } + } + + return true; +} + +} // namespace priv + +} // namespace sf |