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 switch (
const auto type = stream.read<
ChunkType>()) {
43 const auto fmtExtraCompressionInfoLength = stream.read<uint32_t>() - 16;
44 stream >>
FMT->format >>
FMT->channels >>
FMT->samplesPerSecond >>
FMT->averageBytesPerSecond >>
FMT->blockAlign >>
FMT->bitsPerSample;
45 if (fmtExtraCompressionInfoLength) {
46 FMT->extraCompressionInfo = stream.read_bytes(fmtExtraCompressionInfoLength);
52 DATA->data = stream.read_bytes(stream.read<uint32_t>());
60 const auto cueNumPoints = stream.read<uint32_t>();
61 for (uint32_t i = 0; i < cueNumPoints; i++) {
63 stream >> point.
id >> point.position >> point.chunk >> point.chunkStart >> point.blockStart >> point.sampleOffset;
64 CUE->cuePoints.push_back(point);
73 const auto plstNumSegments = stream.read<uint32_t>();
74 for (uint32_t i = 0; i < plstNumSegments; i++) {
76 stream >> segment.
id >> segment.length >> segment.repeats;
77 PLST->segments.push_back(segment);
83 const auto factExtraCompressionInfoLength = stream.read<uint32_t>() -
sizeof(uint32_t);
84 stream >>
FACT->samples;
85 if (factExtraCompressionInfoLength) {
86 FACT->extraCompressionInfo = stream.read_bytes(factExtraCompressionInfoLength);
92 stream.skip<uint32_t>();
93 stream >>
SMPL->manufacturer >>
SMPL->product >>
SMPL->samplePeriod >>
SMPL->midiUnityNote >>
SMPL->midiPitchFraction
94 >>
SMPL->smpteFormat >>
SMPL->smpteOffset >>
SMPL->sampleLoops >>
SMPL->samplerData;
95 const auto smplNumLoops = stream.read<uint32_t>();
96 for (uint32_t i = 0; i < smplNumLoops; i++) {
98 stream >> sampleLoop.
id >> sampleLoop.type >> sampleLoop.start >> sampleLoop.end >> sampleLoop.fraction >> sampleLoop.playCount;
99 SMPL->loops.push_back(sampleLoop);
105 if (stream.read<uint32_t>() !=
sizeof(
ChunkINST)) {
108 stream >>
INST->unshiftedNote >>
INST->fineTune >>
INST->gain >>
INST->lowNote >>
INST->highNote >>
INST->lowVelocity >>
INST->highVelocity;
113 if (stream.read<uint32_t>() !=
sizeof(
ChunkCSET)) {
116 stream >>
CSET->codePage >>
CSET->countryCode >>
CSET->language >>
CSET->dialect;
129 JUNK->junk = stream.read_bytes(stream.read<uint32_t>());
134 PAD->padding = stream.read_bytes(stream.read<uint32_t>());
139 FLLR->filler = stream.read_bytes(stream.read<uint32_t>());
143 const auto listLength = stream.read<uint32_t>();
153 while (stream.tell() < infoStart) {
155 const auto metadata = stream.read_string(stream.read<uint32_t>());
156 INFO->metadata.push_back({infoType, metadata});
163 while (stream.tell() < adtlStart) {
167 const auto labelLength = stream.read<uint32_t>();
168 const auto labelID = stream.read<uint32_t>();
169 const auto labelText = stream.read_string(labelLength -
sizeof(uint32_t));
170 ADTL->labels.push_back({labelID, labelText});
174 const auto noteLength = stream.read<uint32_t>();
175 const auto noteID = stream.read<uint32_t>();
176 const auto noteText = stream.read_string(noteLength -
sizeof(uint32_t));
177 ADTL->notes.push_back({noteID, noteText});
181 const auto ltxtLength = stream.read<uint32_t>();
183 stream >> ltxt.
id >> ltxt.sampleLength >> ltxt.purpose >> ltxt.country >> ltxt.language >> ltxt.dialect >> ltxt.codePage;
184 ltxt.label = stream.read_string(ltxtLength - (
sizeof(
ChunkADTL::LTXT) -
sizeof(std::string)));
185 ADTL->labelTexts.push_back(ltxt);
196 Unknown->data = stream.read_bytes(stream.read<uint32_t>());
201 #undef SNDPP_CHUNK_SETUP
204 this->
chunks.push_back(std::move(ptr));
207 if (stream.tell() % 2 != 0) {
222 :
WAV(fs::readFileBuffer(wavPath)) {}
224WAV::operator bool()
const {
225 return this->signature;
237 if (
const auto it = std::ranges::find_if(this->
chunks, [type](
const std::unique_ptr<ChunkBase>& chunk) {
238 return chunk->type == type;
239 }); it != this->
chunks.end()) {
253#define SNDPP_CHUNK_GETTER(TYPE) \
254 const WAV::Chunk##TYPE* WAV::getChunk##TYPE() const { \
255 return dynamic_cast<const Chunk##TYPE*>(this->getFirstChunk(WAV::ChunkType::TYPE)); \
272#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