Coverage Report

Created: 2025-06-24 06:17

/rust/registry/src/index.crates.io-6f17d22bba15001f/hound-3.5.0/src/lib.rs
Line
Count
Source (jump to first uncovered line)
1
// Hound -- A wav encoding and decoding library in Rust
2
// Copyright (C) 2015 Ruud van Asseldonk
3
//
4
// Licensed under the Apache License, Version 2.0 (the "License");
5
// you may not use this file except in compliance with the License.
6
// A copy of the License has been included in the root of the repository.
7
// Unless required by applicable law or agreed to in writing, software
8
// distributed under the License is distributed on an "AS IS" BASIS,
9
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
// See the License for the specific language governing permissions and
11
// limitations under the License.
12
13
//! 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.
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`.
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.
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.
95
    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.
105
0
fn signed_from_u8(x: u8) -> i8 {
106
0
    (x as i16 - 128) as i8
107
0
}
108
109
/// Converts a signed integer in the range -128-127 to an unsigned one in the range 0-255.
110
0
fn u8_from_signed(x: i8) -> u8 {
111
0
    (x as i16 + 128) as u8
112
0
}
113
114
#[test]
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)]
126
0
fn narrow_to_i8(x: i32) -> Result<i8> {
127
    use std::i8;
128
0
    if x < i8::MIN as i32 || x > i8::MAX as i32 {
129
0
        Err(Error::TooWide)
130
    } else {
131
0
        Ok(x as i8)
132
    }
133
0
}
134
135
#[test]
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)]
145
0
fn narrow_to_i16(x: i32) -> Result<i16> {
146
    use std::i16;
147
0
    if x < i16::MIN as i32 || x > i16::MAX as i32 {
148
0
        Err(Error::TooWide)
149
    } else {
150
0
        Ok(x as i16)
151
    }
152
0
}
153
154
#[test]
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)]
164
0
fn narrow_to_i24(x: i32) -> Result<i32> {
165
0
    if x < -(1 << 23) || x > (1 << 23) - 1 {
166
0
        Err(Error::TooWide)
167
    } else {
168
0
        Ok(x)
169
    }
170
0
}
171
172
#[test]
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 {
181
0
    fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()> {
182
0
        self.write_padded(writer, bits, bits / 8)
183
0
    }
184
185
0
    fn write_padded<W: io::Write>(self, writer: &mut W, bits: u16, byte_width: u16) -> Result<()> {
186
0
        match (bits, byte_width) {
187
0
            (8, 1) => Ok(try!(writer.write_u8(u8_from_signed(self)))),
188
0
            (16, 2) => Ok(try!(writer.write_le_i16(self as i16))),
189
0
            (24, 3) => Ok(try!(writer.write_le_i24(self as i32))),
190
0
            (24, 4) => Ok(try!(writer.write_le_i24_4(self as i32))),
191
0
            (32, 4) => Ok(try!(writer.write_le_i32(self as i32))),
192
0
            _ => Err(Error::Unsupported),
193
        }
194
0
    }
195
196
    #[inline(always)]
197
0
    fn as_i16(self) -> i16 {
198
0
        self as i16
199
0
    }
200
201
0
    fn read<R: io::Read>(reader: &mut R, fmt: SampleFormat, bytes: u16, bits: u16) -> Result<i8> {
202
0
        if fmt != SampleFormat::Int {
203
0
            return Err(Error::InvalidSampleFormat);
204
0
        }
205
0
        match (bytes, bits) {
206
0
            (1, 8) => Ok(try!(reader.read_u8().map(signed_from_u8))),
207
0
            (n, _) if n > 1 => Err(Error::TooWide),
208
            // TODO: add a genric decoder for any bit depth.
209
0
            _ => Err(Error::Unsupported),
210
        }
211
0
    }
212
}
213
214
impl Sample for i16 {
215
0
    fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()> {
216
0
        self.write_padded(writer, bits, bits / 8)
217
0
    }
218
219
0
    fn write_padded<W: io::Write>(self, writer: &mut W, bits: u16, byte_width: u16) -> Result<()> {
220
0
        match (bits, byte_width) {
221
0
            (8, 1) => Ok(try!(
222
0
                writer.write_u8(u8_from_signed(try!(narrow_to_i8(self as i32))))
223
            )),
224
0
            (16, 2) => Ok(try!(writer.write_le_i16(self))),
225
0
            (24, 3) => Ok(try!(writer.write_le_i24(self as i32))),
226
0
            (24, 4) => Ok(try!(writer.write_le_i24_4(self as i32))),
227
0
            (32, 4) => Ok(try!(writer.write_le_i32(self as i32))),
228
0
            _ => Err(Error::Unsupported),
229
        }
230
0
    }
231
232
    #[inline(always)]
233
0
    fn as_i16(self) -> i16 {
234
0
        self
235
0
    }
236
237
0
    fn read<R: io::Read>(reader: &mut R, fmt: SampleFormat, bytes: u16, bits: u16) -> Result<i16> {
238
0
        if fmt != SampleFormat::Int {
239
0
            return Err(Error::InvalidSampleFormat);
240
0
        }
241
0
        match (bytes, bits) {
242
0
            (1, 8) => Ok(try!(reader.read_u8().map(signed_from_u8).map(|x| x as i16))),
243
0
            (2, 16) => Ok(try!(reader.read_le_i16())),
244
0
            (n, _) if n > 2 => Err(Error::TooWide),
245
            // TODO: add a generic decoder for any bit depth.
246
0
            _ => Err(Error::Unsupported),
247
        }
248
0
    }
249
}
250
251
impl Sample for i32 {
252
0
    fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()> {
253
0
        self.write_padded(writer, bits, bits / 8)
254
0
    }
255
256
0
    fn write_padded<W: io::Write>(self, writer: &mut W, bits: u16, byte_width: u16) -> Result<()> {
257
0
        match (bits, byte_width) {
258
0
            (8, 1) => Ok(try!(
259
0
                writer.write_u8(u8_from_signed(try!(narrow_to_i8(self))))
260
            )),
261
0
            (16, 2) => Ok(try!(writer.write_le_i16(try!(narrow_to_i16(self))))),
262
0
            (24, 3) => Ok(try!(writer.write_le_i24(try!(narrow_to_i24(self))))),
263
0
            (24, 4) => Ok(try!(writer.write_le_i24_4(try!(narrow_to_i24(self))))),
264
0
            (32, 4) => Ok(try!(writer.write_le_i32(self))),
265
0
            _ => Err(Error::Unsupported),
266
        }
267
0
    }
268
269
    #[inline(always)]
270
0
    fn as_i16(self) -> i16 {
271
0
        self as i16
272
0
    }
273
274
0
    fn read<R: io::Read>(reader: &mut R, fmt: SampleFormat, bytes: u16, bits: u16) -> Result<i32> {
275
0
        if fmt != SampleFormat::Int {
276
0
            return Err(Error::InvalidSampleFormat);
277
0
        }
278
0
        match (bytes, bits) {
279
0
            (1, 8) => Ok(try!(reader.read_u8().map(signed_from_u8).map(|x| x as i32))),
280
0
            (2, 16) => Ok(try!(reader.read_le_i16().map(|x| x as i32))),
281
0
            (3, 24) => Ok(try!(reader.read_le_i24())),
282
0
            (4, 24) => Ok(try!(reader.read_le_i24_4())),
283
0
            (4, 32) => Ok(try!(reader.read_le_i32())),
284
0
            (n, _) if n > 4 => Err(Error::TooWide),
285
            // TODO: add a generic decoder for any bit depth.
286
0
            _ => Err(Error::Unsupported),
287
        }
288
0
    }
289
}
290
291
impl Sample for f32 {
292
0
    fn write<W: io::Write>(self, writer: &mut W, bits: u16) -> Result<()> {
293
0
        self.write_padded(writer, bits, bits / 8)
294
0
    }
295
296
0
    fn write_padded<W: io::Write>(self, writer: &mut W, bits: u16, byte_width: u16) -> Result<()> {
297
0
        match (bits, byte_width) {
298
0
            (32, 4) => Ok(try!(writer.write_le_f32(self))),
299
0
            _ => Err(Error::Unsupported),
300
        }
301
0
    }
Unexecuted instantiation: <f32 as hound::Sample>::write_padded::<std::io::buffered::bufwriter::BufWriter<std::fs::File>>
Unexecuted instantiation: <f32 as hound::Sample>::write_padded::<_>
302
303
0
    fn as_i16(self) -> i16 {
304
0
        panic!("Calling as_i16 with an f32 is invalid.");
305
    }
306
307
0
    fn read<R: io::Read>(reader: &mut R, fmt: SampleFormat, bytes: u16, bits: u16) -> Result<Self> {
308
0
        if fmt != SampleFormat::Float {
309
0
            return Err(Error::InvalidSampleFormat);
310
0
        }
311
0
        match (bytes, bits) {
312
0
            (4, 32) => Ok(try!(reader.read_le_f32())),
313
0
            (n, _) if n > 4 => Err(Error::TooWide),
314
0
            _ => Err(Error::Unsupported),
315
        }
316
0
    }
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 {
395
0
    fn fmt(&self, formatter: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
396
0
        match *self {
397
0
            Error::IoError(ref err) => err.fmt(formatter),
398
0
            Error::FormatError(reason) => {
399
0
                try!(formatter.write_str("Ill-formed WAVE file: "));
400
0
                formatter.write_str(reason)
401
            }
402
            Error::TooWide => {
403
0
                formatter.write_str("The sample has more bits than the destination type.")
404
            }
405
            Error::UnfinishedSample => {
406
0
                formatter.write_str(
407
0
                    "The number of samples written is not a multiple of the number of channels.")
408
            }
409
            Error::Unsupported => {
410
0
                formatter.write_str("The wave format of the file is not supported.")
411
            }
412
            Error::InvalidSampleFormat => {
413
0
                formatter.write_str("The sample format differs from the destination format.")
414
            }
415
        }
416
0
    }
417
}
418
419
impl error::Error for Error {
420
0
    fn description(&self) -> &str {
421
0
        match *self {
422
0
            Error::IoError(ref err) => err.description(),
423
0
            Error::FormatError(reason) => reason,
424
0
            Error::TooWide => "the sample has more bits than the destination type",
425
0
            Error::UnfinishedSample => "the number of samples written is not a multiple of the number of channels",
426
0
            Error::Unsupported => "the wave format of the file is not supported",
427
0
            Error::InvalidSampleFormat => "the sample format differs from the destination format",
428
        }
429
0
    }
430
431
0
    fn cause(&self) -> Option<&error::Error> {
432
0
        match *self {
433
0
            Error::IoError(ref err) => Some(err),
434
0
            Error::FormatError(_) => None,
435
0
            Error::TooWide => None,
436
0
            Error::UnfinishedSample => None,
437
0
            Error::Unsupported => None,
438
0
            Error::InvalidSampleFormat => None,
439
        }
440
0
    }
441
}
442
443
impl From<io::Error> for Error {
444
0
    fn from(err: io::Error) -> Error {
445
0
        Error::IoError(err)
446
0
    }
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
    /// ```
