1use std::fmt;
2use std::fs::File;
3use std::io::{self, BufReader, Read, Seek, SeekFrom};
4use std::iter::FusedIterator;
5use std::marker::PhantomData;
6use std::path::Path;
7
8use crate::sample::{decode_block, Codec};
9use crate::{
10 Error, Result, Sample, SampleFormat, WavSpec, WavSpecEx, GUID_PCM, TAG_EXTENSIBLE,
11 TAG_IEEE_FLOAT, TAG_PCM,
12};
13
14const BLOCK: usize = 64 * 1024;
16
17pub struct WavReader<R> {
25 inner: R,
26 spec: WavSpecEx,
27 codec: Codec,
28 data_len: u32,
30 remaining: u32,
32 buf: Vec<u8>,
33 pos: usize,
34 end: usize,
35}
36
37impl WavReader<BufReader<File>> {
38 pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
40 let file = File::open(path)?;
41 WavReader::new(BufReader::new(file))
42 }
43}
44
45impl<R: Read> WavReader<R> {
46 pub fn new(mut reader: R) -> Result<Self> {
52 let mut riff = [0u8; 12];
53 reader.read_exact(&mut riff)?;
54 match &riff[0..4] {
55 b"RIFF" => {}
56 b"RF64" | b"BW64" => return Err(Error::Unsupported("RF64 containers (over 4 GiB)")),
57 b"RIFX" => return Err(Error::Unsupported("RIFX big-endian containers")),
58 _ => return Err(Error::Format("not a RIFF file")),
59 }
60 if &riff[8..12] != b"WAVE" {
61 return Err(Error::Format("RIFF form type is not WAVE"));
62 }
63
64 let mut format: Option<(WavSpecEx, Codec)> = None;
65 let (spec, codec, data_len) = loop {
66 let mut header = [0u8; 8];
67 read_chunk_header(&mut reader, &mut header)?;
68 if !header[0..4].iter().all(|b| (0x20..=0x7E).contains(b)) {
69 return Err(Error::Format("chunk id is not printable ASCII"));
70 }
71 let size = u32::from_le_bytes([header[4], header[5], header[6], header[7]]);
72 match &header[0..4] {
73 b"fmt " => {
74 if format.is_some() {
75 return Err(Error::Format("duplicate fmt chunk"));
76 }
77 format = Some(parse_fmt(&mut reader, size)?);
78 }
79 b"data" => {
80 let (spec, codec) = match format {
81 Some(f) => f,
82 None => return Err(Error::Format("data chunk before fmt chunk")),
83 };
84 let block_align =
85 u32::from(spec.spec.channels) * u32::from(spec.bytes_per_sample);
86 if size % block_align != 0 {
87 return Err(Error::Format(
88 "data length is not a multiple of the frame size",
89 ));
90 }
91 break (spec, codec, size);
92 }
93 _ => skip_chunk(&mut reader, size)?,
94 }
95 };
96
97 Ok(WavReader {
98 inner: reader,
99 spec,
100 codec,
101 data_len,
102 remaining: data_len,
103 buf: vec![0u8; BLOCK],
104 pos: 0,
105 end: 0,
106 })
107 }
108
109 pub fn spec(&self) -> WavSpec {
111 self.spec.spec
112 }
113
114 pub fn spec_ex(&self) -> WavSpecEx {
116 self.spec
117 }
118
119 pub fn duration(&self) -> u32 {
121 self.data_len / self.block_align()
122 }
123
124 pub fn len(&self) -> u32 {
129 self.data_len / u32::from(self.codec.container)
130 }
131
132 pub fn is_empty(&self) -> bool {
134 self.data_len == 0
135 }
136
137 pub fn samples<S: Sample>(&mut self) -> Samples<'_, R, S> {
143 let pending = self.check_read::<S>().err();
144 Samples {
145 reader: self,
146 pending,
147 done: false,
148 _sample: PhantomData,
149 }
150 }
151
152 pub fn into_samples<S: Sample>(self) -> IntoSamples<R, S> {
154 let pending = self.check_read::<S>().err();
155 IntoSamples {
156 reader: self,
157 pending,
158 done: false,
159 _sample: PhantomData,
160 }
161 }
162
163 pub fn read_samples<S: Sample>(&mut self, buf: &mut [S]) -> Result<usize> {
170 self.check_read::<S>()?;
171 let width = self.codec.width();
172 let mut filled = 0;
173 while filled < buf.len() {
174 let available = (self.end - self.pos) / width;
175 if available == 0 {
176 if self.refill()? {
177 continue;
178 }
179 break;
180 }
181 let n = available.min(buf.len() - filled);
182 let bytes = n * width;
183 decode_block(
184 &self.codec,
185 &self.buf[self.pos..self.pos + bytes],
186 &mut buf[filled..filled + n],
187 );
188 self.pos += bytes;
189 filled += n;
190 }
191 Ok(filled)
192 }
193
194 pub fn into_inner(self) -> R {
198 self.inner
199 }
200
201 fn block_align(&self) -> u32 {
202 u32::from(self.spec.spec.channels) * u32::from(self.codec.container)
203 }
204
205 fn check_read<S: Sample>(&self) -> Result<()> {
206 if <S as crate::sample::SampleOps>::accepts_read(&self.codec) {
207 Ok(())
208 } else {
209 Err(Error::TooWide)
210 }
211 }
212
213 fn samples_remaining(&self) -> usize {
215 let buffered = self.end - self.pos;
216 let declared = self.remaining as usize;
217 (buffered + declared) / self.codec.width()
218 }
219
220 #[inline]
222 fn next_sample<S: Sample>(&mut self) -> Option<Result<S>> {
223 let width = self.codec.width();
224 if self.pos + width > self.end {
225 match self.refill() {
226 Ok(true) => {}
227 Ok(false) => return None,
228 Err(e) => return Some(Err(e)),
229 }
230 }
231 let bytes = &self.buf[self.pos..self.pos + width];
232 self.pos += width;
233 Some(Ok(<S as crate::sample::SampleOps>::decode(
234 bytes,
235 &self.codec,
236 )))
237 }
238
239 #[inline(never)]
246 fn refill(&mut self) -> Result<bool> {
247 let width = self.codec.width();
248 let leftover = self.end - self.pos;
249 if leftover > 0 && self.pos > 0 {
250 self.buf.copy_within(self.pos..self.end, 0);
251 }
252 self.pos = 0;
253 self.end = leftover;
254 while self.end < width {
255 let room = self.buf.len() - self.end;
256 let want = room.min(self.remaining as usize);
257 if want == 0 {
258 break;
259 }
260 match self.inner.read(&mut self.buf[self.end..self.end + want]) {
261 Ok(0) => {
262 return Err(Error::Format(
263 "stream ends before the declared end of the data chunk",
264 ))
265 }
266 Ok(n) => {
267 let n = n.min(want);
268 self.end += n;
269 self.remaining -= n as u32;
270 }
271 Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
272 Err(e) => return Err(Error::Io(e)),
273 }
274 }
275 if self.end >= width {
276 Ok(true)
277 } else if self.end == 0 {
278 Ok(false)
279 } else {
280 Err(Error::Format(
281 "stream ends before the declared end of the data chunk",
282 ))
283 }
284 }
285}
286
287impl<R: Read + Seek> WavReader<R> {
288 pub fn seek(&mut self, frame: u32) -> io::Result<()> {
294 if frame > self.duration() {
295 return Err(io::Error::new(
296 io::ErrorKind::InvalidInput,
297 "seek past the end of the data chunk",
298 ));
299 }
300 let target = u64::from(frame) * u64::from(self.block_align());
301 let consumed = u64::from(self.data_len - self.remaining);
302 let current = self.inner.stream_position()?;
303 let data_start = current - consumed;
304 self.inner.seek(SeekFrom::Start(data_start + target))?;
305 self.pos = 0;
306 self.end = 0;
307 self.remaining = self.data_len - target as u32;
308 Ok(())
309 }
310}
311
312fn read_chunk_header<R: Read>(reader: &mut R, header: &mut [u8; 8]) -> Result<()> {
315 let mut got = 0;
316 while got < header.len() {
317 match reader.read(&mut header[got..]) {
318 Ok(0) if got == 0 => return Err(Error::Format("no data chunk")),
319 Ok(0) => {
320 return Err(Error::Io(io::Error::new(
321 io::ErrorKind::UnexpectedEof,
322 "stream ends inside a chunk header",
323 )))
324 }
325 Ok(n) => got += n,
326 Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
327 Err(e) => return Err(Error::Io(e)),
328 }
329 }
330 Ok(())
331}
332
333fn skip<R: Read>(reader: &mut R, bytes: u64) -> Result<()> {
334 let copied = io::copy(&mut reader.by_ref().take(bytes), &mut io::sink())?;
335 if copied != bytes {
336 return Err(Error::Io(io::Error::new(
337 io::ErrorKind::UnexpectedEof,
338 "stream ends inside a chunk",
339 )));
340 }
341 Ok(())
342}
343
344fn skip_chunk<R: Read>(reader: &mut R, size: u32) -> Result<()> {
347 skip(reader, u64::from(size))?;
348 if size & 1 == 1 {
349 skip_odd_pad(reader)?;
350 }
351 Ok(())
352}
353
354fn skip_odd_pad<R: Read>(reader: &mut R) -> Result<()> {
355 let mut pad = [0u8; 1];
356 loop {
357 match reader.read(&mut pad) {
358 Ok(0) => return Err(Error::Format("missing pad byte after odd-sized chunk")),
359 Ok(_) if pad[0] == 0 => return Ok(()),
360 Ok(_) => return Err(Error::Format("nonzero pad byte after odd-sized chunk")),
361 Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
362 Err(e) => return Err(Error::Io(e)),
363 }
364 }
365}
366
367fn parse_fmt<R: Read>(reader: &mut R, size: u32) -> Result<(WavSpecEx, Codec)> {
368 if size < 16 {
369 return Err(Error::Format("fmt chunk too small"));
370 }
371 let mut head = [0u8; 16];
372 reader.read_exact(&mut head)?;
373 let mut consumed: u64 = 16;
374
375 let tag = u16::from_le_bytes([head[0], head[1]]);
376 let channels = u16::from_le_bytes([head[2], head[3]]);
377 let sample_rate = u32::from_le_bytes([head[4], head[5], head[6], head[7]]);
378 let block_align = u16::from_le_bytes([head[12], head[13]]);
380 let bits_per_sample = u16::from_le_bytes([head[14], head[15]]);
381
382 let mut extension: Option<[u8; 22]> = None;
383 if size >= 18 {
384 let mut cb = [0u8; 2];
385 reader.read_exact(&mut cb)?;
386 consumed += 2;
387 let cb_size = u16::from_le_bytes(cb);
388 if tag == TAG_EXTENSIBLE {
389 if size < 40 || cb_size < 22 {
390 return Err(Error::Format(
391 "fmt chunk too small for WAVE_FORMAT_EXTENSIBLE",
392 ));
393 }
394 let mut ext = [0u8; 22];
395 reader.read_exact(&mut ext)?;
396 consumed += 22;
397 extension = Some(ext);
398 }
399 } else if tag == TAG_EXTENSIBLE {
400 return Err(Error::Format(
401 "fmt chunk too small for WAVE_FORMAT_EXTENSIBLE",
402 ));
403 }
404 skip(reader, u64::from(size) - consumed)?;
405 if size & 1 == 1 {
406 skip_odd_pad(reader)?;
407 }
408
409 if channels == 0 {
410 return Err(Error::Format("zero channels"));
411 }
412 if sample_rate == 0 {
413 return Err(Error::Format("zero sample rate"));
414 }
415 if block_align == 0 || block_align % channels != 0 {
416 return Err(Error::Format(
417 "block align is not a nonzero multiple of the channel count",
418 ));
419 }
420 let container = block_align / channels;
421 let container_bits = u32::from(container) * 8;
423
424 if u32::from(bits_per_sample) > container_bits {
427 return Err(Error::Format("bits per sample exceed the container width"));
428 }
429
430 let (format, bits) = match tag {
431 TAG_PCM => (SampleFormat::Int, bits_per_sample),
432 TAG_IEEE_FLOAT => (SampleFormat::Float, bits_per_sample),
433 TAG_EXTENSIBLE => {
434 let ext = match extension {
435 Some(e) => e,
436 None => {
437 return Err(Error::Format(
438 "fmt chunk too small for WAVE_FORMAT_EXTENSIBLE",
439 ))
440 }
441 };
442 let valid_bits = u16::from_le_bytes([ext[0], ext[1]]);
443 let guid = &ext[6..22];
445 let format = match (guid[0], guid[1], guid[2..16] == GUID_PCM[2..]) {
446 (0x01, 0x00, true) => SampleFormat::Int,
447 (0x03, 0x00, true) => SampleFormat::Float,
448 _ => return Err(Error::Unsupported("sub-format GUID")),
449 };
450 let bits = if valid_bits == 0 {
451 bits_per_sample
452 } else {
453 valid_bits
454 };
455 (format, bits)
456 }
457 _ => return Err(Error::Unsupported("compressed or unknown format tag")),
458 };
459
460 if bits == 0 {
461 return Err(Error::Format("zero bits per sample"));
462 }
463 if u32::from(bits) > container_bits {
464 return Err(Error::Format("bits per sample exceed the container width"));
465 }
466 match format {
467 SampleFormat::Int => {
468 if container > 4 {
469 return Err(Error::Unsupported("PCM samples wider than 32 bits"));
470 }
471 if container == 1 && bits != 8 {
473 return Err(Error::Format("8-bit PCM must declare 8 valid bits"));
474 }
475 }
476 SampleFormat::Float => {
477 if !((bits == 32 && container == 4) || (bits == 64 && container == 8)) {
478 return Err(Error::Unsupported(
479 "float samples other than 32-bit and 64-bit",
480 ));
481 }
482 }
483 }
484
485 let spec = WavSpecEx {
486 spec: WavSpec {
487 channels,
488 sample_rate,
489 bits_per_sample: bits,
490 sample_format: format,
491 },
492 bytes_per_sample: container,
493 };
494 Ok((spec, Codec::new(format, bits, container)))
495}
496
497pub struct Samples<'a, R, S> {
499 reader: &'a mut WavReader<R>,
500 pending: Option<Error>,
501 done: bool,
502 _sample: PhantomData<S>,
503}
504
505impl<'a, R: Read, S: Sample> Iterator for Samples<'a, R, S> {
506 type Item = Result<S>;
507
508 #[inline]
509 fn next(&mut self) -> Option<Result<S>> {
510 if self.done {
511 return None;
512 }
513 if let Some(e) = self.pending.take() {
514 self.done = true;
515 return Some(Err(e));
516 }
517 let item = self.reader.next_sample::<S>();
518 if let Some(Err(_)) = item {
519 self.done = true;
520 }
521 item
522 }
523
524 fn size_hint(&self) -> (usize, Option<usize>) {
525 if self.done {
526 (0, Some(0))
527 } else {
528 (0, Some(self.reader.samples_remaining()))
529 }
530 }
531}
532
533impl<'a, R: Read, S: Sample> FusedIterator for Samples<'a, R, S> {}
534
535pub struct IntoSamples<R, S> {
537 reader: WavReader<R>,
538 pending: Option<Error>,
539 done: bool,
540 _sample: PhantomData<S>,
541}
542
543impl<R, S> IntoSamples<R, S> {
544 pub fn into_inner(self) -> WavReader<R> {
546 self.reader
547 }
548}
549
550impl<R: Read, S: Sample> Iterator for IntoSamples<R, S> {
551 type Item = Result<S>;
552
553 #[inline]
554 fn next(&mut self) -> Option<Result<S>> {
555 if self.done {
556 return None;
557 }
558 if let Some(e) = self.pending.take() {
559 self.done = true;
560 return Some(Err(e));
561 }
562 let item = self.reader.next_sample::<S>();
563 if let Some(Err(_)) = item {
564 self.done = true;
565 }
566 item
567 }
568
569 fn size_hint(&self) -> (usize, Option<usize>) {
570 if self.done {
571 (0, Some(0))
572 } else {
573 (0, Some(self.reader.samples_remaining()))
574 }
575 }
576}
577
578impl<R: Read, S: Sample> FusedIterator for IntoSamples<R, S> {}
579
580impl<R> fmt::Debug for WavReader<R> {
581 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
582 f.debug_struct("WavReader")
583 .field("spec", &self.spec)
584 .field("data_len", &self.data_len)
585 .field("remaining", &self.remaining)
586 .finish_non_exhaustive()
587 }
588}
589
590impl<R, S> fmt::Debug for Samples<'_, R, S> {
591 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
592 f.debug_struct("Samples")
593 .field("pending", &self.pending.is_some())
594 .field("done", &self.done)
595 .finish_non_exhaustive()
596 }
597}
598
599impl<R, S> fmt::Debug for IntoSamples<R, S> {
600 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
601 f.debug_struct("IntoSamples")
602 .field("pending", &self.pending.is_some())
603 .field("done", &self.done)
604 .finish_non_exhaustive()
605 }
606}