kaudio/
wav.rs

1// Copyright (c) Kyutai, all rights reserved.
2// This source code is licensed under the license found in the
3// LICENSE file in the root directory of this source tree.
4
5use std::io::prelude::*;
6
7pub trait Sample {
8    fn to_i16(&self) -> i16;
9}
10
11impl Sample for f32 {
12    fn to_i16(&self) -> i16 {
13        (self.clamp(-1.0, 1.0) * 32767.0) as i16
14    }
15}
16
17impl Sample for f64 {
18    fn to_i16(&self) -> i16 {
19        (self.clamp(-1.0, 1.0) * 32767.0) as i16
20    }
21}
22
23impl Sample for i16 {
24    fn to_i16(&self) -> i16 {
25        *self
26    }
27}
28
29pub fn write_pcm_as_wav<W: Write, S: Sample>(
30    w: &mut W,
31    samples: &[S],
32    sample_rate: u32,
33    n_channels: u32,
34) -> std::io::Result<()> {
35    let len = 12u32; // header
36    let len = len + 24u32; // fmt
37    let len = len + samples.len() as u32 * 2 + 8; // data
38    let bytes_per_second = sample_rate * 2 * n_channels;
39    w.write_all(b"RIFF")?;
40    w.write_all(&(len - 8).to_le_bytes())?; // total length minus 8 bytes
41    w.write_all(b"WAVE")?;
42
43    // Format block
44    w.write_all(b"fmt ")?;
45    w.write_all(&16u32.to_le_bytes())?; // bits per sample
46    w.write_all(&1u16.to_le_bytes())?; // 1: PCM int, 2: PCM float
47    w.write_all(&(n_channels as u16).to_le_bytes())?;
48    w.write_all(&sample_rate.to_le_bytes())?;
49    w.write_all(&bytes_per_second.to_le_bytes())?;
50    w.write_all(&2u16.to_le_bytes())?; // 2 bytes of data per sample
51    w.write_all(&16u16.to_le_bytes())?; // bits per sample
52
53    // Data block
54    w.write_all(b"data")?;
55    w.write_all(&(samples.len() as u32 * 2).to_le_bytes())?;
56    for sample in samples.iter() {
57        w.write_all(&sample.to_i16().to_le_bytes())?
58    }
59    Ok(())
60}