//! Sound representation. use crate::durandal::err::*; use std::io; /// Writes a WAVE file from a sound. /// /// # Errors /// /// Errors if `out` cannot be written to. pub fn write_wav(out: &mut impl io::Write, snd: &impl Sound) -> ResultS<()> { let smp_rate = u32::from(snd.rate()); let smp_size = smp_rate * 2; let dat_size = snd.len() as u32 * 2; out.write_all(b"RIFF")?; out.write_all(&u32::to_le_bytes(36 + dat_size))?; out.write_all(b"WAVE")?; out.write_all(b"fmt ")?; out.write_all(&u32::to_le_bytes(16))?; // PCM out.write_all(&u16::to_le_bytes(1))?; // mono out.write_all(&u16::to_le_bytes(1))?; out.write_all(&u32::to_le_bytes(smp_rate))?; out.write_all(&u32::to_le_bytes(smp_size))?; // block alignment out.write_all(&u16::to_le_bytes(2))?; // bits per sample out.write_all(&u16::to_le_bytes(16))?; out.write_all(b"data")?; out.write_all(&u32::to_le_bytes(dat_size))?; for p in 0..snd.len() { let sample = snd.index(p); out.write_all(&sample.to_le_bytes())?; } Ok(()) } /// Any PCM stream which may be represented as a 16-bit PCM stream. pub trait Sound { /// Returns the sample rate. fn rate(&self) -> u16; /// Returns the number of samples. fn len(&self) -> usize; /// Returns the `n`th sample. /// /// May panic if `n` exceeds the length of this sound. fn index(&self, n: usize) -> i16; /// Returns the number of the first sample of the loop, or `0`. fn lp_beg(&self) -> usize; /// Returns the number of the last sample of the loop, or `0`. fn lp_end(&self) -> usize; /// Returns `true` if there are no samples in this sound. fn is_empty(&self) -> bool {self.len() == 0} /// The same as `index`, but will not panic if out of bounds. fn get(&self, n: usize) -> Option { if n < self.len() { Some(self.index(n)) } else { None } } } impl Sound16 { /// Creates a new `Sound16`. pub fn new(rate: u16, lp_beg: usize, lp_end: usize, len: usize) -> Self { Self{rate, lp_beg, lp_end, data: Vec::with_capacity(len)} } /// Creates a new `Sound16` from an unsigned 8-bit stream. pub fn new_from_8(rate: u16, lp_beg: usize, lp_end: usize, b: &[u8]) -> Self { let mut snd = Self::new(rate, lp_beg, lp_end, b.len()); for &sample in b { snd.data.push(Self::sample_from_8(sample)); } snd } /// Creates a new `Sound16` from a signed 16-bit stream. pub fn new_from_16(rate: u16, lp_beg: usize, lp_end: usize, b: &[u8]) -> Self { let mut snd = Self::new(rate, lp_beg, lp_end, b.len() / 2); for i in (0..b.len()).step_by(2) { snd.data.push(i16::from_le_bytes([b[i], b[i + 1]])); } snd } /// Creates a signed 16-bit sample from an unsigned 8-bit sample. pub fn sample_from_8(sample: u8) -> i16 {(i16::from(sample) - 0x80) << 8} } impl Sound for Sound16 { fn rate(&self) -> u16 {self.rate} fn len(&self) -> usize {self.data.len()} fn index(&self, p: usize) -> i16 {self.data[p]} fn lp_beg(&self) -> usize {self.lp_beg} fn lp_end(&self) -> usize {self.lp_end} } /// A 16-bit PCM stream. pub struct Sound16 { rate: u16, lp_beg: usize, lp_end: usize, /// The raw signed PCM data of this sound. pub data: Vec, } // EOF