use crate::prelude::*;
use cpal::{traits::DeviceTrait, StreamConfig};
pub type CpalResult = Result<<cpal::Device as DeviceTrait>::Stream, cpal::BuildStreamError>;
impl From<unt::SampleRate> for cpal::SampleRate {
fn from(value: unt::SampleRate) -> Self {
Self(value.0)
}
}
impl From<cpal::SampleRate> for unt::SampleRate {
fn from(value: cpal::SampleRate) -> Self {
Self(value.0)
}
}
impl<F: Send + 'static + SongFunc> Song<F> {
#[allow(clippy::missing_errors_doc)]
pub fn build_output_stream<E: FnMut(cpal::StreamError) + Send + 'static>(
mut self,
device: &cpal::Device,
buffer_size: cpal::BufferSize,
error_callback: E,
) -> CpalResult {
let channels = F::Sample::size_u8();
let mut time = unt::Time::ZERO;
let timeout = if self.length == unt::Time::MAX {
None
} else {
Some(self.length.into_raw(self.sample_rate).into())
};
device.build_output_stream(
&StreamConfig {
channels: u16::from(channels),
sample_rate: self.sample_rate.into(),
buffer_size,
},
move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
let mut idx = 0;
while idx < data.len() {
let sample = self.song.eval(time);
for j in 0..(channels as usize) {
#[allow(clippy::cast_possible_truncation)]
{
data[idx] = sample[j] as f32;
}
idx += 1;
}
}
time.advance();
},
error_callback,
timeout,
)
}
}