506
0
    pub fn into_header_for_infinite_file(self) -> Vec<u8> {
507
0
        let mut c = std::io::Cursor::new(Vec::with_capacity(0x44));
508
0
        {
509
0
            let w = WavWriter::new(&mut c, self);
510
0
            drop(w);
511
0
        }
512
0
        let mut v = c.into_inner();
513
0
514
0
        // Set WAVE chunk size to a special signal value
515
0
        v[4] = 0xFF; v[5] = 0xFF; v[6] = 0xFF; v[7] = 0xFF;
516
0
517
0
        // Detect fmt size, get offset of data chunk's size and set it to signal value
518
0
        if v[16] == 0x10 {
519
0
            // pcm wave
520
0
            v[0x28] = 0xFF; v[0x29] = 0xFF; v[0x2A] = 0xFF; v[0x2B] = 0xFF; 
521
0
        } else if v[16] == 0x28 {
522
0
            // extensible
523
0
            v[0x40] = 0xFF; v[0x41] = 0xFF; v[0x42] = 0xFF; v[0x43] = 0xFF; 
524
0
        } else {
525
0
            unreachable!()
526
        }
527
528
0
        v
529
0
    }
530
}
531
532
#[test]
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]
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]
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]
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]
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]
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]
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]
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]
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)]
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]
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]
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
}