doukutsu-rs/src/sound/wav.rs

122 lines
3.2 KiB
Rust
Raw Normal View History

2021-08-16 06:48:17 +00:00
use std::fmt;
use std::io;
use std::io::ErrorKind;
use byteorder::{ReadBytesExt, LE};
2020-09-02 22:58:11 +00:00
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct RiffChunk {
id: [u8; 4],
2021-08-16 06:48:17 +00:00
length: u32,
2020-09-02 22:58:11 +00:00
}
impl fmt::Display for RiffChunk {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use std::ascii::escape_default as esc;
2021-08-16 06:48:17 +00:00
write!(
f,
"chunk \"{}{}{}{}\", length: {}",
2020-09-02 22:58:11 +00:00
esc(self.id[0]),
esc(self.id[1]),
esc(self.id[2]),
esc(self.id[3]),
self.length
)
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct WavFormat {
pub channels: u16,
pub sample_rate: u32,
2021-08-16 06:48:17 +00:00
pub bit_depth: u16,
2020-09-02 22:58:11 +00:00
}
impl fmt::Display for WavFormat {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2021-08-16 06:48:17 +00:00
write!(f, "{} channels, {} Hz, {}-bit", self.channels, self.sample_rate, self.bit_depth)
2020-09-02 22:58:11 +00:00
}
}
#[derive(Clone)]
pub struct WavSample {
pub format: WavFormat,
2021-08-16 06:48:17 +00:00
pub data: Vec<u8>,
2020-09-02 22:58:11 +00:00
}
impl fmt::Display for WavSample {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2021-08-16 06:48:17 +00:00
write!(
f,
"{}, {} samples",
2020-09-02 22:58:11 +00:00
self.format,
// num_bytes / bytes_per_sample
self.data.len() / ((self.format.bit_depth / 8) * self.format.channels) as usize
)
}
}
impl RiffChunk {
pub fn read_from<R: io::Read>(mut f: R) -> io::Result<RiffChunk> {
let mut id = [0; 4];
2021-08-16 06:48:17 +00:00
2020-09-02 22:58:11 +00:00
f.read_exact(&mut id)?;
let length = f.read_u32::<LE>()?;
2021-08-16 06:48:17 +00:00
2020-09-02 22:58:11 +00:00
Ok(RiffChunk { id, length })
}
}
impl WavSample {
pub fn read_from<R: io::Read>(mut f: R) -> io::Result<WavSample> {
let riff = RiffChunk::read_from(&mut f)?;
2021-08-16 06:48:17 +00:00
2020-09-02 22:58:11 +00:00
match &riff.id {
2021-08-16 06:48:17 +00:00
b"RIFF" => {}
b"RIFX" => return Err(io::Error::new(ErrorKind::InvalidData, "Cannot handle RIFX data!".to_owned())),
_ => {
return Err(io::Error::new(ErrorKind::InvalidData, format!("Expected RIFF signature, found {}", riff)))
}
2020-09-02 22:58:11 +00:00
}
2021-08-16 06:48:17 +00:00
2020-09-02 22:58:11 +00:00
let mut rfmt = [0; 4];
2021-08-16 06:48:17 +00:00
2020-09-02 22:58:11 +00:00
f.read_exact(&mut rfmt)?;
2021-08-16 06:48:17 +00:00
if rfmt != *b"WAVE" {
return Err(io::Error::new(ErrorKind::InvalidData, "Expected 'WAVE' RIFF chunk.".to_owned()));
}
2020-09-02 22:58:11 +00:00
let fmt = RiffChunk::read_from(&mut f)?;
2021-08-16 06:48:17 +00:00
if fmt.id != *b"fmt " {
return Err(io::Error::new(ErrorKind::InvalidData, "Expected 'fmt ' RIFF chunk.".to_owned()));
}
2020-09-02 22:58:11 +00:00
let afmt = f.read_u16::<LE>()?;
2021-08-16 06:48:17 +00:00
if afmt != 1 {
return Err(io::Error::new(ErrorKind::InvalidData, "Only PCM audio data is supported.".to_owned()));
}
2020-09-02 22:58:11 +00:00
let channels = f.read_u16::<LE>()?;
2021-08-16 06:48:17 +00:00
let samples = f.read_u32::<LE>()?;
2020-09-02 22:58:11 +00:00
let _brate = f.read_u32::<LE>()?;
let _balgn = f.read_u16::<LE>()?;
2021-08-16 06:48:17 +00:00
let bits = f.read_u16::<LE>()?;
2020-09-02 22:58:11 +00:00
let data = RiffChunk::read_from(&mut f)?;
2021-08-16 06:48:17 +00:00
if data.id != *b"data" {
return Err(io::Error::new(ErrorKind::InvalidData, "Expected 'data' RIFF chunk.".to_owned()));
}
2020-09-02 22:58:11 +00:00
let mut buf = vec![0; data.length as usize];
2021-08-16 06:48:17 +00:00
2020-09-02 22:58:11 +00:00
f.read_exact(&mut buf)?;
2021-08-16 06:48:17 +00:00
Ok(WavSample { format: WavFormat { channels, sample_rate: samples, bit_depth: bits }, data: buf })
2020-09-02 22:58:11 +00:00
}
}