|  | // Hound -- A wav encoding and decoding library in Rust | 
|  | // Copyright (C) 2015 Ruud van Asseldonk | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // A copy of the License has been included in the root of the repository. | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | use std::fs; | 
|  | use std::io; | 
|  | use std::mem; | 
|  | use std::io::{Seek, Write}; | 
|  | use std::mem::MaybeUninit; | 
|  | use std::path; | 
|  | use super::{Error, Result, Sample, SampleFormat, WavSpec, WavSpecEx}; | 
|  | use ::read; | 
|  |  | 
|  | /// Extends the functionality of `io::Write` with additional methods. | 
|  | /// | 
|  | /// The methods may be used on any type that implements `io::Write`. | 
|  | pub trait WriteExt: io::Write { | 
|  | /// Writes an unsigned 8-bit integer. | 
|  | fn write_u8(&mut self, x: u8) -> io::Result<()>; | 
|  |  | 
|  | /// Writes a signed 16-bit integer in little endian format. | 
|  | fn write_le_i16(&mut self, x: i16) -> io::Result<()>; | 
|  |  | 
|  | /// Writes an unsigned 16-bit integer in little endian format. | 
|  | fn write_le_u16(&mut self, x: u16) -> io::Result<()>; | 
|  |  | 
|  | /// Writes a signed 24-bit integer in little endian format. | 
|  | /// | 
|  | /// The most significant byte of the `i32` is ignored. | 
|  | fn write_le_i24(&mut self, x: i32) -> io::Result<()>; | 
|  |  | 
|  | /// Writes a signed 24-bit integer in 4-byte little endian format. | 
|  | /// | 
|  | /// The most significant byte of the `i32` is replaced with zeroes. | 
|  | fn write_le_i24_4(&mut self, x: i32) -> io::Result<()>; | 
|  |  | 
|  | /// Writes an unsigned 24-bit integer in little endian format. | 
|  | /// | 
|  | /// The most significant byte of the `u32` is ignored. | 
|  | fn write_le_u24(&mut self, x: u32) -> io::Result<()>; | 
|  |  | 
|  | /// Writes a signed 32-bit integer in little endian format. | 
|  | fn write_le_i32(&mut self, x: i32) -> io::Result<()>; | 
|  |  | 
|  | /// Writes an unsigned 32-bit integer in little endian format. | 
|  | fn write_le_u32(&mut self, x: u32) -> io::Result<()>; | 
|  |  | 
|  | /// Writes an IEEE float in little endian format. | 
|  | fn write_le_f32(&mut self, x: f32) -> io::Result<()>; | 
|  | } | 
|  |  | 
|  | impl<W> WriteExt for W | 
|  | where W: io::Write | 
|  | { | 
|  | #[inline(always)] | 
|  | fn write_u8(&mut self, x: u8) -> io::Result<()> { | 
|  | let buf = [x]; | 
|  | self.write_all(&buf) | 
|  | } | 
|  |  | 
|  | #[inline(always)] | 
|  | fn write_le_i16(&mut self, x: i16) -> io::Result<()> { | 
|  | self.write_le_u16(x as u16) | 
|  | } | 
|  |  | 
|  | #[inline(always)] | 
|  | fn write_le_u16(&mut self, x: u16) -> io::Result<()> { | 
|  | let mut buf = [0u8; 2]; | 
|  | buf[0] = (x & 0xff) as u8; | 
|  | buf[1] = (x >> 8) as u8; | 
|  | self.write_all(&buf) | 
|  | } | 
|  |  | 
|  | #[inline(always)] | 
|  | fn write_le_i24(&mut self, x: i32) -> io::Result<()> { | 
|  | self.write_le_u24(x as u32) | 
|  | } | 
|  |  | 
|  | #[inline(always)] | 
|  | fn write_le_i24_4(&mut self, x: i32) -> io::Result<()> { | 
|  | self.write_le_u32((x as u32) & 0x00_ff_ff_ff) | 
|  | } | 
|  |  | 
|  | #[inline(always)] | 
|  | fn write_le_u24(&mut self, x: u32) -> io::Result<()> { | 
|  | let mut buf = [0u8; 3]; | 
|  | buf[0] = ((x >> 00) & 0xff) as u8; | 
|  | buf[1] = ((x >> 08) & 0xff) as u8; | 
|  | buf[2] = ((x >> 16) & 0xff) as u8; | 
|  | self.write_all(&buf) | 
|  | } | 
|  |  | 
|  | #[inline(always)] | 
|  | fn write_le_i32(&mut self, x: i32) -> io::Result<()> { | 
|  | self.write_le_u32(x as u32) | 
|  | } | 
|  |  | 
|  | #[inline(always)] | 
|  | fn write_le_u32(&mut self, x: u32) -> io::Result<()> { | 
|  | let mut buf = [0u8; 4]; | 
|  | buf[0] = ((x >> 00) & 0xff) as u8; | 
|  | buf[1] = ((x >> 08) & 0xff) as u8; | 
|  | buf[2] = ((x >> 16) & 0xff) as u8; | 
|  | buf[3] = ((x >> 24) & 0xff) as u8; | 
|  | self.write_all(&buf) | 
|  | } | 
|  |  | 
|  | #[inline(always)] | 
|  | fn write_le_f32(&mut self, x: f32) -> io::Result<()> { | 
|  | let u = unsafe { mem::transmute::<f32, u32>(x) }; | 
|  | self.write_le_u32(u) | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Generates a bitmask with `channels` ones in the least significant bits. | 
|  | /// | 
|  | /// According to the [spec](https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ksmedia/ns-ksmedia-waveformatextensible#remarks), | 
|  | /// if `channels` is greater than the number of bits in the channel mask, 18 non-reserved bits, | 
|  | /// extra channels are not assigned to any physical speaker location.  In this scenario, this | 
|  | /// function will return a filled channel mask. | 
|  | fn channel_mask(channels: u16) -> u32 { | 
|  | // Clamp to 0-18 to stay within reserved bits. | 
|  | let channels = if channels > 18 { 18 } else { channels }; | 
|  | (0..channels as u32).map(|c| 1 << c).fold(0, |a, c| a | c) | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn verify_channel_mask() { | 
|  | assert_eq!(channel_mask(0), 0); | 
|  | assert_eq!(channel_mask(1), 1); | 
|  | assert_eq!(channel_mask(2), 3); | 
|  | assert_eq!(channel_mask(3), 7); | 
|  | assert_eq!(channel_mask(4), 0xF); | 
|  | assert_eq!(channel_mask(8), 0xFF); | 
|  | assert_eq!(channel_mask(16), 0xFFFF); | 
|  | // expect channels >= 18 to yield the same mask | 
|  | assert_eq!(channel_mask(18), 0x3FFFF); | 
|  | assert_eq!(channel_mask(32), 0x3FFFF); | 
|  | assert_eq!(channel_mask(64), 0x3FFFF); | 
|  | assert_eq!(channel_mask(129), 0x3FFFF); | 
|  | } | 
|  |  | 
|  | /// A writer that accepts samples and writes the WAVE format. | 
|  | /// | 
|  | /// The writer needs a `WavSpec` or `WavSpecEx` that describes the audio | 
|  | /// properties. Then samples can be written with `write_sample`. Channel data is | 
|  | /// interleaved. The number of samples written must be a multiple of the number | 
|  | /// of channels. After all samples have been written, the file must be | 
|  | /// finalized. This can be done by calling `finalize`. If `finalize` is not | 
|  | /// called, the file will be finalized upon drop. However, finalization may | 
|  | /// fail, and without calling `finalize`, such a failure cannot be observed. | 
|  | pub struct WavWriter<W> | 
|  | where W: io::Write + io::Seek | 
|  | { | 
|  | /// Specifies properties of the audio data. | 
|  | spec: WavSpec, | 
|  |  | 
|  | /// The (container) bytes per sample. This is the bit rate / 8 rounded up. | 
|  | bytes_per_sample: u16, | 
|  |  | 
|  | /// The writer that will be written to. | 
|  | writer: W, | 
|  |  | 
|  | /// The number of bytes written to the data section. | 
|  | /// | 
|  | /// This is an `u32` because WAVE cannot accomodate more data. | 
|  | data_bytes_written: u32, | 
|  |  | 
|  | /// Whether the header has been finalized. | 
|  | finalized: bool, | 
|  |  | 
|  | /// The buffer for the sample writer, which is recycled throughout calls to | 
|  | /// avoid allocating frequently. | 
|  | sample_writer_buffer: Vec<MaybeUninit<u8>>, | 
|  |  | 
|  | /// The offset of the length field of the data chunk. | 
|  | /// | 
|  | /// This field needs to be overwritten after all data has been written. To | 
|  | /// support different size fmt chunks, and other chunks interspersed, the | 
|  | /// offset is flexible. | 
|  | data_len_offset: u32, | 
|  | } | 
|  |  | 
|  | enum FmtKind { | 
|  | PcmWaveFormat, | 
|  | WaveFormatExtensible, | 
|  | } | 
|  |  | 
|  | impl<W> WavWriter<W> | 
|  | where W: io::Write + io::Seek | 
|  | { | 
|  | /// Creates a writer that writes the WAVE format to the underlying writer. | 
|  | /// | 
|  | /// The underlying writer is assumed to be at offset 0. `WavWriter` employs | 
|  | /// *no* buffering internally. It is recommended to wrap the writer in a | 
|  | /// `BufWriter` to avoid too many `write` calls. The `create()` constructor | 
|  | /// does this automatically. | 
|  | /// | 
|  | /// This writes parts of the header immediately, hence a `Result` is | 
|  | /// returned. | 
|  | pub fn new(writer: W, spec: WavSpec) -> Result<WavWriter<W>> { | 
|  | let spec_ex = WavSpecEx { | 
|  | spec: spec, | 
|  | bytes_per_sample: (spec.bits_per_sample + 7) / 8, | 
|  | }; | 
|  | WavWriter::new_with_spec_ex(writer, spec_ex) | 
|  | } | 
|  |  | 
|  |  | 
|  | /// Creates a writer that writes the WAVE format to the underlying writer. | 
|  | /// | 
|  | /// The underlying writer is assumed to be at offset 0. `WavWriter` employs | 
|  | /// *no* buffering internally. It is recommended to wrap the writer in a | 
|  | /// `BufWriter` to avoid too many `write` calls. The `create()` constructor | 
|  | /// does this automatically. | 
|  | /// | 
|  | /// This writes parts of the header immediately, hence a `Result` is | 
|  | /// returned. | 
|  | pub fn new_with_spec_ex(writer: W, spec_ex: WavSpecEx) -> Result<WavWriter<W>> { | 
|  | let spec = spec_ex.spec; | 
|  |  | 
|  | // Write the older PCMWAVEFORMAT structure if possible, because it is | 
|  | // more widely supported. For more than two channels or more than 16 | 
|  | // bits per sample, the newer WAVEFORMATEXTENSIBLE is required. See also | 
|  | // https://msdn.microsoft.com/en-us/library/ms713497.aspx. | 
|  | let fmt_kind = if spec.channels > 2 || spec.bits_per_sample > 16 { | 
|  | FmtKind::WaveFormatExtensible | 
|  | } else { | 
|  | FmtKind::PcmWaveFormat | 
|  | }; | 
|  |  | 
|  | let mut writer = WavWriter { | 
|  | spec: spec, | 
|  | bytes_per_sample: spec_ex.bytes_per_sample, | 
|  | writer: writer, | 
|  | data_bytes_written: 0, | 
|  | sample_writer_buffer: Vec::new(), | 
|  | finalized: false, | 
|  | data_len_offset: match fmt_kind { | 
|  | FmtKind::WaveFormatExtensible => 64, | 
|  | FmtKind::PcmWaveFormat => 40, | 
|  | }, | 
|  | }; | 
|  |  | 
|  | // Hound can only write those bit depths. If something else was | 
|  | // requested, fail early, rather than writing a header but then failing | 
|  | // at the first sample. | 
|  | let supported = match spec.bits_per_sample { | 
|  | 8 => true, | 
|  | 16 => true, | 
|  | 24 => true, | 
|  | 32 => true, | 
|  | _ => false, | 
|  | }; | 
|  |  | 
|  | if !supported { | 
|  | return Err(Error::Unsupported) | 
|  | } | 
|  |  | 
|  | // Write headers, up to the point where data should be written. | 
|  | try!(writer.write_headers(fmt_kind)); | 
|  |  | 
|  | Ok(writer) | 
|  | } | 
|  |  | 
|  | /// Writes the RIFF WAVE header, fmt chunk, and data chunk header. | 
|  | fn write_headers(&mut self, fmt_kind: FmtKind) -> io::Result<()> { | 
|  | // Write to an in-memory buffer before writing to the underlying writer. | 
|  | let mut header = [0u8; 68]; | 
|  |  | 
|  | { | 
|  | let mut buffer = io::Cursor::new(&mut header[..]); | 
|  |  | 
|  | // Write the headers for the RIFF WAVE format. | 
|  | try!(buffer.write_all("RIFF".as_bytes())); | 
|  |  | 
|  | // Skip 4 bytes that will be filled with the file size afterwards. | 
|  | try!(buffer.write_le_u32(0)); | 
|  |  | 
|  | try!(buffer.write_all("WAVE".as_bytes())); | 
|  | try!(buffer.write_all("fmt ".as_bytes())); | 
|  |  | 
|  | match fmt_kind { | 
|  | FmtKind::PcmWaveFormat => { | 
|  | try!(self.write_pcmwaveformat(&mut buffer)); | 
|  | } | 
|  | FmtKind::WaveFormatExtensible => { | 
|  | try!(self.write_waveformatextensible(&mut buffer)); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Finally the header of the "data" chunk. The number of bytes | 
|  | // that this will take is not known at this point. The 0 will | 
|  | // be overwritten later. | 
|  | try!(buffer.write_all("data".as_bytes())); | 
|  | try!(buffer.write_le_u32(0)); | 
|  | } | 
|  |  | 
|  | // The data length field are the last 4 bytes of the header. | 
|  | let header_len = self.data_len_offset as usize + 4; | 
|  |  | 
|  | self.writer.write_all(&header[..header_len]) | 
|  | } | 
|  |  | 
|  | /// Writes the spec as a WAVEFORMAT structure. | 
|  | /// | 
|  | /// The `WAVEFORMAT` struct is a subset of both `WAVEFORMATEX` and | 
|  | /// `WAVEFORMATEXTENSIBLE`. This does not write the `wFormatTag` member. | 
|  | fn write_waveformat(&self, buffer: &mut io::Cursor<&mut [u8]>) -> io::Result<()> { | 
|  | let spec = &self.spec; | 
|  | // The field nChannels. | 
|  | try!(buffer.write_le_u16(spec.channels)); | 
|  |  | 
|  | // The field nSamplesPerSec. | 
|  | try!(buffer.write_le_u32(spec.sample_rate)); | 
|  | let bytes_per_sec = spec.sample_rate | 
|  | * self.bytes_per_sample as u32 | 
|  | * spec.channels as u32; | 
|  |  | 
|  | // The field nAvgBytesPerSec; | 
|  | try!(buffer.write_le_u32(bytes_per_sec)); | 
|  |  | 
|  | // The field nBlockAlign. Block align * sample rate = bytes per sec. | 
|  | try!(buffer.write_le_u16((bytes_per_sec / spec.sample_rate) as u16)); | 
|  |  | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | /// Writes the content of the fmt chunk as PCMWAVEFORMAT struct. | 
|  | fn write_pcmwaveformat(&mut self, buffer: &mut io::Cursor<&mut [u8]>) -> io::Result<()> { | 
|  | // Write the size of the WAVE header chunk. | 
|  | try!(buffer.write_le_u32(16)); | 
|  |  | 
|  | // The following is based on the PCMWAVEFORMAT struct as documented at | 
|  | // https://msdn.microsoft.com/en-us/library/ms712832.aspx. See also | 
|  | // http://soundfile.sapp.org/doc/WaveFormat/. | 
|  |  | 
|  | // The field wFormatTag | 
|  | match self.spec.sample_format { | 
|  | // WAVE_FORMAT_PCM | 
|  | SampleFormat::Int => { | 
|  | try!(buffer.write_le_u16(1)); | 
|  | }, | 
|  | // WAVE_FORMAT_IEEE_FLOAT | 
|  | SampleFormat::Float => { | 
|  | if self.spec.bits_per_sample == 32 { | 
|  | try!(buffer.write_le_u16(3)); | 
|  | } else { | 
|  | panic!("Invalid number of bits per sample. \ | 
|  | When writing SampleFormat::Float, \ | 
|  | bits_per_sample must be 32."); | 
|  | } | 
|  | }, | 
|  | }; | 
|  |  | 
|  | try!(self.write_waveformat(buffer)); | 
|  |  | 
|  | // The field wBitsPerSample, the real number of bits per sample. | 
|  | try!(buffer.write_le_u16(self.spec.bits_per_sample)); | 
|  |  | 
|  | // Note: for WAVEFORMATEX, there would be another 16-byte field `cbSize` | 
|  | // here that should be set to zero. And the header size would be 18 | 
|  | // rather than 16. | 
|  |  | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | /// Writes the contents of the fmt chunk as WAVEFORMATEXTENSIBLE struct. | 
|  | fn write_waveformatextensible(&mut self, buffer: &mut io::Cursor<&mut [u8]>) -> io::Result<()> { | 
|  | // Write the size of the WAVE header chunk. | 
|  | try!(buffer.write_le_u32(40)); | 
|  |  | 
|  | // The following is based on the WAVEFORMATEXTENSIBLE struct, documented | 
|  | // at https://msdn.microsoft.com/en-us/library/ms713496.aspx and | 
|  | // https://msdn.microsoft.com/en-us/library/ms713462.aspx. | 
|  |  | 
|  | // The field wFormatTag, value 1 means WAVE_FORMAT_PCM, but we use | 
|  | // the slightly more sophisticated WAVE_FORMAT_EXTENSIBLE. | 
|  | try!(buffer.write_le_u16(0xfffe)); | 
|  |  | 
|  | try!(self.write_waveformat(buffer)); | 
|  |  | 
|  | // The field wBitsPerSample. This is actually the size of the | 
|  | // container, so this is a multiple of 8. | 
|  | try!(buffer.write_le_u16(self.bytes_per_sample as u16 * 8)); | 
|  | // The field cbSize, the number of remaining bytes in the struct. | 
|  | try!(buffer.write_le_u16(22)); | 
|  | // The field wValidBitsPerSample, the real number of bits per sample. | 
|  | try!(buffer.write_le_u16(self.spec.bits_per_sample)); | 
|  | // The field dwChannelMask. | 
|  | // TODO: add the option to specify the channel mask. For now, use | 
|  | // the default assignment. | 
|  | try!(buffer.write_le_u32(channel_mask(self.spec.channels))); | 
|  |  | 
|  | // The field SubFormat. | 
|  | let subformat_guid = match self.spec.sample_format { | 
|  | // PCM audio with integer samples. | 
|  | SampleFormat::Int => super::KSDATAFORMAT_SUBTYPE_PCM, | 
|  | // PCM audio with 32-bit IEEE float samples. | 
|  | SampleFormat::Float => { | 
|  | if self.spec.bits_per_sample == 32 { | 
|  | super::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT | 
|  | } else { | 
|  | panic!("Invalid number of bits per sample. \ | 
|  | When writing SampleFormat::Float, \ | 
|  | bits_per_sample must be 32."); | 
|  | } | 
|  | } | 
|  | }; | 
|  | try!(buffer.write_all(&subformat_guid)); | 
|  |  | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | /// Writes a single sample for one channel. | 
|  | /// | 
|  | /// WAVE interleaves channel data, so the channel that this writes the | 
|  | /// sample to depends on previous writes. This will return an error if the | 
|  | /// sample does not fit in the number of bits specified in the `WavSpec`. | 
|  | #[inline] | 
|  | pub fn write_sample<S: Sample>(&mut self, sample: S) -> Result<()> { | 
|  | try!(sample.write_padded( | 
|  | &mut self.writer, | 
|  | self.spec.bits_per_sample, | 
|  | self.bytes_per_sample, | 
|  | )); | 
|  | self.data_bytes_written += self.bytes_per_sample as u32; | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | /// Create an efficient writer that writes 16-bit integer samples only. | 
|  | /// | 
|  | /// When it is known what the kind of samples will be, many dynamic checks | 
|  | /// can be omitted. Furthermore, this writer employs buffering internally, | 
|  | /// which allows omitting return value checks except on flush. The internal | 
|  | /// buffer will be sized such that exactly `num_samples` samples can be | 
|  | /// written to it, and the buffer is recycled across calls to | 
|  | /// `get_i16_writer()` if the previous buffer was sufficiently large. | 
|  | /// | 
|  | /// # Panics | 
|  | /// | 
|  | /// Panics if the spec does not match a 16 bits per sample integer format. | 
|  | /// | 
|  | /// Attempting to write more than `num_samples` samples to the writer will | 
|  | /// panic too. | 
|  | pub fn get_i16_writer<'s>(&'s mut self, | 
|  | num_samples: u32) | 
|  | -> SampleWriter16<'s, W> { | 
|  | if self.spec.sample_format != SampleFormat::Int { | 
|  | panic!("When calling get_i16_writer, the sample format must be int."); | 
|  | } | 
|  | if self.spec.bits_per_sample != 16 { | 
|  | panic!("When calling get_i16_writer, the number of bits per sample must be 16."); | 
|  | } | 
|  |  | 
|  | let num_bytes = num_samples as usize * 2; | 
|  |  | 
|  | if self.sample_writer_buffer.len() < num_bytes { | 
|  | // We need a bigger buffer. There is no point in growing the old | 
|  | // one, as we are going to overwrite the samples anyway, so just | 
|  | // allocate a new one. | 
|  | let mut new_buffer = Vec::<MaybeUninit<u8>>::with_capacity(num_bytes); | 
|  |  | 
|  | // The potentially garbage memory here will not be exposed: the | 
|  | // buffer is only exposed when flushing, but `flush()` asserts that | 
|  | // all samples have been written. | 
|  | unsafe { new_buffer.set_len(num_bytes); } | 
|  |  | 
|  | self.sample_writer_buffer = new_buffer; | 
|  | } | 
|  |  | 
|  | SampleWriter16 { | 
|  | writer: &mut self.writer, | 
|  | buffer: &mut self.sample_writer_buffer[..num_bytes], | 
|  | data_bytes_written: &mut self.data_bytes_written, | 
|  | index: 0, | 
|  | } | 
|  | } | 
|  |  | 
|  | fn update_header(&mut self) -> Result<()> { | 
|  | // The header size minus magic and 32-bit filesize (8 bytes). | 
|  | // The data chunk length (4 bytes) is the last part of the header. | 
|  | let header_size = self.data_len_offset + 4 - 8; | 
|  | let file_size = self.data_bytes_written + header_size; | 
|  |  | 
|  | try!(self.writer.seek(io::SeekFrom::Start(4))); | 
|  | try!(self.writer.write_le_u32(file_size)); | 
|  | try!(self.writer.seek(io::SeekFrom::Start(self.data_len_offset as u64))); | 
|  | try!(self.writer.write_le_u32(self.data_bytes_written)); | 
|  |  | 
|  | // Signal error if the last sample was not finished, but do so after | 
|  | // everything has been written, so that no data is lost, even though | 
|  | // the file is now ill-formed. | 
|  | if (self.data_bytes_written / self.bytes_per_sample as u32) | 
|  | % self.spec.channels as u32 != 0 { | 
|  | Err(Error::UnfinishedSample) | 
|  | } else { | 
|  | Ok(()) | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Updates the WAVE header and flushes the underlying writer. | 
|  | /// | 
|  | /// Flush writes the WAVE header to the underlying writer to make the | 
|  | /// written bytes a valid wav file, and then flushes the writer. It is still | 
|  | /// possible to write more samples after flushing. | 
|  | /// | 
|  | /// Flush can be used for “checkpointing”. Even if after the flush there is | 
|  | /// an IO error or the writing process dies, the file can still be read by a | 
|  | /// compliant decoder up to the last flush. | 
|  | /// | 
|  | /// Note that if the number of samples written is not a multiple of the | 
|  | /// channel count, the intermediate wav file will not be valid. In that case | 
|  | /// `flush()` will still flush the data and write the (invalid) wav file, | 
|  | /// but `Error::UnfinishedSample` will be returned afterwards. | 
|  | /// | 
|  | /// It is not necessary to call `finalize()` directly after `flush()`, if no | 
|  | /// samples have been written after flushing. | 
|  | pub fn flush(&mut self) -> Result<()> { | 
|  | let current_pos = try!(self.writer.seek(io::SeekFrom::Current(0))); | 
|  | try!(self.update_header()); | 
|  | try!(self.writer.flush()); | 
|  | try!(self.writer.seek(io::SeekFrom::Start(current_pos))); | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | /// Updates the WAVE header (which requires knowing all samples). | 
|  | /// | 
|  | /// This method must be called after all samples have been written. If it | 
|  | /// is not called, the destructor will finalize the file, but any errors | 
|  | /// that occur in the process cannot be observed in that manner. | 
|  | pub fn finalize(mut self) -> Result<()> { | 
|  | self.finalized = true; | 
|  | try!(self.update_header()); | 
|  | // We need to perform a flush here to truly capture all errors before | 
|  | // the writer is dropped: for a buffered writer, the write to the buffer | 
|  | // may succeed, but the write to the underlying writer may fail. So | 
|  | // flush explicitly. | 
|  | try!(self.writer.flush()); | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | /// Returns information about the WAVE file being written. | 
|  | /// | 
|  | /// This is the same spec that was passed to `WavWriter::new()`. For a | 
|  | /// writer constructed with `WavWriter::new_append()` or | 
|  | /// `WavWriter::append()`, this method returns the spec of the file being | 
|  | /// appended to. | 
|  | pub fn spec(&self) -> WavSpec { | 
|  | self.spec | 
|  | } | 
|  |  | 
|  | /// Returns the duration of the file written so far, in samples. | 
|  | /// | 
|  | /// The duration is independent of the number of channels. It is expressed | 
|  | /// in units of samples. The duration in seconds can be obtained by | 
|  | /// dividing this number by the sample rate. | 
|  | pub fn duration(&self) -> u32 { | 
|  | self.data_bytes_written / (self.bytes_per_sample as u32 * self.spec.channels as u32) | 
|  | } | 
|  |  | 
|  | /// Returns the number of samples in the file written so far. | 
|  | /// | 
|  | /// The length of the file is its duration (in samples) times the number of | 
|  | /// channels. | 
|  | pub fn len(&self) -> u32 { | 
|  | self.data_bytes_written / self.bytes_per_sample as u32 | 
|  | } | 
|  | } | 
|  |  | 
|  | impl<W> Drop for WavWriter<W> | 
|  | where W: io::Write + io::Seek | 
|  | { | 
|  | fn drop(&mut self) { | 
|  | // If the file was not explicitly finalized (to update the headers), do | 
|  | // it in the drop. This can fail, but drop should not panic, so a | 
|  | // failure is ignored silently here. | 
|  | if !self.finalized { | 
|  | let _r = self.update_header(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Reads the relevant parts of the header required to support append. | 
|  | /// | 
|  | /// Returns (spec_ex, data_len, data_len_offset). | 
|  | fn read_append<W: io::Read + io::Seek>(mut reader: &mut W) -> Result<(WavSpecEx, u32, u32)> { | 
|  | let (spec_ex, data_len) = { | 
|  | try!(read::read_wave_header(&mut reader)); | 
|  | try!(read::read_until_data(&mut reader)) | 
|  | }; | 
|  |  | 
|  | // Record the position of the data chunk length, so we can overwrite it | 
|  | // later. | 
|  | let data_len_offset = try!(reader.seek(io::SeekFrom::Current(0))) as u32 - 4; | 
|  |  | 
|  | let spec = spec_ex.spec; | 
|  | let num_samples = data_len / spec_ex.bytes_per_sample as u32; | 
|  |  | 
|  | // There must not be trailing bytes in the data chunk, otherwise the | 
|  | // bytes we write will be off. | 
|  | if num_samples * spec_ex.bytes_per_sample as u32 != data_len { | 
|  | let msg = "data chunk length is not a multiple of sample size"; | 
|  | return Err(Error::FormatError(msg)); | 
|  | } | 
|  |  | 
|  | // Hound cannot read or write other bit depths than those, so rather | 
|  | // than refusing to write later, fail early. | 
|  | let supported = match (spec_ex.bytes_per_sample, spec.bits_per_sample) { | 
|  | (1, 8) => true, | 
|  | (2, 16) => true, | 
|  | (3, 24) => true, | 
|  | (4, 32) => true, | 
|  | _ => false, | 
|  | }; | 
|  |  | 
|  | if !supported { | 
|  | return Err(Error::Unsupported); | 
|  | } | 
|  |  | 
|  | // The number of samples must be a multiple of the number of channels, | 
|  | // otherwise the last inter-channel sample would not have data for all | 
|  | // channels. | 
|  | if num_samples % spec_ex.spec.channels as u32 != 0 { | 
|  | return Err(Error::FormatError("invalid data chunk length")); | 
|  | } | 
|  |  | 
|  | Ok((spec_ex, data_len, data_len_offset)) | 
|  | } | 
|  |  | 
|  | impl WavWriter<io::BufWriter<fs::File>> { | 
|  | /// Creates a writer that writes the WAVE format to a file. | 
|  | /// | 
|  | /// This is a convenience constructor that creates the file, wraps it in a | 
|  | /// `BufWriter`, and then constructs a `WavWriter` from it. The file will | 
|  | /// be overwritten if it exists. | 
|  | pub fn create<P: AsRef<path::Path>>(filename: P, | 
|  | spec: WavSpec) | 
|  | -> Result<WavWriter<io::BufWriter<fs::File>>> { | 
|  | let file = try!(fs::File::create(filename)); | 
|  | let buf_writer = io::BufWriter::new(file); | 
|  | WavWriter::new(buf_writer, spec) | 
|  | } | 
|  |  | 
|  | /// Creates a writer that appends samples to an existing file. | 
|  | /// | 
|  | /// This is a convenience constructor that opens the file in append mode, | 
|  | /// reads its header using a buffered reader, and then constructs an | 
|  | /// appending `WavWriter` that writes to the file using a `BufWriter`. | 
|  | /// | 
|  | /// See `WavWriter::new_append()` for more details about append behavior. | 
|  | pub fn append<P: AsRef<path::Path>>(filename: P) -> Result<WavWriter<io::BufWriter<fs::File>>> { | 
|  | // Open the file in append mode, start reading from the start. | 
|  | let mut file = try!(fs::OpenOptions::new().read(true).write(true).open(filename)); | 
|  | try!(file.seek(io::SeekFrom::Start(0))); | 
|  |  | 
|  | // Read the header using a buffered reader. | 
|  | let mut buf_reader = io::BufReader::new(file); | 
|  | let (spec_ex, data_len, data_len_offset) = try!(read_append(&mut buf_reader)); | 
|  | let mut file = buf_reader.into_inner(); | 
|  |  | 
|  | // Seek to the data position, and from now on, write using a buffered | 
|  | // writer. | 
|  | try!(file.seek(io::SeekFrom::Current(data_len as i64))); | 
|  | let buf_writer = io::BufWriter::new(file); | 
|  |  | 
|  | let writer = WavWriter { | 
|  | spec: spec_ex.spec, | 
|  | bytes_per_sample: spec_ex.bytes_per_sample, | 
|  | writer: buf_writer, | 
|  | data_bytes_written: data_len, | 
|  | sample_writer_buffer: Vec::new(), | 
|  | finalized: false, | 
|  | data_len_offset: data_len_offset, | 
|  | }; | 
|  |  | 
|  | Ok(writer) | 
|  | } | 
|  | } | 
|  |  | 
|  | impl<W> WavWriter<W> where W: io::Read + io::Write + io::Seek { | 
|  | /// Creates a writer that appends samples to an existing file stream. | 
|  | /// | 
|  | /// This first reads the existing header to obtain the spec, then seeks to | 
|  | /// the end of the writer. The writer then appends new samples to the end of | 
|  | /// the stream. | 
|  | /// | 
|  | /// The underlying writer is assumed to be at offset 0. | 
|  | /// | 
|  | /// If the existing file includes a fact chunk, it will not be updated after | 
|  | /// appending, and hence become outdated. For files produced by Hound this | 
|  | /// is not an issue, because Hound never writes a fact chunk. For all the | 
|  | /// formats that Hound can write, the fact chunk is redundant. | 
|  | pub fn new_append(mut writer: W) -> Result<WavWriter<W>> { | 
|  | let (spec_ex, data_len, data_len_offset) = try!(read_append(&mut writer)); | 
|  | try!(writer.seek(io::SeekFrom::Current(data_len as i64))); | 
|  | let writer = WavWriter { | 
|  | spec: spec_ex.spec, | 
|  | bytes_per_sample: spec_ex.bytes_per_sample, | 
|  | writer: writer, | 
|  | data_bytes_written: data_len, | 
|  | sample_writer_buffer: Vec::new(), | 
|  | finalized: false, | 
|  | data_len_offset: data_len_offset, | 
|  | }; | 
|  |  | 
|  | Ok(writer) | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /// A writer that specifically only writes integer samples of 16 bits per sample. | 
|  | /// | 
|  | /// The writer buffers written samples internally so they can be written in a | 
|  | /// single batch later on. This has two advantages when performance is | 
|  | /// important: | 
|  | /// | 
|  | ///  * There is no need for error handling during writing, only on flush. This | 
|  | ///    eliminates a lot of branches. | 
|  | ///  * The buffer can be written once, which reduces the overhead of the write | 
|  | ///    call. Because writing to an `io::BufWriter` is implemented with a | 
|  | ///    `memcpy` (even for single bytes), there is a large overhead to writing | 
|  | ///    small amounts of data such as a 16-bit sample. By writing large blocks | 
|  | ///    (or by not using `BufWriter`) this overhead can be avoided. | 
|  | /// | 
|  | /// A `SampleWriter16` can be obtained by calling [`WavWriter::get_i16_writer`]( | 
|  | /// struct.WavWriter.html#method.get_i16_writer). | 
|  | pub struct SampleWriter16<'parent, W> where W: io::Write + io::Seek + 'parent { | 
|  | /// The writer borrowed from the wrapped WavWriter. | 
|  | writer: &'parent mut W, | 
|  |  | 
|  | /// The internal buffer that samples are written to before they are flushed. | 
|  | buffer: &'parent mut [MaybeUninit<u8>], | 
|  |  | 
|  | /// Reference to the `data_bytes_written` field of the writer. | 
|  | data_bytes_written: &'parent mut u32, | 
|  |  | 
|  | /// The index into the buffer where the next bytes will be written. | 
|  | index: u32, | 
|  | } | 
|  |  | 
|  | impl<'parent, W: io::Write + io::Seek> SampleWriter16<'parent, W> { | 
|  | /// Writes a single sample for one channel. | 
|  | /// | 
|  | /// WAVE interleaves channel data, so the channel that this writes the | 
|  | /// sample to depends on previous writes. | 
|  | /// | 
|  | /// Unlike `WavWriter::write_sample()`, no range check is performed. Only | 
|  | /// the least significant 16 bits are considered, everything else is | 
|  | /// discarded.  Apart from that check, this method is more efficient than | 
|  | /// `WavWriter::write_sample()`, because it can avoid dispatching on the | 
|  | /// number of bits. That was done already when the `SampleWriter16` was | 
|  | /// constructed. | 
|  | /// | 
|  | /// Note that nothing is actually written until `flush()` is called. | 
|  | #[inline(always)] | 
|  | pub fn write_sample<S: Sample>(&mut self, sample: S) { | 
|  | assert!((self.index as usize) + 2 <= self.buffer.len(), | 
|  | "Trying to write more samples than reserved for the sample writer."); | 
|  |  | 
|  | // SAFETY: We performed the bounds check in the above assertion. | 
|  | unsafe { self.write_sample_unchecked(sample) }; | 
|  | } | 
|  |  | 
|  | unsafe fn write_u16_le_unchecked(&mut self, value: u16) { | 
|  | // On little endian machines the compiler produces assembly code | 
|  | // that merges the following two lines into a single instruction. | 
|  | *self.buffer.get_unchecked_mut(self.index as usize) = MaybeUninit::new(value as u8); | 
|  | self.buffer.get_unchecked_mut(self.index as usize).assume_init(); | 
|  | *self.buffer.get_unchecked_mut(self.index as usize + 1) = MaybeUninit::new((value >> 8) as u8); | 
|  | self.buffer.get_unchecked_mut(self.index as usize + 1).assume_init(); | 
|  | } | 
|  |  | 
|  | /// Like `write_sample()`, but does not perform a bounds check when writing | 
|  | /// to the internal buffer. | 
|  | /// | 
|  | /// It is the responsibility of the programmer to ensure that no more | 
|  | /// samples are written than allocated when the writer was created. | 
|  | #[inline(always)] | 
|  | pub unsafe fn write_sample_unchecked<S: Sample>(&mut self, sample: S) { | 
|  | self.write_u16_le_unchecked(sample.as_i16() as u16); | 
|  | self.index += 2; | 
|  | } | 
|  |  | 
|  | /// Flush the internal buffer to the underlying writer. | 
|  | /// | 
|  | /// # Panics | 
|  | /// | 
|  | /// Panics if insufficient samples (less than specified when the writer was | 
|  | /// constructed) have been written with `write_sample()`. | 
|  | pub fn flush(self) -> Result<()> { | 
|  | if self.index as usize != self.buffer.len() { | 
|  | panic!("Insufficient samples written to the sample writer."); | 
|  | } | 
|  |  | 
|  | // SAFETY: casting `self.buffer` to a `*const [MaybeUninit<u8>]` is safe | 
|  | // since the caller guarantees that `self.buffer` is initialized, and | 
|  | // `MaybeUninit<u8>` is guaranteed to have the same layout as `u8`. The | 
|  | // pointer obtained is valid since it refers to memory owned by | 
|  | // `self.buffer` which is a reference and thus guaranteed to be valid | 
|  | // for reads. This is copied from the nightly implementation for | 
|  | // slice_assume_init_ref. | 
|  | let slice = unsafe { &*(self.buffer as *const [MaybeUninit<u8>] as *const [u8]) }; | 
|  |  | 
|  | try!(self.writer.write_all(slice)); | 
|  |  | 
|  | *self.data_bytes_written += self.buffer.len() as u32; | 
|  | Ok(()) | 
|  | } | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn short_write_should_signal_error() { | 
|  | use SampleFormat; | 
|  |  | 
|  | let mut buffer = io::Cursor::new(Vec::new()); | 
|  |  | 
|  | let write_spec = WavSpec { | 
|  | channels: 17, | 
|  | sample_rate: 48000, | 
|  | bits_per_sample: 8, | 
|  | sample_format: SampleFormat::Int, | 
|  | }; | 
|  |  | 
|  | // Deliberately write one sample less than 17 * 5. | 
|  | let mut writer = WavWriter::new(&mut buffer, write_spec).unwrap(); | 
|  | for s in 0..17 * 5 - 1 { | 
|  | writer.write_sample(s as i16).unwrap(); | 
|  | } | 
|  | let error = writer.finalize().err().unwrap(); | 
|  |  | 
|  | match error { | 
|  | Error::UnfinishedSample => {} | 
|  | _ => panic!("UnfinishedSample error should have been returned."), | 
|  | } | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn wide_write_should_signal_error() { | 
|  | let mut buffer = io::Cursor::new(Vec::new()); | 
|  |  | 
|  | let spec8 = WavSpec { | 
|  | channels: 1, | 
|  | sample_rate: 44100, | 
|  | bits_per_sample: 8, | 
|  | sample_format: SampleFormat::Int, | 
|  | }; | 
|  | { | 
|  | let mut writer = WavWriter::new(&mut buffer, spec8).unwrap(); | 
|  | assert!(writer.write_sample(127_i8).is_ok()); | 
|  | assert!(writer.write_sample(127_i16).is_ok()); | 
|  | assert!(writer.write_sample(127_i32).is_ok()); | 
|  | assert!(writer.write_sample(128_i16).is_err()); | 
|  | assert!(writer.write_sample(128_i32).is_err()); | 
|  | } | 
|  |  | 
|  | let spec16 = WavSpec { bits_per_sample: 16, ..spec8 }; | 
|  | { | 
|  | let mut writer = WavWriter::new(&mut buffer, spec16).unwrap(); | 
|  | assert!(writer.write_sample(32767_i16).is_ok()); | 
|  | assert!(writer.write_sample(32767_i32).is_ok()); | 
|  | assert!(writer.write_sample(32768_i32).is_err()); | 
|  | } | 
|  |  | 
|  | let spec24 = WavSpec { bits_per_sample: 24, ..spec8 }; | 
|  | { | 
|  | let mut writer = WavWriter::new(&mut buffer, spec24).unwrap(); | 
|  | assert!(writer.write_sample(8_388_607_i32).is_ok()); | 
|  | assert!(writer.write_sample(8_388_608_i32).is_err()); | 
|  | } | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn s24_wav_write() { | 
|  | use std::fs::File; | 
|  | use std::io::Read; | 
|  | let mut buffer = io::Cursor::new(Vec::new()); | 
|  |  | 
|  | let spec = WavSpecEx { | 
|  | spec: WavSpec { | 
|  | channels: 2, | 
|  | sample_rate: 48000, | 
|  | bits_per_sample: 24, | 
|  | sample_format: SampleFormat::Int, | 
|  | }, | 
|  | bytes_per_sample: 4, | 
|  | }; | 
|  | { | 
|  | let mut writer = WavWriter::new_with_spec_ex(&mut buffer, spec).unwrap(); | 
|  | assert!(writer.write_sample(-96_i32).is_ok()); | 
|  | assert!(writer.write_sample(23_052_i32).is_ok()); | 
|  | assert!(writer.write_sample(8_388_607_i32).is_ok()); | 
|  | assert!(writer.write_sample(-8_360_672_i32).is_ok()); | 
|  | } | 
|  |  | 
|  | let mut expected = Vec::new(); | 
|  | File::open("testsamples/waveformatextensible-24bit-4byte-48kHz-stereo.wav") | 
|  | .unwrap() | 
|  | .read_to_end(&mut expected) | 
|  | .unwrap(); | 
|  |  | 
|  | assert_eq!(buffer.into_inner(), expected); | 
|  | } |