Mercurial > hg > libxtract
changeset 233:6c04845f83dd
Add WaveFile class for loading audio files in simpletest
author | Jamie Bullock <jamie@jamiebullock.com> |
---|---|
date | Wed, 04 Jun 2014 18:09:43 +0100 |
parents | f7a7a54e9de4 |
children | 5ee4d256b937 |
files | examples/simpletest/WaveFile.cpp examples/simpletest/WaveFile.h |
diffstat | 2 files changed, 238 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/simpletest/WaveFile.cpp Wed Jun 04 18:09:43 2014 +0100 @@ -0,0 +1,172 @@ +#include "WaveFile.h" + +#include <fstream> +#include <iostream> +#include <cstdint> +#include <cassert> +#include <cstring> + +namespace +{ + struct RIFFChunk + { + std::uint32_t chunkID; + std::uint32_t chunkSize; + std::uint32_t format; + }; + struct fmtChunk + { + std::uint32_t chunkID; + std::uint32_t chunkSize; + std::uint16_t audioFormat; + std::uint16_t numChannels; + std::uint32_t sampleRate; + std::uint32_t byteRate; + std::uint16_t blockAlign; + std::uint16_t bitsPerSample; + }; + struct WaveHeader + { + RIFFChunk riff; + fmtChunk fmt; + }; +} + +WaveFile::WaveFile() : data(nullptr), size(0) +{ +} +WaveFile::WaveFile(const std::string &filename) : data(nullptr), size(0) +{ + Load(filename); +} +WaveFile::~WaveFile() +{ + Unload(); +} + +bool WaveFile::Load(const std::string &filename) +{ + if (IsLoaded()) + { + Unload(); + } + + std::fstream file(filename, std::ios::in | std::ios::binary); + + if (!file.is_open()) + { + std::cerr << "Error: Could not open file." << std::endl; + return false; + } + + WaveHeader header; + std::memset(&header, 0, sizeof(WaveHeader)); + + while (file.peek() != std::char_traits<char>::eof()) + { + std::uint32_t chunkID; + std::uint32_t chunkSize; + + file.read(reinterpret_cast<char*>(&chunkID), sizeof(std::uint32_t)); + file.read(reinterpret_cast<char*>(&chunkSize), sizeof(std::uint32_t)); + + switch (chunkID) + { + case 'FFIR': + { + header.riff.chunkID = chunkID; + header.riff.chunkSize = chunkSize; + file.read(reinterpret_cast<char*>(&header.riff.format), sizeof(std::uint32_t)); + + if (header.riff.format != 'EVAW') + { + std::cerr << "Error: Not a valid WAVE file." << std::endl; + return false; + } + + break; + } + case ' tmf': + { + header.fmt.chunkID = chunkID; + header.fmt.chunkSize = chunkSize; + file.read(reinterpret_cast<char*>(&header.fmt.audioFormat), sizeof(std::uint16_t)); + file.read(reinterpret_cast<char*>(&header.fmt.numChannels), sizeof(std::uint16_t)); + file.read(reinterpret_cast<char*>(&header.fmt.sampleRate), sizeof(std::uint32_t)); + file.read(reinterpret_cast<char*>(&header.fmt.byteRate), sizeof(std::uint32_t)); + file.read(reinterpret_cast<char*>(&header.fmt.blockAlign), sizeof(std::uint16_t)); + file.read(reinterpret_cast<char*>(&header.fmt.bitsPerSample), sizeof(std::uint16_t)); + + if (header.fmt.audioFormat != PCM && + header.fmt.audioFormat != WAVE_FORMAT_IEEE_FLOAT) + { + std::cerr << "Error: Not in valid format" << std::endl; + return false; + } + if (header.fmt.bitsPerSample % 2 != 0) + { + std::cerr << "Error: Invalid number of bits per sample" << std::endl; + return false; + } + if (header.fmt.byteRate != (header.fmt.sampleRate * header.fmt.numChannels * header.fmt.bitsPerSample / 8)) + { + std::cerr << "Error: Invalid byte rate" << std::endl; + return false; + } + if (header.fmt.blockAlign != (header.fmt.numChannels * header.fmt.bitsPerSample / 8)) + { + std::cerr << "Error: Invalid block align" << std::endl; + return false; + } + + break; + } + case 'atad': + { + assert(data == nullptr); + size = chunkSize; + data = new char[size]; + file.read(data, chunkSize); + + break; + } + default: + { + file.ignore(chunkSize); + + break; + } + } + } + + // Check that we got all chunks + if (header.riff.chunkID != 'FFIR') + { + std::cerr << "Error: Missing RIFF chunk." << std::endl; + return false; + } + if (header.fmt.chunkID != ' tmf') + { + std::cerr << "Error: Missing fmt chunk." << std::endl; + return false; + } + if (data == nullptr || size == 0) + { + std::cerr << "Error: Missing data chunk." << std::endl; + return false; + } + + // Fill meta struct + meta.audioFormat = static_cast<AudioFormat>(header.fmt.audioFormat); + meta.numChannels = header.fmt.numChannels; + meta.sampleRate = header.fmt.sampleRate; + meta.bitsPerSample = header.fmt.bitsPerSample; + + return true; +} +void WaveFile::Unload() +{ + delete[] data; + data = nullptr; + size = 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/simpletest/WaveFile.h Wed Jun 04 18:09:43 2014 +0100 @@ -0,0 +1,66 @@ +#ifndef WaveFile_h__ +#define WaveFile_h__ + +#include <string> + +///\note All meta data is undefined if IsLoaded() == false +class WaveFile +{ +public: + enum AudioFormat + { + PCM = 1, + WAVE_FORMAT_IEEE_FLOAT = 3 + }; + + WaveFile(); + WaveFile(const std::string &filename); + ~WaveFile(); + + bool Load(const std::string &filename); + void Unload(); + + inline bool IsLoaded() const + { + return (data != nullptr && size != 0); + } + + inline AudioFormat GetAudioFormat() const + { + return meta.audioFormat; + } + inline unsigned int GetNumChannels() const + { + return meta.numChannels; + } + inline unsigned int GetSampleRate() const + { + return meta.sampleRate; + } + inline unsigned int GetBitsPerSample() const + { + return meta.bitsPerSample; + } + + inline const char *GetData() const + { + return data; + } + inline std::size_t GetDataSize() const + { + return size; + } + +private: + struct Meta + { + AudioFormat audioFormat; + unsigned int numChannels; + unsigned int sampleRate; + unsigned int bitsPerSample; + } meta; + char *data; + std::size_t size; +}; + +#endif // WaveFile_h__