5#include <BufferStream.h>
17 BufferStreamReadOnly stream{wavData.data(), wavData.size()};
19 this->
signature = stream.read<uint32_t>();
21 stream.set_big_endian(
true);
26 const auto totalLength = stream.read<uint32_t>();
27 if (stream.read<uint32_t>() !=
RIFF_TYPE) {
31 while (stream.tell() < totalLength) {
32 std::unique_ptr<ChunkBase> ptr;
34 #define SNDPP_CHUNK_SETUP(ID) \
35 auto* ID = new Chunk##ID; \
39 const auto type = stream.read<
ChunkType>();
45 const auto fmtExtraCompressionInfoLength = stream.read<uint32_t>() - 16;
46 stream >>
FMT->format >>
FMT->channels >>
FMT->samplesPerSecond >>
FMT->averageBytesPerSecond >>
FMT->blockAlign >>
FMT->bitsPerSample;
47 if (fmtExtraCompressionInfoLength) {
48 FMT->extraCompressionInfo = stream.read_bytes(fmtExtraCompressionInfoLength);
54 DATA->data = stream.read_bytes(stream.read<uint32_t>());
62 const auto cueNumPoints = stream.read<uint32_t>();
63 for (uint32_t i = 0; i < cueNumPoints; i++) {
65 stream >> point.
id >> point.position >> point.chunk >> point.chunkStart >> point.blockStart >> point.sampleOffset;
66 CUE->cuePoints.push_back(point);
75 const auto plstNumSegments = stream.read<uint32_t>();
76 for (uint32_t i = 0; i < plstNumSegments; i++) {
78 stream >> segment.
id >> segment.length >> segment.repeats;
79 PLST->segments.push_back(segment);
85 const auto factExtraCompressionInfoLength = stream.read<uint32_t>() -
sizeof(uint32_t);
86 stream >>
FACT->samples;
87 if (factExtraCompressionInfoLength) {
88 FACT->extraCompressionInfo = stream.read_bytes(factExtraCompressionInfoLength);
94 stream.skip<uint32_t>();
95 stream >>
SMPL->manufacturer >>
SMPL->product >>
SMPL->samplePeriod >>
SMPL->midiUnityNote >>
SMPL->midiPitchFraction
96 >>
SMPL->smpteFormat >>
SMPL->smpteOffset >>
SMPL->sampleLoops >>
SMPL->samplerData;
97 const auto smplNumLoops = stream.read<uint32_t>();
98 for (uint32_t i = 0; i < smplNumLoops; i++) {
100 stream >> sampleLoop.
id >> sampleLoop.type >> sampleLoop.start >> sampleLoop.end >> sampleLoop.fraction >> sampleLoop.playCount;
101 SMPL->loops.push_back(sampleLoop);
107 if (stream.read<uint32_t>() !=
sizeof(
ChunkINST)) {
110 stream >>
INST->unshiftedNote >>
INST->fineTune >>
INST->gain >>
INST->lowNote >>
INST->highNote >>
INST->lowVelocity >>
INST->highVelocity;
115 if (stream.read<uint32_t>() !=
sizeof(
ChunkCSET)) {
118 stream >>
CSET->codePage >>
CSET->countryCode >>
CSET->language >>
CSET->dialect;
131 JUNK->junk = stream.read_bytes(stream.read<uint32_t>());
136 PAD->padding = stream.read_bytes(stream.read<uint32_t>());
141 FLLR->filler = stream.read_bytes(stream.read<uint32_t>());
145 const auto listLength = stream.read<uint32_t>();
155 while (stream.tell() < infoStart) {
157 const auto metadata = stream.read_string(stream.read<uint32_t>());
158 INFO->metadata.push_back({infoType, metadata});
165 while (stream.tell() < adtlStart) {
170 const auto labelLength = stream.read<uint32_t>();
171 const auto labelID = stream.read<uint32_t>();
172 const auto labelText = stream.read_string(labelLength -
sizeof(uint32_t));
173 ADTL->labels.push_back({labelID, labelText});
177 const auto noteLength = stream.read<uint32_t>();
178 const auto noteID = stream.read<uint32_t>();
179 const auto noteText = stream.read_string(noteLength -
sizeof(uint32_t));
180 ADTL->notes.push_back({noteID, noteText});
184 const auto ltxtLength = stream.read<uint32_t>();
186 stream >> ltxt.
id >> ltxt.sampleLength >> ltxt.purpose >> ltxt.country >> ltxt.language >> ltxt.dialect >> ltxt.codePage;
187 ltxt.label = stream.read_string(ltxtLength - (
sizeof(
ChunkADTL::LTXT) -
sizeof(std::string)));
188 ADTL->labelTexts.push_back(ltxt);
199 Unknown->data = stream.read_bytes(stream.read<uint32_t>());
204 #undef SNDPP_CHUNK_SETUP
207 this->
chunks.push_back(std::move(ptr));
210 if (stream.tell() % 2 != 0) {
225 :
WAV(fs::readFileBuffer(wavPath)) {}
227WAV::operator bool()
const {
228 return this->signature;
240 if (
const auto it = std::find_if(this->
chunks.begin(), this->chunks.end(), [type](
const std::unique_ptr<ChunkBase>& chunk) {
241 return chunk->type == type;
242 }); it != this->chunks.end()) {
256#define SNDPP_CHUNK_GETTER(TYPE) \
257 const WAV::Chunk##TYPE* WAV::getChunk##TYPE() const { \
258 return dynamic_cast<const Chunk##TYPE*>(this->getFirstChunk(WAV::ChunkType::TYPE)); \
275#undef SNDPP_CHUNK_GETTER
#define SNDPP_CHUNK_GETTER(TYPE)
#define SNDPP_CHUNK_SETUP(ID)
std::vector< std::unique_ptr< ChunkBase > > chunks
const std::vector< std::unique_ptr< ChunkBase > > & getChunks() const
const ChunkBase * getFirstChunk(WAV::ChunkType type) const
uint32_t getSignature() const
void setSignature(uint32_t newSignature)
static constexpr auto RIFF_TYPE
constexpr auto FFIR_SIGNATURE
constexpr auto RIFX_SIGNATURE
constexpr auto RIFF_SIGNATURE
std::array< uint8_t, 16 > md5