diff options
author | Jamie Bullock <jamie@jamiebullock.com> | 2014-06-04 18:09:43 +0100 |
---|---|---|
committer | Jamie Bullock <jamie@jamiebullock.com> | 2014-06-04 18:10:59 +0100 |
commit | 8d6a75dddfedb54db4f70a3600013530df2acda1 (patch) | |
tree | 383198e125920d62553ce4aeb5c50672ef987b4f /examples/simpletest | |
parent | cff6ba15377fa37bd7801cba4b71ae2e64e1ad5f (diff) | |
download | LibXtract-8d6a75dddfedb54db4f70a3600013530df2acda1.tar.gz LibXtract-8d6a75dddfedb54db4f70a3600013530df2acda1.tar.bz2 LibXtract-8d6a75dddfedb54db4f70a3600013530df2acda1.zip |
Add WaveFile class for loading audio files in simpletest
Diffstat (limited to 'examples/simpletest')
-rw-r--r-- | examples/simpletest/WaveFile.cpp | 172 | ||||
-rw-r--r-- | examples/simpletest/WaveFile.h | 66 |
2 files changed, 238 insertions, 0 deletions
diff --git a/examples/simpletest/WaveFile.cpp b/examples/simpletest/WaveFile.cpp new file mode 100644 index 0000000..6f127ae --- /dev/null +++ b/examples/simpletest/WaveFile.cpp @@ -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; +} diff --git a/examples/simpletest/WaveFile.h b/examples/simpletest/WaveFile.h new file mode 100644 index 0000000..b684b41 --- /dev/null +++ b/examples/simpletest/WaveFile.h @@ -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__ |