139 lines
2.8 KiB
Rust
139 lines
2.8 KiB
Rust
//! Sound representation.
|
|
|
|
use crate::durandal::err::*;
|
|
use std::io;
|
|
|
|
pub fn write_wav(out: &mut impl io::Write, snd: &impl Sound) -> ResultS<()>
|
|
{
|
|
let rate = u32::from(snd.rate());
|
|
let bps = rate * 2;
|
|
let ssize = bps * snd.len() as u32;
|
|
let fsize = 36 + ssize;
|
|
|
|
out.write_all(b"RIFF")?;
|
|
out.write_all(&fsize.to_le_bytes())?;
|
|
out.write_all(b"WAVE")?;
|
|
out.write_all(b"fmt ")?;
|
|
out.write_all(&16u32.to_le_bytes())?;
|
|
out.write_all(&1u16.to_le_bytes())?; // PCM
|
|
out.write_all(&1u16.to_le_bytes())?; // mono
|
|
out.write_all(&rate.to_le_bytes())?; // rate
|
|
out.write_all(&bps.to_le_bytes())?; // bytes per second
|
|
out.write_all(&2u16.to_le_bytes())?; // block alignment
|
|
out.write_all(&16u16.to_le_bytes())?; // bits per sample
|
|
out.write_all(b"data")?;
|
|
out.write_all(&ssize.to_le_bytes())?;
|
|
|
|
for p in 0..snd.len() {
|
|
let sample = snd.index(p);
|
|
out.write_all(&sample.to_le_bytes())?;
|
|
}
|
|
|
|
if ssize & 1 == 1 {
|
|
out.write_all(&[0])?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub trait Sound
|
|
{
|
|
fn rate(&self) -> u16;
|
|
fn len(&self) -> usize;
|
|
fn index(&self, p: usize) -> i16;
|
|
|
|
fn is_empty(&self) -> bool
|
|
{
|
|
self.len() == 0
|
|
}
|
|
|
|
fn get(&self, p: usize) -> Option<i16>
|
|
{
|
|
if p < self.len() {
|
|
Some(self.index(p))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Sound8
|
|
{
|
|
/// Creates a new Sound8.
|
|
pub fn new(rate: u16, len: usize) -> Self
|
|
{
|
|
Self{rate, data: Vec::with_capacity(len)}
|
|
}
|
|
}
|
|
|
|
impl Sound16
|
|
{
|
|
/// Creates a new Sound16.
|
|
pub fn new(rate: u16, len: usize) -> Self
|
|
{
|
|
Self{rate, data: Vec::with_capacity(len)}
|
|
}
|
|
|
|
/// Creates a new Sound16 from an unsigned 8-bit stream.
|
|
pub fn new_from_8(rate: u16, b: &[u8]) -> Self
|
|
{
|
|
let mut snd = Sound16::new(rate, b.len());
|
|
|
|
for &sample in b {
|
|
snd.data.push(Sound16::sample_from_8(sample));
|
|
}
|
|
|
|
snd
|
|
}
|
|
|
|
/// Creates a new Sound16 from a signed 16-bit stream.
|
|
pub fn new_from_16(rate: u16, b: &[u8]) -> Self
|
|
{
|
|
let mut snd = Sound16::new(rate, b.len() / 2);
|
|
|
|
for (&x, &y) in b.iter().step_by(2).zip(b.iter().step_by(2).next()) {
|
|
snd.data.push(i16::from_be_bytes([x, y]));
|
|
}
|
|
|
|
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 Sound8
|
|
{
|
|
fn rate(&self) -> u16 {self.rate}
|
|
fn len(&self) -> usize {self.data.len()}
|
|
|
|
fn index(&self, p: usize) -> i16
|
|
{
|
|
Sound16::sample_from_8(self.data[p])
|
|
}
|
|
}
|
|
|
|
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]}
|
|
}
|
|
|
|
pub struct Sound8
|
|
{
|
|
rate: u16,
|
|
pub data: Vec<u8>,
|
|
}
|
|
|
|
pub struct Sound16
|
|
{
|
|
rate: u16,
|
|
pub data: Vec<i16>,
|
|
}
|
|
|
|
// EOF
|