/rust/registry/src/index.crates.io-6f17d22bba15001f/hound-3.5.0/src/read.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Hound -- A wav encoding and decoding library in Rust |
2 | | // Copyright (C) 2015 Ruud van Asseldonk |
3 | | // |
4 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
5 | | // you may not use this file except in compliance with the License. |
6 | | // A copy of the License has been included in the root of the repository. |
7 | | // Unless required by applicable law or agreed to in writing, software |
8 | | // distributed under the License is distributed on an "AS IS" BASIS, |
9 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
10 | | // See the License for the specific language governing permissions and |
11 | | // limitations under the License. |
12 | | |
13 | | use std::cmp; |
14 | | use std::fs; |
15 | | use std::io; |
16 | | use std::marker; |
17 | | use std::mem; |
18 | | use std::path; |
19 | | use super::{Error, Result, Sample, SampleFormat, WavSpec, WavSpecEx}; |
20 | | |
21 | | /// Extends the functionality of `io::Read` with additional methods. |
22 | | /// |
23 | | /// The methods may be used on any type that implements `io::Read`. |
24 | | pub trait ReadExt: io::Read { |
25 | | /// Reads as many bytes as `buf` is long. |
26 | | /// |
27 | | /// This may issue multiple `read` calls internally. An error is returned |
28 | | /// if `read` read 0 bytes before the buffer is full. |
29 | | // TODO: There is an RFC proposing a method like this for the standard library. |
30 | | fn read_into(&mut self, buf: &mut [u8]) -> io::Result<()>; |
31 | | |
32 | | /// Reads `n` bytes and returns them in a vector. |
33 | | fn read_bytes(&mut self, n: usize) -> io::Result<Vec<u8>>; |
34 | | |
35 | | /// Skip over `n` bytes. |
36 | | fn skip_bytes(&mut self, n: usize) -> io::Result<()>; |
37 | | |
38 | | /// Reads a single byte and interprets it as an 8-bit signed integer. |
39 | | fn read_i8(&mut self) -> io::Result<i8>; |
40 | | |
41 | | /// Reads a single byte and interprets it as an 8-bit unsigned integer. |
42 | | fn read_u8(&mut self) -> io::Result<u8>; |
43 | | |
44 | | /// Reads two bytes and interprets them as a little-endian 16-bit signed integer. |
45 | | fn read_le_i16(&mut self) -> io::Result<i16>; |
46 | | |
47 | | /// Reads two bytes and interprets them as a little-endian 16-bit unsigned integer. |
48 | | fn read_le_u16(&mut self) -> io::Result<u16>; |
49 | | |
50 | | /// Reads three bytes and interprets them as a little-endian 24-bit signed integer. |
51 | | /// |
52 | | /// The sign bit will be extended into the most significant byte. |
53 | | fn read_le_i24(&mut self) -> io::Result<i32>; |
54 | | |
55 | | /// Reads four bytes and interprets them as a little-endian 24-bit signed integer. |
56 | | /// |
57 | | /// The sign bit will be extended into the most significant byte. |
58 | | fn read_le_i24_4(&mut self) -> io::Result<i32>; |
59 | | |
60 | | /// Reads three bytes and interprets them as a little-endian 24-bit unsigned integer. |
61 | | /// |
62 | | /// The most significant byte will be 0. |
63 | | fn read_le_u24(&mut self) -> io::Result<u32>; |
64 | | |
65 | | /// Reads four bytes and interprets them as a little-endian 32-bit signed integer. |
66 | | fn read_le_i32(&mut self) -> io::Result<i32>; |
67 | | |
68 | | /// Reads four bytes and interprets them as a little-endian 32-bit unsigned integer. |
69 | | fn read_le_u32(&mut self) -> io::Result<u32>; |
70 | | |
71 | | /// Reads four bytes and interprets them as a little-endian 32-bit IEEE float. |
72 | | fn read_le_f32(&mut self) -> io::Result<f32>; |
73 | | } |
74 | | |
75 | | impl<R> ReadExt for R |
76 | | where R: io::Read |
77 | | { |
78 | | #[inline(always)] |
79 | 0 | fn read_into(&mut self, buf: &mut [u8]) -> io::Result<()> { |
80 | 0 | let mut n = 0; |
81 | 0 | while n < buf.len() { |
82 | 0 | let progress = try!(self.read(&mut buf[n..])); |
83 | 0 | if progress > 0 { |
84 | 0 | n += progress; |
85 | 0 | } else { |
86 | 0 | return Err(io::Error::new(io::ErrorKind::Other, "Failed to read enough bytes.")); |
87 | | } |
88 | | } |
89 | 0 | Ok(()) |
90 | 0 | } |
91 | | |
92 | | #[inline(always)] |
93 | 0 | fn skip_bytes(&mut self, n: usize) -> io::Result<()> { |
94 | 0 | // Read from the input in chunks of 1024 bytes at a time, and discard |
95 | 0 | // the result. 1024 is a tradeoff between doing a lot of calls, and |
96 | 0 | // using too much stack space. This method is not in a hot path, so it |
97 | 0 | // can afford to do this. |
98 | 0 | let mut n_read = 0; |
99 | 0 | let mut buf = [0u8; 1024]; |
100 | 0 | while n_read < n { |
101 | 0 | let end = cmp::min(n - n_read, 1024); |
102 | 0 | let progress = try!(self.read(&mut buf[0..end])); |
103 | 0 | if progress > 0 { |
104 | 0 | n_read += progress; |
105 | 0 | } else { |
106 | 0 | return Err(io::Error::new(io::ErrorKind::Other, "Failed to read enough bytes.")); |
107 | | } |
108 | | } |
109 | 0 | Ok(()) |
110 | 0 | } |
111 | | |
112 | | #[inline(always)] |
113 | 0 | fn read_bytes(&mut self, n: usize) -> io::Result<Vec<u8>> { |
114 | 0 | // We allocate a runtime fixed size buffer, and we are going to read |
115 | 0 | // into it, so zeroing or filling the buffer is a waste. This method |
116 | 0 | // is safe, because the contents of the buffer are only exposed when |
117 | 0 | // they have been overwritten completely by the read. |
118 | 0 | let mut buf = Vec::with_capacity(n); |
119 | 0 | unsafe { buf.set_len(n); } |
120 | 0 | try!(self.read_into(&mut buf[..])); |
121 | 0 | Ok(buf) |
122 | 0 | } |
123 | | |
124 | | #[inline(always)] |
125 | 0 | fn read_i8(&mut self) -> io::Result<i8> { |
126 | 0 | self.read_u8().map(|x| x as i8) |
127 | 0 | } |
128 | | |
129 | | #[inline(always)] |
130 | 0 | fn read_u8(&mut self) -> io::Result<u8> { |
131 | 0 | let mut buf = [0u8; 1]; |
132 | 0 | try!(self.read_into(&mut buf)); |
133 | 0 | Ok(buf[0]) |
134 | 0 | } |
135 | | |
136 | | #[inline(always)] |
137 | 0 | fn read_le_i16(&mut self) -> io::Result<i16> { |
138 | 0 | self.read_le_u16().map(|x| x as i16) |
139 | 0 | } |
140 | | |
141 | | #[inline(always)] |
142 | 0 | fn read_le_u16(&mut self) -> io::Result<u16> { |
143 | 0 | let mut buf = [0u8; 2]; |
144 | 0 | try!(self.read_into(&mut buf)); |
145 | 0 | Ok((buf[1] as u16) << 8 | (buf[0] as u16)) |
146 | 0 | } |
147 | | |
148 | | #[inline(always)] |
149 | 0 | fn read_le_i24(&mut self) -> io::Result<i32> { |
150 | 0 | self.read_le_u24().map(|x| |
151 | | // Test the sign bit, if it is set, extend the sign bit into the |
152 | | // most significant byte. |
153 | 0 | if x & (1 << 23) == 0 { |
154 | 0 | x as i32 |
155 | | } else { |
156 | 0 | (x | 0xff_00_00_00) as i32 |
157 | 0 | } |
158 | 0 | ) |
159 | 0 | } |
160 | | |
161 | | #[inline(always)] |
162 | 0 | fn read_le_i24_4(&mut self) -> io::Result<i32> { |
163 | 0 | self.read_le_u32().map(|x| |
164 | | // Test the sign bit, if it is set, extend the sign bit into the |
165 | | // most significant byte. Otherwise, mask out the top byte. |
166 | 0 | if x & (1 << 23) == 0 { |
167 | 0 | (x & 0x00_ff_ff_ff) as i32 |
168 | | } else { |
169 | 0 | (x | 0xff_00_00_00) as i32 |
170 | 0 | } |
171 | 0 | ) |
172 | 0 | } |
173 | | |
174 | | #[inline(always)] |
175 | 0 | fn read_le_u24(&mut self) -> io::Result<u32> { |
176 | 0 | let mut buf = [0u8; 3]; |
177 | 0 | try!(self.read_into(&mut buf)); |
178 | 0 | Ok((buf[2] as u32) << 16 | (buf[1] as u32) << 8 | (buf[0] as u32)) |
179 | 0 | } |
180 | | |
181 | | #[inline(always)] |
182 | 0 | fn read_le_i32(&mut self) -> io::Result<i32> { |
183 | 0 | self.read_le_u32().map(|x| x as i32) |
184 | 0 | } |
185 | | |
186 | | #[inline(always)] |
187 | 0 | fn read_le_u32(&mut self) -> io::Result<u32> { |
188 | 0 | let mut buf = [0u8; 4]; |
189 | 0 | try!(self.read_into(&mut buf)); |
190 | 0 | Ok((buf[3] as u32) << 24 | (buf[2] as u32) << 16 | |
191 | 0 | (buf[1] as u32) << 8 | (buf[0] as u32) << 0) |
192 | 0 | } |
193 | | |
194 | | #[inline(always)] |
195 | 0 | fn read_le_f32(&mut self) -> io::Result<f32> { |
196 | 0 | self.read_le_u32().map(|u| unsafe { mem::transmute(u) }) |
197 | 0 | } |
198 | | } |
199 | | |
200 | | /// The different chunks that a WAVE file can contain. |
201 | | enum ChunkKind { |
202 | | Fmt, |
203 | | Fact, |
204 | | Data, |
205 | | Unknown, |
206 | | } |
207 | | |
208 | | /// Describes the structure of a chunk in the WAVE file. |
209 | | struct ChunkHeader { |
210 | | pub kind: ChunkKind, |
211 | | pub len: u32, |
212 | | } |
213 | | |
214 | | /// A reader that reads the WAVE format from the underlying reader. |
215 | | /// |
216 | | /// A `WavReader` is a streaming reader. It reads data from the underlying |
217 | | /// reader on demand, and it reads no more than strictly necessary. No internal |
218 | | /// buffering is performed on the underlying reader, but this can easily be |
219 | | /// added by wrapping the reader in an `io::BufReader`. The `open` constructor |
220 | | /// takes care of this for you. |
221 | | pub struct WavReader<R> { |
222 | | /// Specification of the file as found in the fmt chunk. |
223 | | spec: WavSpec, |
224 | | |
225 | | /// The number of bytes used to store a sample in the stream. |
226 | | bytes_per_sample: u16, |
227 | | |
228 | | /// The number of samples in the data chunk. |
229 | | /// |
230 | | /// The data chunk is limited to a 4 GiB length because its header has a |
231 | | /// 32-bit length field. A sample takes at least one byte to store, so the |
232 | | /// number of samples is always less than 2^32. |
233 | | num_samples: u32, |
234 | | |
235 | | /// The number of samples read so far. |
236 | | samples_read: u32, |
237 | | |
238 | | /// The reader from which the WAVE format is read. |
239 | | reader: R, |
240 | | } |
241 | | |
242 | | /// An iterator that yields samples of type `S` read from a `WavReader`. |
243 | | /// |
244 | | /// The type `S` must have at least as many bits as the bits per sample of the |
245 | | /// file, otherwise every iteration will return an error. |
246 | | pub struct WavSamples<'wr, R, S> |
247 | | where R: 'wr |
248 | | { |
249 | | reader: &'wr mut WavReader<R>, |
250 | | phantom_sample: marker::PhantomData<S>, |
251 | | } |
252 | | |
253 | | /// An iterator that yields samples of type `S` read from a `WavReader`. |
254 | | /// |
255 | | /// The type `S` must have at least as many bits as the bits per sample of the |
256 | | /// file, otherwise every iteration will return an error. |
257 | | pub struct WavIntoSamples<R, S> { |
258 | | reader: WavReader<R>, |
259 | | phantom_sample: marker::PhantomData<S>, |
260 | | } |
261 | | |
262 | | /// Reads the RIFF WAVE header, returns the supposed file size. |
263 | | /// |
264 | | /// This function can be used to quickly check if the file could be a wav file |
265 | | /// by reading 12 bytes of the header. If an `Ok` is returned, the file is |
266 | | /// likely a wav file. If an `Err` is returned, it is definitely not a wav |
267 | | /// file. |
268 | | /// |
269 | | /// The returned file size cannot be larger than 2<sup>32</sup> + 7 bytes. |
270 | 0 | pub fn read_wave_header<R: io::Read>(reader: &mut R) -> Result<u64> { |
271 | 0 | // Every WAVE file starts with the four bytes 'RIFF' and a file length. |
272 | 0 | // TODO: the old approach of having a slice on the stack and reading |
273 | 0 | // into it is more cumbersome, but also avoids a heap allocation. Is |
274 | 0 | // the compiler smart enough to avoid the heap allocation anyway? I |
275 | 0 | // would not expect it to be. |
276 | 0 | if b"RIFF" != &try!(reader.read_bytes(4))[..] { |
277 | 0 | return Err(Error::FormatError("no RIFF tag found")); |
278 | 0 | } |
279 | | |
280 | 0 | let file_len = try!(reader.read_le_u32()); |
281 | | |
282 | | // Next four bytes indicate the file type, which should be WAVE. |
283 | 0 | if b"WAVE" != &try!(reader.read_bytes(4))[..] { |
284 | 0 | return Err(Error::FormatError("no WAVE tag found")); |
285 | 0 | } |
286 | 0 |
|
287 | 0 | // The stored file length does not include the "RIFF" magic and 4-byte |
288 | 0 | // length field, so the total size is 8 bytes more than what is stored. |
289 | 0 | Ok(file_len as u64 + 8) |
290 | 0 | } |
291 | | |
292 | | /// Reads chunks until a data chunk is encountered. |
293 | | /// |
294 | | /// Returns the information from the fmt chunk and the length of the data |
295 | | /// chunk in bytes. Afterwards, the reader will be positioned at the first |
296 | | /// content byte of the data chunk. |
297 | 0 | pub fn read_until_data<R: io::Read>(mut reader: R) -> Result<(WavSpecEx, u32)> { |
298 | 0 | let mut spec_opt = None; |
299 | | |
300 | | loop { |
301 | 0 | let header = try!(WavReader::read_chunk_header(&mut reader)); |
302 | 0 | match header.kind { |
303 | | ChunkKind::Fmt => { |
304 | 0 | let spec = try!(WavReader::read_fmt_chunk(&mut reader, header.len)); |
305 | 0 | spec_opt = Some(spec); |
306 | | } |
307 | 0 | ChunkKind::Fact => { |
308 | 0 | // All (compressed) non-PCM formats must have a fact chunk |
309 | 0 | // (Rev. 3 documentation). The chunk contains at least one |
310 | 0 | // value, the number of samples in the file. |
311 | 0 | // |
312 | 0 | // The number of samples field is redundant for sampled |
313 | 0 | // data, since the Data chunk indicates the length of the |
314 | 0 | // data. The number of samples can be determined from the |
315 | 0 | // length of the data and the container size as determined |
316 | 0 | // from the Format chunk. |
317 | 0 | // http://www-mmsp.ece.mcgill.ca/documents/audioformats/wave/wave.html |
318 | 0 | let _samples_per_channel = reader.read_le_u32(); |
319 | 0 | } |
320 | | ChunkKind::Data => { |
321 | | // The "fmt" chunk must precede the "data" chunk. Any |
322 | | // chunks that come after the data chunk will be ignored. |
323 | 0 | if let Some(spec) = spec_opt { |
324 | 0 | return Ok((spec, header.len)); |
325 | | } else { |
326 | 0 | return Err(Error::FormatError("missing fmt chunk")); |
327 | | } |
328 | | } |
329 | | ChunkKind::Unknown => { |
330 | | // Ignore the chunk; skip all of its bytes. |
331 | 0 | try!(reader.skip_bytes(header.len as usize)); |
332 | | } |
333 | | } |
334 | | // If no data chunk is ever encountered, the function will return |
335 | | // via one of the try! macros that return an Err on end of file. |
336 | | } |
337 | 0 | } |
338 | | |
339 | | impl<R> WavReader<R> |
340 | | where R: io::Read |
341 | | { |
342 | | /// Attempts to read an 8-byte chunk header. |
343 | 0 | fn read_chunk_header(reader: &mut R) -> Result<ChunkHeader> { |
344 | 0 | let mut kind_str = [0; 4]; |
345 | 0 | try!(reader.read_into(&mut kind_str)); |
346 | 0 | let len = try!(reader.read_le_u32()); |
347 | | |
348 | 0 | let kind = match &kind_str[..] { |
349 | 0 | b"fmt " => ChunkKind::Fmt, |
350 | 0 | b"fact" => ChunkKind::Fact, |
351 | 0 | b"data" => ChunkKind::Data, |
352 | 0 | _ => ChunkKind::Unknown, |
353 | | }; |
354 | | |
355 | 0 | Ok(ChunkHeader { kind: kind, len: len }) |
356 | 0 | } |
357 | | |
358 | | /// Reads the fmt chunk of the file, returns the information it provides. |
359 | 0 | fn read_fmt_chunk(reader: &mut R, chunk_len: u32) -> Result<WavSpecEx> { |
360 | 0 | // A minimum chunk length of at least 16 is assumed. Note: actually, |
361 | 0 | // the first 14 bytes contain enough information to fully specify the |
362 | 0 | // file. I have not encountered a file with a 14-byte fmt section |
363 | 0 | // though. If you ever encounter such file, please contact me. |
364 | 0 | if chunk_len < 16 { |
365 | 0 | return Err(Error::FormatError("invalid fmt chunk size")); |
366 | 0 | } |
367 | | |
368 | | // Read the WAVEFORMAT struct, as defined at |
369 | | // https://msdn.microsoft.com/en-us/library/ms713498.aspx. |
370 | | // ``` |
371 | | // typedef struct { |
372 | | // WORD wFormatTag; |
373 | | // WORD nChannels; |
374 | | // DWORD nSamplesPerSec; |
375 | | // DWORD nAvgBytesPerSec; |
376 | | // WORD nBlockAlign; |
377 | | // } WAVEFORMAT; |
378 | | // ``` |
379 | | // The WAVEFORMATEX struct has two more members, as defined at |
380 | | // https://msdn.microsoft.com/en-us/library/ms713497.aspx |
381 | | // ``` |
382 | | // typedef struct { |
383 | | // WORD wFormatTag; |
384 | | // WORD nChannels; |
385 | | // DWORD nSamplesPerSec; |
386 | | // DWORD nAvgBytesPerSec; |
387 | | // WORD nBlockAlign; |
388 | | // WORD wBitsPerSample; |
389 | | // WORD cbSize; |
390 | | // } WAVEFORMATEX; |
391 | | // ``` |
392 | | // There is also PCMWAVEFORMAT as defined at |
393 | | // https://msdn.microsoft.com/en-us/library/dd743663.aspx. |
394 | | // ``` |
395 | | // typedef struct { |
396 | | // WAVEFORMAT wf; |
397 | | // WORD wBitsPerSample; |
398 | | // } PCMWAVEFORMAT; |
399 | | // ``` |
400 | | // In either case, the minimal length of the fmt section is 16 bytes, |
401 | | // meaning that it does include the `wBitsPerSample` field. (The name |
402 | | // is misleading though, because it is the number of bits used to store |
403 | | // a sample, not all of the bits need to be valid for all versions of |
404 | | // the WAVE format.) |
405 | 0 | let format_tag = try!(reader.read_le_u16()); |
406 | 0 | let n_channels = try!(reader.read_le_u16()); |
407 | 0 | let n_samples_per_sec = try!(reader.read_le_u32()); |
408 | 0 | let n_bytes_per_sec = try!(reader.read_le_u32()); |
409 | 0 | let block_align = try!(reader.read_le_u16()); |
410 | 0 | let bits_per_sample = try!(reader.read_le_u16()); |
411 | | |
412 | 0 | if n_channels == 0 { |
413 | 0 | return Err(Error::FormatError("file contains zero channels")); |
414 | 0 | } |
415 | 0 |
|
416 | 0 | let bytes_per_sample = block_align / n_channels; |
417 | 0 | // We allow bits_per_sample to be less than bytes_per_sample so that |
418 | 0 | // we can support things such as 24 bit samples in 4 byte containers. |
419 | 0 | if Some(bits_per_sample) > bytes_per_sample.checked_mul(8) { |
420 | 0 | return Err(Error::FormatError("sample bits exceeds size of sample")); |
421 | 0 | } |
422 | 0 |
|
423 | 0 | // This field is redundant, and may be ignored. We do validate it to |
424 | 0 | // fail early for ill-formed files. |
425 | 0 | if Some(n_bytes_per_sec) != (block_align as u32).checked_mul(n_samples_per_sec) { |
426 | 0 | return Err(Error::FormatError("inconsistent fmt chunk")); |
427 | 0 | } |
428 | 0 |
|
429 | 0 | // The bits per sample for a WAVEFORMAT struct is the number of bits |
430 | 0 | // used to store a sample. Therefore, it must be a multiple of 8. |
431 | 0 | if bits_per_sample % 8 != 0 { |
432 | 0 | return Err(Error::FormatError("bits per sample is not a multiple of 8")); |
433 | 0 | } |
434 | 0 |
|
435 | 0 | if bits_per_sample == 0 { |
436 | 0 | return Err(Error::FormatError("bits per sample is 0")); |
437 | 0 | } |
438 | 0 |
|
439 | 0 | let mut spec = WavSpec { |
440 | 0 | channels: n_channels, |
441 | 0 | sample_rate: n_samples_per_sec, |
442 | 0 | bits_per_sample: bits_per_sample, |
443 | 0 | sample_format: SampleFormat::Int, |
444 | 0 | }; |
445 | | |
446 | | // The different format tag definitions can be found in mmreg.h that is |
447 | | // part of the Windows SDK. The vast majority are esoteric vendor- |
448 | | // specific formats. We handle only a few. The following values could |
449 | | // be of interest: |
450 | | const PCM: u16 = 0x0001; |
451 | | const ADPCM: u16 = 0x0002; |
452 | | const IEEE_FLOAT: u16 = 0x0003; |
453 | | const EXTENSIBLE: u16 = 0xfffe; |
454 | | // We may update our WavSpec based on more data we read from the header. |
455 | 0 | match format_tag { |
456 | 0 | PCM => try!(WavReader::read_wave_format_pcm(reader, chunk_len, &spec)), |
457 | 0 | ADPCM => return Err(Error::Unsupported), |
458 | 0 | IEEE_FLOAT => try!(WavReader::read_wave_format_ieee_float(reader, chunk_len, &mut spec)), |
459 | 0 | EXTENSIBLE => try!(WavReader::read_wave_format_extensible(reader, chunk_len, &mut spec)), |
460 | 0 | _ => return Err(Error::Unsupported), |
461 | | }; |
462 | | |
463 | 0 | Ok(WavSpecEx { |
464 | 0 | spec: spec, |
465 | 0 | bytes_per_sample: bytes_per_sample, |
466 | 0 | }) |
467 | 0 | } |
468 | | |
469 | 0 | fn read_wave_format_pcm(mut reader: R, chunk_len: u32, spec: &WavSpec) -> Result<()> { |
470 | | // When there is a PCMWAVEFORMAT struct, the chunk is 16 bytes long. |
471 | | // The WAVEFORMATEX structs includes two extra bytes, `cbSize`. |
472 | 0 | let is_wave_format_ex = match chunk_len { |
473 | 0 | 16 => false, |
474 | 0 | 18 => true, |
475 | | // Other sizes are unexpected, but such files do occur in the wild, |
476 | | // and reading these files is still possible, so we allow this. |
477 | 0 | 40 => true, |
478 | 0 | _ => return Err(Error::FormatError("unexpected fmt chunk size")), |
479 | | }; |
480 | | |
481 | 0 | if is_wave_format_ex { |
482 | | // `cbSize` can be used for non-PCM formats to specify the size of |
483 | | // additional data. However, for WAVE_FORMAT_PCM, the member should |
484 | | // be ignored, see https://msdn.microsoft.com/en-us/library/ms713497.aspx. |
485 | | // Nonzero values do in fact occur in practice. |
486 | 0 | let _cb_size = try!(reader.read_le_u16()); |
487 | | |
488 | | // For WAVE_FORMAT_PCM in WAVEFORMATEX, only 8 or 16 bits per |
489 | | // sample are valid according to |
490 | | // https://msdn.microsoft.com/en-us/library/ms713497.aspx. |
491 | | // 24 bits per sample is explicitly not valid inside a WAVEFORMATEX |
492 | | // structure, but such files do occur in the wild nonetheless, and |
493 | | // there is no good reason why we couldn't read them. |
494 | 0 | match spec.bits_per_sample { |
495 | 0 | 8 => {} |
496 | 0 | 16 => {} |
497 | 0 | 24 => {} |
498 | 0 | _ => return Err(Error::FormatError("bits per sample is not 8 or 16")), |
499 | | } |
500 | 0 | } |
501 | | |
502 | | // If the chunk len was longer than expected, ignore the additional bytes. |
503 | 0 | if chunk_len == 40 { |
504 | 0 | try!(reader.skip_bytes(22)); |
505 | 0 | } |
506 | 0 | Ok(()) |
507 | 0 | } |
508 | | |
509 | 0 | fn read_wave_format_ieee_float(mut reader: R, chunk_len: u32, spec: &mut WavSpec) -> Result<()> { |
510 | 0 | // When there is a PCMWAVEFORMAT struct, the chunk is 16 bytes long. |
511 | 0 | // The WAVEFORMATEX structs includes two extra bytes, `cbSize`. |
512 | 0 | let is_wave_format_ex = chunk_len == 18; |
513 | 0 |
|
514 | 0 | if !is_wave_format_ex && chunk_len != 16 { |
515 | 0 | return Err(Error::FormatError("unexpected fmt chunk size")); |
516 | 0 | } |
517 | 0 |
|
518 | 0 | if is_wave_format_ex { |
519 | | // For WAVE_FORMAT_IEEE_FLOAT which we are reading, there should |
520 | | // be no extra data, so `cbSize` should be 0. |
521 | 0 | let cb_size = try!(reader.read_le_u16()); |
522 | 0 | if cb_size != 0 { |
523 | 0 | return Err(Error::FormatError("unexpected WAVEFORMATEX size")); |
524 | 0 | } |
525 | 0 | } |
526 | | |
527 | | // For WAVE_FORMAT_IEEE_FLOAT, the bits_per_sample field should be |
528 | | // set to `32` according to |
529 | | // https://msdn.microsoft.com/en-us/library/windows/hardware/ff538799(v=vs.85).aspx. |
530 | | // |
531 | | // Note that some applications support 64 bits per sample. This is |
532 | | // not yet supported by hound. |
533 | 0 | if spec.bits_per_sample != 32 { |
534 | 0 | return Err(Error::FormatError("bits per sample is not 32")); |
535 | 0 | } |
536 | 0 |
|
537 | 0 | spec.sample_format = SampleFormat::Float; |
538 | 0 | Ok(()) |
539 | 0 | } |
540 | | |
541 | 0 | fn read_wave_format_extensible(mut reader: R, chunk_len: u32, spec: &mut WavSpec) -> Result<()> { |
542 | 0 | // 16 bytes were read already, there must be two more for the `cbSize` |
543 | 0 | // field, and `cbSize` itself must be at least 22, so the chunk length |
544 | 0 | // must be at least 40. |
545 | 0 | if chunk_len < 40 { |
546 | 0 | return Err(Error::FormatError("unexpected fmt chunk size")); |
547 | 0 | } |
548 | | |
549 | | // `cbSize` is the last field of the WAVEFORMATEX struct. |
550 | 0 | let cb_size = try!(reader.read_le_u16()); |
551 | | |
552 | | // `cbSize` must be at least 22, but in this case we assume that it is |
553 | | // 22, because we would not know how to handle extra data anyway. |
554 | 0 | if cb_size != 22 { |
555 | 0 | return Err(Error::FormatError("unexpected WAVEFORMATEXTENSIBLE size")); |
556 | 0 | } |
557 | | |
558 | | // What follows is the rest of the `WAVEFORMATEXTENSIBLE` struct, as |
559 | | // defined at https://msdn.microsoft.com/en-us/library/ms713496.aspx. |
560 | | // ``` |
561 | | // typedef struct { |
562 | | // WAVEFORMATEX Format; |
563 | | // union { |
564 | | // WORD wValidBitsPerSample; |
565 | | // WORD wSamplesPerBlock; |
566 | | // WORD wReserved; |
567 | | // } Samples; |
568 | | // DWORD dwChannelMask; |
569 | | // GUID SubFormat; |
570 | | // } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; |
571 | | // ``` |
572 | 0 | let valid_bits_per_sample = try!(reader.read_le_u16()); |
573 | 0 | let _channel_mask = try!(reader.read_le_u32()); // Not used for now. |
574 | 0 | let mut subformat = [0u8; 16]; |
575 | 0 | try!(reader.read_into(&mut subformat)); |
576 | | |
577 | | // Several GUIDS are defined. At the moment, only the following are supported: |
578 | | // |
579 | | // * KSDATAFORMAT_SUBTYPE_PCM (PCM audio with integer samples). |
580 | | // * KSDATAFORMAT_SUBTYPE_IEEE_FLOAT (PCM audio with floating point samples). |
581 | 0 | let sample_format = match subformat { |
582 | 0 | super::KSDATAFORMAT_SUBTYPE_PCM => SampleFormat::Int, |
583 | 0 | super::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT => SampleFormat::Float, |
584 | 0 | _ => return Err(Error::Unsupported), |
585 | | }; |
586 | | |
587 | | // Fallback to bits_per_sample if the valid_bits_per_sample is obviously wrong to support non standard headers found in the wild. |
588 | 0 | if valid_bits_per_sample > 0 { |
589 | 0 | spec.bits_per_sample = valid_bits_per_sample; |
590 | 0 | } |
591 | | |
592 | 0 | spec.sample_format = sample_format; |
593 | 0 | Ok(()) |
594 | 0 | } |
595 | | |
596 | | /// Attempts to create a reader that reads the WAVE format. |
597 | | /// |
598 | | /// The header is read immediately. Reading the data will be done on |
599 | | /// demand. |
600 | 0 | pub fn new(mut reader: R) -> Result<WavReader<R>> { |
601 | 0 | try!(read_wave_header(&mut reader)); |
602 | 0 | let (spec_ex, data_len) = try!(read_until_data(&mut reader)); |
603 | | |
604 | 0 | let num_samples = data_len / spec_ex.bytes_per_sample as u32; |
605 | 0 |
|
606 | 0 | // It could be that num_samples * bytes_per_sample < data_len. |
607 | 0 | // If data_len is not a multiple of bytes_per_sample, there is some |
608 | 0 | // trailing data. Either somebody is playing some steganography game, |
609 | 0 | // but more likely something is very wrong, and we should refuse to |
610 | 0 | // decode the file, as it is invalid. |
611 | 0 | if num_samples * spec_ex.bytes_per_sample as u32 != data_len { |
612 | 0 | let msg = "data chunk length is not a multiple of sample size"; |
613 | 0 | return Err(Error::FormatError(msg)); |
614 | 0 | } |
615 | 0 |
|
616 | 0 | // The number of samples must be a multiple of the number of channels, |
617 | 0 | // otherwise the last inter-channel sample would not have data for all |
618 | 0 | // channels. |
619 | 0 | if num_samples % spec_ex.spec.channels as u32 != 0 { |
620 | 0 | return Err(Error::FormatError("invalid data chunk length")); |
621 | 0 | } |
622 | 0 |
|
623 | 0 | let wav_reader = WavReader { |
624 | 0 | spec: spec_ex.spec, |
625 | 0 | bytes_per_sample: spec_ex.bytes_per_sample, |
626 | 0 | num_samples: num_samples, |
627 | 0 | samples_read: 0, |
628 | 0 | reader: reader, |
629 | 0 | }; |
630 | 0 |
|
631 | 0 | Ok(wav_reader) |
632 | 0 | } |
633 | | |
634 | | /// Returns information about the WAVE file. |
635 | 0 | pub fn spec(&self) -> WavSpec { |
636 | 0 | self.spec |
637 | 0 | } |
638 | | |
639 | | /// Returns an iterator over all samples. |
640 | | /// |
641 | | /// The channel data is interleaved. The iterator is streaming. That is, |
642 | | /// if you call this method once, read a few samples, and call this method |
643 | | /// again, the second iterator will not start again from the beginning of |
644 | | /// the file, it will continue where the first iterator stopped. |
645 | | /// |
646 | | /// The type `S` must have at least `spec().bits_per_sample` bits, |
647 | | /// otherwise every iteration will return an error. All bit depths up to |
648 | | /// 32 bits per sample can be decoded into an `i32`, but if you know |
649 | | /// beforehand that you will be reading a file with 16 bits per sample, you |
650 | | /// can save memory by decoding into an `i16`. |
651 | | /// |
652 | | /// The type of `S` (int or float) must match `spec().sample_format`, |
653 | | /// otherwise every iteration will return an error. |
654 | 0 | pub fn samples<'wr, S: Sample>(&'wr mut self) -> WavSamples<'wr, R, S> { |
655 | 0 | WavSamples { |
656 | 0 | reader: self, |
657 | 0 | phantom_sample: marker::PhantomData, |
658 | 0 | } |
659 | 0 | } |
660 | | |
661 | | /// Same as `samples`, but takes ownership of the `WavReader`. |
662 | | /// |
663 | | /// See `samples()` for more info. |
664 | 0 | pub fn into_samples<S: Sample>(self) -> WavIntoSamples<R, S> { |
665 | 0 | WavIntoSamples { |
666 | 0 | reader: self, |
667 | 0 | phantom_sample: marker::PhantomData, |
668 | 0 | } |
669 | 0 | } |
670 | | |
671 | | /// Returns the duration of the file in samples. |
672 | | /// |
673 | | /// The duration is independent of the number of channels. It is expressed |
674 | | /// in units of samples. The duration in seconds can be obtained by |
675 | | /// dividing this number by the sample rate. The duration is independent of |
676 | | /// how many samples have been read already. |
677 | 0 | pub fn duration(&self) -> u32 { |
678 | 0 | self.num_samples / self.spec.channels as u32 |
679 | 0 | } |
680 | | |
681 | | /// Returns the number of values that the sample iterator will yield. |
682 | | /// |
683 | | /// The length of the file is its duration (in samples) times the number of |
684 | | /// channels. The length is independent of how many samples have been read |
685 | | /// already. To get the number of samples left, use `len()` on the |
686 | | /// `samples()` iterator. |
687 | 0 | pub fn len(&self) -> u32 { |
688 | 0 | self.num_samples |
689 | 0 | } |
690 | | |
691 | | /// Destroys the `WavReader` and returns the underlying reader. |
692 | 0 | pub fn into_inner(self) -> R { |
693 | 0 | self.reader |
694 | 0 | } |
695 | | |
696 | | /// Seek to the given time within the file. |
697 | | /// |
698 | | /// The given time is measured in number of samples (independent of the |
699 | | /// number of channels) since the beginning of the audio data. To seek to |
700 | | /// a particular time in seconds, multiply the number of seconds with |
701 | | /// `WavSpec::sample_rate`. The given time should not exceed the duration of |
702 | | /// the file (returned by `duration()`). The behavior when seeking beyond |
703 | | /// `duration()` depends on the reader's `Seek` implementation. |
704 | | /// |
705 | | /// This method requires that the inner reader `R` implements `Seek`. |
706 | 0 | pub fn seek(&mut self, time: u32) -> io::Result<()> |
707 | 0 | where R: io::Seek, |
708 | 0 | { |
709 | 0 | let bytes_per_sample = self.spec.bits_per_sample / 8; |
710 | 0 | let sample_position = time * self.spec.channels as u32; |
711 | 0 | let offset_samples = sample_position as i64 - self.samples_read as i64; |
712 | 0 | let offset_bytes = offset_samples * bytes_per_sample as i64; |
713 | 0 | try!(self.reader.seek(io::SeekFrom::Current(offset_bytes))); |
714 | 0 | self.samples_read = sample_position; |
715 | 0 | Ok(()) |
716 | 0 | } |
717 | | } |
718 | | |
719 | | impl WavReader<io::BufReader<fs::File>> { |
720 | | /// Attempts to create a reader that reads from the specified file. |
721 | | /// |
722 | | /// This is a convenience constructor that opens a `File`, wraps it in a |
723 | | /// `BufReader` and then constructs a `WavReader` from it. |
724 | 0 | pub fn open<P: AsRef<path::Path>>(filename: P) -> Result<WavReader<io::BufReader<fs::File>>> { |
725 | 0 | let file = try!(fs::File::open(filename)); |
726 | 0 | let buf_reader = io::BufReader::new(file); |
727 | 0 | WavReader::new(buf_reader) |
728 | 0 | } |
729 | | } |
730 | | |
731 | 0 | fn iter_next<R, S>(reader: &mut WavReader<R>) -> Option<Result<S>> |
732 | 0 | where R: io::Read, |
733 | 0 | S: Sample |
734 | 0 | { |
735 | 0 | if reader.samples_read < reader.num_samples { |
736 | 0 | reader.samples_read += 1; |
737 | 0 | let sample = Sample::read(&mut reader.reader, |
738 | 0 | reader.spec.sample_format, |
739 | 0 | reader.bytes_per_sample, |
740 | 0 | reader.spec.bits_per_sample); |
741 | 0 | Some(sample.map_err(Error::from)) |
742 | | } else { |
743 | 0 | None |
744 | | } |
745 | 0 | } |
746 | | |
747 | 0 | fn iter_size_hint<R>(reader: &WavReader<R>) -> (usize, Option<usize>) { |
748 | 0 | let samples_left = reader.num_samples - reader.samples_read; |
749 | 0 | (samples_left as usize, Some(samples_left as usize)) |
750 | 0 | } |
751 | | |
752 | | impl<'wr, R, S> Iterator for WavSamples<'wr, R, S> |
753 | | where R: io::Read, |
754 | | S: Sample |
755 | | { |
756 | | type Item = Result<S>; |
757 | | |
758 | 0 | fn next(&mut self) -> Option<Result<S>> { |
759 | 0 | iter_next(&mut self.reader) |
760 | 0 | } |
761 | | |
762 | 0 | fn size_hint(&self) -> (usize, Option<usize>) { |
763 | 0 | iter_size_hint(&self.reader) |
764 | 0 | } |
765 | | } |
766 | | |
767 | | impl<'wr, R, S> ExactSizeIterator for WavSamples<'wr, R, S> |
768 | | where R: io::Read, |
769 | | S: Sample |
770 | | { |
771 | | } |
772 | | |
773 | | impl<R, S> Iterator for WavIntoSamples<R, S> |
774 | | where R: io::Read, |
775 | | S: Sample |
776 | | { |
777 | | type Item = Result<S>; |
778 | | |
779 | 0 | fn next(&mut self) -> Option<Result<S>> { |
780 | 0 | iter_next(&mut self.reader) |
781 | 0 | } |
782 | | |
783 | 0 | fn size_hint(&self) -> (usize, Option<usize>) { |
784 | 0 | iter_size_hint(&self.reader) |
785 | 0 | } |
786 | | } |
787 | | |
788 | | impl<R, S> ExactSizeIterator for WavIntoSamples<R, S> |
789 | | where R: io::Read, |
790 | | S: Sample |
791 | | { |
792 | | } |
793 | | |
794 | | #[test] |
795 | | fn duration_and_len_agree() { |
796 | | let files = &["testsamples/pcmwaveformat-16bit-44100Hz-mono.wav", |
797 | | "testsamples/waveformatex-16bit-44100Hz-stereo.wav", |
798 | | "testsamples/waveformatextensible-32bit-48kHz-stereo.wav"]; |
799 | | |
800 | | for fname in files { |
801 | | let reader = WavReader::open(fname).unwrap(); |
802 | | assert_eq!(reader.spec().channels as u32 * reader.duration(), |
803 | | reader.len()); |
804 | | } |
805 | | } |
806 | | |
807 | | /// Tests reading a wave file with the PCMWAVEFORMAT struct. |
808 | | #[test] |
809 | | fn read_wav_pcm_wave_format_pcm() { |
810 | | let mut wav_reader = WavReader::open("testsamples/pcmwaveformat-16bit-44100Hz-mono.wav") |
811 | | .unwrap(); |
812 | | |
813 | | assert_eq!(wav_reader.spec().channels, 1); |
814 | | assert_eq!(wav_reader.spec().sample_rate, 44100); |
815 | | assert_eq!(wav_reader.spec().bits_per_sample, 16); |
816 | | assert_eq!(wav_reader.spec().sample_format, SampleFormat::Int); |
817 | | |
818 | | let samples: Vec<i16> = wav_reader.samples() |
819 | | .map(|r| r.unwrap()) |
820 | | .collect(); |
821 | | |
822 | | // The test file has been prepared with these exact four samples. |
823 | | assert_eq!(&samples[..], &[2, -3, 5, -7]); |
824 | | } |
825 | | |
826 | | #[test] |
827 | | fn read_wav_skips_unknown_chunks() { |
828 | | // The test samples are the same as without the -extra suffix, but ffmpeg |
829 | | // has kindly added some useless chunks in between the fmt and data chunk. |
830 | | let files = ["testsamples/pcmwaveformat-16bit-44100Hz-mono-extra.wav", |
831 | | "testsamples/waveformatex-16bit-44100Hz-mono-extra.wav"]; |
832 | | |
833 | | for file in &files { |
834 | | let mut wav_reader = WavReader::open(file).unwrap(); |
835 | | |
836 | | assert_eq!(wav_reader.spec().channels, 1); |
837 | | assert_eq!(wav_reader.spec().sample_rate, 44100); |
838 | | assert_eq!(wav_reader.spec().bits_per_sample, 16); |
839 | | assert_eq!(wav_reader.spec().sample_format, SampleFormat::Int); |
840 | | |
841 | | let sample = wav_reader.samples::<i16>().next().unwrap().unwrap(); |
842 | | assert_eq!(sample, 2); |
843 | | } |
844 | | } |
845 | | |
846 | | #[test] |
847 | | fn read_wav_0_valid_bits_fallback() { |
848 | | let mut wav_reader = WavReader::open("testsamples/nonstandard-02.wav") |
849 | | .unwrap(); |
850 | | |
851 | | assert_eq!(wav_reader.spec().channels, 2); |
852 | | assert_eq!(wav_reader.spec().sample_rate, 48000); |
853 | | assert_eq!(wav_reader.spec().bits_per_sample, 32); |
854 | | assert_eq!(wav_reader.spec().sample_format, SampleFormat::Int); |
855 | | |
856 | | let samples: Vec<i32> = wav_reader.samples() |
857 | | .map(|r| r.unwrap()) |
858 | | .collect(); |
859 | | |
860 | | // The test file has been prepared with these exact four samples. |
861 | | assert_eq!(&samples[..], &[19, -229373, 33587161, -2147483497]); |
862 | | } |
863 | | |
864 | | #[test] |
865 | | fn len_and_size_hint_are_correct() { |
866 | | let mut wav_reader = WavReader::open("testsamples/pcmwaveformat-16bit-44100Hz-mono.wav") |
867 | | .unwrap(); |
868 | | |
869 | | assert_eq!(wav_reader.len(), 4); |
870 | | |
871 | | { |
872 | | let mut samples = wav_reader.samples::<i16>(); |
873 | | |
874 | | assert_eq!(samples.size_hint(), (4, Some(4))); |
875 | | samples.next(); |
876 | | assert_eq!(samples.size_hint(), (3, Some(3))); |
877 | | } |
878 | | |
879 | | // Reading should not affect the initial length. |
880 | | assert_eq!(wav_reader.len(), 4); |
881 | | |
882 | | // Creating a new iterator resumes where the previous iterator stopped. |
883 | | { |
884 | | let mut samples = wav_reader.samples::<i16>(); |
885 | | |
886 | | assert_eq!(samples.size_hint(), (3, Some(3))); |
887 | | samples.next(); |
888 | | assert_eq!(samples.size_hint(), (2, Some(2))); |
889 | | } |
890 | | } |
891 | | |
892 | | #[test] |
893 | | fn size_hint_is_exact() { |
894 | | let files = &["testsamples/pcmwaveformat-16bit-44100Hz-mono.wav", |
895 | | "testsamples/waveformatex-16bit-44100Hz-stereo.wav", |
896 | | "testsamples/waveformatextensible-32bit-48kHz-stereo.wav"]; |
897 | | |
898 | | for fname in files { |
899 | | let mut reader = WavReader::open(fname).unwrap(); |
900 | | let len = reader.len(); |
901 | | let mut iter = reader.samples::<i32>(); |
902 | | for i in 0..len { |
903 | | let remaining = (len - i) as usize; |
904 | | assert_eq!(iter.size_hint(), (remaining, Some(remaining))); |
905 | | assert!(iter.next().is_some()); |
906 | | } |
907 | | assert!(iter.next().is_none()); |
908 | | } |
909 | | } |
910 | | |
911 | | #[test] |
912 | | fn samples_equals_into_samples() { |
913 | | let wav_reader_val = WavReader::open("testsamples/pcmwaveformat-8bit-44100Hz-mono.wav").unwrap(); |
914 | | let mut wav_reader_ref = WavReader::open("testsamples/pcmwaveformat-8bit-44100Hz-mono.wav").unwrap(); |
915 | | |
916 | | let samples_val: Vec<i16> = wav_reader_val.into_samples() |
917 | | .map(|r| r.unwrap()) |
918 | | .collect(); |
919 | | |
920 | | let samples_ref: Vec<i16> = wav_reader_ref.samples() |
921 | | .map(|r| r.unwrap()) |
922 | | .collect(); |
923 | | |
924 | | assert_eq!(samples_val, samples_ref); |
925 | | } |
926 | | |
927 | | /// Tests reading a wave file with the WAVEFORMATEX struct. |
928 | | #[test] |
929 | | fn read_wav_wave_format_ex_pcm() { |
930 | | let mut wav_reader = WavReader::open("testsamples/waveformatex-16bit-44100Hz-mono.wav") |
931 | | .unwrap(); |
932 | | |
933 | | assert_eq!(wav_reader.spec().channels, 1); |
934 | | assert_eq!(wav_reader.spec().sample_rate, 44100); |
935 | | assert_eq!(wav_reader.spec().bits_per_sample, 16); |
936 | | assert_eq!(wav_reader.spec().sample_format, SampleFormat::Int); |
937 | | |
938 | | let samples: Vec<i16> = wav_reader.samples() |
939 | | .map(|r| r.unwrap()) |
940 | | .collect(); |
941 | | |
942 | | // The test file has been prepared with these exact four samples. |
943 | | assert_eq!(&samples[..], &[2, -3, 5, -7]); |
944 | | } |
945 | | |
946 | | #[test] |
947 | | fn read_wav_wave_format_ex_ieee_float() { |
948 | | let mut wav_reader = WavReader::open("testsamples/waveformatex-ieeefloat-44100Hz-mono.wav") |
949 | | .unwrap(); |
950 | | |
951 | | assert_eq!(wav_reader.spec().channels, 1); |
952 | | assert_eq!(wav_reader.spec().sample_rate, 44100); |
953 | | assert_eq!(wav_reader.spec().bits_per_sample, 32); |
954 | | assert_eq!(wav_reader.spec().sample_format, SampleFormat::Float); |
955 | | |
956 | | let samples: Vec<f32> = wav_reader.samples() |
957 | | .map(|r| r.unwrap()) |
958 | | .collect(); |
959 | | |
960 | | // The test file has been prepared with these exact four samples. |
961 | | assert_eq!(&samples[..], &[2.0, 3.0, -16411.0, 1019.0]); |
962 | | } |
963 | | |
964 | | #[test] |
965 | | fn read_wav_stereo() { |
966 | | let mut wav_reader = WavReader::open("testsamples/waveformatex-16bit-44100Hz-stereo.wav") |
967 | | .unwrap(); |
968 | | |
969 | | assert_eq!(wav_reader.spec().channels, 2); |
970 | | assert_eq!(wav_reader.spec().sample_rate, 44100); |
971 | | assert_eq!(wav_reader.spec().bits_per_sample, 16); |
972 | | assert_eq!(wav_reader.spec().sample_format, SampleFormat::Int); |
973 | | |
974 | | let samples: Vec<i16> = wav_reader.samples() |
975 | | .map(|r| r.unwrap()) |
976 | | .collect(); |
977 | | |
978 | | // The test file has been prepared with these exact eight samples. |
979 | | assert_eq!(&samples[..], &[2, -3, 5, -7, 11, -13, 17, -19]); |
980 | | |
981 | | } |
982 | | |
983 | | #[test] |
984 | | fn read_wav_pcm_wave_format_8bit() { |
985 | | let mut wav_reader = WavReader::open("testsamples/pcmwaveformat-8bit-44100Hz-mono.wav") |
986 | | .unwrap(); |
987 | | |
988 | | assert_eq!(wav_reader.spec().channels, 1); |
989 | | assert_eq!(wav_reader.spec().bits_per_sample, 8); |
990 | | assert_eq!(wav_reader.spec().sample_format, SampleFormat::Int); |
991 | | |
992 | | let samples: Vec<i16> = wav_reader.samples() |
993 | | .map(|r| r.unwrap()) |
994 | | .collect(); |
995 | | |
996 | | // The test file has been prepared with these exact four samples. |
997 | | assert_eq!(&samples[..], &[19, -53, 89, -127]); |
998 | | } |
999 | | |
1000 | | /// Test reading 24 bit samples in a 4 byte container using the pcmwaveformat header. This is |
1001 | | /// technically a non-compliant wave file, but it is the sort of file generated by |
1002 | | /// 'arecord -f S24_LE -r 48000 -c 2 input.wav' so it should be supported. |
1003 | | #[test] |
1004 | | fn read_wav_pcm_wave_format_24bit_4byte() { |
1005 | | let mut wav_reader = WavReader::open("testsamples/pcmwaveformat-24bit-4byte-48kHz-stereo.wav") |
1006 | | .unwrap(); |
1007 | | |
1008 | | assert_eq!(wav_reader.spec().channels, 2); |
1009 | | assert_eq!(wav_reader.spec().sample_rate, 48_000); |
1010 | | assert_eq!(wav_reader.spec().bits_per_sample, 24); |
1011 | | assert_eq!(wav_reader.spec().sample_format, SampleFormat::Int); |
1012 | | |
1013 | | let samples: Vec<i32> = wav_reader.samples() |
1014 | | .map(|r| r.unwrap()) |
1015 | | .collect(); |
1016 | | |
1017 | | // The test file has been prepared with these exact four samples. |
1018 | | assert_eq!(&samples[..], &[-96, 23_052, 8_388_607, -8_360_672]); |
1019 | | } |
1020 | | |
1021 | | /// Regression test for a real-world wav file encountered in Quake. |
1022 | | #[test] |
1023 | | fn read_wav_wave_format_ex_8bit() { |
1024 | | let mut wav_reader = WavReader::open("testsamples/waveformatex-8bit-11025Hz-mono.wav").unwrap(); |
1025 | | |
1026 | | assert_eq!(wav_reader.spec().channels, 1); |
1027 | | assert_eq!(wav_reader.spec().bits_per_sample, 8); |
1028 | | assert_eq!(wav_reader.spec().sample_format, SampleFormat::Int); |
1029 | | |
1030 | | let samples: Vec<i32> = wav_reader.samples() |
1031 | | .map(|r| r.unwrap()) |
1032 | | .collect(); |
1033 | | |
1034 | | // The audio data has been zeroed out, but for 8-bit files, a zero means a |
1035 | | // sample value of 128. |
1036 | | assert_eq!(&samples[..], &[-128, -128, -128, -128]); |
1037 | | } |
1038 | | |
1039 | | /// This test sample tests both reading the WAVEFORMATEXTENSIBLE header, and 24-bit samples. |
1040 | | #[test] |
1041 | | fn read_wav_wave_format_extensible_pcm_24bit() { |
1042 | | let mut wav_reader = WavReader::open("testsamples/waveformatextensible-24bit-192kHz-mono.wav") |
1043 | | .unwrap(); |
1044 | | |
1045 | | assert_eq!(wav_reader.spec().channels, 1); |
1046 | | assert_eq!(wav_reader.spec().sample_rate, 192_000); |
1047 | | assert_eq!(wav_reader.spec().bits_per_sample, 24); |
1048 | | assert_eq!(wav_reader.spec().sample_format, SampleFormat::Int); |
1049 | | |
1050 | | let samples: Vec<i32> = wav_reader.samples() |
1051 | | .map(|r| r.unwrap()) |
1052 | | .collect(); |
1053 | | |
1054 | | // The test file has been prepared with these exact four samples. |
1055 | | assert_eq!(&samples[..], &[-17, 4_194_319, -6_291_437, 8_355_817]); |
1056 | | } |
1057 | | |
1058 | | /// This test sample tests both reading the WAVEFORMATEXTENSIBLE header, and 24-bit samples with a |
1059 | | /// 4 byte container size. |
1060 | | #[test] |
1061 | | fn read_wav_wave_format_extensible_pcm_24bit_4byte() { |
1062 | | let mut wav_reader = WavReader::open("testsamples/waveformatextensible-24bit-4byte-48kHz-stereo.wav") |
1063 | | .unwrap(); |
1064 | | |
1065 | | assert_eq!(wav_reader.spec().channels, 2); |
1066 | | assert_eq!(wav_reader.spec().sample_rate, 48_000); |
1067 | | assert_eq!(wav_reader.spec().bits_per_sample, 24); |
1068 | | assert_eq!(wav_reader.spec().sample_format, SampleFormat::Int); |
1069 | | |
1070 | | let samples: Vec<i32> = wav_reader.samples() |
1071 | | .map(|r| r.unwrap()) |
1072 | | .collect(); |
1073 | | |
1074 | | // The test file has been prepared with these exact four samples. |
1075 | | assert_eq!(&samples[..], &[-96, 23_052, 8_388_607, -8_360_672]); |
1076 | | } |
1077 | | |
1078 | | #[test] |
1079 | | fn read_wav_32bit() { |
1080 | | let mut wav_reader = WavReader::open("testsamples/waveformatextensible-32bit-48kHz-stereo.wav") |
1081 | | .unwrap(); |
1082 | | |
1083 | | assert_eq!(wav_reader.spec().bits_per_sample, 32); |
1084 | | assert_eq!(wav_reader.spec().sample_format, SampleFormat::Int); |
1085 | | |
1086 | | let samples: Vec<i32> = wav_reader.samples() |
1087 | | .map(|r| r.unwrap()) |
1088 | | .collect(); |
1089 | | |
1090 | | // The test file has been prepared with these exact four samples. |
1091 | | assert_eq!(&samples[..], &[19, -229_373, 33_587_161, -2_147_483_497]); |
1092 | | } |
1093 | | |
1094 | | #[test] |
1095 | | fn read_wav_wave_format_extensible_ieee_float() { |
1096 | | let mut wav_reader = |
1097 | | WavReader::open("testsamples/waveformatextensible-ieeefloat-44100Hz-mono.wav").unwrap(); |
1098 | | |
1099 | | assert_eq!(wav_reader.spec().channels, 1); |
1100 | | assert_eq!(wav_reader.spec().sample_rate, 44100); |
1101 | | assert_eq!(wav_reader.spec().bits_per_sample, 32); |
1102 | | assert_eq!(wav_reader.spec().sample_format, SampleFormat::Float); |
1103 | | |
1104 | | let samples: Vec<f32> = wav_reader.samples() |
1105 | | .map(|r| r.unwrap()) |
1106 | | .collect(); |
1107 | | |
1108 | | // The test file has been prepared with these exact four samples. |
1109 | | assert_eq!(&samples[..], &[2.0, 3.0, -16411.0, 1019.0]); |
1110 | | } |
1111 | | |
1112 | | #[test] |
1113 | | fn read_wav_nonstandard_01() { |
1114 | | // The test sample here is adapted from a file encountered in the wild (data |
1115 | | // chunk replaced with two zero samples, some metadata dropped, and the file |
1116 | | // length in the header fixed). It is not a valid file according to the |
1117 | | // standard, but many players can deal with it nonetheless. (The file even |
1118 | | // contains some metadata; open it in a hex editor if you would like to know |
1119 | | // which program created it.) The file contains a regular PCM format tag, |
1120 | | // but the size of the fmt chunk is one that would be expected of a |
1121 | | // WAVEFORMATEXTENSIBLE chunk. The bits per sample is 24, which is invalid |
1122 | | // for WAVEFORMATEX, but we can read it nonetheless. |
1123 | | let mut wav_reader = WavReader::open("testsamples/nonstandard-01.wav").unwrap(); |
1124 | | |
1125 | | assert_eq!(wav_reader.spec().bits_per_sample, 24); |
1126 | | assert_eq!(wav_reader.spec().sample_format, SampleFormat::Int); |
1127 | | |
1128 | | let samples: Vec<i32> = wav_reader.samples() |
1129 | | .map(|r| r.unwrap()) |
1130 | | .collect(); |
1131 | | |
1132 | | assert_eq!(&samples[..], &[0, 0]); |
1133 | | } |
1134 | | |
1135 | | #[test] |
1136 | | fn wide_read_should_signal_error() { |
1137 | | let mut reader24 = WavReader::open("testsamples/waveformatextensible-24bit-192kHz-mono.wav") |
1138 | | .unwrap(); |
1139 | | |
1140 | | // Even though we know the first value is 17, and it should fit in an `i8`, |
1141 | | // a general 24-bit sample will not fit in an `i8`, so this should fail. |
1142 | | // 16-bit is still not wide enough, but 32-bit should do the trick. |
1143 | | assert!(reader24.samples::<i8>().next().unwrap().is_err()); |
1144 | | assert!(reader24.samples::<i16>().next().unwrap().is_err()); |
1145 | | assert!(reader24.samples::<i32>().next().unwrap().is_ok()); |
1146 | | |
1147 | | let mut reader32 = WavReader::open("testsamples/waveformatextensible-32bit-48kHz-stereo.wav") |
1148 | | .unwrap(); |
1149 | | |
1150 | | // In general, 32-bit samples will not fit in anything but an `i32`. |
1151 | | assert!(reader32.samples::<i8>().next().unwrap().is_err()); |
1152 | | assert!(reader32.samples::<i16>().next().unwrap().is_err()); |
1153 | | assert!(reader32.samples::<i32>().next().unwrap().is_ok()); |
1154 | | } |
1155 | | |
1156 | | #[test] |
1157 | | fn sample_format_mismatch_should_signal_error() { |
1158 | | let mut reader_f32 = WavReader::open("testsamples/waveformatex-ieeefloat-44100Hz-mono.wav") |
1159 | | .unwrap(); |
1160 | | |
1161 | | assert!(reader_f32.samples::<i8>().next().unwrap().is_err()); |
1162 | | assert!(reader_f32.samples::<i16>().next().unwrap().is_err()); |
1163 | | assert!(reader_f32.samples::<i32>().next().unwrap().is_err()); |
1164 | | assert!(reader_f32.samples::<f32>().next().unwrap().is_ok()); |
1165 | | |
1166 | | let mut reader_i8 = WavReader::open("testsamples/pcmwaveformat-8bit-44100Hz-mono.wav").unwrap(); |
1167 | | |
1168 | | assert!(reader_i8.samples::<i8>().next().unwrap().is_ok()); |
1169 | | assert!(reader_i8.samples::<i16>().next().unwrap().is_ok()); |
1170 | | assert!(reader_i8.samples::<i32>().next().unwrap().is_ok()); |
1171 | | assert!(reader_i8.samples::<f32>().next().unwrap().is_err()); |
1172 | | } |
1173 | | |
1174 | | #[test] |
1175 | | fn fuzz_crashes_should_be_fixed() { |
1176 | | use std::fs; |
1177 | | use std::ffi::OsStr; |
1178 | | |
1179 | | // This is a regression test: all crashes and other issues found through |
1180 | | // fuzzing should not cause a crash. |
1181 | | let dir = fs::read_dir("testsamples/fuzz").ok() |
1182 | | .expect("failed to enumerate fuzz test corpus"); |
1183 | | for path in dir { |
1184 | | let path = path.ok().expect("failed to obtain path info").path(); |
1185 | | let is_file = fs::metadata(&path).unwrap().file_type().is_file(); |
1186 | | if is_file && path.extension() == Some(OsStr::new("wav")) { |
1187 | | println!(" testing {} ...", path.to_str() |
1188 | | .expect("unsupported filename")); |
1189 | | let mut reader = match WavReader::open(path) { |
1190 | | Ok(r) => r, |
1191 | | Err(..) => continue, |
1192 | | }; |
1193 | | match reader.spec().sample_format { |
1194 | | SampleFormat::Int => { |
1195 | | for sample in reader.samples::<i32>() { |
1196 | | match sample { |
1197 | | Ok(..) => { } |
1198 | | Err(..) => break, |
1199 | | } |
1200 | | } |
1201 | | } |
1202 | | SampleFormat::Float => { |
1203 | | for sample in reader.samples::<f32>() { |
1204 | | match sample { |
1205 | | Ok(..) => { } |
1206 | | Err(..) => break, |
1207 | | } |
1208 | | } |
1209 | | } |
1210 | | } |
1211 | | } |
1212 | | } |
1213 | | } |
1214 | | |
1215 | | #[test] |
1216 | | fn seek_is_consistent() { |
1217 | | let files = &["testsamples/pcmwaveformat-16bit-44100Hz-mono.wav", |
1218 | | "testsamples/waveformatex-16bit-44100Hz-stereo.wav", |
1219 | | "testsamples/waveformatextensible-32bit-48kHz-stereo.wav"]; |
1220 | | for fname in files { |
1221 | | let mut reader = WavReader::open(fname).unwrap(); |
1222 | | |
1223 | | // Seeking back to the start should "reset" the reader. |
1224 | | let count = reader.samples::<i32>().count(); |
1225 | | reader.seek(0).unwrap(); |
1226 | | assert_eq!(reader.samples_read, 0); |
1227 | | assert_eq!(count, reader.samples::<i32>().count()); |
1228 | | |
1229 | | // Seek to the last sample. |
1230 | | let last_time = reader.duration() - 1; |
1231 | | let channels = reader.spec.channels; |
1232 | | reader.seek(last_time).unwrap(); |
1233 | | { |
1234 | | let mut samples = reader.samples::<i32>(); |
1235 | | for _ in 0..channels { |
1236 | | assert!(samples.next().is_some()); |
1237 | | } |
1238 | | assert!(samples.next().is_none()); |
1239 | | } |
1240 | | |
1241 | | // Seeking beyond the audio data produces no samples. |
1242 | | let num_samples = reader.len(); |
1243 | | reader.seek(num_samples).unwrap(); |
1244 | | assert!(reader.samples::<i32>().next().is_none()); |
1245 | | reader.seek(::std::u32::MAX / channels as u32).unwrap(); |
1246 | | assert!(reader.samples::<i32>().next().is_none()); |
1247 | | } |
1248 | | } |