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