use autd3_driver::derive::*;
use std::{
fs::File,
io::{BufReader, Read},
path::{Path, PathBuf},
};
use crate::error::AudioFileError;
#[derive(Modulation, Clone, PartialEq, Debug)]
pub struct RawPCM {
sample_rate: u32,
path: PathBuf,
config: SamplingConfiguration,
loop_behavior: LoopBehavior,
}
impl RawPCM {
pub fn new(path: impl AsRef<Path>, sample_rate: u32) -> Self {
Self {
sample_rate,
path: path.as_ref().to_path_buf(),
config: SamplingConfiguration::FREQ_4K_HZ,
loop_behavior: LoopBehavior::Infinite,
}
}
fn read_buf(&self) -> Result<Vec<f32>, AudioFileError> {
let f = File::open(&self.path)?;
let mut reader = BufReader::new(f);
let mut raw_buffer = Vec::new();
reader.read_to_end(&mut raw_buffer)?;
Ok(raw_buffer.into_iter().map(f32::from).collect())
}
}
impl Modulation for RawPCM {
fn calc(&self) -> Result<Vec<EmitIntensity>, AUTDInternalError> {
Ok(wav_io::resample::linear(
self.read_buf()?,
1,
self.sample_rate,
self.sampling_config().frequency() as u32,
)
.iter()
.map(|&d| EmitIntensity::new(d.round() as u8))
.collect())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Write;
fn create_dat(path: impl AsRef<Path>, data: &[u8]) -> anyhow::Result<()> {
let mut f = File::create(path)?;
f.write_all(data)?;
Ok(())
}
#[test]
fn test_rawpcm_new() -> anyhow::Result<()> {
let dir = tempfile::tempdir()?;
let path = dir.path().join("tmp.dat");
create_dat(&path, &[0xFF, 0x7F, 0x00])?;
let m = RawPCM::new(&path, 4000);
assert_eq!(
m.calc().unwrap(),
vec![
EmitIntensity::new(0xFF),
EmitIntensity::new(0x7F),
EmitIntensity::new(0x00)
]
);
let m = RawPCM::new("not_exists.dat", 4000);
assert!(m.calc().is_err());
Ok(())
}
#[test]
fn test_rawpcm_clone() -> anyhow::Result<()> {
let dir = tempfile::tempdir()?;
let path = dir.path().join("tmp.dat");
create_dat(&path, &[0xFF, 0xFF])?;
let m = RawPCM::new(&path, 4000);
assert_eq!(m, m.clone());
Ok(())
}
}