2 * Copyright (C) 2013 nu774
3 * For conditions of distribution and use, see copyright notice in COPYING
17 #include "wav_reader.h"
18 #include "m4af_endian.h"
20 #define RIFF_FOURCC(a,b,c,d) ((a)|((b)<<8)|((c)<<16)|((d)<<24))
22 #define TRY_IO(expr) \
28 #define ASSERT_FORMAT(ctx, expr) \
31 if (!ctx->last_error) \
32 ctx->last_error = WAV_INVALID_FORMAT; \
38 pcm_reader_vtbl_t
*vtbl
;
39 pcm_sample_description_t sample_format
;
49 static const uint8_t WAV_GUID_PCM
[] = {
50 1, 0, 0, 0, 0, 0, 0x10, 0, 0x80, 0, 0, 0xaa, 0, 0x38, 0x9b, 0x71
52 static const uint8_t WAV_GUID_FLOAT
[] = {
53 3, 0, 0, 0, 0, 0, 0x10, 0, 0x80, 0, 0, 0xaa, 0, 0x38, 0x9b, 0x71
56 static const pcm_sample_description_t
*wav_get_format(pcm_reader_t
*reader
)
58 return &((wav_reader_t
*)reader
)->sample_format
;
61 static int64_t wav_get_length(pcm_reader_t
*reader
)
63 return ((wav_reader_t
*)reader
)->length
;
66 static int64_t wav_get_position(pcm_reader_t
*reader
)
68 return ((wav_reader_t
*)reader
)->position
;
71 static void wav_teardown(pcm_reader_t
**reader
)
78 int riff_read(wav_reader_t
*reader
, void *buffer
, uint32_t size
)
83 if (reader
->last_error
)
86 rc
= reader
->io
.read(reader
->io_cookie
, buffer
, size
- count
);
90 reader
->last_error
= WAV_IO_ERROR
;
91 } while (rc
> 0 && count
< size
);
92 return count
> 0 ? count
: rc
;
96 int riff_skip(wav_reader_t
*reader
, int64_t count
)
101 if (reader
->last_error
)
105 if (reader
->io
.seek
&&
106 reader
->io
.seek(reader
->io_cookie
, count
, SEEK_CUR
) >= 0)
110 if ((rc
= riff_read(reader
, buff
, count
> 8192 ? 8192 : count
)) > 0)
112 } while (rc
> 0 && count
> 0);
115 reader
->last_error
= WAV_IO_ERROR
;
116 return reader
->last_error
? -1 : 0;
120 int riff_seek(wav_reader_t
*reader
, int64_t off
, int whence
)
123 if (reader
->last_error
)
125 if (!reader
->io
.seek
)
127 if ((rc
= reader
->io
.seek(reader
->io_cookie
, off
, whence
)) < 0)
131 reader
->last_error
= WAV_IO_ERROR
;
136 int64_t riff_tell(wav_reader_t
*reader
)
140 if (reader
->last_error
|| !reader
->io
.tell
)
142 off
= reader
->io
.tell(reader
->io_cookie
);
144 reader
->last_error
= WAV_IO_ERROR
;
151 int riff_read16(wav_reader_t
*reader
, uint16_t *value
)
153 TRY_IO(riff_read(reader
, value
, 2) != 2);
154 *value
= m4af_ltoh16(*value
);
161 int riff_read32(wav_reader_t
*reader
, uint32_t *value
)
163 TRY_IO(riff_read(reader
, value
, 4) != 4);
164 *value
= m4af_ltoh32(*value
);
171 int riff_read64(wav_reader_t
*reader
, uint64_t *value
)
173 TRY_IO(riff_read(reader
, value
, 8) != 8);
174 *value
= m4af_ltoh64(*value
);
181 int riff_scan(wav_reader_t
*reader
, const char *fmt
, ...)
187 while ((c
= *fmt
++)) {
190 TRY_IO(riff_read16(reader
, va_arg(ap
, uint16_t*)));
194 TRY_IO(riff_read32(reader
, va_arg(ap
, uint32_t*)));
198 TRY_IO(riff_read64(reader
, va_arg(ap
, uint64_t*)));
209 uint32_t riff_next_chunk(wav_reader_t
*reader
, uint32_t *chunk_size
)
212 if (riff_scan(reader
, "LL", &fcc
, chunk_size
) == 2)
218 int wav_read_frames(pcm_reader_t
*preader
, void *buffer
, unsigned nframes
)
222 wav_reader_t
*reader
= (wav_reader_t
*)preader
;
224 if (!reader
->ignore_length
&& nframes
> reader
->length
- reader
->position
)
225 nframes
= reader
->length
- reader
->position
;
226 nbytes
= nframes
* reader
->sample_format
.bytes_per_frame
;
228 if ((rc
= riff_read(reader
, buffer
, nbytes
)) < 0)
230 nframes
= rc
/ reader
->sample_format
.bytes_per_frame
;
231 reader
->position
+= nframes
;
237 int riff_ds64(wav_reader_t
*reader
, int64_t *length
)
239 uint32_t fcc
, chunk_size
, table_size
;
240 uint64_t riff_size
, sample_count
;
242 fcc
= riff_next_chunk(reader
, &chunk_size
);
243 ASSERT_FORMAT(reader
,
244 fcc
== RIFF_FOURCC('d','s','6','4') && chunk_size
>= 28);
245 TRY_IO(riff_scan(reader
, "QQQL",
246 &riff_size
, length
, &sample_count
, &table_size
) != 4);
247 TRY_IO(riff_skip(reader
, (chunk_size
- 27) & ~1));
248 reader
->data_offset
+= (chunk_size
+ 9) & ~1;
254 int wav_fmt(wav_reader_t
*reader
, uint32_t size
)
256 uint16_t wFormatTag
, nChannels
, nBlockAlign
, wBitsPerSample
, cbSize
;
257 uint32_t nSamplesPerSec
, nAvgBytesPerSec
, dwChannelMask
= 0;
258 uint16_t wValidBitsPerSample
;
262 ASSERT_FORMAT(reader
, size
>= 16);
263 TRY_IO(riff_scan(reader
, "SSLLSS", &wFormatTag
, &nChannels
,
264 &nSamplesPerSec
, &nAvgBytesPerSec
, &nBlockAlign
,
265 &wBitsPerSample
) != 6);
266 wValidBitsPerSample
= wBitsPerSample
;
268 if (wFormatTag
!= 1 && wFormatTag
!= 3 && wFormatTag
!= 0xfffe) {
269 reader
->last_error
= WAV_UNSUPPORTED_FORMAT
;
272 ASSERT_FORMAT(reader
,
273 nChannels
&& nSamplesPerSec
&& nAvgBytesPerSec
&&
274 nBlockAlign
&& wBitsPerSample
&& !(wBitsPerSample
& 7) &&
275 nBlockAlign
== nChannels
* wBitsPerSample
/ 8);
279 if (wFormatTag
!= 0xfffe)
280 TRY_IO(riff_skip(reader
, (size
- 15) & ~1));
282 ASSERT_FORMAT(reader
, size
>= 40);
283 TRY_IO(riff_scan(reader
, "SSL",
284 &cbSize
, &wValidBitsPerSample
, &dwChannelMask
) != 3);
285 TRY_IO(riff_read(reader
, guid
, 16) != 16);
287 if (memcmp(guid
, WAV_GUID_FLOAT
, 16) == 0)
289 else if (memcmp(guid
, WAV_GUID_PCM
, 16) != 0) {
290 reader
->last_error
= WAV_UNSUPPORTED_FORMAT
;
293 ASSERT_FORMAT(reader
,
294 wValidBitsPerSample
&&
295 wValidBitsPerSample
<= wBitsPerSample
);
296 TRY_IO(riff_skip(reader
, (size
- 39) & ~1));
298 reader
->sample_format
.sample_rate
= nSamplesPerSec
;
299 reader
->sample_format
.bits_per_channel
= wValidBitsPerSample
;
300 reader
->sample_format
.bytes_per_frame
= nBlockAlign
;
301 reader
->sample_format
.channels_per_frame
= nChannels
;
302 reader
->sample_format
.channel_mask
= dwChannelMask
;
304 reader
->sample_format
.sample_type
= PCM_TYPE_FLOAT
;
305 else if (wBitsPerSample
== 8)
306 reader
->sample_format
.sample_type
= PCM_TYPE_UINT
;
308 reader
->sample_format
.sample_type
= PCM_TYPE_SINT
;
315 int wav_parse(wav_reader_t
*reader
, int64_t *data_length
)
317 uint32_t container
, fcc
, chunk_size
;
320 container
= riff_next_chunk(reader
, &chunk_size
);
321 if (container
!= RIFF_FOURCC('R','I','F','F') &&
322 container
!= RIFF_FOURCC('R','F','6','4'))
324 TRY_IO(riff_read32(reader
, &fcc
));
325 if (fcc
!= RIFF_FOURCC('W','A','V','E'))
327 reader
->data_offset
= 12;
329 if (container
== RIFF_FOURCC('R','F','6','4'))
330 riff_ds64(reader
, data_length
);
331 while ((fcc
= riff_next_chunk(reader
, &chunk_size
)) != 0) {
332 if (fcc
== RIFF_FOURCC('f','m','t',' ')) {
333 if (wav_fmt(reader
, chunk_size
) < 0)
335 } else if (fcc
== RIFF_FOURCC('d','a','t','a')) {
336 if (container
== RIFF_FOURCC('R','I','F','F'))
337 *data_length
= chunk_size
;
338 reader
->data_offset
+= 8;
341 TRY_IO(riff_skip(reader
, (chunk_size
+ 1) & ~1));
343 reader
->data_offset
+= (chunk_size
+ 9) & ~1;
345 if (fcc
== RIFF_FOURCC('d','a','t','a'))
351 static pcm_reader_vtbl_t wav_vtable
= {
359 pcm_reader_t
*wav_open(wav_io_context_t
*io_ctx
, void *io_cookie
,
362 wav_reader_t
*reader
= 0;
366 if ((reader
= calloc(1, sizeof(wav_reader_t
))) == 0)
368 memcpy(&reader
->io
, io_ctx
, sizeof(wav_io_context_t
));
369 reader
->io_cookie
= io_cookie
;
370 reader
->ignore_length
= ignore_length
;
371 if (wav_parse(reader
, &data_length
) < 0) {
375 bpf
= reader
->sample_format
.bytes_per_frame
;
376 if (ignore_length
|| !data_length
|| data_length
% bpf
)
377 reader
->length
= INT64_MAX
;
379 reader
->length
= data_length
/ bpf
;
381 if (reader
->length
== INT64_MAX
&& reader
->io
.seek
&& reader
->io
.tell
) {
382 if (reader
->io
.seek(reader
->io_cookie
, 0, SEEK_END
) >= 0) {
383 int64_t size
= reader
->io
.tell(reader
->io_cookie
);
385 reader
->length
= (size
- reader
->data_offset
) / bpf
;
386 reader
->io
.seek(reader
->io_cookie
, reader
->data_offset
, SEEK_SET
);
389 reader
->vtbl
= &wav_vtable
;
390 return (pcm_reader_t
*)reader
;
393 pcm_reader_t
*raw_open(wav_io_context_t
*io_ctx
, void *io_cookie
,
394 const pcm_sample_description_t
*desc
)
396 wav_reader_t
*reader
= 0;
398 if ((reader
= calloc(1, sizeof(wav_reader_t
))) == 0)
400 memcpy(&reader
->io
, io_ctx
, sizeof(wav_io_context_t
));
401 memcpy(&reader
->sample_format
, desc
, sizeof(pcm_sample_description_t
));
402 reader
->io_cookie
= io_cookie
;
403 if (io_ctx
->seek
&& io_ctx
->tell
) {
404 if (reader
->io
.seek(reader
->io_cookie
, 0, SEEK_END
) >= 0) {
405 int64_t size
= reader
->io
.tell(reader
->io_cookie
);
407 reader
->length
= size
/ desc
->bytes_per_frame
;
408 reader
->io
.seek(reader
->io_cookie
, reader
->data_offset
, SEEK_SET
);
411 reader
->length
= INT64_MAX
;
412 reader
->vtbl
= &wav_vtable
;
413 return (pcm_reader_t
*)reader
;