use crossbeam_channel::{Sender, TrySendError, bounded};
use tinyaudio::prelude::*;
pub const AUDIO_RATE: usize = 48_000;
pub struct AudioOutput {
pub tx: Sender<f32>,
_device: Option<Box<dyn std::any::Any>>,
}
impl AudioOutput {
pub fn new(buffer_size: usize) -> Option<Self> {
let (tx, rx) = bounded::<f32>(buffer_size);
let device = {
let config = OutputDeviceParameters {
channels_count: 1, sample_rate: AUDIO_RATE,
channel_sample_count: 1024,
};
match run_output_device(config, move |output| {
for sample in output.iter_mut() {
*sample = rx.try_recv().unwrap_or(0.0);
}
}) {
Ok(device) => Some(Box::new(device) as Box<dyn std::any::Any>),
Err(_) => None, }
};
Some(AudioOutput {
tx,
_device: device,
})
}
pub fn send(&self, sample: f32) -> Result<(), TrySendError<f32>> {
let clamped = sample.clamp(-1.0, 1.0);
self.tx.try_send(clamped)
}
pub fn send_batch(&self, samples: &[f32]) -> usize {
let mut sent = 0;
for &sample in samples {
if self.send(sample).is_ok() {
sent += 1;
} else {
break;
}
}
sent
}
pub fn buffer_fill(&self) -> usize {
self.tx.len()
}
pub fn is_buffer_full(&self) -> bool {
let capacity = self.tx.capacity().unwrap_or(1);
self.buffer_fill() > (capacity * 4 / 5)
}
}