27inline constexpr int16_t imaStepTable[89] = {
28 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
29 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
30 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
31 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
32 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
33 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
34 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
35 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
36 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
43enum class ChunkId : uint_fast8_t
55template <
class BytePo
interType>
65 enum class wFormatTag : uint16_t
86 constexpr char fmt[] =
"fmt ";
87 constexpr char PEAK[] =
"PEAK";
88 constexpr char fact[] =
"fact";
89 constexpr char data[] =
"data";
96template <
typename BytePo
interType>
100 using baseType =
typename std::remove_pointer<BytePointerType>::type;
101 using cvRemovedBaseType =
typename std::remove_cv<baseType>::type;
102 static_assert (std::is_pointer<BytePointerType>::value,
"BytePointerType must be a Pointer type.");
103 static_assert (std::is_same<cvRemovedBaseType,
104 unsigned char>::value,
105 "BytePointerType must be unsigned char* (or CV-qualified).");
108 constexpr WavReader (BytePointerType wavByteArray,
size_t length)
109 : wav (wavByteArray),
112 assert (length > 46);
115 while (offset < length)
117 const auto chunk = parseChunk();
122 formatTag =
static_cast<fmt::wFormatTag
> ((chunk.data[1] << 8) | chunk.data[0]);
123 assert (formatTag == fmt::wFormatTag::PCM || formatTag == fmt::wFormatTag::IeeeFloat || formatTag == fmt::wFormatTag::ImaAdpcm);
124 numChannels = (chunk.data[3] << 8) | chunk.data[2];
125 sampleRate = (chunk.data[5] << 8) | chunk.data[4];
126 wBitsPerSample = (chunk.data[15] << 8) | chunk.data[14];
136 numSamplesPerChannel = chunk.size / numChannels / (wBitsPerSample / 8);
162 return wBitsPerSample;
174 return numSamplesPerChannel;
183 constexpr BytePointerType getDataPointer() const noexcept
185 return dataChunk.data;
188 constexpr fmt::wFormatTag getFormatTag() const noexcept
194 constexpr void parseRiffHeader()
196 assert (wav[0] ==
'R' && wav[1] ==
'I' && wav[2] ==
'F' && wav[3] ==
'F');
197 assert (wav[8] ==
'W' && wav[9] ==
'A' && wav[10] ==
'V' && wav[11] ==
'E');
198 fileSize = (wav[7] << 24) | (wav[6] << 16) | (wav[5] << 8) | wav[4];
201 constexpr Chunk<BytePointerType> parseChunk()
203 unsigned char cid[4] = {};
204 for (
int i = 0; i < 4; ++i)
206 cid[i] = wav[offset + i];
209 ChunkId chunkId = ChunkId::Unknown;
210 if (stringComp (cid, wavChunkId::fmt, 4))
212 chunkId = ChunkId::fmt;
214 else if (stringComp (cid, wavChunkId::PEAK, 4))
216 chunkId = ChunkId::PEAK;
218 else if (stringComp (cid, wavChunkId::fact, 4))
220 chunkId = ChunkId::fact;
222 else if (stringComp (cid, wavChunkId::data, 4))
224 chunkId = ChunkId::data;
227 const uint32_t chunkSize = (wav[offset + 7] << 24) | (wav[offset + 6] << 16) | (wav[offset + 5] << 8) | wav[offset + 4];
228 const size_t dataIndex = offset + 8;
231 offset += chunkSize + 8;
232 return Chunk<BytePointerType> { chunkId, chunkSize, &wav[dataIndex] };
235 const BytePointerType wav;
236 uint32_t fileSize = 0;
237 const size_t length = 0;
241 fmt::wFormatTag formatTag = fmt::wFormatTag::Unknown;
242 uint16_t numChannels = 0;
243 uint32_t sampleRate = 0;
244 uint32_t numSamplesPerChannel = 0;
245 uint16_t wBitsPerSample = 0;
246 Chunk<BytePointerType> dataChunk {};
252template <
typename BytePo
interType>
258 PCMDecoder() =
default;
259 ~PCMDecoder() =
default;
266 : formatTag (reader.getFormatTag()),
278 playing.store (
true);
284 playing.store (
false);
290 readPosition.store (0);
297 template <
typename FloatType,
size_t N>
300 if (! playing.load())
306 assert (0 <= readPosition.load() && readPosition <= numSamples);
311 case fmt::wFormatTag::PCM:
313 auto offset = (bitRate / 8) * numChannels * readPosition.load();
315 for (uint_fast32_t samp = 0; samp < nSamp; ++samp)
317 if (readPosition + samp >= numSamples)
320 readPosition.store (0);
321 playing.store (
false);
328 for (uint32_t b = 32 - bitRate; b < 32; b += 8)
330 temp |= (dataChunk.data[offset] << b);
333 const FloatType s =
static_cast<FloatType
> (temp) / normalizeFactor;
337 readPosition += nSamp;
340 case fmt::wFormatTag::ImaAdpcm:
343 case fmt::wFormatTag::IeeeFloat:
352 bool isPlaying() const noexcept
354 return playing.load();
357 void setLoopPlay (
bool loopPlay)
359 loop.store (loopPlay);
362 bool isLooping() const noexcept
368 const fmt::wFormatTag formatTag;
369 const uint32_t numChannels;
370 const uint32_t numSamples;
371 const uint16_t bitRate;
372 std::atomic<uint32_t> readPosition { 0 };
373 std::atomic<bool> loop {
false };
374 std::atomic<bool> playing {
false };
375 const Chunk<BytePointerType> dataChunk;
376 static constexpr uint32_t normalizeFactor = 2147483648;
A lightweight data structure that stores a pointer to an audio buffer.
Definition: ame_AudioBuffer.hpp:32
uint_fast32_t getNumChannels() const noexcept
Returns the number of channels.
Definition: ame_AudioBuffer.hpp:49
void addSample(const uint_fast32_t destChannel, const uint_fast32_t destSample, const ElementType valueToAdd)
Add a value to a sample in the buffer.
Definition: ame_AudioBuffer.hpp:77
uint_fast32_t getNumSamplesPerChannel() const noexcept
Returns the number of samples per channel.
Definition: ame_AudioBuffer.hpp:55
WAVE file player.
Definition: ame_Pcm.hpp:254
void skipToHome()
Skip to home.
Definition: ame_Pcm.hpp:288
void pause()
Pause.
Definition: ame_Pcm.hpp:282
void process(AudioBlockView< FloatType, N > &block)
Add to sound to AudioBlockView if playing.
Definition: ame_Pcm.hpp:298
void play()
Start (or re-start) playing.
Definition: ame_Pcm.hpp:276
WAVE file reader.
Definition: ame_Pcm.hpp:98
constexpr uint32_t getNumSamples() const noexcept
return number of samples per channel.
Definition: ame_Pcm.hpp:172
constexpr uint16_t getBitRate() const noexcept
return bit rate.
Definition: ame_Pcm.hpp:160
constexpr uint32_t getFileSize() const noexcept
return RIFF header file size.
Definition: ame_Pcm.hpp:148
constexpr uint16_t getNumChannels() const noexcept
return number of channels
Definition: ame_Pcm.hpp:166
constexpr uint32_t getSampleRate() const noexcept
return sample rate.
Definition: ame_Pcm.hpp:154
constexpr Chunk< BytePointerType > getDataChunk() const noexcept
return data chunk.
Definition: ame_Pcm.hpp:178
WaveChunk.
Definition: ame_Pcm.hpp:57