annotate examples/simpletest/WaveFile.cpp @ 285:89fe52066db1 tip master

MSCV missing ssize_t fix
author Jamie Bullock <jamie@jamiebullock.com>
date Tue, 16 Jul 2019 18:29:20 +0100
parents 6c04845f83dd
children
rev   line source
jamie@233 1 #include "WaveFile.h"
jamie@233 2
jamie@233 3 #include <fstream>
jamie@233 4 #include <iostream>
jamie@233 5 #include <cstdint>
jamie@233 6 #include <cassert>
jamie@233 7 #include <cstring>
jamie@233 8
jamie@233 9 namespace
jamie@233 10 {
jamie@233 11 struct RIFFChunk
jamie@233 12 {
jamie@233 13 std::uint32_t chunkID;
jamie@233 14 std::uint32_t chunkSize;
jamie@233 15 std::uint32_t format;
jamie@233 16 };
jamie@233 17 struct fmtChunk
jamie@233 18 {
jamie@233 19 std::uint32_t chunkID;
jamie@233 20 std::uint32_t chunkSize;
jamie@233 21 std::uint16_t audioFormat;
jamie@233 22 std::uint16_t numChannels;
jamie@233 23 std::uint32_t sampleRate;
jamie@233 24 std::uint32_t byteRate;
jamie@233 25 std::uint16_t blockAlign;
jamie@233 26 std::uint16_t bitsPerSample;
jamie@233 27 };
jamie@233 28 struct WaveHeader
jamie@233 29 {
jamie@233 30 RIFFChunk riff;
jamie@233 31 fmtChunk fmt;
jamie@233 32 };
jamie@233 33 }
jamie@233 34
jamie@233 35 WaveFile::WaveFile() : data(nullptr), size(0)
jamie@233 36 {
jamie@233 37 }
jamie@233 38 WaveFile::WaveFile(const std::string &filename) : data(nullptr), size(0)
jamie@233 39 {
jamie@233 40 Load(filename);
jamie@233 41 }
jamie@233 42 WaveFile::~WaveFile()
jamie@233 43 {
jamie@233 44 Unload();
jamie@233 45 }
jamie@233 46
jamie@233 47 bool WaveFile::Load(const std::string &filename)
jamie@233 48 {
jamie@233 49 if (IsLoaded())
jamie@233 50 {
jamie@233 51 Unload();
jamie@233 52 }
jamie@233 53
jamie@233 54 std::fstream file(filename, std::ios::in | std::ios::binary);
jamie@233 55
jamie@233 56 if (!file.is_open())
jamie@233 57 {
jamie@233 58 std::cerr << "Error: Could not open file." << std::endl;
jamie@233 59 return false;
jamie@233 60 }
jamie@233 61
jamie@233 62 WaveHeader header;
jamie@233 63 std::memset(&header, 0, sizeof(WaveHeader));
jamie@233 64
jamie@233 65 while (file.peek() != std::char_traits<char>::eof())
jamie@233 66 {
jamie@233 67 std::uint32_t chunkID;
jamie@233 68 std::uint32_t chunkSize;
jamie@233 69
jamie@233 70 file.read(reinterpret_cast<char*>(&chunkID), sizeof(std::uint32_t));
jamie@233 71 file.read(reinterpret_cast<char*>(&chunkSize), sizeof(std::uint32_t));
jamie@233 72
jamie@233 73 switch (chunkID)
jamie@233 74 {
jamie@233 75 case 'FFIR':
jamie@233 76 {
jamie@233 77 header.riff.chunkID = chunkID;
jamie@233 78 header.riff.chunkSize = chunkSize;
jamie@233 79 file.read(reinterpret_cast<char*>(&header.riff.format), sizeof(std::uint32_t));
jamie@233 80
jamie@233 81 if (header.riff.format != 'EVAW')
jamie@233 82 {
jamie@233 83 std::cerr << "Error: Not a valid WAVE file." << std::endl;
jamie@233 84 return false;
jamie@233 85 }
jamie@233 86
jamie@233 87 break;
jamie@233 88 }
jamie@233 89 case ' tmf':
jamie@233 90 {
jamie@233 91 header.fmt.chunkID = chunkID;
jamie@233 92 header.fmt.chunkSize = chunkSize;
jamie@233 93 file.read(reinterpret_cast<char*>(&header.fmt.audioFormat), sizeof(std::uint16_t));
jamie@233 94 file.read(reinterpret_cast<char*>(&header.fmt.numChannels), sizeof(std::uint16_t));
jamie@233 95 file.read(reinterpret_cast<char*>(&header.fmt.sampleRate), sizeof(std::uint32_t));
jamie@233 96 file.read(reinterpret_cast<char*>(&header.fmt.byteRate), sizeof(std::uint32_t));
jamie@233 97 file.read(reinterpret_cast<char*>(&header.fmt.blockAlign), sizeof(std::uint16_t));
jamie@233 98 file.read(reinterpret_cast<char*>(&header.fmt.bitsPerSample), sizeof(std::uint16_t));
jamie@233 99
jamie@233 100 if (header.fmt.audioFormat != PCM &&
jamie@233 101 header.fmt.audioFormat != WAVE_FORMAT_IEEE_FLOAT)
jamie@233 102 {
jamie@233 103 std::cerr << "Error: Not in valid format" << std::endl;
jamie@233 104 return false;
jamie@233 105 }
jamie@233 106 if (header.fmt.bitsPerSample % 2 != 0)
jamie@233 107 {
jamie@233 108 std::cerr << "Error: Invalid number of bits per sample" << std::endl;
jamie@233 109 return false;
jamie@233 110 }
jamie@233 111 if (header.fmt.byteRate != (header.fmt.sampleRate * header.fmt.numChannels * header.fmt.bitsPerSample / 8))
jamie@233 112 {
jamie@233 113 std::cerr << "Error: Invalid byte rate" << std::endl;
jamie@233 114 return false;
jamie@233 115 }
jamie@233 116 if (header.fmt.blockAlign != (header.fmt.numChannels * header.fmt.bitsPerSample / 8))
jamie@233 117 {
jamie@233 118 std::cerr << "Error: Invalid block align" << std::endl;
jamie@233 119 return false;
jamie@233 120 }
jamie@233 121
jamie@233 122 break;
jamie@233 123 }
jamie@233 124 case 'atad':
jamie@233 125 {
jamie@233 126 assert(data == nullptr);
jamie@233 127 size = chunkSize;
jamie@233 128 data = new char[size];
jamie@233 129 file.read(data, chunkSize);
jamie@233 130
jamie@233 131 break;
jamie@233 132 }
jamie@233 133 default:
jamie@233 134 {
jamie@233 135 file.ignore(chunkSize);
jamie@233 136
jamie@233 137 break;
jamie@233 138 }
jamie@233 139 }
jamie@233 140 }
jamie@233 141
jamie@233 142 // Check that we got all chunks
jamie@233 143 if (header.riff.chunkID != 'FFIR')
jamie@233 144 {
jamie@233 145 std::cerr << "Error: Missing RIFF chunk." << std::endl;
jamie@233 146 return false;
jamie@233 147 }
jamie@233 148 if (header.fmt.chunkID != ' tmf')
jamie@233 149 {
jamie@233 150 std::cerr << "Error: Missing fmt chunk." << std::endl;
jamie@233 151 return false;
jamie@233 152 }
jamie@233 153 if (data == nullptr || size == 0)
jamie@233 154 {
jamie@233 155 std::cerr << "Error: Missing data chunk." << std::endl;
jamie@233 156 return false;
jamie@233 157 }
jamie@233 158
jamie@233 159 // Fill meta struct
jamie@233 160 meta.audioFormat = static_cast<AudioFormat>(header.fmt.audioFormat);
jamie@233 161 meta.numChannels = header.fmt.numChannels;
jamie@233 162 meta.sampleRate = header.fmt.sampleRate;
jamie@233 163 meta.bitsPerSample = header.fmt.bitsPerSample;
jamie@233 164
jamie@233 165 return true;
jamie@233 166 }
jamie@233 167 void WaveFile::Unload()
jamie@233 168 {
jamie@233 169 delete[] data;
jamie@233 170 data = nullptr;
jamie@233 171 size = 0;
jamie@233 172 }