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_sample_description_t sample_format
;
47 static const uint8_t WAV_GUID_PCM
[] = {
48 1, 0, 0, 0, 0, 0, 0x10, 0, 0x80, 0, 0, 0xaa, 0, 0x38, 0x9b, 0x71
50 static const uint8_t WAV_GUID_FLOAT
[] = {
51 3, 0, 0, 0, 0, 0, 0x10, 0, 0x80, 0, 0, 0xaa, 0, 0x38, 0x9b, 0x71
54 const pcm_sample_description_t
*wav_get_format(wav_reader_t
*reader
)
56 return &reader
->sample_format
;
59 int64_t wav_get_length(wav_reader_t
*reader
)
61 return reader
->length
;
64 int64_t wav_get_position(wav_reader_t
*reader
)
66 return reader
->position
;
69 void wav_teardown(wav_reader_t
**reader
)
76 int riff_read(wav_reader_t
*reader
, void *buffer
, uint32_t size
)
81 if (reader
->last_error
)
84 rc
= reader
->io
.read(reader
->io_cookie
, buffer
, size
- count
);
88 reader
->last_error
= WAV_IO_ERROR
;
89 } while (rc
> 0 && count
< size
);
90 return count
> 0 ? count
: rc
;
94 int riff_skip(wav_reader_t
*reader
, uint32_t count
)
99 if (reader
->last_error
)
103 if (reader
->io
.seek
&&
104 reader
->io
.seek(reader
->io_cookie
, count
, SEEK_CUR
) >= 0)
108 if ((rc
= riff_read(reader
, buff
, count
> 8192 ? 8192 : count
)) > 0)
110 } while (rc
> 0 && count
> 0);
113 reader
->last_error
= WAV_IO_ERROR
;
114 return reader
->last_error
? -1 : 0;
118 int riff_read16(wav_reader_t
*reader
, uint16_t *value
)
120 TRY_IO(riff_read(reader
, value
, 2) != 2);
121 *value
= m4af_ltoh16(*value
);
128 int riff_read32(wav_reader_t
*reader
, uint32_t *value
)
130 TRY_IO(riff_read(reader
, value
, 4) != 4);
131 *value
= m4af_ltoh32(*value
);
138 int riff_read64(wav_reader_t
*reader
, uint64_t *value
)
140 TRY_IO(riff_read(reader
, value
, 8) != 8);
141 *value
= m4af_ltoh64(*value
);
148 int riff_scan(wav_reader_t
*reader
, const char *fmt
, ...)
154 while ((c
= *fmt
++)) {
157 TRY_IO(riff_read16(reader
, va_arg(ap
, uint16_t*)));
161 TRY_IO(riff_read32(reader
, va_arg(ap
, uint32_t*)));
165 TRY_IO(riff_read64(reader
, va_arg(ap
, uint64_t*)));
176 uint32_t riff_next_chunk(wav_reader_t
*reader
, uint32_t *chunk_size
)
179 if (riff_scan(reader
, "LL", &fcc
, chunk_size
) == 2)
184 int wav_read_frames(wav_reader_t
*reader
, void *buffer
, unsigned nframes
)
189 if (!reader
->ignore_length
&& nframes
> reader
->length
- reader
->position
)
190 nframes
= reader
->length
- reader
->position
;
191 nbytes
= nframes
* reader
->sample_format
.bytes_per_frame
;
193 if ((rc
= riff_read(reader
, buffer
, nbytes
)) < 0)
195 nframes
= rc
/ reader
->sample_format
.bytes_per_frame
;
196 reader
->position
+= nframes
;
202 int riff_ds64(wav_reader_t
*reader
, int64_t *length
)
204 uint32_t fcc
, chunk_size
, table_size
;
205 uint64_t riff_size
, sample_count
;
207 fcc
= riff_next_chunk(reader
, &chunk_size
);
208 ASSERT_FORMAT(reader
,
209 fcc
== RIFF_FOURCC('d','s','6','4') && chunk_size
>= 28);
210 TRY_IO(riff_scan(reader
, "QQQL",
211 &riff_size
, length
, &sample_count
, &table_size
) != 4);
214 reader
->last_error
= WAV_UNSUPPORTED_FORMAT
;
220 int wav_fmt(wav_reader_t
*reader
, uint32_t size
)
222 uint16_t wFormatTag
, nChannels
, nBlockAlign
, wBitsPerSample
, cbSize
;
223 uint32_t nSamplesPerSec
, nAvgBytesPerSec
, dwChannelMask
= 0;
224 uint16_t wValidBitsPerSample
;
228 ASSERT_FORMAT(reader
, size
>= 16);
229 TRY_IO(riff_scan(reader
, "SSLLSS", &wFormatTag
, &nChannels
,
230 &nSamplesPerSec
, &nAvgBytesPerSec
, &nBlockAlign
,
231 &wBitsPerSample
) != 6);
232 wValidBitsPerSample
= wBitsPerSample
;
234 if (wFormatTag
!= 1 && wFormatTag
!= 3 && wFormatTag
!= 0xfffe) {
235 reader
->last_error
= WAV_UNSUPPORTED_FORMAT
;
238 ASSERT_FORMAT(reader
,
239 nChannels
&& nSamplesPerSec
&& nAvgBytesPerSec
&&
240 nBlockAlign
&& wBitsPerSample
&& !(wBitsPerSample
& 7) &&
241 nBlockAlign
== nChannels
* wBitsPerSample
/ 8);
245 if (wFormatTag
!= 0xfffe)
246 TRY_IO(riff_skip(reader
, (size
- 15) & ~1));
248 ASSERT_FORMAT(reader
, size
>= 40);
249 TRY_IO(riff_scan(reader
, "SSL",
250 &cbSize
, &wValidBitsPerSample
, &dwChannelMask
) != 3);
251 TRY_IO(riff_read(reader
, guid
, 16) != 16);
253 if (memcmp(guid
, WAV_GUID_FLOAT
, 16) == 0)
255 else if (memcmp(guid
, WAV_GUID_PCM
, 16) != 0) {
256 reader
->last_error
= WAV_UNSUPPORTED_FORMAT
;
259 ASSERT_FORMAT(reader
,
260 wValidBitsPerSample
&&
261 wValidBitsPerSample
<= wBitsPerSample
);
262 TRY_IO(riff_skip(reader
, (size
- 39) & ~1));
264 reader
->sample_format
.sample_rate
= nSamplesPerSec
;
265 reader
->sample_format
.bits_per_channel
= wValidBitsPerSample
;
266 reader
->sample_format
.bytes_per_frame
= nBlockAlign
;
267 reader
->sample_format
.channels_per_frame
= nChannels
;
268 reader
->sample_format
.channel_mask
= dwChannelMask
;
270 reader
->sample_format
.sample_type
= PCM_TYPE_FLOAT
;
271 else if (wBitsPerSample
== 8)
272 reader
->sample_format
.sample_type
= PCM_TYPE_UINT
;
274 reader
->sample_format
.sample_type
= PCM_TYPE_SINT
;
281 int wav_parse(wav_reader_t
*reader
, int64_t *data_length
)
283 uint32_t container
, fcc
, chunk_size
;
286 container
= riff_next_chunk(reader
, &chunk_size
);
287 if (container
!= RIFF_FOURCC('R','I','F','F') &&
288 container
!= RIFF_FOURCC('R','F','6','4'))
290 TRY_IO(riff_read32(reader
, &fcc
));
291 if (fcc
!= RIFF_FOURCC('W','A','V','E'))
293 if (container
== RIFF_FOURCC('R','F','6','4'))
294 riff_ds64(reader
, data_length
);
295 while ((fcc
= riff_next_chunk(reader
, &chunk_size
)) != 0) {
296 if (fcc
== RIFF_FOURCC('f','m','t',' ')) {
297 if (wav_fmt(reader
, chunk_size
) < 0)
299 } else if (fcc
== RIFF_FOURCC('d','a','t','a')) {
300 if (container
== RIFF_FOURCC('R','I','F','F'))
301 *data_length
= chunk_size
;
304 TRY_IO(riff_skip(reader
, (chunk_size
+ 1) & ~1));
306 if (fcc
== RIFF_FOURCC('d','a','t','a'))
312 wav_reader_t
*wav_open(wav_io_context_t
*io_ctx
, void *io_cookie
,
315 wav_reader_t
*reader
;
318 if ((reader
= calloc(1, sizeof(wav_reader_t
))) == 0)
320 memcpy(&reader
->io
, io_ctx
, sizeof(wav_io_context_t
));
321 reader
->io_cookie
= io_cookie
;
322 reader
->ignore_length
= ignore_length
;
323 if (wav_parse(reader
, &data_length
) < 0) {
327 if (ignore_length
|| !data_length
||
328 data_length
% reader
->sample_format
.bytes_per_frame
!= 0)
329 reader
->length
= INT64_MAX
;
331 reader
->length
= data_length
/ reader
->sample_format
.bytes_per_frame
;