surge_hound/write.rs
1// Hound -- A wav encoding and decoding library in Rust
2// Copyright (C) 2015 Ruud van Asseldonk
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// A copy of the License has been included in the root of the repository.
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12
13use std::fs;
14use std::io;
15use std::mem;
16use std::io::{Seek, Write};
17use std::path;
18use super::{Error, Result, Sample, SampleFormat, WavSpec};
19use ::read;
20use ::read::{WavSpecSurge};
21
22/// Extends the functionality of `io::Write` with additional methods.
23///
24/// The methods may be used on any type that implements `io::Write`.
25pub trait WriteExt: io::Write {
26 /// Writes an unsigned 8-bit integer.
27 fn write_u8(&mut self, x: u8) -> io::Result<()>;
28
29 /// Writes a signed 16-bit integer in little endian format.
30 fn write_le_i16(&mut self, x: i16) -> io::Result<()>;
31
32 /// Writes an unsigned 16-bit integer in little endian format.
33 fn write_le_u16(&mut self, x: u16) -> io::Result<()>;
34
35 /// Writes a signed 24-bit integer in little endian format.
36 ///
37 /// The most significant byte of the `i32` is ignored.
38 fn write_le_i24(&mut self, x: i32) -> io::Result<()>;
39
40 /// Writes an unsigned 24-bit integer in little endian format.
41 ///
42 /// The most significant byte of the `u32` is ignored.
43 fn write_le_u24(&mut self, x: u32) -> io::Result<()>;
44
45 /// Writes a signed 32-bit integer in little endian format.
46 fn write_le_i32(&mut self, x: i32) -> io::Result<()>;
47
48 /// Writes an unsigned 32-bit integer in little endian format.
49 fn write_le_u32(&mut self, x: u32) -> io::Result<()>;
50
51 /// Writes an IEEE float in little endian format.
52 fn write_le_f32(&mut self, x: f32) -> io::Result<()>;
53}
54
55impl<W> WriteExt for W
56 where W: io::Write
57{
58 #[inline(always)]
59 fn write_u8(&mut self, x: u8) -> io::Result<()> {
60 let buf = [x];
61 self.write_all(&buf)
62 }
63
64 #[inline(always)]
65 fn write_le_i16(&mut self, x: i16) -> io::Result<()> {
66 self.write_le_u16(x as u16)
67 }
68
69 #[inline(always)]
70 fn write_le_u16(&mut self, x: u16) -> io::Result<()> {
71 let mut buf = [0u8; 2];
72 buf[0] = (x & 0xff) as u8;
73 buf[1] = (x >> 8) as u8;
74 self.write_all(&buf)
75 }
76
77 #[inline(always)]
78 fn write_le_i24(&mut self, x: i32) -> io::Result<()> {
79 self.write_le_u24(x as u32)
80 }
81
82 #[inline(always)]
83 fn write_le_u24(&mut self, x: u32) -> io::Result<()> {
84 let mut buf = [0u8; 3];
85 buf[0] = ( x & 0xff) as u8;
86 buf[1] = ((x >> 8) & 0xff) as u8;
87 buf[2] = ((x >> 16) & 0xff) as u8;
88 self.write_all(&buf)
89 }
90
91 #[inline(always)]
92 fn write_le_i32(&mut self, x: i32) -> io::Result<()> {
93 self.write_le_u32(x as u32)
94 }
95
96 #[inline(always)]
97 fn write_le_u32(&mut self, x: u32) -> io::Result<()> {
98 let mut buf = [0u8; 4];
99 buf[0] = ( x & 0xff) as u8;
100 buf[1] = ((x >> 8) & 0xff) as u8;
101 buf[2] = ((x >> 16) & 0xff) as u8;
102 buf[3] = ((x >> 24) & 0xff) as u8;
103 self.write_all(&buf)
104 }
105
106 #[inline(always)]
107 fn write_le_f32(&mut self, x: f32) -> io::Result<()> {
108 let u = x.to_bits();
109 self.write_le_u32(u)
110 }
111}
112
113/// Generates a bitmask with `channels` ones in the least significant bits.
114fn channel_mask(channels: u16) -> u32 {
115 (0..channels).map(|c| 1 << c).fold(0, |a, c| a | c)
116}
117
118#[test]
119fn verify_channel_mask() {
120 assert_eq!(channel_mask(0), 0);
121 assert_eq!(channel_mask(1), 1);
122 assert_eq!(channel_mask(2), 3);
123 assert_eq!(channel_mask(3), 7);
124 assert_eq!(channel_mask(4), 15);
125}
126
127/// A writer that accepts samples and writes the WAVE format.
128///
129/// The writer needs a `WavSpec` that describes the audio properties. Then
130/// samples can be written with `write_sample`. Channel data is interleaved.
131/// The number of samples written must be a multiple of the number of channels.
132/// After all samples have been written, the file must be finalized. This can
133/// be done by calling `finalize`. If `finalize` is not called, the file will
134/// be finalized upon drop. However, finalization may fail, and without calling
135/// `finalize`, such a failure cannot be observed.
136pub struct WavWriter<W>
137 where W: io::Write + io::Seek
138{
139 /// Specifies properties of the audio data.
140 spec: WavSpec,
141
142 /// The (container) bytes per sample. This is the bit rate / 8 rounded up.
143 bytes_per_sample: u16,
144
145 /// The writer that will be written to.
146 writer: W,
147
148 /// The number of bytes written to the data section.
149 ///
150 /// This is an `u32` because WAVE cannot accomodate more data.
151 data_bytes_written: u32,
152
153 /// Whether the header has been finalized.
154 finalized: bool,
155
156 /// The buffer for the sample writer, which is recycled throughout calls to
157 /// avoid allocating frequently.
158 sample_writer_buffer: Vec<u8>,
159
160 /// The offset of the length field of the data chunk.
161 ///
162 /// This field needs to be overwritten after all data has been written. To
163 /// support different size fmt chunks, and other chunks interspersed, the
164 /// offset is flexible.
165 data_len_offset: u32,
166}
167
168enum FmtKind {
169 PcmWaveFormat,
170 WaveFormatExtensible,
171}
172
173impl<W> WavWriter<W>
174 where W: io::Write + io::Seek
175{
176 /// Creates a writer that writes the WAVE format to the underlying writer.
177 ///
178 /// The underlying writer is assumed to be at offset 0. `WavWriter` employs
179 /// *no* buffering internally. It is recommended to wrap the writer in a
180 /// `BufWriter` to avoid too many `write` calls. The `create()` constructor
181 /// does this automatically.
182 ///
183 /// This writes parts of the header immediately, hence a `Result` is
184 /// returned.
185 pub fn new(writer: W, spec: WavSpec) -> Result<WavWriter<W>> {
186 // Write the older PCMWAVEFORMAT structure if possible, because it is
187 // more widely supported. For more than two channels or more than 16
188 // bits per sample, the newer WAVEFORMATEXTENSIBLE is required. See also
189 // https://msdn.microsoft.com/en-us/library/ms713497.aspx.
190 let fmt_kind = if spec.channels > 2 || spec.bits_per_sample > 16 {
191 FmtKind::WaveFormatExtensible
192 } else {
193 FmtKind::PcmWaveFormat
194 };
195
196 let mut writer = WavWriter {
197 spec,
198 bytes_per_sample: (spec.bits_per_sample + 7) / 8,
199 writer,
200 data_bytes_written: 0,
201 sample_writer_buffer: Vec::new(),
202 finalized: false,
203 data_len_offset: match fmt_kind {
204 FmtKind::WaveFormatExtensible => 64,
205 FmtKind::PcmWaveFormat => 40,
206 },
207 };
208
209 // Hound can only write those bit depths. If something else was
210 // requested, fail early, rather than writing a header but then failing
211 // at the first sample.
212 let supported = matches![spec.bits_per_sample, 8 | 16 | 24 | 32];
213
214 if !supported {
215 return Err(Error::Unsupported)
216 }
217
218 // Write headers, up to the point where data should be written.
219 writer.write_headers(fmt_kind)?;
220
221 Ok(writer)
222 }
223
224 /// Writes the RIFF WAVE header, fmt chunk, and data chunk header.
225 fn write_headers(&mut self, fmt_kind: FmtKind) -> io::Result<()> {
226 // Write to an in-memory buffer before writing to the underlying writer.
227 let mut header = [0u8; 68];
228
229 {
230 let mut buffer = io::Cursor::new(&mut header[..]);
231
232 // Write the headers for the RIFF WAVE format.
233 buffer.write_all("RIFF".as_bytes())?;
234
235 // Skip 4 bytes that will be filled with the file size afterwards.
236 buffer.write_le_u32(0)?;
237
238 buffer.write_all("WAVE".as_bytes())?;
239 buffer.write_all("fmt ".as_bytes())?;
240
241 match fmt_kind {
242 FmtKind::PcmWaveFormat => {
243 self.write_pcmwaveformat(&mut buffer)?;
244 }
245 FmtKind::WaveFormatExtensible => {
246 self.write_waveformatextensible(&mut buffer)?;
247 }
248 }
249
250 // Finally the header of the "data" chunk. The number of bytes
251 // that this will take is not known at this point. The 0 will
252 // be overwritten later.
253 buffer.write_all("data".as_bytes())?;
254 buffer.write_le_u32(0)?;
255 }
256
257 // The data length field are the last 4 bytes of the header.
258 let header_len = self.data_len_offset as usize + 4;
259
260 self.writer.write_all(&header[..header_len])
261 }
262
263 /// Writes the spec as a WAVEFORMAT structure.
264 ///
265 /// The `WAVEFORMAT` struct is a subset of both `WAVEFORMATEX` and
266 /// `WAVEFORMATEXTENSIBLE`. This does not write the `wFormatTag` member.
267 fn write_waveformat(&self, buffer: &mut io::Cursor<&mut [u8]>) -> io::Result<()> {
268 let spec = &self.spec;
269 // The field nChannels.
270 buffer.write_le_u16(spec.channels)?;
271
272 // The field nSamplesPerSec.
273 buffer.write_le_u32(spec.sample_rate)?;
274 let bytes_per_sec = spec.sample_rate
275 * self.bytes_per_sample as u32
276 * spec.channels as u32;
277
278 // The field nAvgBytesPerSec;
279 buffer.write_le_u32(bytes_per_sec)?;
280
281 // The field nBlockAlign. Block align * sample rate = bytes per sec.
282 buffer.write_le_u16((bytes_per_sec / spec.sample_rate) as u16)?;
283
284 Ok(())
285 }
286
287 /// Writes the content of the fmt chunk as PCMWAVEFORMAT struct.
288 fn write_pcmwaveformat(&mut self, buffer: &mut io::Cursor<&mut [u8]>) -> io::Result<()> {
289 // Write the size of the WAVE header chunk.
290 buffer.write_le_u32(16)?;
291
292 // The following is based on the PCMWAVEFORMAT struct as documented at
293 // https://msdn.microsoft.com/en-us/library/ms712832.aspx. See also
294 // http://soundfile.sapp.org/doc/WaveFormat/.
295
296 // The field wFormatTag
297 match self.spec.sample_format {
298 // WAVE_FORMAT_PCM
299 SampleFormat::Int => {
300 buffer.write_le_u16(1)?;
301 },
302 // WAVE_FORMAT_IEEE_FLOAT
303 SampleFormat::Float => {
304 if self.spec.bits_per_sample == 32 {
305 buffer.write_le_u16(3)?;
306 } else {
307 panic!("Invalid number of bits per sample. \
308 When writing SampleFormat::Float, \
309 bits_per_sample must be 32.");
310 }
311 },
312 };
313
314 self.write_waveformat(buffer)?;
315
316 // The field wBitsPerSample, the real number of bits per sample.
317 buffer.write_le_u16(self.spec.bits_per_sample)?;
318
319 // Note: for WAVEFORMATEX, there would be another 16-byte field `cbSize`
320 // here that should be set to zero. And the header size would be 18
321 // rather than 16.
322
323 Ok(())
324 }
325
326 /// Writes the contents of the fmt chunk as WAVEFORMATEXTENSIBLE struct.
327 fn write_waveformatextensible(&mut self, buffer: &mut io::Cursor<&mut [u8]>) -> io::Result<()> {
328 // Write the size of the WAVE header chunk.
329 buffer.write_le_u32(40)?;
330
331 // The following is based on the WAVEFORMATEXTENSIBLE struct, documented
332 // at https://msdn.microsoft.com/en-us/library/ms713496.aspx and
333 // https://msdn.microsoft.com/en-us/library/ms713462.aspx.
334
335 // The field wFormatTag, value 1 means WAVE_FORMAT_PCM, but we use
336 // the slightly more sophisticated WAVE_FORMAT_EXTENSIBLE.
337 buffer.write_le_u16(0xfffe)?;
338
339 self.write_waveformat(buffer)?;
340
341 // The field wBitsPerSample. This is actually the size of the
342 // container, so this is a multiple of 8.
343 buffer.write_le_u16(self.bytes_per_sample as u16 * 8)?;
344 // The field cbSize, the number of remaining bytes in the struct.
345 buffer.write_le_u16(22)?;
346 // The field wValidBitsPerSample, the real number of bits per sample.
347 buffer.write_le_u16(self.spec.bits_per_sample)?;
348 // The field dwChannelMask.
349 // TODO: add the option to specify the channel mask. For now, use
350 // the default assignment.
351 buffer.write_le_u32(channel_mask(self.spec.channels))?;
352
353 // The field SubFormat.
354 let subformat_guid = match self.spec.sample_format {
355 // PCM audio with integer samples.
356 SampleFormat::Int => super::KSDATAFORMAT_SUBTYPE_PCM,
357 // PCM audio with 32-bit IEEE float samples.
358 SampleFormat::Float => {
359 if self.spec.bits_per_sample == 32 {
360 super::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
361 } else {
362 panic!("Invalid number of bits per sample. \
363 When writing SampleFormat::Float, \
364 bits_per_sample must be 32.");
365 }
366 }
367 };
368 buffer.write_all(&subformat_guid)?;
369
370 Ok(())
371 }
372
373 /// Writes a single sample for one channel.
374 ///
375 /// WAVE interleaves channel data, so the channel that this writes the
376 /// sample to depends on previous writes. This will return an error if the
377 /// sample does not fit in the number of bits specified in the `WavSpec`.
378 #[inline]
379 pub fn write_sample<S: Sample>(&mut self, sample: S) -> Result<()> {
380 sample.write(&mut self.writer, self.spec.bits_per_sample)?;
381 self.data_bytes_written += self.bytes_per_sample as u32;
382 Ok(())
383 }
384
385 /// Create an efficient writer that writes 16-bit integer samples only.
386 ///
387 /// When it is known what the kind of samples will be, many dynamic checks
388 /// can be omitted. Furthermore, this writer employs buffering internally,
389 /// which allows omitting return value checks except on flush. The internal
390 /// buffer will be sized such that exactly `num_samples` samples can be
391 /// written to it, and the buffer is recycled across calls to
392 /// `get_i16_writer()` if the previous buffer was sufficiently large.
393 ///
394 /// # Panics
395 ///
396 /// Panics if the spec does not match a 16 bits per sample integer format.
397 ///
398 /// Attempting to write more than `num_samples` samples to the writer will
399 /// panic too.
400 pub fn get_i16_writer(&mut self,
401 num_samples: u32)
402 -> SampleWriter16<'_, W> {
403 if self.spec.sample_format != SampleFormat::Int {
404 panic!("When calling get_i16_writer, the sample format must be int.");
405 }
406 if self.spec.bits_per_sample != 16 {
407 panic!("When calling get_i16_writer, the number of bits per sample must be 16.");
408 }
409
410 let num_bytes = num_samples as usize * 2;
411
412 if self.sample_writer_buffer.len() < num_bytes {
413 // We need a bigger buffer. There is no point in growing the old
414 // one, as we are going to overwrite the samples anyway, so just
415 // allocate a new one.
416 let mut new_buffer = Vec::with_capacity(num_bytes);
417
418 // The potentially garbage memory here will not be exposed: the
419 // buffer is only exposed when flushing, but `flush()` asserts that
420 // all samples have been written.
421 unsafe { new_buffer.set_len(num_bytes); }
422
423 self.sample_writer_buffer = new_buffer;
424 }
425
426 SampleWriter16 {
427 writer: &mut self.writer,
428 buffer: &mut self.sample_writer_buffer[..num_bytes],
429 data_bytes_written: &mut self.data_bytes_written,
430 index: 0,
431 }
432 }
433
434 fn update_header(&mut self) -> Result<()> {
435 // The header size minus magic and 32-bit filesize (8 bytes).
436 // The data chunk length (4 bytes) is the last part of the header.
437 let header_size = self.data_len_offset + 4 - 8;
438 let file_size = self.data_bytes_written + header_size;
439
440 self.writer.seek(io::SeekFrom::Start(4))?;
441 self.writer.write_le_u32(file_size)?;
442 self.writer.seek(io::SeekFrom::Start(self.data_len_offset as u64))?;
443 self.writer.write_le_u32(self.data_bytes_written)?;
444
445 // Signal error if the last sample was not finished, but do so after
446 // everything has been written, so that no data is lost, even though
447 // the file is now ill-formed.
448 if (self.data_bytes_written / self.bytes_per_sample as u32)
449 % self.spec.channels as u32 != 0 {
450 Err(Error::UnfinishedSample)
451 } else {
452 Ok(())
453 }
454 }
455
456 /// Updates the WAVE header and flushes the underlying writer.
457 ///
458 /// Flush writes the WAVE header to the underlying writer to make the
459 /// written bytes a valid wav file, and then flushes the writer. It is still
460 /// possible to write more samples after flushing.
461 ///
462 /// Flush can be used for “checkpointing”. Even if after the flush there is
463 /// an IO error or the writing process dies, the file can still be read by a
464 /// compliant decoder up to the last flush.
465 ///
466 /// Note that if the number of samples written is not a multiple of the
467 /// channel count, the intermediate wav file will not be valid. In that case
468 /// `flush()` will still flush the data and write the (invalid) wav file,
469 /// but `Error::UnfinishedSample` will be returned afterwards.
470 ///
471 /// It is not necessary to call `finalize()` directly after `flush()`, if no
472 /// samples have been written after flushing.
473 pub fn flush(&mut self) -> Result<()> {
474 let current_pos = self.writer.seek(io::SeekFrom::Current(0))?;
475 self.update_header()?;
476 self.writer.flush()?;
477 self.writer.seek(io::SeekFrom::Start(current_pos))?;
478 Ok(())
479 }
480
481 /// Updates the WAVE header (which requires knowing all samples).
482 ///
483 /// This method must be called after all samples have been written. If it
484 /// is not called, the destructor will finalize the file, but any errors
485 /// that occur in the process cannot be observed in that manner.
486 pub fn finalize(mut self) -> Result<()> {
487 self.finalized = true;
488 self.update_header()?;
489 // We need to perform a flush here to truly capture all errors before
490 // the writer is dropped: for a buffered writer, the write to the buffer
491 // may succeed, but the write to the underlying writer may fail. So
492 // flush explicitly.
493 self.writer.flush()?;
494 Ok(())
495 }
496
497 /// Returns information about the WAVE file being written.
498 ///
499 /// This is the same spec that was passed to `WavWriter::new()`. For a
500 /// writer constructed with `WavWriter::new_append()` or
501 /// `WavWriter::append()`, this method returns the spec of the file being
502 /// appended to.
503 pub fn spec(&self) -> WavSpec {
504 self.spec
505 }
506
507 /// Returns the duration of the file written so far, in samples.
508 ///
509 /// The duration is independent of the number of channels. It is expressed
510 /// in units of samples. The duration in seconds can be obtained by
511 /// dividing this number by the sample rate.
512 pub fn duration(&self) -> u32 {
513 self.data_bytes_written / (self.bytes_per_sample as u32 * self.spec.channels as u32)
514 }
515
516 /// Returns the number of samples in the file written so far.
517 ///
518 /// The length of the file is its duration (in samples) times the number of
519 /// channels.
520 pub fn len(&self) -> u32 {
521 self.data_bytes_written / self.bytes_per_sample as u32
522 }
523
524 /// checks whether the writer has zero data bytes written
525 pub fn is_empty(&self) -> bool {
526 self.data_bytes_written == 0
527 }
528}
529
530impl<W> Drop for WavWriter<W>
531 where W: io::Write + io::Seek
532{
533 fn drop(&mut self) {
534 // If the file was not explicitly finalized (to update the headers), do
535 // it in the drop. This can fail, but drop should not panic, so a
536 // failure is ignored silently here.
537 if !self.finalized {
538 let _r = self.update_header();
539 }
540 }
541}
542
543/// Reads the relevant parts of the header required to support append.
544///
545/// Returns (surge_spec, data_len, data_len_offset).
546fn read_append<W: io::Read + io::Seek>(mut reader: &mut W) -> Result<(WavSpecSurge, u32, u32)> {
547 let (surge_spec, data_len) = {
548 read::read_wave_header(&mut reader)?;
549 read::read_until_data(&mut reader)?
550 };
551
552 // Record the position of the data chunk length, so we can overwrite it
553 // later.
554 let data_len_offset = reader.seek(io::SeekFrom::Current(0))? as u32 - 4;
555
556 let spec = surge_spec.specx.unwrap().spec;
557 let num_samples = data_len / surge_spec.specx.unwrap().bytes_per_sample as u32;
558
559 // There must not be trailing bytes in the data chunk, otherwise the
560 // bytes we write will be off.
561 if num_samples * surge_spec.specx.unwrap().bytes_per_sample as u32 != data_len {
562 let msg = "data chunk length is not a multiple of sample size";
563 return Err(Error::FormatError(msg));
564 }
565
566 // Hound cannot read or write other bit depths than those, so rather
567 // than refusing to write later, fail early.
568 let supported = matches![
569 (surge_spec.specx.unwrap().bytes_per_sample, spec.bits_per_sample),
570 (1, 8) | (2, 16) | (3, 24) | (4, 32)
571 ];
572
573 if !supported {
574 return Err(Error::Unsupported);
575 }
576
577 // The number of samples must be a multiple of the number of channels,
578 // otherwise the last inter-channel sample would not have data for all
579 // channels.
580 if num_samples % surge_spec.specx.unwrap().spec.channels as u32 != 0 {
581 return Err(Error::FormatError("invalid data chunk length"));
582 }
583
584 Ok((surge_spec, data_len, data_len_offset))
585}
586
587impl WavWriter<io::BufWriter<fs::File>> {
588 /// Creates a writer that writes the WAVE format to a file.
589 ///
590 /// This is a convenience constructor that creates the file, wraps it in a
591 /// `BufWriter`, and then constructs a `WavWriter` from it. The file will
592 /// be overwritten if it exists.
593 pub fn create<P: AsRef<path::Path>>(filename: P,
594 spec: WavSpec)
595 -> Result<WavWriter<io::BufWriter<fs::File>>> {
596 let file = fs::File::create(filename)?;
597 let buf_writer = io::BufWriter::new(file);
598 WavWriter::new(buf_writer, spec)
599 }
600
601 /// Creates a writer that appends samples to an existing file.
602 ///
603 /// This is a convenience constructor that opens the file in append mode,
604 /// reads its header using a buffered reader, and then constructs an
605 /// appending `WavWriter` that writes to the file using a `BufWriter`.
606 ///
607 /// See `WavWriter::new_append()` for more details about append behavior.
608 pub fn append<P: AsRef<path::Path>>(filename: P) -> Result<WavWriter<io::BufWriter<fs::File>>> {
609 // Open the file in append mode, start reading from the start.
610 let mut file = fs::OpenOptions::new().read(true).write(true).open(filename)?;
611 file.seek(io::SeekFrom::Start(0))?;
612
613 // Read the header using a buffered reader.
614 let mut buf_reader = io::BufReader::new(file);
615 let (surge_spec, data_len, data_len_offset) = read_append(&mut buf_reader)?;
616 let mut file = buf_reader.into_inner();
617
618 // Seek to the data position, and from now on, write using a buffered
619 // writer.
620 file.seek(io::SeekFrom::Current(data_len as i64))?;
621 let buf_writer = io::BufWriter::new(file);
622
623 let writer = WavWriter {
624 spec: surge_spec.specx.unwrap().spec,
625 bytes_per_sample: surge_spec.specx.unwrap().bytes_per_sample,
626 writer: buf_writer,
627 data_bytes_written: data_len,
628 sample_writer_buffer: Vec::new(),
629 finalized: false,
630 data_len_offset,
631 };
632
633 Ok(writer)
634 }
635}
636
637impl<W> WavWriter<W> where W: io::Read + io::Write + io::Seek {
638 /// Creates a writer that appends samples to an existing file stream.
639 ///
640 /// This first reads the existing header to obtain the spec, then seeks to
641 /// the end of the writer. The writer then appends new samples to the end of
642 /// the stream.
643 ///
644 /// The underlying writer is assumed to be at offset 0.
645 ///
646 /// If the existing file includes a fact chunk, it will not be updated after
647 /// appending, and hence become outdated. For files produced by Hound this
648 /// is not an issue, because Hound never writes a fact chunk. For all the
649 /// formats that Hound can write, the fact chunk is redundant.
650 pub fn new_append(mut writer: W) -> Result<WavWriter<W>> {
651 let (surge_spec, data_len, data_len_offset) = read_append(&mut writer)?;
652 writer.seek(io::SeekFrom::Current(data_len as i64))?;
653 let writer = WavWriter {
654 spec: surge_spec.specx.unwrap().spec,
655 bytes_per_sample: surge_spec.specx.unwrap().bytes_per_sample,
656 writer,
657 data_bytes_written: data_len,
658 sample_writer_buffer: Vec::new(),
659 finalized: false,
660 data_len_offset,
661 };
662
663 Ok(writer)
664 }
665}
666
667
668/// A writer that specifically only writes integer samples of 16 bits per sample.
669///
670/// The writer buffers written samples internally so they can be written in a
671/// single batch later on. This has two advantages when performance is
672/// important:
673///
674/// * There is no need for error handling during writing, only on flush. This
675/// eliminates a lot of branches.
676/// * The buffer can be written once, which reduces the overhead of the write
677/// call. Because writing to an `io::BufWriter` is implemented with a
678/// `memcpy` (even for single bytes), there is a large overhead to writing
679/// small amounts of data such as a 16-bit sample. By writing large blocks
680/// (or by not using `BufWriter`) this overhead can be avoided.
681///
682/// A `SampleWriter16` can be obtained by calling [`WavWriter::get_i16_writer`](
683/// struct.WavWriter.html#method.get_i16_writer).
684pub struct SampleWriter16<'parent, W> where W: io::Write + io::Seek + 'parent {
685 /// The writer borrowed from the wrapped WavWriter.
686 writer: &'parent mut W,
687
688 /// The internal buffer that samples are written to before they are flushed.
689 buffer: &'parent mut [u8],
690
691 /// Reference to the `data_bytes_written` field of the writer.
692 data_bytes_written: &'parent mut u32,
693
694 /// The index into the buffer where the next bytes will be written.
695 index: u32,
696}
697
698impl<'parent, W: io::Write + io::Seek> SampleWriter16<'parent, W> {
699 /// Writes a single sample for one channel.
700 ///
701 /// WAVE interleaves channel data, so the channel that this writes the
702 /// sample to depends on previous writes.
703 ///
704 /// Unlike `WavWriter::write_sample()`, no range check is performed. Only
705 /// the least significant 16 bits are considered, everything else is
706 /// discarded. Apart from that check, this method is more efficient than
707 /// `WavWriter::write_sample()`, because it can avoid dispatching on the
708 /// number of bits. That was done already when the `SampleWriter16` was
709 /// constructed.
710 ///
711 /// Note that nothing is actually written until `flush()` is called.
712 #[inline(always)]
713 pub fn write_sample<S: Sample>(&mut self, sample: S) {
714 assert!((self.index as usize) <= self.buffer.len() - 2,
715 "Trying to write more samples than reserved for the sample writer.");
716
717 let s = sample.as_i16() as u16;
718
719 // Write the sample in little endian to the buffer.
720 self.buffer[self.index as usize] = s as u8;
721 self.buffer[self.index as usize + 1] = (s >> 8) as u8;
722
723 self.index += 2;
724 }
725
726 #[cfg(target_arch = "x86_64")]
727 unsafe fn write_u16_le_unchecked(&mut self, value: u16) {
728 // x86_64 is little endian, so we do not need to shuffle bytes around;
729 // we can just store the 16-bit integer in the buffer directly.
730 let ptr: *mut u16 = mem::transmute(self.buffer.get_unchecked_mut(self.index as usize));
731 *ptr = value;
732 }
733
734 #[cfg(not(target_arch = "x86_64"))]
735 unsafe fn write_u16_le_unchecked(&mut self, value: u16) {
736 // Write a sample in little-endian to the buffer, independent of the
737 // endianness of the architecture we are running on.
738 let idx = self.index as usize;
739 *self.buffer.get_unchecked_mut(idx) = value as u8;
740 *self.buffer.get_unchecked_mut(idx + 1) = (value >> 8) as u8;
741 }
742
743 /// Like `write_sample()`, but does not perform a bounds check when writing
744 /// to the internal buffer.
745 ///
746 /// It is the responsibility of the programmer to ensure that no more
747 /// samples are written than allocated when the writer was created.
748 ///
749 #[inline(always)]
750 pub fn write_sample_unchecked<S: Sample>(&mut self, sample: S) {
751 unsafe {
752 self.write_u16_le_unchecked(sample.as_i16() as u16);
753 }
754 self.index += 2;
755 }
756
757 /// Flush the internal buffer to the underlying writer.
758 ///
759 /// # Panics
760 ///
761 /// Panics if insufficient samples (less than specified when the writer was
762 /// constructed) have been written with `write_sample()`.
763 pub fn flush(self) -> Result<()> {
764 if self.index as usize != self.buffer.len() {
765 panic!("Insufficient samples written to the sample writer.");
766 }
767
768 self.writer.write_all(&self.buffer)?;
769 *self.data_bytes_written += self.buffer.len() as u32;
770 Ok(())
771 }
772}
773
774#[test]
775fn short_write_should_signal_error() {
776 use SampleFormat;
777
778 let mut buffer = io::Cursor::new(Vec::new());
779
780 let write_spec = WavSpec {
781 channels: 17,
782 sample_rate: 48000,
783 bits_per_sample: 8,
784 sample_format: SampleFormat::Int,
785 };
786
787 // Deliberately write one sample less than 17 * 5.
788 let mut writer = WavWriter::new(&mut buffer, write_spec).unwrap();
789 for s in 0..17 * 5 - 1 {
790 writer.write_sample(s as i16).unwrap();
791 }
792 let error = writer.finalize().err().unwrap();
793
794 match error {
795 Error::UnfinishedSample => {}
796 _ => panic!("UnfinishedSample error should have been returned."),
797 }
798}
799
800#[test]
801fn wide_write_should_signal_error() {
802 let mut buffer = io::Cursor::new(Vec::new());
803
804 let spec8 = WavSpec {
805 channels: 1,
806 sample_rate: 44100,
807 bits_per_sample: 8,
808 sample_format: SampleFormat::Int,
809 };
810 {
811 let mut writer = WavWriter::new(&mut buffer, spec8).unwrap();
812 assert!(writer.write_sample(127_i8).is_ok());
813 assert!(writer.write_sample(127_i16).is_ok());
814 assert!(writer.write_sample(127_i32).is_ok());
815 assert!(writer.write_sample(128_i16).is_err());
816 assert!(writer.write_sample(128_i32).is_err());
817 }
818
819 let spec16 = WavSpec { bits_per_sample: 16, ..spec8 };
820 {
821 let mut writer = WavWriter::new(&mut buffer, spec16).unwrap();
822 assert!(writer.write_sample(32767_i16).is_ok());
823 assert!(writer.write_sample(32767_i32).is_ok());
824 assert!(writer.write_sample(32768_i32).is_err());
825 }
826
827 let spec24 = WavSpec { bits_per_sample: 24, ..spec8 };
828 {
829 let mut writer = WavWriter::new(&mut buffer, spec24).unwrap();
830 assert!(writer.write_sample(8_388_607_i32).is_ok());
831 assert!(writer.write_sample(8_388_608_i32).is_err());
832 }
833}