Manually track the source decoder sample pos
[alure.git] / src / decoders / wave.cpp
blobe2e4c6c7cec87eb2c93fefa68d6ec890c7296437
2 #include "wave.hpp"
4 #include <stdexcept>
5 #include <iostream>
6 #include <cstring>
8 #include "buffer.h"
11 namespace alure
14 static const ALubyte SUBTYPE_PCM[] = {
15 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
16 0x00, 0x38, 0x9b, 0x71
18 static const ALubyte SUBTYPE_FLOAT[] = {
19 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
20 0x00, 0x38, 0x9b, 0x71
23 static const ALubyte SUBTYPE_BFORMAT_PCM[] = {
24 0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
25 0xca, 0x00, 0x00, 0x00
27 static const ALubyte SUBTYPE_BFORMAT_FLOAT[] = {
28 0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
29 0xca, 0x00, 0x00, 0x00
32 static const int CHANNELS_MONO = 0x04;
33 static const int CHANNELS_STEREO = 0x01 | 0x02;
34 static const int CHANNELS_QUAD = 0x01 | 0x02 | 0x10 | 0x20;
35 static const int CHANNELS_5DOT1 = 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400;
36 static const int CHANNELS_5DOT1_REAR = 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20;
37 static const int CHANNELS_6DOT1 = 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400;
38 static const int CHANNELS_7DOT1 = 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x200 | 0x400;
41 static ALuint read_le32(std::istream &stream)
43 char buf[4];
44 if(!stream.read(buf, sizeof(buf)) || stream.gcount() != sizeof(buf))
45 return 0;
46 return ((ALuint(buf[0] )&0x000000ff) | (ALuint(buf[1]<< 8)&0x0000ff00) |
47 (ALuint(buf[2]<<16)&0x00ff0000) | (ALuint(buf[3]<<24)&0xff000000));
50 static ALushort read_le16(std::istream &stream)
52 char buf[2];
53 if(!stream.read(buf, sizeof(buf)) || stream.gcount() != sizeof(buf))
54 return 0;
55 return ((ALushort(buf[0] )&0x00ff) | (ALushort(buf[1]<<8)&0xff00));
59 class WaveDecoder : public Decoder {
60 UniquePtr<std::istream> mFile;
62 ChannelConfig mChannelConfig;
63 SampleType mSampleType;
64 ALuint mFrequency;
65 ALuint mFrameSize;
67 // In sample frames, relative to sample data start
68 std::pair<ALuint,ALuint> mLoopPts;
70 // In bytes from beginning of file
71 std::istream::pos_type mStart, mEnd;
73 public:
74 WaveDecoder(UniquePtr<std::istream> file, ChannelConfig channels, SampleType type, ALuint frequency, ALuint framesize,
75 std::istream::pos_type start, std::istream::pos_type end, ALuint loopstart, ALuint loopend)
76 : mFile(std::move(file)), mChannelConfig(channels), mSampleType(type), mFrequency(frequency)
77 , mFrameSize(framesize), mLoopPts{loopstart,loopend}, mStart(start), mEnd(end)
78 { }
79 ~WaveDecoder() override final;
81 ALuint getFrequency() const override final;
82 ChannelConfig getChannelConfig() const override final;
83 SampleType getSampleType() const override final;
85 uint64_t getLength() const override final;
86 bool seek(uint64_t pos) override final;
88 std::pair<uint64_t,uint64_t> getLoopPoints() const override final;
90 ALuint read(ALvoid *ptr, ALuint count) override final;
93 WaveDecoder::~WaveDecoder()
98 ALuint WaveDecoder::getFrequency() const
100 return mFrequency;
103 ChannelConfig WaveDecoder::getChannelConfig() const
105 return mChannelConfig;
108 SampleType WaveDecoder::getSampleType() const
110 return mSampleType;
114 uint64_t WaveDecoder::getLength() const
116 return (mEnd - mStart) / mFrameSize;
119 bool WaveDecoder::seek(uint64_t pos)
121 std::streamsize offset = pos*mFrameSize + mStart;
122 mFile->clear();
123 if(offset > mEnd || !mFile->seekg(offset))
124 return false;
125 return true;
128 std::pair<uint64_t,uint64_t> WaveDecoder::getLoopPoints() const
130 return mLoopPts;
133 ALuint WaveDecoder::read(ALvoid *ptr, ALuint count)
135 mFile->clear();
137 auto pos = mFile->tellg();
138 size_t len = count * mFrameSize;
139 ALuint total = 0;
141 if(pos < mEnd)
143 len = std::min<std::istream::pos_type>(len, mEnd-pos);
144 #ifdef __BIG_ENDIAN__
145 switch(mSampleType)
147 case SampleType::Float32:
148 while(total < len && mFile->good() && !mFile->eof())
150 char temp[256];
151 size_t todo = std::min(len-total, sizeof(temp));
153 mFile->read(temp, todo);
154 std::streamsize got = mFile->gcount();
156 for(std::streamsize i = 0;i < got;++i)
157 reinterpret_cast<char*>(ptr)[total+i] = temp[i^3];
159 total += got;
161 total /= mFrameSize;
162 break;
164 case SampleType::Int16:
165 while(total < len && mFile->good() && !mFile->eof())
167 char temp[256];
168 size_t todo = std::min(len-total, sizeof(temp));
170 mFile->read(temp, todo);
171 std::streamsize got = mFile->gcount();
173 for(std::streamsize i = 0;i < got;++i)
174 reinterpret_cast<char*>(ptr)[total+i] = temp[i^1];
176 total += got;
178 total /= mFrameSize;
179 break;
181 case SampleType::UInt8:
182 case SampleType::Mulaw:
183 #else
185 #endif
186 mFile->read(reinterpret_cast<char*>(ptr), len);
187 total = mFile->gcount() / mFrameSize;
191 return total;
195 SharedPtr<Decoder> WaveDecoderFactory::createDecoder(UniquePtr<std::istream> &file)
197 ChannelConfig channels = ChannelConfig::Mono;
198 SampleType type = SampleType::UInt8;
199 ALuint frequency = 0;
200 ALuint framesize = 0;
201 ALuint loop_pts[2]{0, 0};
202 ALuint blockalign = 0;
203 ALuint framealign = 0;
205 char tag[4]{};
206 if(!file->read(tag, 4) || file->gcount() != 4 || memcmp(tag, "RIFF", 4) != 0)
207 return nullptr;
208 ALuint totalsize = read_le32(*file) & ~1u;
209 if(!file->read(tag, 4) || file->gcount() != 4 || memcmp(tag, "WAVE", 4) != 0)
210 return nullptr;
212 while(file->good() && !file->eof() && totalsize > 8)
214 if(!file->read(tag, 4) || file->gcount() != 4)
215 return nullptr;
216 ALuint size = read_le32(*file);
217 if(size < 2) return nullptr;
218 totalsize -= 8;
220 size = std::min((size+1) & ~1u, totalsize);
221 totalsize -= size;
223 if(memcmp(tag, "fmt ", 4) == 0)
225 /* 'fmt ' tag needs at least 16 bytes. */
226 if(size < 16) goto next_chunk;
228 /* format type */
229 ALushort fmttype = read_le16(*file); size -= 2;
231 /* mono or stereo data */
232 int chancount = read_le16(*file); size -= 2;
234 /* sample frequency */
235 frequency = read_le32(*file); size -= 4;
237 /* skip average bytes per second */
238 read_le32(*file); size -= 4;
240 /* bytes per block */
241 blockalign = read_le16(*file); size -= 2;
243 /* bits per sample */
244 int bitdepth = read_le16(*file); size -= 2;
246 /* Look for any extra data and try to find the format */
247 ALuint extrabytes = 0;
248 if(size >= 2)
250 extrabytes = read_le16(*file);
251 size -= 2;
253 extrabytes = std::min<ALuint>(extrabytes, size);
255 /* Format type should be 0x0001 for integer PCM data, 0x0003 for
256 * float PCM data, 0x0007 for muLaw, and 0xFFFE extensible data.
258 if(fmttype == 0x0001)
260 if(chancount == 1)
261 channels = ChannelConfig::Mono;
262 else if(chancount == 2)
263 channels = ChannelConfig::Stereo;
264 else
265 goto next_chunk;
267 if(bitdepth == 8)
268 type = SampleType::UInt8;
269 else if(bitdepth == 16)
270 type = SampleType::Int16;
271 else
272 goto next_chunk;
274 else if(fmttype == 0x0003)
276 if(chancount == 1)
277 channels = ChannelConfig::Mono;
278 else if(chancount == 2)
279 channels = ChannelConfig::Stereo;
280 else
281 goto next_chunk;
283 if(bitdepth == 32)
284 type = SampleType::Float32;
285 else
286 goto next_chunk;
288 else if(fmttype == 0x0007)
290 if(chancount == 1)
291 channels = ChannelConfig::Mono;
292 else if(chancount == 2)
293 channels = ChannelConfig::Stereo;
294 else
295 goto next_chunk;
297 if(bitdepth == 8)
298 type = SampleType::Mulaw;
299 else
300 goto next_chunk;
302 else if(fmttype == 0xFFFE)
304 if(size < 22)
305 goto next_chunk;
307 char subtype[16];
308 ALushort validbits = read_le16(*file); size -= 2;
309 ALuint chanmask = read_le32(*file); size -= 4;
310 file->read(subtype, 16); size -= file->gcount();
312 /* Padded bit depths not supported */
313 if(validbits != bitdepth)
314 goto next_chunk;
316 if(memcmp(subtype, SUBTYPE_BFORMAT_PCM, 16) == 0 || memcmp(subtype, SUBTYPE_BFORMAT_FLOAT, 16) == 0)
318 if(chanmask != 0)
319 goto next_chunk;
321 if(chancount == 3)
322 channels = ChannelConfig::BFormat2D;
323 else if(chancount == 4)
324 channels = ChannelConfig::BFormat3D;
325 else
326 goto next_chunk;
328 else if(memcmp(subtype, SUBTYPE_PCM, 16) == 0 || memcmp(subtype, SUBTYPE_FLOAT, 16) == 0)
330 if(chancount == 1 && chanmask == CHANNELS_MONO)
331 channels = ChannelConfig::Mono;
332 else if(chancount == 2 && chanmask == CHANNELS_STEREO)
333 channels = ChannelConfig::Stereo;
334 else if(chancount == 4 && chanmask == CHANNELS_QUAD)
335 channels = ChannelConfig::Quad;
336 else if(chancount == 6 && (chanmask == CHANNELS_5DOT1 || chanmask == CHANNELS_5DOT1_REAR))
337 channels = ChannelConfig::X51;
338 else if(chancount == 7 && chanmask == CHANNELS_6DOT1)
339 channels = ChannelConfig::X61;
340 else if(chancount == 8 && chanmask == CHANNELS_7DOT1)
341 channels = ChannelConfig::X71;
342 else
343 goto next_chunk;
346 if(memcmp(subtype, SUBTYPE_PCM, 16) == 0 || memcmp(subtype, SUBTYPE_BFORMAT_PCM, 16) == 0)
348 if(bitdepth == 8)
349 type = SampleType::UInt8;
350 else if(bitdepth == 16)
351 type = SampleType::Int16;
352 else
353 goto next_chunk;
355 else if(memcmp(subtype, SUBTYPE_FLOAT, 16) == 0 || memcmp(subtype, SUBTYPE_BFORMAT_FLOAT, 16) == 0)
357 if(bitdepth == 32)
358 type = SampleType::Float32;
359 else
360 goto next_chunk;
362 else
363 goto next_chunk;
365 else
366 goto next_chunk;
368 framesize = FramesToBytes(1, channels, type);
370 /* Calculate the number of frames per block (ADPCM will need extra
371 * consideration). */
372 framealign = blockalign / framesize;
374 else if(memcmp(tag, "smpl", 4) == 0)
376 /* sampler data needs at least 36 bytes */
377 if(size < 36) goto next_chunk;
379 /* Most of this only affects MIDI sampling, but we only care about
380 * the loop definitions at the end. */
381 /*ALuint manufacturer =*/ read_le32(*file);
382 /*ALuint product =*/ read_le32(*file);
383 /*ALuint smpperiod =*/ read_le32(*file);
384 /*ALuint unitynote =*/ read_le32(*file);
385 /*ALuint pitchfrac =*/ read_le32(*file);
386 /*ALuint smptefmt =*/ read_le32(*file);
387 /*ALuint smpteoffset =*/ read_le32(*file);
388 ALuint loopcount = read_le32(*file);
389 /*ALuint extrabytes =*/ read_le32(*file);
390 size -= 36;
392 for(ALuint i = 0;i < loopcount && size >= 24;++i)
394 /*ALuint id =*/ read_le32(*file);
395 ALuint type = read_le32(*file);
396 ALuint loopstart = read_le32(*file);
397 ALuint loopend = read_le32(*file);
398 /*ALuint frac =*/ read_le32(*file);
399 ALuint numloops = read_le32(*file);
400 size -= 24;
402 /* Only handle indefinite forward loops. */
403 if(type == 0 || numloops == 0)
405 loop_pts[0] = loopstart;
406 loop_pts[1] = loopend;
407 break;
411 else if(memcmp(tag, "data", 4) == 0)
413 if(framesize == 0 || !Context::GetCurrent().isSupported(channels, type))
414 goto next_chunk;
416 /* Make sure there's at least one sample frame of audio data. */
417 std::istream::pos_type start = file->tellg();
418 std::istream::pos_type end = start + std::istream::pos_type(size - (size%framesize));
419 if(end-start >= framesize)
421 /* Loop points are byte offsets relative to the data start.
422 * Convert to sample frame offsets. */
423 return MakeShared<WaveDecoder>(std::move(file),
424 channels, type, frequency, framesize, start, end,
425 loop_pts[0] / blockalign * framealign,
426 loop_pts[1] / blockalign * framealign
431 next_chunk:
432 if(size > 0)
433 file->ignore(size);
436 return nullptr;