wave_stream/
lib.rs

1//! wave_stream is a library that allows reading and writing wave files. Random-access reading and writing
2//! is supported, as well as reading via an enumerable and writing via an enumerable. Unlike other wave
3//! libraries, the whole file is not sucked into memory.
4//!
5//! Read through the example below to understand how to read a wav's metadata, read the wav, and write a wav.
6//!
7//! It's generally reccomended that you read and write wav files as float (f32). (Unless you're cropping and
8//! appending existing 16-bit, 24-bit, or 8-bit waves files.) wave_stream does not implement any way to
9//! noise-shape or dither floating-point or 24-bit samples to 16-bit or 8-bit. (The author reccomends using
10//! sox to convert floating-point wave files to lower bits-per-sample, as sox implements great noise shaping.)
11//!
12//! Note: The wav file format is limited to no more then 4GB. Wave_stream does not support proposed extensions
13//! to the wav file format that exceed this limitation.
14//!
15//! # Example
16//!
17//! ``` rust
18//! use std::f32::consts::{PI, TAU};
19//! use std::io::Result;
20//! use std::path::Path;
21//!
22//! use wave_stream::open_wav::OpenWav;
23//! use wave_stream::samples_by_channel::SamplesByChannel;
24//! use wave_stream::wave_header::{Channels, SampleFormat, WavHeader};
25//! use wave_stream::wave_reader::{RandomAccessOpenWavReader, StreamOpenWavReader};
26//! use wave_stream::{read_wav_from_file_path, write_wav_to_file_path};
27//!
28//! fn main() {
29//!     let open_wav = read_wav_from_file_path(Path::new("some.wav")).unwrap();
30//!
31//!     // Inspect metadata
32//!     // ******************************
33//!     println!("Number of channels: {0}, samples per second: {1}, bits per sample: {2}, length in samples: {3}",
34//!         open_wav.num_channels(),
35//!         open_wav.bits_per_sample(),
36//!         open_wav.sample_rate(),
37//!         open_wav.len_samples());
38//!
39//!     // Read via random access
40//!     // ******************************
41//!     let mut random_access_wave_reader = open_wav.get_random_access_f32_reader().unwrap();
42//!     let first_sample = random_access_wave_reader.read_sample(0).unwrap();
43//!     println!(
44//!         "First sample, front_left: {0}",
45//!         first_sample.front_left.expect("front_left missing")
46//!     );
47//!
48//!     // Read via an enumerable: Find the loudest sample in the wave file
49//!     // ******************************
50//!     let open_wav = read_wav_from_file_path(Path::new("some.wav")).unwrap();
51//!     let mut loudest_sample = f32::MIN;
52//!
53//!     // Note that the wave is read as f32 values in this example.
54//!     // Reading as 8-bit, (i8) 16-bit, (i16) and 24-bit (i32) is also supported.
55//!     // Upsampling during reads is supported. (You can read an 8-bit wav file as f32)
56//!     // Downsampling during reads isn't supported. (You can't read a floating point wav file as i8)
57//!     //
58//!     // In general:
59//!     // - For audio manipulation: f32 is *strongly* reccomended
60//!     // - Only use i16, i32, (or i8), when cutting existing audio without manipulation
61//!     let iterator = open_wav.get_stream_f32_reader().unwrap().into_iter();
62//!
63//!     for samples_result in iterator {
64//!         let samples = samples_result.unwrap();
65//!
66//!         for sample in samples.to_vec() {
67//!             loudest_sample = f32::max(loudest_sample, sample);
68//!         }
69//!     }
70//!
71//!     println!("Loudest sample: {0}", loudest_sample);
72//!
73//!     // Write via random access
74//!     // ******************************
75//!     let sample_rate = 96000;
76//!     let header = WavHeader {
77//!         sample_format: SampleFormat::Float,
78//!         channels: Channels::new()
79//!             .front_left(),
80//!         sample_rate,
81//!     };
82//!
83//!     let open_wav = write_wav_to_file_path(Path::new("ramp.wav"), header).unwrap();
84//!
85//!     // Note that the wave is written as f32 (32-bit float). 8-bit (i8), 16-bit (i16), and 24-bit (i32) integer are
86//!     // also supprted.
87//!     // Downconverting (IE, float -> 16-bit) is *not* supported. In general, it's best to perform audio manipulation
88//!     // using f32. Outputting to an integer format like 16-bit (CD quality) will only sound good if you implement your
89//!     // own noise shaper or dithering algorithm. A command-line tool like sox will perform excellent noise shaping if
90//!     // you write a 32-bit float wav, and then use sox to convert it to 16-bit.
91//!     let mut random_access_wave_writer = open_wav.get_random_access_f32_writer().unwrap();
92//!
93//!     let samples_in_ramp = 2000;
94//!     let samples_in_ramp_f32 = samples_in_ramp as f32;
95//!     for sample in 0usize..((sample_rate * 3) as usize) {
96//!         // Write 3 seconds of samples
97//!         let modulo = (sample % samples_in_ramp) as f32;
98//!         let sample_value = (2f32 * modulo / samples_in_ramp_f32) - 1f32;
99//!         random_access_wave_writer
100//!             .write_samples(
101//!                 sample,
102//!                 SamplesByChannel::new()
103//!                     .front_left(sample_value))
104//!             .unwrap();
105//!     }
106//!
107//!     random_access_wave_writer.flush().unwrap();
108//!
109//!     // Write via iterator
110//!     // ******************************
111//!     let header = WavHeader {
112//!         sample_format: SampleFormat::Float,
113//!         channels: Channels::new()
114//!             .front_left(),
115//!         sample_rate,
116//!     };
117//!
118//!     let open_wav = write_wav_to_file_path(Path::new("sine.wav"), header).unwrap();
119//!     let sine_iterator = SineIterator {
120//!         period: (sample_rate / 60) as f32,
121//!         current_sample: PI, // Start at 0 crossing
122//!     };
123//!     let sine_iterator_three_seconds = sine_iterator.take((sample_rate * 3u32) as usize); // Write 3 seconds
124//!     open_wav.write_all_f32(sine_iterator_three_seconds).unwrap();
125//! }
126//!
127//! // Used when writing via iterator
128//! struct SineIterator {
129//!     period: f32,
130//!     current_sample: f32,
131//! }
132//!
133//! // Used when writing via iterator
134//! impl Iterator for SineIterator {
135//!     type Item = Result<SamplesByChannel<f32>>;
136//!
137//!     fn next(&mut self) -> Option<Result<SamplesByChannel<f32>>> {
138//!         let result = (self.current_sample / self.period * TAU).sin();
139//!         self.current_sample += 1f32;
140//!
141//!         if self.current_sample > self.period {
142//!             self.current_sample = 0f32;
143//!         }
144//!
145//!         return Some(Ok(SamplesByChannel::new()
146//!             .front_left(result)));
147//!     }
148//! }
149//!
150//! ```
151
152use std::fs::File;
153use std::io::{BufReader, BufWriter, ErrorKind, Read, Result, Seek, Write};
154use std::path::Path;
155
156pub mod open_wav;
157pub mod reader;
158pub mod wave_header;
159pub mod wave_reader;
160pub mod wave_writer;
161pub mod writer;
162
163mod assertions;
164mod constants;
165pub mod samples_by_channel;
166mod upconvert;
167
168use reader::ReadEx;
169use wave_header::*;
170use wave_reader::*;
171use wave_writer::*;
172use writer::WriteEx;
173
174/// Reads a wav from a given path
175///
176/// # Arguments
177///
178/// * 'file_path' - A Path that is the path to the wav file to read
179///
180pub fn read_wav_from_file_path(file_path: &Path) -> Result<OpenWavReader<BufReader<File>>> {
181    let file = File::open(file_path)?;
182    let reader = BufReader::new(file);
183
184    read_wav(reader)
185}
186
187/// Reads a wav from a Read struct
188///
189/// # Arguments
190///
191/// * 'reader' - A Read struct. It is strongly recommended that this struct implement some form of buffering, such as via a BufReader
192pub fn read_wav<TReader: 'static + Read>(mut reader: TReader) -> Result<OpenWavReader<TReader>> {
193    // Verify that this is a RIFF file
194    reader.assert_str(
195        "RIFF",
196        ErrorKind::InvalidInput,
197        "Not a WAVE file (Missing RIFF Header)",
198    )?;
199    let _file_length = reader.read_u32()?;
200    reader.assert_str(
201        "WAVE",
202        ErrorKind::Unsupported,
203        "Not a WAVE file (Missing WAVE header)",
204    )?;
205
206    // file position is 12
207
208    let mut subchunk_size = 0usize;
209    let header = WavHeader::from_reader(&mut reader, &mut subchunk_size)?;
210
211    // subchunk size doesn't include 4-letter prefix and 4-byte length
212
213    OpenWavReader::new(reader, header, 20 + subchunk_size)
214}
215
216/// Starts writing a wav to a Path. Returns an OpenWavWriter struct that is used to write the contents of the wav
217///
218/// # Arguments
219///
220/// * 'file_path' - The path to where the wav will be written
221/// * 'header' - The header information in the wav. This specifies things like sampling rate, sample bit depth, ect
222///
223/// # Examples
224///
225/// ```
226/// use std::path::Path;
227///
228/// use wave_stream::samples_by_channel::SamplesByChannel;
229/// use wave_stream::wave_header::{Channels, SampleFormat, WavHeader};
230/// use wave_stream::{read_wav_from_file_path, write_wav_to_file_path};
231///
232/// let header = WavHeader {
233///     sample_format: SampleFormat::Float,
234///     channels: Channels {
235///             front_left: true,
236///             front_right: true,
237///             front_center: false,
238///             low_frequency: false,
239///             back_left: false,
240///             back_right: false,
241///             front_left_of_center: false,
242///             front_right_of_center: false,
243///             back_center: false,
244///             side_left: false,
245///             side_right: false,
246///             top_center: false,
247///             top_front_left: false,
248///             top_front_center: false,
249///             top_front_right: false,
250///             top_back_left: false,
251///             top_back_center: false,
252///             top_back_right: false,
253///         },
254///     sample_rate: 96000,
255/// };
256/// let mut open_wav = write_wav_to_file_path(Path::new("some.wav"), header).unwrap();
257/// let mut writer = open_wav.get_random_access_f32_writer().unwrap();
258///
259/// // Sample 0
260/// writer.write_samples(0, SamplesByChannel {
261///             front_left: Some(0.0),
262///             front_right: Some(0.0),
263///             front_center: None,
264///             low_frequency: None,
265///             back_left: None,
266///             back_right: None,
267///             front_left_of_center: None,
268///             front_right_of_center: None,
269///             back_center: None,
270///             side_left: None,
271///             side_right: None,
272///             top_center: None,
273///             top_front_left: None,
274///             top_front_center: None,
275///             top_front_right: None,
276///             top_back_left: None,
277///             top_back_center: None,
278///             top_back_right: None,
279///         }).unwrap();
280///
281/// // Sample 1
282/// writer.write_samples(1, SamplesByChannel {
283///             front_left: Some(0.0),
284///             front_right: Some(0.0),
285///             front_center: None,
286///             low_frequency: None,
287///             back_left: None,
288///             back_right: None,
289///             front_left_of_center: None,
290///             front_right_of_center: None,
291///             back_center: None,
292///             side_left: None,
293///             side_right: None,
294///             top_center: None,
295///             top_front_left: None,
296///             top_front_center: None,
297///             top_front_right: None,
298///             top_back_left: None,
299///             top_back_center: None,
300///             top_back_right: None,
301///         }).unwrap();
302///
303/// // Sample 2
304/// writer.write_samples(2, SamplesByChannel {
305///             front_left: Some(0.0),
306///             front_right: Some(0.0),
307///             front_center: None,
308///             low_frequency: None,
309///             back_left: None,
310///             back_right: None,
311///             front_left_of_center: None,
312///             front_right_of_center: None,
313///             back_center: None,
314///             side_left: None,
315///             side_right: None,
316///             top_center: None,
317///             top_front_left: None,
318///             top_front_center: None,
319///             top_front_right: None,
320///             top_back_left: None,
321///             top_back_center: None,
322///             top_back_right: None,
323///         }).unwrap();
324///
325/// writer.flush().unwrap();
326/// ```
327pub fn write_wav_to_file_path(file_path: &Path, header: WavHeader) -> Result<OpenWavWriter> {
328    let file = File::create(file_path)?;
329    let writer = BufWriter::new(file);
330
331    write_wav(writer, header)
332}
333
334/// Starts writing a wav to a (Write + Seek) struct. Returns an OpenWavWriter struct that is used to write the contents of the wav
335///
336/// # Arguments
337///
338/// * 'writer' - The (Write + Seek) struct to write the wav into. It is strongly recommended that this struct implement some form of buffering, such as via a BufWriter
339/// * 'header' - The header information in the wav. This specifies things like sampling rate, sample bit depth, ect
340pub fn write_wav<TWriter: 'static + Write + Seek>(
341    mut writer: TWriter,
342    header: WavHeader,
343) -> Result<OpenWavWriter> {
344    // Write RIFF header and format
345    writer.write(b"RIFF    WAVE")?;
346
347    WavHeader::to_writer(&mut writer, &header)?;
348
349    OpenWavWriter::new(writer, header)
350}
351
352#[cfg(test)]
353mod tests {
354    use std::fmt::Debug;
355    use std::i8;
356    use std::io::{Cursor, Take};
357
358    use tempfile::tempdir;
359
360    use super::*;
361    use crate::open_wav::OpenWav;
362    use crate::samples_by_channel::SamplesByChannel;
363    use crate::upconvert::{
364        INT_16_DIVIDE_FOR_FLOAT, INT_24_DIVIDE_FOR_FLOAT, INT_8_ADD_FOR_FLOAT_ABS,
365        INT_8_DIVIDE_FOR_FLOAT,
366    };
367
368    #[test]
369    fn open_sanity() {
370        let open_wav = read_wav_from_file_path(Path::new("test_data/short_float.wav")).unwrap();
371        assert_eq!(SampleFormat::Float, open_wav.sample_format());
372        assert_eq!(1, open_wav.num_channels());
373        assert_eq!(32, open_wav.bits_per_sample());
374        assert_eq!(48000, open_wav.sample_rate());
375        assert_eq!(1267, open_wav.len_samples());
376
377        let open_wav = read_wav_from_file_path(Path::new("test_data/short_24.wav")).unwrap();
378        assert_eq!(SampleFormat::Int24, open_wav.sample_format());
379        assert_eq!(1, open_wav.num_channels());
380        assert_eq!(24, open_wav.bits_per_sample());
381        assert_eq!(48000, open_wav.sample_rate());
382        assert_eq!(1267, open_wav.len_samples());
383
384        let open_wav = read_wav_from_file_path(Path::new("test_data/short_16.wav")).unwrap();
385        assert_eq!(SampleFormat::Int16, open_wav.sample_format());
386        assert_eq!(1, open_wav.num_channels());
387        assert_eq!(16, open_wav.bits_per_sample());
388        assert_eq!(48000, open_wav.sample_rate());
389        assert_eq!(1267, open_wav.len_samples());
390    }
391
392    #[test]
393    fn read_float_sanity() {
394        let open_wav = read_wav_from_file_path(Path::new("test_data/short_float.wav")).unwrap();
395        let wave_reader_float = open_wav.get_random_access_f32_reader().unwrap();
396        assert_eq!(
397            SampleFormat::Float,
398            wave_reader_float.info().sample_format()
399        );
400        assert_eq!(1, wave_reader_float.info().num_channels());
401        assert_eq!(32, wave_reader_float.info().bits_per_sample());
402        assert_eq!(48000, wave_reader_float.info().sample_rate());
403        assert_eq!(1267, wave_reader_float.info().len_samples());
404    }
405
406    #[test]
407    fn read_random_i8() {
408        read_random(
409            Path::new("test_data/short_8.wav"),
410            Box::new(|open_wav| open_wav.get_random_access_i8_reader()),
411            i8::from_le_bytes([0x7D]),
412            i8::from_le_bytes([0x7F]),
413            i8::from_le_bytes([0x7A]),
414        )
415        .unwrap();
416    }
417
418    #[test]
419    fn read_random_i8_as_i16() {
420        read_random(
421            Path::new("test_data/short_8.wav"),
422            Box::new(|open_wav| open_wav.get_random_access_i16_reader()),
423            32255,
424            32767,
425            31487,
426        )
427        .unwrap();
428    }
429
430    #[test]
431    fn read_random_i8_as_i24() {
432        read_random(
433            Path::new("test_data/short_8.wav"),
434            Box::new(|open_wav| open_wav.get_random_access_i24_reader()),
435            8257535,
436            8388607,
437            8060927,
438        )
439        .unwrap();
440    }
441
442    #[test]
443    fn read_random_i8_as_f32() {
444        read_random(
445            Path::new("test_data/short_8.wav"),
446            Box::new(|open_wav| open_wav.get_random_access_f32_reader()),
447            0.9843137,
448            1.0,
449            0.9607843,
450        )
451        .unwrap();
452    }
453
454    #[test]
455    fn read_random_i16() {
456        read_random(
457            Path::new("test_data/short_16.wav"),
458            Box::new(|open_wav| open_wav.get_random_access_i16_reader()),
459            i16::from_le_bytes([0x61, 0xFD]),
460            i16::from_le_bytes([0xF9, 0xFD]),
461            i16::from_le_bytes([0x9C, 0xFE]),
462        )
463        .unwrap();
464    }
465
466    #[test]
467    fn read_random_i16_as_i24() {
468        read_random(
469            Path::new("test_data/short_16.wav"),
470            Box::new(|open_wav| open_wav.get_random_access_i24_reader()),
471            -171776,
472            -132864,
473            -91136,
474        )
475        .unwrap();
476    }
477
478    #[test]
479    fn read_random_i16_as_f32() {
480        read_random(
481            Path::new("test_data/short_16.wav"),
482            Box::new(|open_wav| open_wav.get_random_access_f32_reader()),
483            -0.020462334,
484            -0.015823603,
485            -0.010849178,
486        )
487        .unwrap();
488    }
489
490    #[test]
491    fn read_random_i24() {
492        read_random(
493            Path::new("test_data/short_24.wav"),
494            Box::new(|open_wav| open_wav.get_random_access_i24_reader()),
495            i32::from_le_bytes([0x00, 0x2E, 0x61, 0xFD]) >> 8,
496            i32::from_le_bytes([0x00, 0xE7, 0xF8, 0xFD]) >> 8,
497            i32::from_le_bytes([0x00, 0x94, 0x9C, 0xFE]) >> 8,
498        )
499        .unwrap();
500    }
501
502    #[test]
503    fn read_random_i24_as_f32() {
504        read_random(
505            Path::new("test_data/short_24.wav"),
506            Box::new(|open_wav| open_wav.get_random_access_f32_reader()),
507            -0.020471752,
508            -0.015841544,
509            -0.010846555,
510        )
511        .unwrap();
512    }
513
514    #[test]
515    fn read_random_f32() {
516        read_random(
517            Path::new("test_data/short_float.wav"),
518            Box::new(|open_wav| open_wav.get_random_access_f32_reader()),
519            f32::from_le_bytes([0x6D, 0xB4, 0xA7, 0xBC]),
520            f32::from_le_bytes([0x02, 0xC6, 0x81, 0xBC]),
521            f32::from_le_bytes([0xA0, 0xB5, 0x31, 0xBC]),
522        )
523        .unwrap();
524    }
525
526    fn read_random<T: Debug + PartialEq>(
527        path: &Path,
528        get_random_access_reader: Box<
529            dyn FnOnce(OpenWavReader<BufReader<File>>) -> Result<RandomAccessWavReader<T>>,
530        >,
531        expected_sample_0: T,
532        expected_sample_1: T,
533        expected_sample_end: T,
534    ) -> Result<()> {
535        let open_wav = read_wav_from_file_path(path)?;
536        let mut wave_reader = get_random_access_reader(open_wav)?;
537
538        let actual_sample = wave_reader.read_sample(0)?;
539        assert_eq!(
540            expected_sample_0,
541            actual_sample.front_left.expect("Front left missing"),
542            "Wrong sample read at sample 0, channel 0"
543        );
544
545        let actual_sample = wave_reader.read_sample(1)?;
546        assert_eq!(
547            expected_sample_1,
548            actual_sample.front_left.expect("Front left missing"),
549            "Wrong sample read at sample 1, channel 0"
550        );
551
552        let actual_sample = wave_reader.read_sample(wave_reader.info().len_samples() - 1)?;
553        assert_eq!(
554            expected_sample_end,
555            actual_sample.front_left.expect("Front left missing"),
556            "Wrong sample read at sample 1266, channel 0"
557        );
558
559        Ok(())
560    }
561
562    #[test]
563    fn read_stream_f32_sanity() {
564        let file = File::open(Path::new("test_data/short_float.wav")).unwrap();
565        let reader = BufReader::new(file).take(u64::MAX); // calling "take" forces reader to be just a Read, instead of a Read + Seek
566
567        let open_wav = read_wav(reader).unwrap();
568        let wave_reader_float = open_wav.get_stream_f32_reader().unwrap();
569        assert_eq!(
570            SampleFormat::Float,
571            wave_reader_float.info().sample_format()
572        );
573        assert_eq!(1, wave_reader_float.info().num_channels());
574        assert_eq!(32, wave_reader_float.info().bits_per_sample());
575        assert_eq!(48000, wave_reader_float.info().sample_rate());
576        assert_eq!(1267, wave_reader_float.info().len_samples());
577    }
578
579    #[test]
580    fn read_stream_i8() {
581        read_stream(
582            Path::new("test_data/short_8.wav"),
583            Box::new(|open_wav| open_wav.get_stream_i8_reader()),
584            i8::from_le_bytes([0x7D]),
585            i8::from_le_bytes([0x7F]),
586            i8::from_le_bytes([0x7A]),
587        )
588        .unwrap();
589    }
590
591    #[test]
592    fn read_stream_i8_as_i16() {
593        read_stream(
594            Path::new("test_data/short_8.wav"),
595            Box::new(|open_wav| open_wav.get_stream_i16_reader()),
596            32255,
597            32767,
598            31487,
599        )
600        .unwrap();
601    }
602
603    #[test]
604    fn read_stream_i8_as_i24() {
605        read_stream(
606            Path::new("test_data/short_8.wav"),
607            Box::new(|open_wav| open_wav.get_stream_i24_reader()),
608            8257535,
609            8388607,
610            8060927,
611        )
612        .unwrap();
613    }
614
615    #[test]
616    fn read_stream_i8_as_f32() {
617        read_stream(
618            Path::new("test_data/short_8.wav"),
619            Box::new(|open_wav| open_wav.get_stream_f32_reader()),
620            0.9843137,
621            1.0,
622            0.9607843,
623        )
624        .unwrap();
625    }
626
627    #[test]
628    fn read_stream_i16() {
629        read_stream(
630            Path::new("test_data/short_16.wav"),
631            Box::new(|open_wav| open_wav.get_stream_i16_reader()),
632            i16::from_le_bytes([0x61, 0xFD]),
633            i16::from_le_bytes([0xF9, 0xFD]),
634            i16::from_le_bytes([0x9C, 0xFE]),
635        )
636        .unwrap();
637    }
638
639    #[test]
640    fn read_stream_i16_as_i24() {
641        read_stream(
642            Path::new("test_data/short_16.wav"),
643            Box::new(|open_wav| open_wav.get_stream_i24_reader()),
644            -171776,
645            -132864,
646            -91136,
647        )
648        .unwrap();
649    }
650
651    #[test]
652    fn read_stream_i16_as_f32() {
653        read_stream(
654            Path::new("test_data/short_16.wav"),
655            Box::new(|open_wav| open_wav.get_stream_f32_reader()),
656            -0.020462334,
657            -0.015823603,
658            -0.010849178,
659        )
660        .unwrap();
661    }
662
663    #[test]
664    fn read_stream_i24() {
665        read_stream(
666            Path::new("test_data/short_24.wav"),
667            Box::new(|open_wav| open_wav.get_stream_i24_reader()),
668            i32::from_le_bytes([0x00, 0x2E, 0x61, 0xFD]) >> 8,
669            i32::from_le_bytes([0x00, 0xE7, 0xF8, 0xFD]) >> 8,
670            i32::from_le_bytes([0x00, 0x94, 0x9C, 0xFE]) >> 8,
671        )
672        .unwrap();
673    }
674
675    #[test]
676    fn read_stream_i24_as_f32() {
677        read_stream(
678            Path::new("test_data/short_24.wav"),
679            Box::new(|open_wav| open_wav.get_stream_f32_reader()),
680            -0.020471752,
681            -0.015841544,
682            -0.010846555,
683        )
684        .unwrap();
685    }
686
687    #[test]
688    fn read_stream_f32() {
689        read_stream(
690            Path::new("test_data/short_float.wav"),
691            Box::new(|open_wav| open_wav.get_stream_f32_reader()),
692            f32::from_le_bytes([0x6D, 0xB4, 0xA7, 0xBC]),
693            f32::from_le_bytes([0x02, 0xC6, 0x81, 0xBC]),
694            f32::from_le_bytes([0xA0, 0xB5, 0x31, 0xBC]),
695        )
696        .unwrap();
697    }
698
699    fn read_stream<T: Debug + PartialEq + Default + Clone>(
700        path: &Path,
701        get_stream_reader: Box<
702            dyn FnOnce(OpenWavReader<Take<BufReader<File>>>) -> Result<StreamWavReader<T>>,
703        >,
704        expected_sample_0: T,
705        expected_sample_1: T,
706        expected_sample_end: T,
707    ) -> Result<()> {
708        let mut current_sample: usize = 0;
709
710        let file = File::open(path)?;
711        // calling "take" forces reader to be just a Read, instead of a Read + Seek
712        let reader = BufReader::new(file).take(u64::MAX);
713
714        let open_wav = read_wav(reader)?;
715
716        let iterator = get_stream_reader(open_wav)?.into_iter();
717        for samples_result in iterator {
718            let samples = samples_result?;
719
720            assert!(samples.front_left.is_some(), "Front left sample not read");
721            assert_eq!(None, samples.front_right, "Sample should not be read");
722            assert_eq!(None, samples.front_center, "Sample should not be read");
723            assert_eq!(None, samples.low_frequency, "Sample should not be read");
724            assert_eq!(None, samples.back_left, "Sample should not be read");
725            assert_eq!(None, samples.back_right, "Sample should not be read");
726            assert_eq!(
727                None, samples.front_left_of_center,
728                "Sample should not be read"
729            );
730            assert_eq!(
731                None, samples.front_right_of_center,
732                "Sample should not be read"
733            );
734            assert_eq!(None, samples.back_center, "Sample should not be read");
735            assert_eq!(None, samples.side_left, "Sample should not be read");
736            assert_eq!(None, samples.side_right, "Sample should not be read");
737            assert_eq!(None, samples.top_center, "Sample should not be read");
738            assert_eq!(None, samples.top_front_left, "Sample should not be read");
739            assert_eq!(None, samples.top_front_center, "Sample should not be read");
740            assert_eq!(None, samples.top_front_right, "Sample should not be read");
741            assert_eq!(None, samples.top_back_left, "Sample should not be read");
742            assert_eq!(None, samples.top_back_center, "Sample should not be read");
743            assert_eq!(None, samples.top_back_right, "Sample should not be read");
744
745            if current_sample == 0 {
746                assert_eq!(
747                    expected_sample_0,
748                    samples.front_left.unwrap(),
749                    "Wrong sample read at sample 0, channel 0"
750                );
751            } else if current_sample == 1 {
752                assert_eq!(
753                    expected_sample_1,
754                    samples.front_left.unwrap(),
755                    "Wrong sample read at sample 1, channel 0"
756                );
757            } else if current_sample == 1266 {
758                assert_eq!(
759                    expected_sample_end,
760                    samples.front_left.unwrap(),
761                    "Wrong sample read at sample 1266, channel 0"
762                );
763            }
764
765            current_sample += 1;
766        }
767
768        assert_eq!(1267, current_sample, "Wrong number of samples read");
769
770        Ok(())
771    }
772
773    fn test_with_file(file_test_callback: Box<dyn FnOnce(&Path) -> Result<()>>) {
774        let temp_dir = tempdir().unwrap();
775
776        {
777            let path = temp_dir.path().join("tempwav.wav");
778            file_test_callback(&path).unwrap();
779        }
780    }
781
782    #[test]
783    fn write_sanity() {
784        test_with_file(Box::new(|path| {
785            let header = WavHeader {
786                sample_format: SampleFormat::Float,
787                channels: Channels::new()
788                    .front_left()
789                    .front_right()
790                    .front_center()
791                    .low_frequency()
792                    .back_left()
793                    .back_right(),
794                sample_rate: 96000,
795            };
796            let mut open_wav = write_wav_to_file_path(path, header)?;
797
798            assert_eq!(
799                SampleFormat::Float,
800                open_wav.sample_format(),
801                "Wrong sample format"
802            );
803            assert_eq!(6, open_wav.num_channels(), "Wrong channels");
804            assert_eq!(96000, open_wav.sample_rate(), "Wrong sampling rate");
805            assert_eq!(4, open_wav.bytes_per_sample(), "Wrong bytes per sample");
806            assert_eq!(32, open_wav.bits_per_sample(), "Wrong bits per sample");
807
808            open_wav.flush()?;
809
810            let open_wav = read_wav_from_file_path(path)?;
811
812            assert_eq!(
813                SampleFormat::Float,
814                open_wav.sample_format(),
815                "Wrong sample format when reading"
816            );
817            assert_eq!(6, open_wav.num_channels(), "Wrong channels when reading");
818            assert_eq!(
819                96000,
820                open_wav.sample_rate(),
821                "Wrong sampling rate when reading"
822            );
823            assert_eq!(
824                4,
825                open_wav.bytes_per_sample(),
826                "Wrong bytes per sample when reading"
827            );
828            assert_eq!(
829                32,
830                open_wav.bits_per_sample(),
831                "Wrong bits per sample when reading"
832            );
833            assert_eq!(0, open_wav.len_samples(), "Wrong length when reading");
834
835            Ok(())
836        }));
837    }
838
839    #[test]
840    fn write_random_i8() {
841        write_random(
842            SampleFormat::Int8,
843            Box::new(|open_wav| open_wav.get_random_access_i8_reader()),
844            Box::new(|sample_value| sample_value),
845            Box::new(|open_wav| open_wav.get_random_access_i8_writer()),
846            Box::new(|sample_value| sample_value as i8),
847        );
848    }
849
850    #[test]
851    fn write_random_i8_as_i16() {
852        write_random(
853            SampleFormat::Int16,
854            // Wav is upconverted from 8-bit to 16-bit on read
855            Box::new(|open_wav| open_wav.get_random_access_i16_reader()),
856            Box::new(|sample_value| {
857                let sample_value = sample_value as i32;
858                if sample_value > 0 {
859                    return (((sample_value + 1) / 256) - 1) as i8;
860                } else {
861                    // sample_value < 0 {
862                    return (sample_value / 256) as i8;
863                }
864            }),
865            Box::new(|open_wav| open_wav.get_random_access_i8_writer()),
866            Box::new(|sample_value| sample_value as i8),
867        );
868    }
869
870    #[test]
871    fn write_random_i8_as_i24() {
872        write_random(
873            SampleFormat::Int24,
874            // Wav is upconverted from 8-bit to 24-bit on read
875            Box::new(|open_wav| open_wav.get_random_access_i24_reader()),
876            Box::new(|sample_value| {
877                if sample_value > 0 {
878                    return (((sample_value + 1) / 65536) - 1) as i8;
879                } else {
880                    // sample_value < 0 {
881                    return (sample_value / 65536) as i8;
882                }
883            }),
884            Box::new(|open_wav| open_wav.get_random_access_i8_writer()),
885            Box::new(|sample_value| sample_value as i8),
886        );
887    }
888
889    #[test]
890    fn write_random_i8_as_f32() {
891        write_random(
892            SampleFormat::Float,
893            Box::new(|open_wav| open_wav.get_random_access_f32_reader()),
894            Box::new(|sample_value| {
895                let sample_int_8_abs = (sample_value + 1.0) * INT_8_DIVIDE_FOR_FLOAT;
896                let sample_int_8_as_float = sample_int_8_abs - INT_8_ADD_FOR_FLOAT_ABS;
897                return sample_int_8_as_float as i8;
898            }),
899            Box::new(|open_wav| open_wav.get_random_access_i8_writer()),
900            Box::new(|sample_value| sample_value as i8),
901        );
902    }
903
904    #[test]
905    fn write_random_i16() {
906        write_random(
907            SampleFormat::Int16,
908            Box::new(|open_wav| open_wav.get_random_access_i16_reader()),
909            Box::new(|sample_value| sample_value),
910            Box::new(|open_wav| open_wav.get_random_access_i16_writer()),
911            Box::new(|sample_value| sample_value as i16),
912        );
913    }
914
915    #[test]
916    fn write_random_i16_as_i24() {
917        write_random(
918            SampleFormat::Int24,
919            // Wav is upconverted from 16-bit to 24-bit on read
920            Box::new(|open_wav| open_wav.get_random_access_i24_reader()),
921            Box::new(|sample_value| {
922                if sample_value > 0 {
923                    return (((sample_value + 1) / 256) - 1) as i16;
924                } else {
925                    // sample_value < 0 {
926                    return (sample_value / 256) as i16;
927                }
928            }),
929            Box::new(|open_wav| open_wav.get_random_access_i16_writer()),
930            Box::new(|sample_value| sample_value as i16),
931        );
932    }
933
934    #[test]
935    fn write_random_i16_as_f32() {
936        write_random(
937            SampleFormat::Float,
938            Box::new(|open_wav| open_wav.get_random_access_f32_reader()),
939            Box::new(|sample_value| (sample_value * INT_16_DIVIDE_FOR_FLOAT) as i16),
940            Box::new(|open_wav| open_wav.get_random_access_i16_writer()),
941            Box::new(|sample_value| sample_value as i16),
942        );
943    }
944
945    #[test]
946    fn write_random_i24() {
947        write_random(
948            SampleFormat::Int24,
949            Box::new(|open_wav| open_wav.get_random_access_i24_reader()),
950            Box::new(|sample_value| sample_value),
951            Box::new(|open_wav| open_wav.get_random_access_i24_writer()),
952            Box::new(|sample_value| sample_value as i32),
953        );
954    }
955
956    #[test]
957    fn write_random_i24_as_f32() {
958        write_random(
959            SampleFormat::Float,
960            Box::new(|open_wav| open_wav.get_random_access_f32_reader()),
961            Box::new(|sample_value| (sample_value * INT_24_DIVIDE_FOR_FLOAT - 0.5) as i32),
962            Box::new(|open_wav| open_wav.get_random_access_i24_writer()),
963            Box::new(|sample_value| sample_value as i32),
964        );
965    }
966
967    #[test]
968    fn write_random_f32() {
969        write_random(
970            SampleFormat::Float,
971            Box::new(|open_wav| open_wav.get_random_access_f32_reader()),
972            Box::new(|sample_value| sample_value),
973            Box::new(|open_wav| open_wav.get_random_access_f32_writer()),
974            Box::new(|sample_value| sample_value as f32),
975        );
976    }
977
978    fn write_random<T: Debug + PartialEq + 'static, TFile: Debug + PartialEq + 'static>(
979        sample_format: SampleFormat,
980        get_random_access_reader: Box<
981            dyn FnOnce(OpenWavReader<BufReader<File>>) -> Result<RandomAccessWavReader<TFile>>,
982        >,
983        convert_sample_to_read: Box<dyn Fn(TFile) -> T>,
984        get_random_access_writer: Box<
985            dyn FnOnce(OpenWavWriter) -> Result<RandomAccessWavWriter<T>>,
986        >,
987        convert_sample_to_write: Box<dyn Fn(i32) -> T>,
988    ) {
989        test_with_file(Box::new(move |path| {
990            let header = WavHeader {
991                sample_format,
992                channels: Channels {
993                    front_left: true,
994                    front_right: true,
995                    front_center: true,
996                    low_frequency: true,
997                    back_left: true,
998                    back_right: true,
999                    front_left_of_center: true,
1000                    front_right_of_center: true,
1001                    back_center: true,
1002                    side_left: true,
1003                    side_right: true,
1004                    top_center: true,
1005                    top_front_left: true,
1006                    top_front_center: true,
1007                    top_front_right: true,
1008                    top_back_left: true,
1009                    top_back_center: true,
1010                    top_back_right: true,
1011                },
1012                sample_rate: 96000,
1013            };
1014            let open_wav = write_wav_to_file_path(path, header)?;
1015            let mut writer = get_random_access_writer(open_wav)?;
1016
1017            for sample_inv in 0..100usize {
1018                let sample = 99 - sample_inv;
1019                let sample_value = (sample as i32) * 18;
1020                let samples_by_channel = SamplesByChannel::<T> {
1021                    front_left: Some(convert_sample_to_write(sample_value + 0i32)),
1022                    front_right: Some(convert_sample_to_write(sample_value + 1)),
1023                    front_center: Some(convert_sample_to_write(sample_value + 2)),
1024                    low_frequency: Some(convert_sample_to_write(sample_value + 3)),
1025                    back_left: Some(convert_sample_to_write(sample_value + 4)),
1026                    back_right: Some(convert_sample_to_write(sample_value + 5)),
1027                    front_left_of_center: Some(convert_sample_to_write(sample_value + 6)),
1028                    front_right_of_center: Some(convert_sample_to_write(sample_value + 7)),
1029                    back_center: Some(convert_sample_to_write(sample_value + 8)),
1030                    side_left: Some(convert_sample_to_write(sample_value + 9)),
1031                    side_right: Some(convert_sample_to_write(sample_value + 10)),
1032                    top_center: Some(convert_sample_to_write(sample_value + 11)),
1033                    top_front_left: Some(convert_sample_to_write(sample_value + 12)),
1034                    top_front_center: Some(convert_sample_to_write(sample_value + 13)),
1035                    top_front_right: Some(convert_sample_to_write(sample_value + 14)),
1036                    top_back_left: Some(convert_sample_to_write(sample_value + 15)),
1037                    top_back_center: Some(convert_sample_to_write(sample_value + 16)),
1038                    top_back_right: Some(convert_sample_to_write(sample_value + 17)),
1039                };
1040                writer.write_samples(sample, samples_by_channel)?;
1041            }
1042
1043            writer.flush()?;
1044
1045            let open_wav = read_wav_from_file_path(path)?;
1046            assert_eq!(100, open_wav.len_samples(), "Wrong length of samples");
1047
1048            let mut reader = get_random_access_reader(open_wav)?;
1049
1050            for sample in 0..100usize {
1051                let samples_by_channel = reader.read_sample(sample)?;
1052
1053                assert_eq!(
1054                    convert_sample_to_write((sample as i32) * 18 + (0 as i32)),
1055                    convert_sample_to_read(samples_by_channel.front_left.expect("front_left")),
1056                    "Wrong sample read at {sample}, channel front_left"
1057                );
1058                assert_eq!(
1059                    convert_sample_to_write((sample as i32) * 18 + (1 as i32)),
1060                    convert_sample_to_read(samples_by_channel.front_right.expect("front_right")),
1061                    "Wrong sample read at {sample}, channel front_right"
1062                );
1063                assert_eq!(
1064                    convert_sample_to_write((sample as i32) * 18 + (2 as i32)),
1065                    convert_sample_to_read(samples_by_channel.front_center.expect("front_center")),
1066                    "Wrong sample read at {sample}, channel front_center"
1067                );
1068                assert_eq!(
1069                    convert_sample_to_write((sample as i32) * 18 + (3 as i32)),
1070                    convert_sample_to_read(
1071                        samples_by_channel.low_frequency.expect("low_frequency")
1072                    ),
1073                    "Wrong sample read at {sample}, channel low_frequency"
1074                );
1075                assert_eq!(
1076                    convert_sample_to_write((sample as i32) * 18 + (4 as i32)),
1077                    convert_sample_to_read(samples_by_channel.back_left.expect("back_left")),
1078                    "Wrong sample read at {sample}, channel back_left"
1079                );
1080                assert_eq!(
1081                    convert_sample_to_write((sample as i32) * 18 + (5 as i32)),
1082                    convert_sample_to_read(samples_by_channel.back_right.expect("back_right")),
1083                    "Wrong sample read at {sample}, channel back_right"
1084                );
1085                assert_eq!(
1086                    convert_sample_to_write((sample as i32) * 18 + (6 as i32)),
1087                    convert_sample_to_read(
1088                        samples_by_channel
1089                            .front_left_of_center
1090                            .expect("front_left_of_center")
1091                    ),
1092                    "Wrong sample read at {sample}, channel front_left_of_center"
1093                );
1094                assert_eq!(
1095                    convert_sample_to_write((sample as i32) * 18 + (7 as i32)),
1096                    convert_sample_to_read(
1097                        samples_by_channel
1098                            .front_right_of_center
1099                            .expect("front_right_of_center")
1100                    ),
1101                    "Wrong sample read at {sample}, channel front_right_of_center"
1102                );
1103                assert_eq!(
1104                    convert_sample_to_write((sample as i32) * 18 + (8 as i32)),
1105                    convert_sample_to_read(samples_by_channel.back_center.expect("back_center")),
1106                    "Wrong sample read at {sample}, channel back_center"
1107                );
1108                assert_eq!(
1109                    convert_sample_to_write((sample as i32) * 18 + (9 as i32)),
1110                    convert_sample_to_read(samples_by_channel.side_left.expect("side_left")),
1111                    "Wrong sample read at {sample}, channel side_left"
1112                );
1113                assert_eq!(
1114                    convert_sample_to_write((sample as i32) * 18 + (10 as i32)),
1115                    convert_sample_to_read(samples_by_channel.side_right.expect("side_right")),
1116                    "Wrong sample read at {sample}, channel side_right"
1117                );
1118                assert_eq!(
1119                    convert_sample_to_write((sample as i32) * 18 + (11 as i32)),
1120                    convert_sample_to_read(samples_by_channel.top_center.expect("top_center")),
1121                    "Wrong sample read at {sample}, channel top_center"
1122                );
1123                assert_eq!(
1124                    convert_sample_to_write((sample as i32) * 18 + (12 as i32)),
1125                    convert_sample_to_read(
1126                        samples_by_channel.top_front_left.expect("top_front_left")
1127                    ),
1128                    "Wrong sample read at {sample}, channel top_front_left"
1129                );
1130                assert_eq!(
1131                    convert_sample_to_write((sample as i32) * 18 + (13 as i32)),
1132                    convert_sample_to_read(
1133                        samples_by_channel
1134                            .top_front_center
1135                            .expect("top_front_center")
1136                    ),
1137                    "Wrong sample read at {sample}, channel top_front_center"
1138                );
1139                assert_eq!(
1140                    convert_sample_to_write((sample as i32) * 18 + (14 as i32)),
1141                    convert_sample_to_read(
1142                        samples_by_channel.top_front_right.expect("top_front_right")
1143                    ),
1144                    "Wrong sample read at {sample}, channel top_front_right"
1145                );
1146                assert_eq!(
1147                    convert_sample_to_write((sample as i32) * 18 + (15 as i32)),
1148                    convert_sample_to_read(
1149                        samples_by_channel.top_back_left.expect("top_back_left")
1150                    ),
1151                    "Wrong sample read at {sample}, channel top_back_left"
1152                );
1153                assert_eq!(
1154                    convert_sample_to_write((sample as i32) * 18 + (16 as i32)),
1155                    convert_sample_to_read(
1156                        samples_by_channel.top_back_center.expect("top_back_center")
1157                    ),
1158                    "Wrong sample read at {sample}, channel top_back_center"
1159                );
1160                assert_eq!(
1161                    convert_sample_to_write((sample as i32) * 18 + (17 as i32)),
1162                    convert_sample_to_read(
1163                        samples_by_channel.top_back_right.expect("top_back_right")
1164                    ),
1165                    "Wrong sample read at {sample}, channel top_back_right"
1166                );
1167            }
1168
1169            Ok(())
1170        }));
1171    }
1172
1173    #[test]
1174    fn write_random_max_samples() {
1175        test_with_file(Box::new(move |_path| {
1176            let header = WavHeader {
1177                sample_format: SampleFormat::Int8,
1178                channels: Channels {
1179                    front_left: false,
1180                    front_right: false,
1181                    front_center: true,
1182                    low_frequency: false,
1183                    back_left: false,
1184                    back_right: false,
1185                    front_left_of_center: false,
1186                    front_right_of_center: false,
1187                    back_center: false,
1188                    side_left: false,
1189                    side_right: false,
1190                    top_center: false,
1191                    top_front_left: false,
1192                    top_front_center: false,
1193                    top_front_right: false,
1194                    top_back_left: false,
1195                    top_back_center: false,
1196                    top_back_right: false,
1197                },
1198                sample_rate: 96000,
1199            };
1200
1201            //let open_wav = write_wav_to_file_path(path, header)?;
1202            let buffer: Vec<u8> = Vec::new();
1203            let cursor = Cursor::new(buffer);
1204            let open_wav = OpenWavWriter::new_max_samples(cursor, header, 1)?;
1205            let mut writer = open_wav.get_random_access_i8_writer()?;
1206
1207            let samples_by_channel = SamplesByChannel::<i8> {
1208                front_left: None,
1209                front_right: None,
1210                front_center: Some(1),
1211                low_frequency: None,
1212                back_left: None,
1213                back_right: None,
1214                front_left_of_center: None,
1215                front_right_of_center: None,
1216                back_center: None,
1217                side_left: None,
1218                side_right: None,
1219                top_center: None,
1220                top_front_left: None,
1221                top_front_center: None,
1222                top_front_right: None,
1223                top_back_left: None,
1224                top_back_center: None,
1225                top_back_right: None,
1226            };
1227            writer.write_samples(0, samples_by_channel.clone())?;
1228
1229            let err = writer
1230                .write_samples(1, samples_by_channel.clone())
1231                .expect_err("Writing at the max length should fail");
1232
1233            assert_eq!(ErrorKind::Unsupported, err.kind());
1234
1235            let err = writer
1236                .write_samples(2, samples_by_channel)
1237                .expect_err("Writing beyond the max length should fail");
1238
1239            assert_eq!(ErrorKind::Unsupported, err.kind());
1240
1241            Ok(())
1242        }));
1243    }
1244
1245    #[test]
1246    fn write_stream_i8() {
1247        write_stream(
1248            Path::new("test_data/short_8.wav"),
1249            SampleFormat::Int8,
1250            Box::new(|open_wav| open_wav.get_stream_i8_reader()),
1251            Box::new(|open_wav, read_samples_iter| open_wav.write_all_i8(read_samples_iter)),
1252            Box::new(|open_wav| open_wav.get_random_access_i8_reader()),
1253        )
1254    }
1255
1256    #[test]
1257    fn write_stream_i8_as_i16() {
1258        write_stream(
1259            Path::new("test_data/short_8.wav"),
1260            SampleFormat::Int16,
1261            Box::new(|open_wav| open_wav.get_stream_i8_reader()),
1262            Box::new(|open_wav, read_samples_iter| open_wav.write_all_i8(read_samples_iter)),
1263            Box::new(|open_wav| open_wav.get_random_access_i16_reader()),
1264        )
1265    }
1266
1267    #[test]
1268    fn write_stream_i8_as_i24() {
1269        write_stream(
1270            Path::new("test_data/short_8.wav"),
1271            SampleFormat::Int24,
1272            Box::new(|open_wav| open_wav.get_stream_i8_reader()),
1273            Box::new(|open_wav, read_samples_iter| open_wav.write_all_i8(read_samples_iter)),
1274            Box::new(|open_wav| open_wav.get_random_access_i24_reader()),
1275        )
1276    }
1277
1278    #[test]
1279    fn write_stream_i8_as_f32() {
1280        write_stream(
1281            Path::new("test_data/short_8.wav"),
1282            SampleFormat::Float,
1283            Box::new(|open_wav| open_wav.get_stream_i8_reader()),
1284            Box::new(|open_wav, read_samples_iter| open_wav.write_all_i8(read_samples_iter)),
1285            Box::new(|open_wav| open_wav.get_random_access_f32_reader()),
1286        )
1287    }
1288
1289    #[test]
1290    fn write_stream_i16() {
1291        write_stream(
1292            Path::new("test_data/short_16.wav"),
1293            SampleFormat::Int16,
1294            Box::new(|open_wav| open_wav.get_stream_i16_reader()),
1295            Box::new(|open_wav, read_samples_iter| open_wav.write_all_i16(read_samples_iter)),
1296            Box::new(|open_wav| open_wav.get_random_access_i16_reader()),
1297        )
1298    }
1299
1300    #[test]
1301    fn write_stream_i16_as_i24() {
1302        write_stream(
1303            Path::new("test_data/short_16.wav"),
1304            SampleFormat::Int24,
1305            Box::new(|open_wav| open_wav.get_stream_i16_reader()),
1306            Box::new(|open_wav, read_samples_iter| open_wav.write_all_i16(read_samples_iter)),
1307            Box::new(|open_wav| open_wav.get_random_access_i24_reader()),
1308        )
1309    }
1310
1311    #[test]
1312    fn write_stream_i16_as_f32() {
1313        write_stream(
1314            Path::new("test_data/short_16.wav"),
1315            SampleFormat::Float,
1316            Box::new(|open_wav| open_wav.get_stream_i16_reader()),
1317            Box::new(|open_wav, read_samples_iter| open_wav.write_all_i16(read_samples_iter)),
1318            Box::new(|open_wav| open_wav.get_random_access_f32_reader()),
1319        )
1320    }
1321
1322    #[test]
1323    fn write_stream_i24() {
1324        write_stream(
1325            Path::new("test_data/short_24.wav"),
1326            SampleFormat::Int24,
1327            Box::new(|open_wav| open_wav.get_stream_i24_reader()),
1328            Box::new(|open_wav, read_samples_iter| open_wav.write_all_i24(read_samples_iter)),
1329            Box::new(|open_wav| open_wav.get_random_access_i24_reader()),
1330        )
1331    }
1332
1333    #[test]
1334    fn write_stream_i24_as_f32() {
1335        write_stream(
1336            Path::new("test_data/short_24.wav"),
1337            SampleFormat::Float,
1338            Box::new(|open_wav| open_wav.get_stream_i24_reader()),
1339            Box::new(|open_wav, read_samples_iter| open_wav.write_all_i24(read_samples_iter)),
1340            Box::new(|open_wav| open_wav.get_random_access_f32_reader()),
1341        )
1342    }
1343
1344    #[test]
1345    fn write_stream_f32() {
1346        write_stream(
1347            Path::new("test_data/short_float.wav"),
1348            SampleFormat::Float,
1349            Box::new(|open_wav| open_wav.get_stream_f32_reader()),
1350            Box::new(|open_wav, read_samples_iter| open_wav.write_all_f32(read_samples_iter)),
1351            Box::new(|open_wav| open_wav.get_random_access_f32_reader()),
1352        )
1353    }
1354
1355    fn write_stream<
1356        T: Debug + PartialEq + Default + Clone + 'static,
1357        TFile: Debug + PartialEq + Default + Clone + 'static,
1358    >(
1359        read_path: &Path,
1360        sample_format: SampleFormat,
1361        get_stream_reader: Box<
1362            dyn FnOnce(OpenWavReader<BufReader<File>>) -> Result<StreamWavReader<T>>,
1363        >,
1364        write_all: Box<dyn FnOnce(OpenWavWriter, StreamWavReaderIterator<T>) -> Result<()>>,
1365        get_random_access_reader: Box<
1366            dyn Fn(OpenWavReader<BufReader<File>>) -> Result<RandomAccessWavReader<TFile>>,
1367        >,
1368    ) {
1369        let read_path_buf = read_path.to_path_buf();
1370
1371        test_with_file(Box::new(move |path| {
1372            let read_path = read_path_buf.as_path();
1373            let source_wav = read_wav_from_file_path(read_path)?;
1374
1375            let header = WavHeader {
1376                sample_format,
1377                channels: source_wav.channels().clone(),
1378                sample_rate: source_wav.sample_rate(),
1379            };
1380            let open_wav = write_wav_to_file_path(path, header)?;
1381
1382            let read_samples_iter = get_stream_reader(source_wav)?.into_iter();
1383            write_all(open_wav, read_samples_iter)?;
1384
1385            let expected_wav = read_wav_from_file_path(read_path)?;
1386            let actual_wav = read_wav_from_file_path(path)?;
1387
1388            assert_eq!(expected_wav.num_channels(), actual_wav.num_channels());
1389            assert_eq!(expected_wav.len_samples(), actual_wav.len_samples());
1390
1391            let len_samples = expected_wav.len_samples();
1392
1393            let mut expected_wav_reader = get_random_access_reader(expected_wav)?;
1394            let mut actual_wav_reader = get_random_access_reader(actual_wav)?;
1395
1396            for sample_ctr in 0..len_samples {
1397                let expected_samples = expected_wav_reader.read_sample(sample_ctr)?;
1398                let actual_samples = actual_wav_reader.read_sample(sample_ctr)?;
1399
1400                assert_eq!(
1401                    expected_samples, actual_samples,
1402                    "Wrong value for sample {sample_ctr}"
1403                );
1404            }
1405
1406            Ok(())
1407        }));
1408    }
1409
1410    #[test]
1411    fn write_stream_max_samples() {
1412        test_with_file(Box::new(move |_path| {
1413            let header = WavHeader {
1414                sample_format: SampleFormat::Int8,
1415                channels: Channels {
1416                    front_left: false,
1417                    front_right: false,
1418                    front_center: true,
1419                    low_frequency: false,
1420                    back_left: false,
1421                    back_right: false,
1422                    front_left_of_center: false,
1423                    front_right_of_center: false,
1424                    back_center: false,
1425                    side_left: false,
1426                    side_right: false,
1427                    top_center: false,
1428                    top_front_left: false,
1429                    top_front_center: false,
1430                    top_front_right: false,
1431                    top_back_left: false,
1432                    top_back_center: false,
1433                    top_back_right: false,
1434                },
1435                sample_rate: 96000,
1436            };
1437
1438            let samples_by_channel = SamplesByChannel::<i8> {
1439                front_left: None,
1440                front_right: None,
1441                front_center: Some(1),
1442                low_frequency: None,
1443                back_left: None,
1444                back_right: None,
1445                front_left_of_center: None,
1446                front_right_of_center: None,
1447                back_center: None,
1448                side_left: None,
1449                side_right: None,
1450                top_center: None,
1451                top_front_left: None,
1452                top_front_center: None,
1453                top_front_right: None,
1454                top_back_left: None,
1455                top_back_center: None,
1456                top_back_right: None,
1457            };
1458
1459            // (Should work) Write a 1-sample file
1460            let buffer: Vec<u8> = Vec::new();
1461            let cursor = Cursor::new(buffer);
1462            let open_wav = OpenWavWriter::new_max_samples(cursor, header.clone(), 1)?;
1463            let samples = vec![Ok(samples_by_channel.clone())];
1464            open_wav.write_all_i8(samples.into_iter())?;
1465
1466            // (Should fail) Write a 2-sample file
1467            let buffer: Vec<u8> = Vec::new();
1468            let cursor = Cursor::new(buffer);
1469            let open_wav = OpenWavWriter::new_max_samples(cursor, header.clone(), 1)?;
1470            let samples = vec![
1471                Ok(samples_by_channel.clone()),
1472                Ok(samples_by_channel.clone()),
1473            ];
1474            let err = open_wav
1475                .write_all_i8(samples.into_iter())
1476                .expect_err("Should not be able to exceed the supported file length");
1477            assert_eq!(ErrorKind::Unsupported, err.kind());
1478
1479            // (Should fail) Write a 3-sample file
1480            let buffer: Vec<u8> = Vec::new();
1481            let cursor = Cursor::new(buffer);
1482            let open_wav = OpenWavWriter::new_max_samples(cursor, header, 1)?;
1483            let samples = vec![
1484                Ok(samples_by_channel.clone()),
1485                Ok(samples_by_channel.clone()),
1486                Ok(samples_by_channel),
1487            ];
1488            let err = open_wav
1489                .write_all_i8(samples.into_iter())
1490                .expect_err("Should not be able to exceed the supported file length");
1491            assert_eq!(ErrorKind::Unsupported, err.kind());
1492
1493            Ok(())
1494        }));
1495    }
1496}