13 constexpr int FORMAT_TYPE_PCM
= 0x0001;
14 constexpr int FORMAT_TYPE_FLOAT
= 0x0003;
15 constexpr int FORMAT_TYPE_MULAW
= 0x0007;
16 constexpr int FORMAT_TYPE_EXTENSIBLE
= 0xFFFE;
19 using ubyte16
= ALubyte
[16];
20 alure::Array
<ALubyte
,16> mGuid
;
23 inline bool operator==(const IDType::ubyte16
&lhs
, const IDType
&rhs
)
25 static_assert(sizeof(lhs
) == sizeof(rhs
.mGuid
), "Invalid ID size");
26 return std::equal(std::begin(lhs
), std::end(lhs
), rhs
.mGuid
.begin());
29 const IDType SUBTYPE_PCM
{{{
30 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
31 0x00, 0x38, 0x9b, 0x71
33 const IDType SUBTYPE_FLOAT
{{{
34 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
35 0x00, 0x38, 0x9b, 0x71
38 const IDType SUBTYPE_BFORMAT_PCM
{{{
39 0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
40 0xca, 0x00, 0x00, 0x00
42 const IDType SUBTYPE_BFORMAT_FLOAT
{{{
43 0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
44 0xca, 0x00, 0x00, 0x00
47 constexpr int CHANNELS_MONO
= 0x04;
48 constexpr int CHANNELS_STEREO
= 0x01 | 0x02;
49 constexpr int CHANNELS_QUAD
= 0x01 | 0x02 | 0x10 | 0x20;
50 constexpr int CHANNELS_5DOT1
= 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400;
51 constexpr int CHANNELS_5DOT1_REAR
= 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20;
52 constexpr int CHANNELS_6DOT1
= 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400;
53 constexpr int CHANNELS_7DOT1
= 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x200 | 0x400;
56 ALuint
read_le32(std::istream
&stream
)
59 if(!stream
.read(buf
, sizeof(buf
)) || stream
.gcount() != sizeof(buf
))
61 return ((ALuint(buf
[0] )&0x000000ff) | (ALuint(buf
[1]<< 8)&0x0000ff00) |
62 (ALuint(buf
[2]<<16)&0x00ff0000) | (ALuint(buf
[3]<<24)&0xff000000));
65 ALushort
read_le16(std::istream
&stream
)
68 if(!stream
.read(buf
, sizeof(buf
)) || stream
.gcount() != sizeof(buf
))
70 return ((ALushort(buf
[0] )&0x00ff) | (ALushort(buf
[1]<<8)&0xff00));
77 class WaveDecoder final
: public Decoder
{
78 UniquePtr
<std::istream
> mFile
;
80 ChannelConfig mChannelConfig
{ChannelConfig::Mono
};
81 SampleType mSampleType
{SampleType::UInt8
};
85 // In sample frames, relative to sample data start
86 std::pair
<uint64_t,uint64_t> mLoopPts
{0, 0};
88 // In bytes from beginning of file
89 std::istream::pos_type mStart
{0}, mEnd
{0};
90 std::istream::pos_type mCurrentPos
{0};
93 WaveDecoder(UniquePtr
<std::istream
> file
, ChannelConfig channels
, SampleType type
,
94 ALuint frequency
, ALuint framesize
, std::istream::pos_type start
,
95 std::istream::pos_type end
, uint64_t loopstart
, uint64_t loopend
) noexcept
96 : mFile(std::move(file
)), mChannelConfig(channels
), mSampleType(type
), mFrequency(frequency
)
97 , mFrameSize(framesize
), mLoopPts
{loopstart
,loopend
}, mStart(start
), mEnd(end
)
98 { mCurrentPos
= mFile
->tellg(); }
99 ~WaveDecoder() override
{ }
101 ALuint
getFrequency() const noexcept override
;
102 ChannelConfig
getChannelConfig() const noexcept override
;
103 SampleType
getSampleType() const noexcept override
;
105 uint64_t getLength() const noexcept override
;
106 bool seek(uint64_t pos
) noexcept override
;
108 std::pair
<uint64_t,uint64_t> getLoopPoints() const noexcept override
;
110 ALuint
read(ALvoid
*ptr
, ALuint count
) noexcept override
;
113 ALuint
WaveDecoder::getFrequency() const noexcept
{ return mFrequency
; }
114 ChannelConfig
WaveDecoder::getChannelConfig() const noexcept
{ return mChannelConfig
; }
115 SampleType
WaveDecoder::getSampleType() const noexcept
{ return mSampleType
; }
117 uint64_t WaveDecoder::getLength() const noexcept
118 { return (mEnd
- mStart
) / mFrameSize
; }
120 bool WaveDecoder::seek(uint64_t pos
) noexcept
122 std::streamsize offset
= pos
*mFrameSize
+ mStart
;
124 if(offset
> mEnd
|| !mFile
->seekg(offset
))
126 mCurrentPos
= offset
;
130 std::pair
<uint64_t,uint64_t> WaveDecoder::getLoopPoints() const noexcept
{ return mLoopPts
; }
132 ALuint
WaveDecoder::read(ALvoid
*ptr
, ALuint count
) noexcept
137 if(mCurrentPos
< mEnd
)
139 ALuint len
= static_cast<ALuint
>(
140 std::min
<std::istream::pos_type
>(count
*mFrameSize
, mEnd
-mCurrentPos
)
142 #ifdef __BIG_ENDIAN__
145 case SampleType::Float32
:
146 while(total
< len
&& mFile
->good() && !mFile
->eof())
149 ALuint todo
= std::min
<ALuint
>(len
-total
, sizeof(temp
));
151 mFile
->read(temp
, todo
);
152 ALuint got
= static_cast<ALuint
>(mFile
->gcount());
154 for(ALuint i
= 0;i
< got
;++i
)
155 reinterpret_cast<char*>(ptr
)[total
+i
] = temp
[i
^3];
159 if(got
< todo
) break;
164 case SampleType::Int16
:
165 while(total
< len
&& mFile
->good() && !mFile
->eof())
168 ALuint todo
= std::min
<ALuint
>(len
-total
, sizeof(temp
));
170 mFile
->read(temp
, todo
);
171 ALuint got
= static_cast<ALuint
>(mFile
->gcount());
173 for(ALuint i
= 0;i
< got
;++i
)
174 reinterpret_cast<char*>(ptr
)[total
+i
] = temp
[i
^1];
178 if(got
< todo
) break;
183 case SampleType::UInt8
:
184 case SampleType::Mulaw
:
188 mFile
->read(reinterpret_cast<char*>(ptr
), len
);
189 ALuint got
= static_cast<ALuint
>(mFile
->gcount());
192 total
= got
/ mFrameSize
;
200 SharedPtr
<Decoder
> WaveDecoderFactory::createDecoder(UniquePtr
<std::istream
> &file
) noexcept
202 ChannelConfig channels
= ChannelConfig::Mono
;
203 SampleType type
= SampleType::UInt8
;
204 ALuint frequency
= 0;
205 ALuint framesize
= 0;
206 uint64_t loop_pts
[2]{0, 0};
207 ALuint blockalign
= 0;
208 ALuint framealign
= 0;
211 if(!file
->read(tag_
, 4) || file
->gcount() != 4 || memcmp(tag_
, "RIFF", 4) != 0)
213 ALuint totalsize
= read_le32(*file
) & ~1u;
214 if(!file
->read(tag_
, 4) || file
->gcount() != 4 || memcmp(tag_
, "WAVE", 4) != 0)
217 while(file
->good() && !file
->eof() && totalsize
> 8)
219 if(!file
->read(tag_
, 4) || file
->gcount() != 4)
221 ALuint size
= read_le32(*file
);
222 if(size
< 2) return nullptr;
225 size
= std::min(size
, totalsize
);
226 ALuint padbyte
= size
& 1u;
227 totalsize
-= size
+padbyte
;
229 StringView
tag(tag_
, 4);
232 /* 'fmt ' tag needs at least 16 bytes. */
233 if(size
< 16) goto next_chunk
;
235 int fmttype
= read_le16(*file
); size
-= 2;
236 int chancount
= read_le16(*file
); size
-= 2;
237 frequency
= read_le32(*file
); size
-= 4;
239 /* skip average bytes per second */
240 read_le32(*file
); size
-= 4;
242 blockalign
= read_le16(*file
); size
-= 2;
243 int bitdepth
= read_le16(*file
); size
-= 2;
245 /* Look for any extra data and try to find the format */
246 ALuint extrabytes
= 0;
249 extrabytes
= read_le16(*file
);
252 extrabytes
= std::min
<ALuint
>(extrabytes
, size
);
254 if(fmttype
== FORMAT_TYPE_PCM
)
257 channels
= ChannelConfig::Mono
;
258 else if(chancount
== 2)
259 channels
= ChannelConfig::Stereo
;
264 type
= SampleType::UInt8
;
265 else if(bitdepth
== 16)
266 type
= SampleType::Int16
;
270 else if(fmttype
== FORMAT_TYPE_FLOAT
)
273 channels
= ChannelConfig::Mono
;
274 else if(chancount
== 2)
275 channels
= ChannelConfig::Stereo
;
280 type
= SampleType::Float32
;
284 else if(fmttype
== FORMAT_TYPE_MULAW
)
287 channels
= ChannelConfig::Mono
;
288 else if(chancount
== 2)
289 channels
= ChannelConfig::Stereo
;
294 type
= SampleType::Mulaw
;
298 else if(fmttype
== FORMAT_TYPE_EXTENSIBLE
)
300 if(size
< 22) goto next_chunk
;
303 ALushort validbits
= read_le16(*file
); size
-= 2;
304 ALuint chanmask
= read_le32(*file
); size
-= 4;
305 file
->read(reinterpret_cast<char*>(subtype
), 16);
306 size
-= static_cast<ALuint
>(file
->gcount());
308 /* Padded bit depths not supported */
309 if(validbits
!= bitdepth
)
312 if(subtype
== SUBTYPE_BFORMAT_PCM
|| subtype
== SUBTYPE_BFORMAT_FLOAT
)
318 channels
= ChannelConfig::BFormat2D
;
319 else if(chancount
== 4)
320 channels
= ChannelConfig::BFormat3D
;
324 else if(subtype
== SUBTYPE_PCM
|| subtype
== SUBTYPE_FLOAT
)
326 if(chancount
== 1 && chanmask
== CHANNELS_MONO
)
327 channels
= ChannelConfig::Mono
;
328 else if(chancount
== 2 && chanmask
== CHANNELS_STEREO
)
329 channels
= ChannelConfig::Stereo
;
330 else if(chancount
== 4 && chanmask
== CHANNELS_QUAD
)
331 channels
= ChannelConfig::Quad
;
332 else if(chancount
== 6 && (chanmask
== CHANNELS_5DOT1
|| chanmask
== CHANNELS_5DOT1_REAR
))
333 channels
= ChannelConfig::X51
;
334 else if(chancount
== 7 && chanmask
== CHANNELS_6DOT1
)
335 channels
= ChannelConfig::X61
;
336 else if(chancount
== 8 && chanmask
== CHANNELS_7DOT1
)
337 channels
= ChannelConfig::X71
;
342 if(subtype
== SUBTYPE_PCM
|| subtype
== SUBTYPE_BFORMAT_PCM
)
345 type
= SampleType::UInt8
;
346 else if(bitdepth
== 16)
347 type
= SampleType::Int16
;
351 else if(subtype
== SUBTYPE_FLOAT
|| subtype
== SUBTYPE_BFORMAT_FLOAT
)
354 type
= SampleType::Float32
;
364 framesize
= FramesToBytes(1, channels
, type
);
366 /* Calculate the number of frames per block (ADPCM will need extra
368 framealign
= blockalign
/ framesize
;
370 else if(tag
== "smpl")
372 /* sampler data needs at least 36 bytes */
373 if(size
< 36) goto next_chunk
;
375 /* Most of this only affects MIDI sampling, but we only care about
376 * the loop definitions at the end. */
377 /*ALuint manufacturer =*/ read_le32(*file
);
378 /*ALuint product =*/ read_le32(*file
);
379 /*ALuint smpperiod =*/ read_le32(*file
);
380 /*ALuint unitynote =*/ read_le32(*file
);
381 /*ALuint pitchfrac =*/ read_le32(*file
);
382 /*ALuint smptefmt =*/ read_le32(*file
);
383 /*ALuint smpteoffset =*/ read_le32(*file
);
384 ALuint loopcount
= read_le32(*file
);
385 /*ALuint extrabytes =*/ read_le32(*file
);
388 for(ALuint i
= 0;i
< loopcount
&& size
>= 24;++i
)
390 /*ALuint id =*/ read_le32(*file
);
391 ALuint type
= read_le32(*file
);
392 ALuint loopstart
= read_le32(*file
);
393 ALuint loopend
= read_le32(*file
);
394 /*ALuint frac =*/ read_le32(*file
);
395 ALuint numloops
= read_le32(*file
);
398 /* Only handle indefinite forward loops. */
399 if(type
== 0 && numloops
== 0)
401 loop_pts
[0] = loopstart
;
402 loop_pts
[1] = loopend
;
407 else if(tag
== "data")
409 if(framesize
== 0 || !Context::GetCurrent().isSupported(channels
, type
))
412 /* Make sure there's at least one sample frame of audio data. */
413 std::istream::pos_type start
= file
->tellg();
414 std::istream::pos_type end
= start
+ std::istream::pos_type(size
- (size
%framesize
));
415 if(end
-start
>= framesize
)
417 /* Loop points are byte offsets relative to the data start.
418 * Convert to sample frame offsets. */
419 return MakeShared
<WaveDecoder
>(std::move(file
),
420 channels
, type
, frequency
, framesize
, start
, end
,
421 loop_pts
[0] / blockalign
* framealign
,
422 loop_pts
[1] / blockalign
* framealign