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 //! Hound, a wav encoding and decoding library.
14 //!
15 //! Examples
16 //! ========
17 //!
18 //! The following example renders a 440 Hz sine wave, and stores it as as a
19 //! mono wav file with a sample rate of 44.1 kHz and 16 bits per sample.
20 //!
21 //! ```
22 //! use std::f32::consts::PI;
23 //! use std::i16;
24 //! use hound;
25 //!
26 //! let spec = hound::WavSpec {
27 //!     channels: 1,
28 //!     sample_rate: 44100,
29 //!     bits_per_sample: 16,
30 //!     sample_format: hound::SampleFormat::Int,
31 //! };
32 //! let mut writer = hound::WavWriter::create("sine.wav", spec).unwrap();
33 //! for t in (0 .. 44100).map(|x| x as f32 / 44100.0) {
34 //!     let sample = (t * 440.0 * 2.0 * PI).sin();
35 //!     let amplitude = i16::MAX as f32;
36 //!     writer.write_sample((sample * amplitude) as i16).unwrap();
37 //! }
38 //! writer.finalize().unwrap();
39 //! ```
40 //!
41 //! The following example computes the root mean square (RMS) of an audio file
42 //! with at most 16 bits per sample.
43 //!
44 //! ```
45 //! use hound;
46 //!
47 //! let mut reader = hound::WavReader::open("testsamples/pop.wav").unwrap();
48 //! let sqr_sum = reader.samples::<i16>()
49 //!                     .fold(0.0, |sqr_sum, s| {
50 //!     let sample = s.unwrap() as f64;
51 //!     sqr_sum + sample * sample
52 //! });
53 //! println!("RMS is {}", (sqr_sum / reader.len() as f64).sqrt());
54 //! ```
55 
56 #![warn(missing_docs)]
57 
58 use std::error;
59 use std::fmt;
60 use std::io;
61 use std::result;
62 use read::ReadExt;
63 use write::WriteExt;
64 
65 mod read;
66 mod write;
67 
68 pub use read::{WavReader, WavIntoSamples, WavSamples, read_wave_header};
69 pub use write::{SampleWriter16, WavWriter};
70 
71 /// A type that can be used to represent audio samples.
72 ///
73 /// Via this trait, decoding can be generic over `i8`, `i16`, `i32` and `f32`.
74 ///
75 /// All integer formats with bit depths up to 32 bits per sample can be decoded
76 /// into `i32`, but it takes up more memory. If you know beforehand that you
77 /// will be reading a file with 16 bits per sample, then decoding into an `i16`
78 /// will be sufficient.
79 pub trait Sample: Sized {
80     /// Writes the audio sample to the WAVE data chunk.
write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()>81     fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()>;
82 
83     /// Writes the audio sample to the WAVE data chunk, zero padding the size of
84     /// the written sample out to `byte_width`.
write_padded<W: io::Write>(self, writer: &mut W, bits: u16, byte_width: u16) -> Result<()>85     fn write_padded<W: io::Write>(self, writer: &mut W, bits: u16, byte_width: u16) -> Result<()>;
86 
87     /// Reads the audio sample from the WAVE data chunk.
read<R: io::Read>(reader: &mut R, SampleFormat, bytes: u16, bits: u16) -> Result<Self>88     fn read<R: io::Read>(reader: &mut R, SampleFormat, bytes: u16, bits: u16) -> Result<Self>;
89 
90     /// Cast the sample to a 16-bit sample.
91     ///
92     /// This does not change the value of the sample, it only casts it. The
93     /// value is assumed to fit within the range. This is not verified,
94     /// truncation may occur.
as_i16(self) -> i1695     fn as_i16(self) -> i16;
96 }
97 
98 /// Converts an unsigned integer in the range 0-255 to a signed one in the range -128-127.
99 ///
100 /// Presumably, the designers of the WAVE format did not like consistency. For
101 /// all bit depths except 8, samples are stored as little-endian _signed_
102 /// integers. However, an 8-bit sample is instead stored as an _unsigned_
103 /// integer. Hound abstracts away this idiosyncrasy by providing only signed
104 /// sample types.
signed_from_u8(x: u8) -> i8105 fn signed_from_u8(x: u8) -> i8 {
106     (x as i16 - 128) as i8
107 }
108 
109 /// Converts a signed integer in the range -128-127 to an unsigned one in the range 0-255.
u8_from_signed(x: i8) -> u8110 fn u8_from_signed(x: i8) -> u8 {
111     (x as i16 + 128) as u8
112 }
113 
114 #[test]
u8_sign_conversion_is_bijective()115 fn u8_sign_conversion_is_bijective() {
116     for x in 0..255 {
117         assert_eq!(x, u8_from_signed(signed_from_u8(x)));
118     }
119     for x in -128..127 {
120         assert_eq!(x, signed_from_u8(u8_from_signed(x)));
121     }
122 }
123 
124 /// Tries to cast the sample to an 8-bit signed integer, returning an error on overflow.
125 #[inline(always)]
narrow_to_i8(x: i32) -> Result<i8>126 fn narrow_to_i8(x: i32) -> Result<i8> {
127     use std::i8;
128     if x < i8::MIN as i32 || x > i8::MAX as i32 {
129         Err(Error::TooWide)
130     } else {
131         Ok(x as i8)
132     }
133 }
134 
135 #[test]
verify_narrow_to_i8()136 fn verify_narrow_to_i8() {
137     assert!(narrow_to_i8(127).is_ok());
138     assert!(narrow_to_i8(128).is_err());
139     assert!(narrow_to_i8(-128).is_ok());
140     assert!(narrow_to_i8(-129).is_err());
141 }
142 
143 /// Tries to cast the sample to a 16-bit signed integer, returning an error on overflow.
144 #[inline(always)]
narrow_to_i16(x: i32) -> Result<i16>145 fn narrow_to_i16(x: i32) -> Result<i16> {
146     use std::i16;
147     if x < i16::MIN as i32 || x > i16::MAX as i32 {
148         Err(Error::TooWide)
149     } else {
150         Ok(x as i16)
151     }
152 }
153 
154 #[test]
verify_narrow_to_i16()155 fn verify_narrow_to_i16() {
156     assert!(narrow_to_i16(32767).is_ok());
157     assert!(narrow_to_i16(32768).is_err());
158     assert!(narrow_to_i16(-32768).is_ok());
159     assert!(narrow_to_i16(-32769).is_err());
160 }
161 
162 /// Tries to cast the sample to a 24-bit signed integer, returning an error on overflow.
163 #[inline(always)]
narrow_to_i24(x: i32) -> Result<i32>164 fn narrow_to_i24(x: i32) -> Result<i32> {
165     if x < -(1 << 23) || x > (1 << 23) - 1 {
166         Err(Error::TooWide)
167     } else {
168         Ok(x)
169     }
170 }
171 
172 #[test]
verify_narrow_to_i24()173 fn verify_narrow_to_i24() {
174     assert!(narrow_to_i24(8_388_607).is_ok());
175     assert!(narrow_to_i24(8_388_608).is_err());
176     assert!(narrow_to_i24(-8_388_608).is_ok());
177     assert!(narrow_to_i24(-8_388_609).is_err());
178 }
179 
180 impl Sample for i8 {
write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()>181     fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()> {
182         self.write_padded(writer, bits, bits / 8)
183     }
184 
write_padded<W: io::Write>(self, writer: &mut W, bits: u16, byte_width: u16) -> Result<()>185     fn write_padded<W: io::Write>(self, writer: &mut W, bits: u16, byte_width: u16) -> Result<()> {
186         match (bits, byte_width) {
187             (8, 1) => Ok(try!(writer.write_u8(u8_from_signed(self)))),
188             (16, 2) => Ok(try!(writer.write_le_i16(self as i16))),
189             (24, 3) => Ok(try!(writer.write_le_i24(self as i32))),
190             (24, 4) => Ok(try!(writer.write_le_i24_4(self as i32))),
191             (32, 4) => Ok(try!(writer.write_le_i32(self as i32))),
192             _ => Err(Error::Unsupported),
193         }
194     }
195 
196     #[inline(always)]
as_i16(self) -> i16197     fn as_i16(self) -> i16 {
198         self as i16
199     }
200 
read<R: io::Read>(reader: &mut R, fmt: SampleFormat, bytes: u16, bits: u16) -> Result<i8>201     fn read<R: io::Read>(reader: &mut R, fmt: SampleFormat, bytes: u16, bits: u16) -> Result<i8> {
202         if fmt != SampleFormat::Int {
203             return Err(Error::InvalidSampleFormat);
204         }
205         match (bytes, bits) {
206             (1, 8) => Ok(try!(reader.read_u8().map(signed_from_u8))),
207             (n, _) if n > 1 => Err(Error::TooWide),
208             // TODO: add a genric decoder for any bit depth.
209             _ => Err(Error::Unsupported),
210         }
211     }
212 }
213 
214 impl Sample for i16 {
write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()>215     fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()> {
216         self.write_padded(writer, bits, bits / 8)
217     }
218 
write_padded<W: io::Write>(self, writer: &mut W, bits: u16, byte_width: u16) -> Result<()>219     fn write_padded<W: io::Write>(self, writer: &mut W, bits: u16, byte_width: u16) -> Result<()> {
220         match (bits, byte_width) {
221             (8, 1) => Ok(try!(
222                 writer.write_u8(u8_from_signed(try!(narrow_to_i8(self as i32))))
223             )),
224             (16, 2) => Ok(try!(writer.write_le_i16(self))),
225             (24, 3) => Ok(try!(writer.write_le_i24(self as i32))),
226             (24, 4) => Ok(try!(writer.write_le_i24_4(self as i32))),
227             (32, 4) => Ok(try!(writer.write_le_i32(self as i32))),
228             _ => Err(Error::Unsupported),
229         }
230     }
231 
232     #[inline(always)]
as_i16(self) -> i16233     fn as_i16(self) -> i16 {
234         self
235     }
236 
read<R: io::Read>(reader: &mut R, fmt: SampleFormat, bytes: u16, bits: u16) -> Result<i16>237     fn read<R: io::Read>(reader: &mut R, fmt: SampleFormat, bytes: u16, bits: u16) -> Result<i16> {
238         if fmt != SampleFormat::Int {
239             return Err(Error::InvalidSampleFormat);
240         }
241         match (bytes, bits) {
242             (1, 8) => Ok(try!(reader.read_u8().map(signed_from_u8).map(|x| x as i16))),
243             (2, 16) => Ok(try!(reader.read_le_i16())),
244             (n, _) if n > 2 => Err(Error::TooWide),
245             // TODO: add a generic decoder for any bit depth.
246             _ => Err(Error::Unsupported),
247         }
248     }
249 }
250 
251 impl Sample for i32 {
write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()>252     fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()> {
253         self.write_padded(writer, bits, bits / 8)
254     }
255 
write_padded<W: io::Write>(self, writer: &mut W, bits: u16, byte_width: u16) -> Result<()>256     fn write_padded<W: io::Write>(self, writer: &mut W, bits: u16, byte_width: u16) -> Result<()> {
257         match (bits, byte_width) {
258             (8, 1) => Ok(try!(
259                 writer.write_u8(u8_from_signed(try!(narrow_to_i8(self))))
260             )),
261             (16, 2) => Ok(try!(writer.write_le_i16(try!(narrow_to_i16(self))))),
262             (24, 3) => Ok(try!(writer.write_le_i24(try!(narrow_to_i24(self))))),
263             (24, 4) => Ok(try!(writer.write_le_i24_4(try!(narrow_to_i24(self))))),
264             (32, 4) => Ok(try!(writer.write_le_i32(self))),
265             _ => Err(Error::Unsupported),
266         }
267     }
268 
269     #[inline(always)]
as_i16(self) -> i16270     fn as_i16(self) -> i16 {
271         self as i16
272     }
273 
read<R: io::Read>(reader: &mut R, fmt: SampleFormat, bytes: u16, bits: u16) -> Result<i32>274     fn read<R: io::Read>(reader: &mut R, fmt: SampleFormat, bytes: u16, bits: u16) -> Result<i32> {
275         if fmt != SampleFormat::Int {
276             return Err(Error::InvalidSampleFormat);
277         }
278         match (bytes, bits) {
279             (1, 8) => Ok(try!(reader.read_u8().map(signed_from_u8).map(|x| x as i32))),
280             (2, 16) => Ok(try!(reader.read_le_i16().map(|x| x as i32))),
281             (3, 24) => Ok(try!(reader.read_le_i24())),
282             (4, 24) => Ok(try!(reader.read_le_i24_4())),
283             (4, 32) => Ok(try!(reader.read_le_i32())),
284             (n, _) if n > 4 => Err(Error::TooWide),
285             // TODO: add a generic decoder for any bit depth.
286             _ => Err(Error::Unsupported),
287         }
288     }
289 }
290 
291 impl Sample for f32 {
write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()>292     fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()> {
293         self.write_padded(writer, bits, bits / 8)
294     }
295 
write_padded<W: io::Write>(self, writer: &mut W, bits: u16, byte_width: u16) -> Result<()>296     fn write_padded<W: io::Write>(self, writer: &mut W, bits: u16, byte_width: u16) -> Result<()> {
297         match (bits, byte_width) {
298             (32, 4) => Ok(try!(writer.write_le_f32(self))),
299             _ => Err(Error::Unsupported),
300         }
301     }
302 
as_i16(self) -> i16303     fn as_i16(self) -> i16 {
304         panic!("Calling as_i16 with an f32 is invalid.");
305     }
306 
read<R: io::Read>(reader: &mut R, fmt: SampleFormat, bytes: u16, bits: u16) -> Result<Self>307     fn read<R: io::Read>(reader: &mut R, fmt: SampleFormat, bytes: u16, bits: u16) -> Result<Self> {
308         if fmt != SampleFormat::Float {
309             return Err(Error::InvalidSampleFormat);
310         }
311         match (bytes, bits) {
312             (4, 32) => Ok(try!(reader.read_le_f32())),
313             (n, _) if n > 4 => Err(Error::TooWide),
314             _ => Err(Error::Unsupported),
315         }
316     }
317 }
318 
319 /// Specifies whether a sample is stored as an "IEEE Float" or an integer.
320 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
321 pub enum SampleFormat {
322     /// Wave files with the `WAVE_FORMAT_IEEE_FLOAT` format tag store samples as floating point
323     /// values.
324     ///
325     /// Values are normally in the range [-1.0, 1.0].
326     Float,
327     /// Wave files with the `WAVE_FORMAT_PCM` format tag store samples as integer values.
328     Int,
329 }
330 
331 /// Specifies properties of the audio data.
332 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
333 pub struct WavSpec {
334     /// The number of channels.
335     pub channels: u16,
336 
337     /// The number of samples per second.
338     ///
339     /// A common value is 44100, this is 44.1 kHz which is used for CD audio.
340     pub sample_rate: u32,
341 
342     /// The number of bits per sample.
343     ///
344     /// A common value is 16 bits per sample, which is used for CD audio.
345     pub bits_per_sample: u16,
346 
347     /// Whether the wav's samples are float or integer values.
348     pub sample_format: SampleFormat,
349 }
350 
351 /// Specifies properties of the audio data, as well as the layout of the stream.
352 #[derive(Clone, Copy)]
353 pub struct WavSpecEx {
354     /// The normal information about the audio data.
355     ///
356     /// Bits per sample here is the number of _used_ bits per sample, not the
357     /// number of bits used to _store_ a sample.
358     pub spec: WavSpec,
359 
360     /// The number of bytes used to store a sample.
361     pub bytes_per_sample: u16,
362 }
363 
364 /// The error type for operations on `WavReader` and `WavWriter`.
365 #[derive(Debug)]
366 pub enum Error {
367     /// An IO error occured in the underlying reader or writer.
368     IoError(io::Error),
369     /// Ill-formed WAVE data was encountered.
370     FormatError(&'static str),
371     /// The sample has more bits than the destination type.
372     ///
373     /// When iterating using the `samples` iterator, this means that the
374     /// destination type (produced by the iterator) is not wide enough to hold
375     /// the sample. When writing, this means that the sample cannot be written,
376     /// because it requires more bits than the bits per sample specified.
377     TooWide,
378     /// The number of samples written is not a multiple of the number of channels.
379     UnfinishedSample,
380     /// The format is not supported.
381     Unsupported,
382     /// The sample format is different than the destination format.
383     ///
384     /// When iterating using the `samples` iterator, this means the destination
385     /// type (produced by the iterator) has a different sample format than the
386     /// samples in the wav file.
387     ///
388     /// For example, this will occur if the user attempts to produce `i32`
389     /// samples (which have a `SampleFormat::Int`) from a wav file that
390     /// contains floating point data (`SampleFormat::Float`).
391     InvalidSampleFormat,
392 }
393 
394 impl fmt::Display for Error {
fmt(&self, formatter: &mut fmt::Formatter) -> result::Result<(), fmt::Error>395     fn fmt(&self, formatter: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
396         match *self {
397             Error::IoError(ref err) => err.fmt(formatter),
398             Error::FormatError(reason) => {
399                 try!(formatter.write_str("Ill-formed WAVE file: "));
400                 formatter.write_str(reason)
401             }
402             Error::TooWide => {
403                 formatter.write_str("The sample has more bits than the destination type.")
404             }
405             Error::UnfinishedSample => {
406                 formatter.write_str(
407                     "The number of samples written is not a multiple of the number of channels.")
408             }
409             Error::Unsupported => {
410                 formatter.write_str("The wave format of the file is not supported.")
411             }
412             Error::InvalidSampleFormat => {
413                 formatter.write_str("The sample format differs from the destination format.")
414             }
415         }
416     }
417 }
418 
419 impl error::Error for Error {
description(&self) -> &str420     fn description(&self) -> &str {
421         match *self {
422             Error::IoError(ref err) => err.description(),
423             Error::FormatError(reason) => reason,
424             Error::TooWide => "the sample has more bits than the destination type",
425             Error::UnfinishedSample => "the number of samples written is not a multiple of the number of channels",
426             Error::Unsupported => "the wave format of the file is not supported",
427             Error::InvalidSampleFormat => "the sample format differs from the destination format",
428         }
429     }
430 
cause(&self) -> Option<&error::Error>431     fn cause(&self) -> Option<&error::Error> {
432         match *self {
433             Error::IoError(ref err) => Some(err),
434             Error::FormatError(_) => None,
435             Error::TooWide => None,
436             Error::UnfinishedSample => None,
437             Error::Unsupported => None,
438             Error::InvalidSampleFormat => None,
439         }
440     }
441 }
442 
443 impl From<io::Error> for Error {
from(err: io::Error) -> Error444     fn from(err: io::Error) -> Error {
445         Error::IoError(err)
446     }
447 }
448 
449 /// A type for results generated by Hound where the error type is hard-wired.
450 pub type Result<T> = result::Result<T, Error>;
451 
452 // The WAVEFORMATEXTENSIBLE struct can contain several subformats.
453 // These are identified by a GUID. The various GUIDS can be found in the file
454 // mmreg.h that is part of the Windows SDK. The following GUIDS are defined:
455 // - PCM:        00000001-0000-0010-8000-00aa00389b71
456 // - IEEE_FLOAT: 00000003-0000-0010-8000-00aa00389b71
457 // When written to a wav file, the byte order of a GUID is native for the first
458 // three sections, which is assumed to be little endian, and big endian for the
459 // last 8-byte section (which does contain a hyphen, for reasons unknown to me).
460 
461 /// Subformat type for PCM audio with integer samples.
462 const KSDATAFORMAT_SUBTYPE_PCM: [u8; 16] = [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80,
463                                             0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71];
464 
465 /// Subformat type for IEEE_FLOAT audio with float samples.
466 const KSDATAFORMAT_SUBTYPE_IEEE_FLOAT: [u8; 16] = [0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
467                                                    0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71];
468 
469 
470 impl WavSpec {
471     /// Get "stand-alone" wav header representing infinite or unknown size wav file.
472     /// Use this if you need to write audio data to non-seekable sinks (like stdout).
473     ///
474     /// Actual samples are supposed to be written using low-level [`Sample::write`] call.
475     ///
476     /// Such wav files are produced e.g. by FFmpeg and have `0xFFFFFFFF` instead of chunk sizes.
477     ///
478     /// Note that such files may be non-standard. Consider using [`WavWriter`] for better API.
479     ///
480     /// Example:
481     ///
482     /// ```no_run
483     /// extern crate hound;
484     /// use std::io::Write;
485     ///
486     /// let spec = hound::WavSpec {
487     ///     bits_per_sample: 16,
488     ///     channels: 1,
489     ///     sample_format: hound::SampleFormat::Int,
490     ///     sample_rate: 16000,
491     /// };
492     ///
493     /// let v = spec.into_header_for_infinite_file();
494     ///
495     /// let so = std::io::stdout();
496     /// let mut so = so.lock();
497     /// so.write_all(&v[..]).unwrap();
498     ///
499     /// loop {
500     ///    for i in 0..126 {
501     ///       let x : i16 = (i * 256) as i16;
502     ///       hound::Sample::write(x, &mut so, 16).unwrap();
503     ///    }
504     /// }
505     /// ```
into_header_for_infinite_file(self) -> Vec<u8>506     pub fn into_header_for_infinite_file(self) -> Vec<u8> {
507         let mut c = std::io::Cursor::new(Vec::with_capacity(0x44));
508         {
509             let w = WavWriter::new(&mut c, self);
510             drop(w);
511         }
512         let mut v = c.into_inner();
513 
514         // Set WAVE chunk size to a special signal value
515         v[4] = 0xFF; v[5] = 0xFF; v[6] = 0xFF; v[7] = 0xFF;
516 
517         // Detect fmt size, get offset of data chunk's size and set it to signal value
518         if v[16] == 0x10 {
519             // pcm wave
520             v[0x28] = 0xFF; v[0x29] = 0xFF; v[0x2A] = 0xFF; v[0x2B] = 0xFF;
521         } else if v[16] == 0x28 {
522             // extensible
523             v[0x40] = 0xFF; v[0x41] = 0xFF; v[0x42] = 0xFF; v[0x43] = 0xFF;
524         } else {
525             unreachable!()
526         }
527 
528         v
529     }
530 }
531 
532 #[test]
write_read_i16_is_lossless()533 fn write_read_i16_is_lossless() {
534     let mut buffer = io::Cursor::new(Vec::new());
535     let write_spec = WavSpec {
536         channels: 2,
537         sample_rate: 44100,
538         bits_per_sample: 16,
539         sample_format: SampleFormat::Int,
540     };
541 
542     {
543         let mut writer = WavWriter::new(&mut buffer, write_spec).unwrap();
544         for s in -1024_i16..1024 {
545             writer.write_sample(s).unwrap();
546         }
547         writer.finalize().unwrap();
548     }
549 
550     {
551         buffer.set_position(0);
552         let mut reader = WavReader::new(&mut buffer).unwrap();
553         assert_eq!(write_spec, reader.spec());
554         assert_eq!(reader.len(), 2048);
555         for (expected, read) in (-1024_i16..1024).zip(reader.samples()) {
556             assert_eq!(expected, read.unwrap());
557         }
558     }
559 }
560 
561 #[test]
write_read_i16_via_sample_writer_is_lossless()562 fn write_read_i16_via_sample_writer_is_lossless() {
563     let mut buffer = io::Cursor::new(Vec::new());
564     let write_spec = WavSpec {
565         channels: 2,
566         sample_rate: 44100,
567         bits_per_sample: 16,
568         sample_format: SampleFormat::Int,
569     };
570 
571     {
572         let mut writer = WavWriter::new(&mut buffer, write_spec).unwrap();
573         {
574             {
575                 let mut sample_writer = writer.get_i16_writer(1024);
576                 for s in -1024_i16..0 {
577                     sample_writer.write_sample(s);
578                 }
579                 sample_writer.flush().unwrap();
580             }
581 
582             {
583                 let mut sample_writer = writer.get_i16_writer(1024);
584                 for s in 0i16..1024 {
585                     unsafe { sample_writer.write_sample_unchecked(s); }
586                 }
587                 sample_writer.flush().unwrap();
588             }
589         }
590         writer.finalize().unwrap();
591     }
592 
593     {
594         buffer.set_position(0);
595         let mut reader = WavReader::new(&mut buffer).unwrap();
596         assert_eq!(write_spec, reader.spec());
597         assert_eq!(reader.len(), 2048);
598         for (expected, read) in (-1024_i16..1024).zip(reader.samples()) {
599             assert_eq!(expected, read.unwrap());
600         }
601     }
602 }
603 
604 #[test]
write_read_i8_is_lossless()605 fn write_read_i8_is_lossless() {
606     let mut buffer = io::Cursor::new(Vec::new());
607     let write_spec = WavSpec {
608         channels: 16,
609         sample_rate: 48000,
610         bits_per_sample: 8,
611         sample_format: SampleFormat::Int,
612     };
613 
614     // Write `i8` samples.
615     {
616         let mut writer = WavWriter::new(&mut buffer, write_spec).unwrap();
617         // Iterate over i16 because we cannot specify the upper bound otherwise.
618         for s in -128_i16..127 + 1 {
619             writer.write_sample(s as i8).unwrap();
620         }
621         writer.finalize().unwrap();
622     }
623 
624     // Then read them into `i16`.
625     {
626         buffer.set_position(0);
627         let mut reader = WavReader::new(&mut buffer).unwrap();
628         assert_eq!(write_spec, reader.spec());
629         assert_eq!(reader.len(), 256);
630         for (expected, read) in (-128_i16..127 + 1).zip(reader.samples()) {
631             assert_eq!(expected, read.unwrap());
632         }
633     }
634 }
635 
636 #[test]
write_read_i24_is_lossless()637 fn write_read_i24_is_lossless() {
638     let mut buffer = io::Cursor::new(Vec::new());
639     let write_spec = WavSpec {
640         channels: 16,
641         sample_rate: 96000,
642         bits_per_sample: 24,
643         sample_format: SampleFormat::Int,
644     };
645 
646     // Write `i32` samples, but with at most 24 bits per sample.
647     {
648         let mut writer = WavWriter::new(&mut buffer, write_spec).unwrap();
649         for s in -128_i32..127 + 1 {
650             writer.write_sample(s * 256 * 256).unwrap();
651         }
652         writer.finalize().unwrap();
653     }
654 
655     // Then read them into `i32`. This should extend the sign in the correct
656     // manner.
657     {
658         buffer.set_position(0);
659         let mut reader = WavReader::new(&mut buffer).unwrap();
660         assert_eq!(write_spec, reader.spec());
661         assert_eq!(reader.len(), 256);
662         for (expected, read) in (-128_i32..127 + 1)
663             .map(|x| x * 256 * 256)
664             .zip(reader.samples()) {
665             assert_eq!(expected, read.unwrap());
666         }
667     }
668 }
669 #[test]
write_read_f32_is_lossless()670 fn write_read_f32_is_lossless() {
671     let mut buffer = io::Cursor::new(Vec::new());
672     let write_spec = WavSpec {
673         channels: 2,
674         sample_rate: 44100,
675         bits_per_sample: 32,
676         sample_format: SampleFormat::Float,
677     };
678 
679     {
680         let mut writer = WavWriter::new(&mut buffer, write_spec).unwrap();
681         for s in 1_u32..257 {
682             writer.write_sample(1.0f32 / s as f32).unwrap();
683         }
684         writer.finalize().unwrap();
685     }
686 
687     {
688         buffer.set_position(0);
689         let mut reader = WavReader::new(&mut buffer).unwrap();
690         assert_eq!(write_spec, reader.spec());
691         assert_eq!(reader.len(), 256);
692         for (expected, read) in (1..257)
693             .map(|x| 1.0_f32 / x as f32)
694             .zip(reader.samples()) {
695             assert_eq!(expected, read.unwrap());
696         }
697     }
698 }
699 
700 #[test]
701 #[should_panic]
no_32_bps_for_float_sample_format_panics()702 fn no_32_bps_for_float_sample_format_panics() {
703     let mut buffer = io::Cursor::new(Vec::new());
704     let write_spec = WavSpec {
705         channels: 2,
706         sample_rate: 44100,
707         bits_per_sample: 16, // will panic, because value must be 32 for floating point
708         sample_format: SampleFormat::Float,
709     };
710 
711     WavWriter::new(&mut buffer, write_spec).unwrap();
712 }
713 
714 #[test]
flush_should_produce_valid_file()715 fn flush_should_produce_valid_file() {
716     use std::mem;
717     use std::io::Seek;
718 
719     let mut buffer = io::Cursor::new(Vec::new());
720     let samples = &[2, 4, 5, 7, 11, 13];
721 
722     {
723         let spec = WavSpec {
724             channels: 2,
725             sample_rate: 44100,
726             bits_per_sample: 16,
727             sample_format: SampleFormat::Int,
728         };
729         let mut writer = WavWriter::new(&mut buffer, spec).unwrap();
730 
731         for &x in samples {
732             writer.write_sample(x).unwrap();
733         }
734 
735         // We should be able to see everything up to the flush later.
736         writer.flush().unwrap();
737 
738         // Write more samples. These should be in the buffer, but not read by the
739         // reader if we don't finalize the writer.
740         writer.write_sample(17).unwrap();
741         writer.write_sample(19).unwrap();
742 
743         mem::forget(writer);
744     }
745 
746     buffer.seek(io::SeekFrom::Start(0)).unwrap();
747 
748     let mut reader = WavReader::new(&mut buffer).unwrap();
749     let read_samples: Vec<i16> = reader.samples()
750         .map(|r| r.unwrap())
751         .collect();
752 
753     // We expect to see all samples up to the flush, but not the later ones.
754     assert_eq!(&read_samples[..], &samples[..]);
755 }
756 
757 #[test]
new_append_should_append()758 fn new_append_should_append() {
759     use std::io::Seek;
760 
761     let mut buffer = io::Cursor::new(Vec::new());
762     let samples = &[2, 5, 7, 11];
763     let spec = WavSpec {
764         channels: 2,
765         sample_rate: 44100,
766         bits_per_sample: 16,
767         sample_format: SampleFormat::Int,
768     };
769 
770     // Write initial file.
771     {
772         let mut writer = WavWriter::new(&mut buffer, spec).unwrap();
773         for s in samples { writer.write_sample(*s).unwrap(); }
774     }
775 
776     buffer.seek(io::SeekFrom::Start(0)).unwrap();
777 
778     // Append samples (the same ones a second time).
779     {
780         let mut writer = WavWriter::new_append(&mut buffer).unwrap();
781         assert_eq!(writer.spec(), spec);
782         for s in samples { writer.write_sample(*s).unwrap(); }
783     }
784 
785     buffer.seek(io::SeekFrom::Start(0)).unwrap();
786 
787     let mut reader = WavReader::new(&mut buffer).unwrap();
788     let read_samples: Vec<i16> = reader.samples()
789         .map(|r| r.unwrap())
790         .collect();
791 
792     // We expect to see all samples up to the flush, but not the later ones.
793     assert_eq!(&read_samples[..], &[2, 5, 7, 11, 2, 5, 7, 11]);
794 }
795 
796 #[test]
new_append_does_not_corrupt_files()797 fn new_append_does_not_corrupt_files() {
798     use std::io::Read;
799     use std::fs;
800 
801     let sample_files = [
802         "testsamples/pcmwaveformat-16bit-44100Hz-mono-extra.wav",
803         "testsamples/pcmwaveformat-16bit-44100Hz-mono.wav",
804         "testsamples/pcmwaveformat-8bit-44100Hz-mono.wav",
805         "testsamples/pop.wav",
806         "testsamples/waveformatex-16bit-44100Hz-mono-extra.wav",
807         "testsamples/waveformatex-16bit-44100Hz-mono.wav",
808         "testsamples/waveformatex-16bit-44100Hz-stereo.wav",
809         "testsamples/waveformatextensible-24bit-192kHz-mono.wav",
810         "testsamples/waveformatextensible-32bit-48kHz-stereo.wav",
811         "testsamples/nonstandard-01.wav",
812         "testsamples/nonstandard-02.wav",
813         "testsamples/waveformatex-8bit-11025Hz-mono.wav",
814     ];
815 
816     for fname in &sample_files {
817         print!("testing {} ... ", fname);
818 
819         let mut buffer = Vec::new();
820         let mut f = fs::File::open(fname).unwrap();
821         f.read_to_end(&mut buffer).unwrap();
822 
823         let samples_orig: Vec<i32>;
824         let samples_after: Vec<i32>;
825 
826         // Read samples first.
827         let mut cursor = io::Cursor::new(buffer);
828         {
829             let mut reader = WavReader::new(&mut cursor).unwrap();
830             samples_orig = reader.samples().map(|r| r.unwrap()).collect();
831         }
832         buffer = cursor.into_inner();
833 
834         // Open in append mode and append one sample.
835         let mut cursor = io::Cursor::new(buffer);
836         {
837             let mut writer = WavWriter::new_append(&mut cursor).unwrap();
838             writer.write_sample(41_i8).unwrap();
839             writer.write_sample(43_i8).unwrap();
840         }
841         buffer = cursor.into_inner();
842 
843         {
844             let cursor = io::Cursor::new(buffer);
845             let mut reader = WavReader::new(cursor)
846                 .expect("Reading wav failed after append.");
847             samples_after = reader.samples().map(|r| r.unwrap()).collect();
848         }
849 
850         assert_eq!(&samples_orig[..], &samples_after[..samples_orig.len()]);
851         assert_eq!(samples_after[samples_after.len() - 2], 41_i32);
852         assert_eq!(samples_after[samples_after.len() - 1], 43_i32);
853 
854         println!("ok");
855     }
856 }
857 
858 #[cfg(test)]
assert_contents(fname: &str, expected: &[i16])859 fn assert_contents(fname: &str, expected: &[i16]) {
860     let mut reader = WavReader::open(fname).unwrap();
861     let samples: Vec<i16> = reader.samples().map(|s| s.unwrap()).collect();
862     assert_eq!(&samples[..], expected);
863 }
864 
865 #[test]
append_works_on_files()866 fn append_works_on_files() {
867     use std::fs;
868 
869     let spec = WavSpec {
870         channels: 1,
871         sample_rate: 44100,
872         bits_per_sample: 16,
873         sample_format: SampleFormat::Int,
874     };
875 
876     let mut writer = WavWriter::create("append.wav", spec).unwrap();
877     writer.write_sample(11_i16).unwrap();
878     writer.write_sample(13_i16).unwrap();
879     writer.write_sample(17_i16).unwrap();
880     writer.finalize().unwrap();
881 
882     assert_contents("append.wav", &[11, 13, 17]);
883 
884     let len = fs::metadata("append.wav").unwrap().len();
885 
886     let mut appender = WavWriter::append("append.wav").unwrap();
887 
888     appender.write_sample(19_i16).unwrap();
889     appender.write_sample(23_i16).unwrap();
890     appender.finalize().unwrap();
891 
892     // We appended four bytes of audio data (2 16-bit samples), so the file
893     // should have grown by 4 bytes.
894     assert_eq!(fs::metadata("append.wav").unwrap().len(), len + 4);
895 
896     assert_contents("append.wav", &[11, 13, 17, 19, 23]);
897 }
898 
899 #[cfg(test)]
900 #[test]
test_into_header_for_infinite_file()901 fn test_into_header_for_infinite_file() {
902     let spec = WavSpec {
903         bits_per_sample: 16,
904         channels: 1,
905         sample_format: SampleFormat::Int,
906         sample_rate: 16000,
907     };
908     let v = spec.into_header_for_infinite_file();
909     assert_eq!(&v[..], &b"RIFF\xFF\xFF\xFF\xFFWAVE\
910 fmt \x10\x00\x00\x00\x01\x00\x01\x00\x80\x3e\x00\x00\x00\x7d\x00\x00\x02\x00\x10\x00\
911 data\xFF\xFF\xFF\xFF"[..]);
912 
913     let spec = WavSpec {
914         bits_per_sample: 16,
915         channels: 10,
916         sample_format: SampleFormat::Int,
917         sample_rate: 16000,
918     };
919     let v = spec.into_header_for_infinite_file();
920     assert_eq!(&v[..], &b"RIFF\xFF\xFF\xFF\xFFWAVE\
921 fmt \x28\x00\x00\x00\xfe\xff\x0a\x00\x80\x3e\x00\x00\x00\xe2\x04\x00\
922 \x14\x00\x10\x00\x16\x00\x10\x00\xff\x03\x00\x00\x01\x00\x00\x00\
923 \x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71\
924 data\xFF\xFF\xFF\xFF"[..]);
925 }
926