#pragma once #include #include #include #include #include #include namespace wav { struct riff_chunk { char chunk_id[4]; // "RIFF" uint32_t chunk_size; // size of rest of file char format[4]; // "WAVE" }; //8-bit samples are stored as unsigned bytes, ranging // from 0 to 255. 16-bit samples are stored as 2's-complement // signed integers, ranging from -32768 to 32767. :( struct fmt_chunk { char chunk_id[4]; // "fmt " uint32_t chunk_size; // size of rest of subchunk uint16_t audio_format; // 1 == PCM uint16_t channels; // 1 == mono, 2 = stereo uint32_t sample_rate; // eg. 44100 uint32_t byte_rate; // == sample_rate * channels * bits_per_sample/8 uint16_t block_align; // channels * bits_per_sample/8 uint16_t bits_per_sample; // 8 }; struct data_chunk { char chunk_id[4]; // "data" uint32_t chunk_size; // size of actual sound // + data }; static_assert(sizeof(riff_chunk) == 12, "wrong size"); static_assert(sizeof(fmt_chunk) == 24, "wrong size"); static_assert(sizeof(data_chunk) == 8, "wrong size"); class handle{ struct const_iterator; // forward decl public: handle(std::string filename){ file.open(filename, std::ios_base::in); read(riff); assert(strncmp("RIFF", riff.chunk_id, 4) == 0); assert(strncmp("WAVE", riff.format, 4) == 0); read(fmt); assert(strncmp("fmt ", fmt.chunk_id, 4) == 0); assert(fmt.audio_format == 1); assert(fmt.channels == 1); assert(fmt.bits_per_sample == 8); read(data); assert(strncmp("data", data.chunk_id, 4) == 0); } const_iterator begin(){ return {this}; } const_iterator end(){ return {}; } void rewind(unsigned int sample){ auto start = sizeof(riff) + sizeof(fmt) + sizeof(data); auto offset = sample * fmt.bits_per_sample / 8 * fmt.channels; file.pubseekpos(start + offset, std::ios_base::in); } private: struct const_iterator : public boost::iterator_facade{ const_iterator() = default; const_iterator(handle* bp) : back_ptr(bp) { ++*this; } private: friend class boost::iterator_core_access; void increment() { uint8_t data = 0; if(back_ptr->file.sgetn(reinterpret_cast(&data), 1) > 0){ value = data / 255.0 - 0.5; } else { back_ptr = nullptr; } } bool equal(const_iterator const& other) const { return back_ptr == other.back_ptr; } double const & dereference() const { return value; } handle* back_ptr = nullptr; double value; }; template void read(T& thing){ file.sgetn(reinterpret_cast(&thing), sizeof(T)); } std::filebuf file; riff_chunk riff; fmt_chunk fmt; data_chunk data; }; }