surge_hound/
lib.rs

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 surge_hound as 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 surge_hound as 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
58use std::error;
59use std::fmt;
60use std::io;
61use std::result;
62use read::ReadExt;
63use write::WriteExt;
64
65mod read;
66mod write;
67
68pub use read::{WavReader, WavIntoSamples, WavSamples, read_wave_header, WavSpecSurge};
69pub 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.
79pub trait Sample: Sized {
80    /// Writes the audio sample to the WAVE data chunk.
81    fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()>;
82
83    /// Reads the audio sample from the WAVE data chunk.
84    fn read<R: io::Read>(reader: &mut R, _: SampleFormat, bytes: u16, bits: u16) -> Result<Self>;
85
86    /// Cast the sample to a 16-bit sample.
87    ///
88    /// This does not change the value of the sample, it only casts it. The
89    /// value is assumed to fit within the range. This is not verified,
90    /// truncation may occur.
91    fn as_i16(&self) -> i16;
92}
93
94/// Converts an unsigned integer in the range 0-255 to a signed one in the range -128-127.
95///
96/// Presumably, the designers of the WAVE format did not like consistency. For
97/// all bit depths except 8, samples are stored as little-endian _signed_
98/// integers. However, an 8-bit sample is instead stored as an _unsigned_
99/// integer. Hound abstracts away this idiosyncrasy by providing only signed
100/// sample types.
101fn signed_from_u8(x: u8) -> i8 {
102    (x as i16 - 128) as i8
103}
104
105/// Converts a signed integer in the range -128-127 to an unsigned one in the range 0-255.
106fn u8_from_signed(x: i8) -> u8 {
107    (x as i16 + 128) as u8
108}
109
110#[test]
111fn u8_sign_conversion_is_bijective() {
112    for x in 0..255 {
113        assert_eq!(x, u8_from_signed(signed_from_u8(x)));
114    }
115    for x in -128..127 {
116        assert_eq!(x, signed_from_u8(u8_from_signed(x)));
117    }
118}
119
120/// Tries to cast the sample to an 8-bit signed integer, returning an error on overflow.
121#[inline(always)]
122fn narrow_to_i8(x: i32) -> Result<i8> {
123    use std::i8;
124    if x < i8::MIN as i32 || x > i8::MAX as i32 {
125        Err(Error::TooWide)
126    } else {
127        Ok(x as i8)
128    }
129}
130
131#[test]
132fn verify_narrow_to_i8() {
133    assert!(narrow_to_i8(127).is_ok());
134    assert!(narrow_to_i8(128).is_err());
135    assert!(narrow_to_i8(-128).is_ok());
136    assert!(narrow_to_i8(-129).is_err());
137}
138
139/// Tries to cast the sample to a 16-bit signed integer, returning an error on overflow.
140#[inline(always)]
141fn narrow_to_i16(x: i32) -> Result<i16> {
142    use std::i16;
143    if x < i16::MIN as i32 || x > i16::MAX as i32 {
144        Err(Error::TooWide)
145    } else {
146        Ok(x as i16)
147    }
148}
149
150#[test]
151fn verify_narrow_to_i16() {
152    assert!(narrow_to_i16(32767).is_ok());
153    assert!(narrow_to_i16(32768).is_err());
154    assert!(narrow_to_i16(-32768).is_ok());
155    assert!(narrow_to_i16(-32769).is_err());
156}
157
158/// Tries to cast the sample to a 24-bit signed integer, returning an error on overflow.
159#[inline(always)]
160fn narrow_to_i24(x: i32) -> Result<i32> {
161    if x < -(1 << 23) || x > (1 << 23) - 1 {
162        Err(Error::TooWide)
163    } else {
164        Ok(x)
165    }
166}
167
168#[test]
169fn verify_narrow_to_i24() {
170    assert!(narrow_to_i24(8_388_607).is_ok());
171    assert!(narrow_to_i24(8_388_608).is_err());
172    assert!(narrow_to_i24(-8_388_608).is_ok());
173    assert!(narrow_to_i24(-8_388_609).is_err());
174}
175
176impl Sample for i8 {
177    fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()> {
178        match bits {
179            8 => Ok(writer.write_u8(u8_from_signed(self))?),
180            16 => Ok(writer.write_le_i16(self as i16)?),
181            24 => Ok(writer.write_le_i24(self as i32)?),
182            32 => Ok(writer.write_le_i32(self as i32)?),
183            _ => Err(Error::Unsupported),
184        }
185    }
186
187    #[inline(always)]
188    fn as_i16(&self) -> i16 {
189        *self as i16
190    }
191
192    fn read<R: io::Read>(reader: &mut R, fmt: SampleFormat, bytes: u16, bits: u16) -> Result<i8> {
193        if fmt != SampleFormat::Int {
194            return Err(Error::InvalidSampleFormat);
195        }
196        match (bytes, bits) {
197            (1, 8) => Ok(reader.read_u8().map(signed_from_u8)?),
198            (n, _) if n > 1 => Err(Error::TooWide),
199            // TODO: add a genric decoder for any bit depth.
200            _ => Err(Error::Unsupported),
201        }
202    }
203}
204
205impl Sample for i16 {
206    fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()> {
207        match bits {
208            8 => Ok(writer.write_u8(u8_from_signed(narrow_to_i8(self as i32)?))?),
209            16 => Ok(writer.write_le_i16(self)?),
210            24 => Ok(writer.write_le_i24(self as i32)?),
211            32 => Ok(writer.write_le_i32(self as i32)?),
212            _ => Err(Error::Unsupported),
213        }
214    }
215
216    #[inline(always)]
217    fn as_i16(&self) -> i16 {
218        *self
219    }
220
221    fn read<R: io::Read>(reader: &mut R, fmt: SampleFormat, bytes: u16, bits: u16) -> Result<i16> {
222        if fmt != SampleFormat::Int {
223            return Err(Error::InvalidSampleFormat);
224        }
225        match (bytes, bits) {
226            (1, 8) => Ok(reader.read_u8().map(signed_from_u8).map(|x| x as i16)?),
227            (2, 16) => Ok(reader.read_le_i16()?),
228            (n, _) if n > 2 => Err(Error::TooWide),
229            // TODO: add a generic decoder for any bit depth.
230            _ => Err(Error::Unsupported),
231        }
232    }
233}
234
235impl Sample for i32 {
236    fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()> {
237        match bits {
238            8 => Ok(writer.write_u8(u8_from_signed(narrow_to_i8(self)?))?),
239            16 => Ok(writer.write_le_i16(narrow_to_i16(self)?)?),
240            24 => Ok(writer.write_le_i24(narrow_to_i24(self)?)?),
241            32 => Ok(writer.write_le_i32(self)?),
242            _ => Err(Error::Unsupported),
243        }
244    }
245
246    #[inline(always)]
247    fn as_i16(&self) -> i16 {
248        *self as i16
249    }
250
251    fn read<R: io::Read>(reader: &mut R, fmt: SampleFormat, bytes: u16, bits: u16) -> Result<i32> {
252        if fmt != SampleFormat::Int {
253            return Err(Error::InvalidSampleFormat);
254        }
255        match (bytes, bits) {
256            (1, 8) => Ok(reader.read_u8().map(signed_from_u8).map(|x| x as i32)?),
257            (2, 16) => Ok(reader.read_le_i16().map(|x| x as i32)?),
258            (3, 24) => Ok(reader.read_le_i24()?),
259            (4, 32) => Ok(reader.read_le_i32()?),
260            (n, _) if n > 4 => Err(Error::TooWide),
261            // TODO: add a generic decoder for any bit depth.
262            _ => Err(Error::Unsupported),
263        }
264    }
265}
266
267impl Sample for f32 {
268    fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()> {
269        match bits {
270            32 => Ok(writer.write_le_f32(self)?),
271            _ => Err(Error::Unsupported),
272        }
273    }
274
275    fn as_i16(&self) -> i16 {
276        panic!("Calling as_i16 with an f32 is invalid.");
277    }
278
279    fn read<R: io::Read>(reader: &mut R, fmt: SampleFormat, bytes: u16, bits: u16) -> Result<Self> {
280        if fmt != SampleFormat::Float {
281            return Err(Error::InvalidSampleFormat);
282        }
283        match (bytes, bits) {
284            (4, 32) => Ok(reader.read_le_f32()?),
285            (n, _) if n > 4 => Err(Error::TooWide),
286            _ => Err(Error::Unsupported),
287        }
288    }
289}
290
291/// Specifies whether a sample is stored as an "IEEE Float" or an integer.
292#[derive(Clone, Copy, Debug, PartialEq, Eq)]
293pub enum SampleFormat {
294    /// Wave files with the `WAVE_FORMAT_IEEE_FLOAT` format tag store samples as floating point
295    /// values.
296    ///
297    /// Values are normally in the range [-1.0, 1.0].
298    Float,
299    /// Wave files with the `WAVE_FORMAT_PCM` format tag store samples as integer values.
300    Int,
301}
302
303/// Specifies properties of the audio data.
304#[derive(Clone, Copy, Debug, PartialEq, Eq)]
305pub struct WavSpec {
306    /// The number of channels.
307    pub channels: u16,
308
309    /// The number of samples per second.
310    ///
311    /// A common value is 44100, this is 44.1 kHz which is used for CD audio.
312    pub sample_rate: u32,
313
314    /// The number of bits per sample.
315    ///
316    /// A common value is 16 bits per sample, which is used for CD audio.
317    pub bits_per_sample: u16,
318
319    /// Whether the wav's samples are float or integer values.
320    pub sample_format: SampleFormat,
321}
322
323/// The error type for operations on `WavReader` and `WavWriter`.
324#[derive(Debug)]
325pub enum Error {
326    /// An IO error occured in the underlying reader or writer.
327    IoError(io::Error),
328    /// Ill-formed WAVE data was encountered.
329    FormatError(&'static str),
330    /// The sample has more bits than the destination type.
331    ///
332    /// When iterating using the `samples` iterator, this means that the
333    /// destination type (produced by the iterator) is not wide enough to hold
334    /// the sample. When writing, this means that the sample cannot be written,
335    /// because it requires more bits than the bits per sample specified.
336    TooWide,
337    /// The number of samples written is not a multiple of the number of channels.
338    UnfinishedSample,
339    /// The format is not supported.
340    Unsupported,
341    /// The sample format is different than the destination format.
342    ///
343    /// When iterating using the `samples` iterator, this means the destination
344    /// type (produced by the iterator) has a different sample format than the
345    /// samples in the wav file.
346    ///
347    /// For example, this will occur if the user attempts to produce `i32`
348    /// samples (which have a `SampleFormat::Int`) from a wav file that
349    /// contains floating point data (`SampleFormat::Float`).
350    InvalidSampleFormat,
351}
352
353impl fmt::Display for Error {
354    fn fmt(&self, formatter: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
355        match *self {
356            Error::IoError(ref err) => err.fmt(formatter),
357            Error::FormatError(reason) => {
358                formatter.write_str("Ill-formed WAVE file: ")?;
359                formatter.write_str(reason)
360            }
361            Error::TooWide => {
362                formatter.write_str("The sample has more bits than the destination type.")
363            }
364            Error::UnfinishedSample => {
365                formatter.write_str(
366                    "The number of samples written is not a multiple of the number of channels.")
367            }
368            Error::Unsupported => {
369                formatter.write_str("The wave format of the file is not supported.")
370            }
371            Error::InvalidSampleFormat => {
372                formatter.write_str("The sample format differs from the destination format.")
373            }
374        }
375    }
376}
377
378impl error::Error for Error {
379    #[allow(deprecated)]
380    fn description(&self) -> &str {
381        match *self {
382            Error::IoError(ref err) => err.description(),
383            Error::FormatError(reason) => reason,
384            Error::TooWide => "the sample has more bits than the destination type",
385            Error::UnfinishedSample => "the number of samples written is not a multiple of the number of channels",
386            Error::Unsupported => "the wave format of the file is not supported",
387            Error::InvalidSampleFormat => "the sample format differs from the destination format",
388        }
389    }
390
391    fn cause(&self) -> Option<&dyn error::Error> {
392        match *self {
393            Error::IoError(ref err) => Some(err),
394            Error::FormatError(_) => None,
395            Error::TooWide => None,
396            Error::UnfinishedSample => None,
397            Error::Unsupported => None,
398            Error::InvalidSampleFormat => None,
399        }
400    }
401}
402
403impl From<io::Error> for Error {
404    fn from(err: io::Error) -> Error {
405        Error::IoError(err)
406    }
407}
408
409/// A type for results generated by Hound where the error type is hard-wired.
410pub type Result<T> = result::Result<T, Error>;
411
412// The WAVEFORMATEXTENSIBLE struct can contain several subformats.
413// These are identified by a GUID. The various GUIDS can be found in the file
414// mmreg.h that is part of the Windows SDK. The following GUIDS are defined:
415// - PCM:        00000001-0000-0010-8000-00aa00389b71
416// - IEEE_FLOAT: 00000003-0000-0010-8000-00aa00389b71
417// When written to a wav file, the byte order of a GUID is native for the first
418// three sections, which is assumed to be little endian, and big endian for the
419// last 8-byte section (which does contain a hyphen, for reasons unknown to me).
420
421/// Subformat type for PCM audio with integer samples.
422const KSDATAFORMAT_SUBTYPE_PCM: [u8; 16] = [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80,
423                                            0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71];
424
425/// Subformat type for IEEE_FLOAT audio with float samples.
426const KSDATAFORMAT_SUBTYPE_IEEE_FLOAT: [u8; 16] = [0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
427                                                   0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71];
428
429#[test]
430fn write_read_i16_is_lossless() {
431    let mut buffer = io::Cursor::new(Vec::new());
432    let write_spec = WavSpec {
433        channels: 2,
434        sample_rate: 44100,
435        bits_per_sample: 16,
436        sample_format: SampleFormat::Int,
437    };
438
439    {
440        let mut writer = WavWriter::new(&mut buffer, write_spec).unwrap();
441        for s in -1024_i16..1024 {
442            writer.write_sample(s).unwrap();
443        }
444        writer.finalize().unwrap();
445    }
446
447    {
448        buffer.set_position(0);
449        let mut reader = WavReader::new(&mut buffer).unwrap();
450        assert_eq!(write_spec, reader.spec());
451        assert_eq!(reader.len(), 2048);
452        for (expected, read) in (-1024_i16..1024).zip(reader.samples()) {
453            assert_eq!(expected, read.unwrap());
454        }
455    }
456}
457
458#[test]
459fn write_read_i16_via_sample_writer_is_lossless() {
460    let mut buffer = io::Cursor::new(Vec::new());
461    let write_spec = WavSpec {
462        channels: 2,
463        sample_rate: 44100,
464        bits_per_sample: 16,
465        sample_format: SampleFormat::Int,
466    };
467
468    {
469        let mut writer = WavWriter::new(&mut buffer, write_spec).unwrap();
470        {
471            {
472                let mut sample_writer = writer.get_i16_writer(1024);
473                for s in -1024_i16..0 {
474                    sample_writer.write_sample(s);
475                }
476                sample_writer.flush().unwrap();
477            }
478
479            {
480                let mut sample_writer = writer.get_i16_writer(1024);
481                for s in 0i16..1024 {
482                    sample_writer.write_sample_unchecked(s);
483                }
484                sample_writer.flush().unwrap();
485            }
486        }
487        writer.finalize().unwrap();
488    }
489
490    {
491        buffer.set_position(0);
492        let mut reader = WavReader::new(&mut buffer).unwrap();
493        assert_eq!(write_spec, reader.spec());
494        assert_eq!(reader.len(), 2048);
495        for (expected, read) in (-1024_i16..1024).zip(reader.samples()) {
496            assert_eq!(expected, read.unwrap());
497        }
498    }
499}
500
501#[test]
502fn write_read_i8_is_lossless() {
503    let mut buffer = io::Cursor::new(Vec::new());
504    let write_spec = WavSpec {
505        channels: 16,
506        sample_rate: 48000,
507        bits_per_sample: 8,
508        sample_format: SampleFormat::Int,
509    };
510
511    // Write `i8` samples.
512    {
513        let mut writer = WavWriter::new(&mut buffer, write_spec).unwrap();
514        // Iterate over i16 because we cannot specify the upper bound otherwise.
515        for s in -128_i16..127 + 1 {
516            writer.write_sample(s as i8).unwrap();
517        }
518        writer.finalize().unwrap();
519    }
520
521    // Then read them into `i16`.
522    {
523        buffer.set_position(0);
524        let mut reader = WavReader::new(&mut buffer).unwrap();
525        assert_eq!(write_spec, reader.spec());
526        assert_eq!(reader.len(), 256);
527        for (expected, read) in (-128_i16..127 + 1).zip(reader.samples()) {
528            assert_eq!(expected, read.unwrap());
529        }
530    }
531}
532
533#[test]
534fn write_read_i24_is_lossless() {
535    let mut buffer = io::Cursor::new(Vec::new());
536    let write_spec = WavSpec {
537        channels: 16,
538        sample_rate: 96000,
539        bits_per_sample: 24,
540        sample_format: SampleFormat::Int,
541    };
542
543    // Write `i32` samples, but with at most 24 bits per sample.
544    {
545        let mut writer = WavWriter::new(&mut buffer, write_spec).unwrap();
546        for s in -128_i32..127 + 1 {
547            writer.write_sample(s * 256 * 256).unwrap();
548        }
549        writer.finalize().unwrap();
550    }
551
552    // Then read them into `i32`. This should extend the sign in the correct
553    // manner.
554    {
555        buffer.set_position(0);
556        let mut reader = WavReader::new(&mut buffer).unwrap();
557        assert_eq!(write_spec, reader.spec());
558        assert_eq!(reader.len(), 256);
559        for (expected, read) in (-128_i32..127 + 1)
560            .map(|x| x * 256 * 256)
561            .zip(reader.samples()) {
562            assert_eq!(expected, read.unwrap());
563        }
564    }
565}
566#[test]
567fn write_read_f32_is_lossless() {
568    let mut buffer = io::Cursor::new(Vec::new());
569    let write_spec = WavSpec {
570        channels: 2,
571        sample_rate: 44100,
572        bits_per_sample: 32,
573        sample_format: SampleFormat::Float,
574    };
575
576    {
577        let mut writer = WavWriter::new(&mut buffer, write_spec).unwrap();
578        for s in 1_u32..257 {
579            writer.write_sample(1.0f32 / s as f32).unwrap();
580        }
581        writer.finalize().unwrap();
582    }
583
584    {
585        buffer.set_position(0);
586        let mut reader = WavReader::new(&mut buffer).unwrap();
587        assert_eq!(write_spec, reader.spec());
588        assert_eq!(reader.len(), 256);
589        for (expected, read) in (1..257)
590            .map(|x| 1.0_f32 / x as f32)
591            .zip(reader.samples()) {
592            assert_eq!(expected, read.unwrap());
593        }
594    }
595}
596
597#[test]
598#[should_panic]
599fn no_32_bps_for_float_sample_format_panics() {
600    let mut buffer = io::Cursor::new(Vec::new());
601    let write_spec = WavSpec {
602        channels: 2,
603        sample_rate: 44100,
604        bits_per_sample: 16, // will panic, because value must be 32 for floating point
605        sample_format: SampleFormat::Float,
606    };
607
608    WavWriter::new(&mut buffer, write_spec).unwrap();
609}
610
611#[test]
612fn flush_should_produce_valid_file() {
613    use std::mem;
614    use std::io::Seek;
615
616    let mut buffer = io::Cursor::new(Vec::new());
617    let samples = &[2, 4, 5, 7, 11, 13];
618
619    {
620        let spec = WavSpec {
621            channels: 2,
622            sample_rate: 44100,
623            bits_per_sample: 16,
624            sample_format: SampleFormat::Int,
625        };
626        let mut writer = WavWriter::new(&mut buffer, spec).unwrap();
627
628        for &x in samples {
629            writer.write_sample(x).unwrap();
630        }
631
632        // We should be able to see everything up to the flush later.
633        writer.flush().unwrap();
634
635        // Write more samples. These should be in the buffer, but not read by the
636        // reader if we don't finalize the writer.
637        writer.write_sample(17).unwrap();
638        writer.write_sample(19).unwrap();
639
640        mem::forget(writer);
641    }
642
643    buffer.seek(io::SeekFrom::Start(0)).unwrap();
644
645    let mut reader = WavReader::new(&mut buffer).unwrap();
646    let read_samples: Vec<i16> = reader.samples()
647        .map(|r| r.unwrap())
648        .collect();
649
650    // We expect to see all samples up to the flush, but not the later ones.
651    assert_eq!(&read_samples[..], &samples[..]);
652}
653
654#[test]
655fn new_append_should_append() {
656    use std::io::Seek;
657
658    let mut buffer = io::Cursor::new(Vec::new());
659    let samples = &[2, 5, 7, 11];
660    let spec = WavSpec {
661        channels: 2,
662        sample_rate: 44100,
663        bits_per_sample: 16,
664        sample_format: SampleFormat::Int,
665    };
666
667    // Write initial file.
668    {
669        let mut writer = WavWriter::new(&mut buffer, spec).unwrap();
670        for s in samples { writer.write_sample(*s).unwrap(); }
671    }
672
673    buffer.seek(io::SeekFrom::Start(0)).unwrap();
674
675    // Append samples (the same ones a second time).
676    {
677        let mut writer = WavWriter::new_append(&mut buffer).unwrap();
678        assert_eq!(writer.spec(), spec);
679        for s in samples { writer.write_sample(*s).unwrap(); }
680    }
681
682    buffer.seek(io::SeekFrom::Start(0)).unwrap();
683
684    let mut reader = WavReader::new(&mut buffer).unwrap();
685    let read_samples: Vec<i16> = reader.samples()
686        .map(|r| r.unwrap())
687        .collect();
688
689    // We expect to see all samples up to the flush, but not the later ones.
690    assert_eq!(&read_samples[..], &[2, 5, 7, 11, 2, 5, 7, 11]);
691}
692
693#[test]
694fn new_append_does_not_corrupt_files() {
695    use std::io::Read;
696    use std::fs;
697
698    let sample_files = [
699        "testsamples/pcmwaveformat-16bit-44100Hz-mono-extra.wav",
700        "testsamples/pcmwaveformat-16bit-44100Hz-mono.wav",
701        "testsamples/pcmwaveformat-8bit-44100Hz-mono.wav",
702        "testsamples/pop.wav",
703        "testsamples/waveformatex-16bit-44100Hz-mono-extra.wav",
704        "testsamples/waveformatex-16bit-44100Hz-mono.wav",
705        "testsamples/waveformatex-16bit-44100Hz-stereo.wav",
706        "testsamples/waveformatextensible-24bit-192kHz-mono.wav",
707        "testsamples/waveformatextensible-32bit-48kHz-stereo.wav",
708        "testsamples/nonstandard-01.wav",
709        "testsamples/waveformatex-8bit-11025Hz-mono.wav",
710    ];
711
712    for fname in &sample_files {
713        print!("testing {} ... ", fname);
714
715        let mut buffer = Vec::new();
716        let mut f = fs::File::open(fname).unwrap();
717        f.read_to_end(&mut buffer).unwrap();
718
719        let samples_orig: Vec<i32>;
720        let samples_after: Vec<i32>;
721
722        // Read samples first.
723        let mut cursor = io::Cursor::new(buffer);
724        {
725            let mut reader = WavReader::new(&mut cursor).unwrap();
726            samples_orig = reader.samples().map(|r| r.unwrap()).collect();
727        }
728        buffer = cursor.into_inner();
729
730        // Open in append mode and append one sample.
731        let mut cursor = io::Cursor::new(buffer);
732        {
733            let mut writer = WavWriter::new_append(&mut cursor).unwrap();
734            writer.write_sample(41_i8).unwrap();
735            writer.write_sample(43_i8).unwrap();
736        }
737        buffer = cursor.into_inner();
738
739        {
740            let cursor = io::Cursor::new(buffer);
741            let mut reader = WavReader::new(cursor)
742                .expect("Reading wav failed after append.");
743            samples_after = reader.samples().map(|r| r.unwrap()).collect();
744        }
745
746        assert_eq!(&samples_orig[..], &samples_after[..samples_orig.len()]);
747        assert_eq!(samples_after[samples_after.len() - 2], 41_i32);
748        assert_eq!(samples_after[samples_after.len() - 1], 43_i32);
749
750        println!("ok");
751    }
752}
753
754#[cfg(test)]
755fn assert_contents(fname: &str, expected: &[i16]) {
756    let mut reader = WavReader::open(fname).unwrap();
757    let samples: Vec<i16> = reader.samples().map(|s| s.unwrap()).collect();
758    assert_eq!(&samples[..], expected);
759}
760
761#[test]
762fn append_works_on_files() {
763    use std::fs;
764
765    let spec = WavSpec {
766        channels: 1,
767        sample_rate: 44100,
768        bits_per_sample: 16,
769        sample_format: SampleFormat::Int,
770    };
771
772    let mut writer = WavWriter::create("append.wav", spec).unwrap();
773    writer.write_sample(11_i16).unwrap();
774    writer.write_sample(13_i16).unwrap();
775    writer.write_sample(17_i16).unwrap();
776    writer.finalize().unwrap();
777
778    assert_contents("append.wav", &[11, 13, 17]);
779
780    let len = fs::metadata("append.wav").unwrap().len();
781
782    let mut appender = WavWriter::append("append.wav").unwrap();
783
784    appender.write_sample(19_i16).unwrap();
785    appender.write_sample(23_i16).unwrap();
786    appender.finalize().unwrap();
787
788    // We appended four bytes of audio data (2 16-bit samples), so the file
789    // should have grown by 4 bytes.
790    assert_eq!(fs::metadata("append.wav").unwrap().len(), len + 4);
791
792    assert_contents("append.wav", &[11, 13, 17, 19, 23]);
793}