use std::sync::Arc;
use crate::{NextSample, Sound};
#[derive(Clone)]
pub struct MemorySound {
samples: Arc<Vec<i16>>,
channel_count: u16,
sample_rate: u32,
next_sample: usize,
should_loop: bool,
}
#[derive(Debug)]
pub struct UnsupportedMetadataChangeError {}
impl std::fmt::Display for UnsupportedMetadataChangeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"unsupported MetadataChanged encountered when consuming Sound"
)
}
}
impl std::error::Error for UnsupportedMetadataChangeError {}
impl MemorySound {
pub fn from_sound(mut orig: impl Sound) -> Result<Self, crate::Error> {
let channel_count = orig.channel_count();
let sample_rate = orig.sample_rate();
let mut samples = Vec::new();
loop {
let sample = orig.next_sample()?;
match sample {
crate::NextSample::Sample(s) => {
samples.push(s);
}
crate::NextSample::MetadataChanged => {
if orig.channel_count() != channel_count || orig.sample_rate() != sample_rate {
return Err(crate::Error::IoError(std::io::Error::other(
UnsupportedMetadataChangeError {},
)));
}
let channel_idx = samples.len() % channel_count as usize;
if channel_idx != 0 {
let outputs_to_stay_in_sync = channel_count as usize - channel_idx;
samples.extend(std::iter::repeat(0).take(outputs_to_stay_in_sync));
}
}
crate::NextSample::Paused | crate::NextSample::Finished => break,
}
}
Ok(MemorySound {
samples: Arc::new(samples),
channel_count,
sample_rate,
next_sample: 0,
should_loop: false,
})
}
pub fn from_samples(
samples: Arc<Vec<i16>>,
channel_count: u16,
sample_rate: u32,
) -> MemorySound {
MemorySound {
samples,
channel_count,
sample_rate,
next_sample: 0,
should_loop: false,
}
}
pub fn set_looping(&mut self, should_loop: bool) {
self.should_loop = should_loop;
}
}
impl Sound for MemorySound {
fn channel_count(&self) -> u16 {
self.channel_count
}
fn sample_rate(&self) -> u32 {
self.sample_rate
}
fn next_sample(&mut self) -> Result<NextSample, crate::Error> {
if let Some(sample) = self.samples.get(self.next_sample) {
self.next_sample += 1;
Ok(NextSample::Sample(*sample))
} else if self.should_loop && !self.samples.is_empty() {
self.next_sample = 0;
self.next_sample()
} else {
Ok(NextSample::Finished)
}
}
fn on_start_of_batch(&mut self) {}
}
#[cfg(test)]
#[path = "./tests/memory_sound.rs"]
mod tests;