15 alure::Array
<ALubyte
,16> mGuid
;
16 using char16
= char[16];
19 inline bool operator==(const IDType::char16
&lhs
, const IDType
&rhs
)
21 static_assert(sizeof(lhs
) == sizeof(rhs
.mGuid
), "Invalid ID size");
22 return std::equal(std::begin(lhs
), std::end(lhs
), rhs
.mGuid
.begin());
25 const IDType SUBTYPE_PCM
{{{
26 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
27 0x00, 0x38, 0x9b, 0x71
29 const IDType SUBTYPE_FLOAT
{{{
30 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
31 0x00, 0x38, 0x9b, 0x71
34 const IDType SUBTYPE_BFORMAT_PCM
{{{
35 0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
36 0xca, 0x00, 0x00, 0x00
38 const IDType SUBTYPE_BFORMAT_FLOAT
{{{
39 0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
40 0xca, 0x00, 0x00, 0x00
43 constexpr int CHANNELS_MONO
= 0x04;
44 constexpr int CHANNELS_STEREO
= 0x01 | 0x02;
45 constexpr int CHANNELS_QUAD
= 0x01 | 0x02 | 0x10 | 0x20;
46 constexpr int CHANNELS_5DOT1
= 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400;
47 constexpr int CHANNELS_5DOT1_REAR
= 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20;
48 constexpr int CHANNELS_6DOT1
= 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400;
49 constexpr int CHANNELS_7DOT1
= 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x200 | 0x400;
52 static ALuint
read_le32(std::istream
&stream
)
55 if(!stream
.read(buf
, sizeof(buf
)) || stream
.gcount() != sizeof(buf
))
57 return ((ALuint(buf
[0] )&0x000000ff) | (ALuint(buf
[1]<< 8)&0x0000ff00) |
58 (ALuint(buf
[2]<<16)&0x00ff0000) | (ALuint(buf
[3]<<24)&0xff000000));
61 static ALushort
read_le16(std::istream
&stream
)
64 if(!stream
.read(buf
, sizeof(buf
)) || stream
.gcount() != sizeof(buf
))
66 return ((ALushort(buf
[0] )&0x00ff) | (ALushort(buf
[1]<<8)&0xff00));
74 class WaveDecoder final
: public Decoder
{
75 UniquePtr
<std::istream
> mFile
;
77 ChannelConfig mChannelConfig
{ChannelConfig::Mono
};
78 SampleType mSampleType
{SampleType::UInt8
};
82 // In sample frames, relative to sample data start
83 std::pair
<uint64_t,uint64_t> mLoopPts
{0, 0};
85 // In bytes from beginning of file
86 std::istream::pos_type mStart
{0}, mEnd
{0};
87 std::istream::pos_type mCurrentPos
{0};
90 WaveDecoder(UniquePtr
<std::istream
> file
, ChannelConfig channels
, SampleType type
,
91 ALuint frequency
, ALuint framesize
, std::istream::pos_type start
,
92 std::istream::pos_type end
, uint64_t loopstart
, uint64_t loopend
) noexcept
93 : mFile(std::move(file
)), mChannelConfig(channels
), mSampleType(type
), mFrequency(frequency
)
94 , mFrameSize(framesize
), mLoopPts
{loopstart
,loopend
}, mStart(start
), mEnd(end
)
95 { mCurrentPos
= mFile
->tellg(); }
96 ~WaveDecoder() override
;
98 ALuint
getFrequency() const noexcept override
;
99 ChannelConfig
getChannelConfig() const noexcept override
;
100 SampleType
getSampleType() const noexcept override
;
102 uint64_t getLength() const noexcept override
;
103 bool seek(uint64_t pos
) noexcept override
;
105 std::pair
<uint64_t,uint64_t> getLoopPoints() const noexcept override
;
107 ALuint
read(ALvoid
*ptr
, ALuint count
) noexcept override
;
110 WaveDecoder::~WaveDecoder()
115 ALuint
WaveDecoder::getFrequency() const noexcept
116 { return mFrequency
; }
118 ChannelConfig
WaveDecoder::getChannelConfig() const noexcept
119 { return mChannelConfig
; }
121 SampleType
WaveDecoder::getSampleType() const noexcept
122 { return mSampleType
; }
125 uint64_t WaveDecoder::getLength() const noexcept
126 { return (mEnd
- mStart
) / mFrameSize
; }
128 bool WaveDecoder::seek(uint64_t pos
) noexcept
130 std::streamsize offset
= pos
*mFrameSize
+ mStart
;
132 if(offset
> mEnd
|| !mFile
->seekg(offset
))
134 mCurrentPos
= offset
;
138 std::pair
<uint64_t,uint64_t> WaveDecoder::getLoopPoints() const noexcept
143 ALuint
WaveDecoder::read(ALvoid
*ptr
, ALuint count
) noexcept
148 if(mCurrentPos
< mEnd
)
150 ALuint len
= static_cast<ALuint
>(
151 std::min
<std::istream::pos_type
>(count
*mFrameSize
, mEnd
-mCurrentPos
)
153 #ifdef __BIG_ENDIAN__
156 case SampleType::Float32
:
157 while(total
< len
&& mFile
->good() && !mFile
->eof())
160 ALuint todo
= std::min
<ALuint
>(len
-total
, sizeof(temp
));
162 mFile
->read(temp
, todo
);
163 ALuint got
= static_cast<ALuint
>(mFile
->gcount());
165 for(ALuint i
= 0;i
< got
;++i
)
166 reinterpret_cast<char*>(ptr
)[total
+i
] = temp
[i
^3];
174 case SampleType::Int16
:
175 while(total
< len
&& mFile
->good() && !mFile
->eof())
178 ALuint todo
= std::min
<ALuint
>(len
-total
, sizeof(temp
));
180 mFile
->read(temp
, todo
);
181 ALuint got
= static_cast<ALuint
>(mFile
->gcount());
183 for(ALuint i
= 0;i
< got
;++i
)
184 reinterpret_cast<char*>(ptr
)[total
+i
] = temp
[i
^1];
192 case SampleType::UInt8
:
193 case SampleType::Mulaw
:
197 mFile
->read(reinterpret_cast<char*>(ptr
), len
);
198 ALuint got
= static_cast<ALuint
>(mFile
->gcount());
201 total
= got
/ mFrameSize
;
209 SharedPtr
<Decoder
> WaveDecoderFactory::createDecoder(UniquePtr
<std::istream
> &file
) noexcept
211 ChannelConfig channels
= ChannelConfig::Mono
;
212 SampleType type
= SampleType::UInt8
;
213 ALuint frequency
= 0;
214 ALuint framesize
= 0;
215 uint64_t loop_pts
[2]{0, 0};
216 ALuint blockalign
= 0;
217 ALuint framealign
= 0;
220 if(!file
->read(tag
, 4) || file
->gcount() != 4 || memcmp(tag
, "RIFF", 4) != 0)
222 ALuint totalsize
= read_le32(*file
) & ~1u;
223 if(!file
->read(tag
, 4) || file
->gcount() != 4 || memcmp(tag
, "WAVE", 4) != 0)
226 while(file
->good() && !file
->eof() && totalsize
> 8)
228 if(!file
->read(tag
, 4) || file
->gcount() != 4)
230 ALuint size
= read_le32(*file
);
231 if(size
< 2) return nullptr;
234 size
= std::min((size
+1) & ~1u, totalsize
);
237 if(memcmp(tag
, "fmt ", 4) == 0)
239 /* 'fmt ' tag needs at least 16 bytes. */
240 if(size
< 16) goto next_chunk
;
243 ALushort fmttype
= read_le16(*file
); size
-= 2;
245 /* mono or stereo data */
246 int chancount
= read_le16(*file
); size
-= 2;
248 /* sample frequency */
249 frequency
= read_le32(*file
); size
-= 4;
251 /* skip average bytes per second */
252 read_le32(*file
); size
-= 4;
254 /* bytes per block */
255 blockalign
= read_le16(*file
); size
-= 2;
257 /* bits per sample */
258 int bitdepth
= read_le16(*file
); size
-= 2;
260 /* Look for any extra data and try to find the format */
261 ALuint extrabytes
= 0;
264 extrabytes
= read_le16(*file
);
267 extrabytes
= std::min
<ALuint
>(extrabytes
, size
);
269 /* Format type should be 0x0001 for integer PCM data, 0x0003 for
270 * float PCM data, 0x0007 for muLaw, and 0xFFFE extensible data.
272 if(fmttype
== 0x0001)
275 channels
= ChannelConfig::Mono
;
276 else if(chancount
== 2)
277 channels
= ChannelConfig::Stereo
;
282 type
= SampleType::UInt8
;
283 else if(bitdepth
== 16)
284 type
= SampleType::Int16
;
288 else if(fmttype
== 0x0003)
291 channels
= ChannelConfig::Mono
;
292 else if(chancount
== 2)
293 channels
= ChannelConfig::Stereo
;
298 type
= SampleType::Float32
;
302 else if(fmttype
== 0x0007)
305 channels
= ChannelConfig::Mono
;
306 else if(chancount
== 2)
307 channels
= ChannelConfig::Stereo
;
312 type
= SampleType::Mulaw
;
316 else if(fmttype
== 0xFFFE)
322 ALushort validbits
= read_le16(*file
); size
-= 2;
323 ALuint chanmask
= read_le32(*file
); size
-= 4;
324 file
->read(subtype
, 16); size
-= file
->gcount();
326 /* Padded bit depths not supported */
327 if(validbits
!= bitdepth
)
330 if(subtype
== SUBTYPE_BFORMAT_PCM
|| subtype
== SUBTYPE_BFORMAT_FLOAT
)
336 channels
= ChannelConfig::BFormat2D
;
337 else if(chancount
== 4)
338 channels
= ChannelConfig::BFormat3D
;
342 else if(subtype
== SUBTYPE_PCM
|| subtype
== SUBTYPE_FLOAT
)
344 if(chancount
== 1 && chanmask
== CHANNELS_MONO
)
345 channels
= ChannelConfig::Mono
;
346 else if(chancount
== 2 && chanmask
== CHANNELS_STEREO
)
347 channels
= ChannelConfig::Stereo
;
348 else if(chancount
== 4 && chanmask
== CHANNELS_QUAD
)
349 channels
= ChannelConfig::Quad
;
350 else if(chancount
== 6 && (chanmask
== CHANNELS_5DOT1
|| chanmask
== CHANNELS_5DOT1_REAR
))
351 channels
= ChannelConfig::X51
;
352 else if(chancount
== 7 && chanmask
== CHANNELS_6DOT1
)
353 channels
= ChannelConfig::X61
;
354 else if(chancount
== 8 && chanmask
== CHANNELS_7DOT1
)
355 channels
= ChannelConfig::X71
;
360 if(subtype
== SUBTYPE_PCM
|| subtype
== SUBTYPE_BFORMAT_PCM
)
363 type
= SampleType::UInt8
;
364 else if(bitdepth
== 16)
365 type
= SampleType::Int16
;
369 else if(subtype
== SUBTYPE_FLOAT
|| subtype
== SUBTYPE_BFORMAT_FLOAT
)
372 type
= SampleType::Float32
;
382 framesize
= FramesToBytes(1, channels
, type
);
384 /* Calculate the number of frames per block (ADPCM will need extra
386 framealign
= blockalign
/ framesize
;
388 else if(memcmp(tag
, "smpl", 4) == 0)
390 /* sampler data needs at least 36 bytes */
391 if(size
< 36) goto next_chunk
;
393 /* Most of this only affects MIDI sampling, but we only care about
394 * the loop definitions at the end. */
395 /*ALuint manufacturer =*/ read_le32(*file
);
396 /*ALuint product =*/ read_le32(*file
);
397 /*ALuint smpperiod =*/ read_le32(*file
);
398 /*ALuint unitynote =*/ read_le32(*file
);
399 /*ALuint pitchfrac =*/ read_le32(*file
);
400 /*ALuint smptefmt =*/ read_le32(*file
);
401 /*ALuint smpteoffset =*/ read_le32(*file
);
402 ALuint loopcount
= read_le32(*file
);
403 /*ALuint extrabytes =*/ read_le32(*file
);
406 for(ALuint i
= 0;i
< loopcount
&& size
>= 24;++i
)
408 /*ALuint id =*/ read_le32(*file
);
409 ALuint type
= read_le32(*file
);
410 ALuint loopstart
= read_le32(*file
);
411 ALuint loopend
= read_le32(*file
);
412 /*ALuint frac =*/ read_le32(*file
);
413 ALuint numloops
= read_le32(*file
);
416 /* Only handle indefinite forward loops. */
417 if(type
== 0 || numloops
== 0)
419 loop_pts
[0] = loopstart
;
420 loop_pts
[1] = loopend
;
425 else if(memcmp(tag
, "data", 4) == 0)
427 if(framesize
== 0 || !Context::GetCurrent().isSupported(channels
, type
))
430 /* Make sure there's at least one sample frame of audio data. */
431 std::istream::pos_type start
= file
->tellg();
432 std::istream::pos_type end
= start
+ std::istream::pos_type(size
- (size
%framesize
));
433 if(end
-start
>= framesize
)
435 /* Loop points are byte offsets relative to the data start.
436 * Convert to sample frame offsets. */
437 return MakeShared
<WaveDecoder
>(std::move(file
),
438 channels
, type
, frequency
, framesize
, start
, end
,
439 loop_pts
[0] / blockalign
* framealign
,
440 loop_pts
[1] / blockalign
* framealign