use std::num::NonZero;
use nord_format::formats::nsmp::codec::FIELD_RATE;
use rodio::buffer::SamplesBuffer;
use rodio::stream::{DeviceSinkBuilder, MixerDeviceSink};
const RATE: NonZero<u32> = match NonZero::new(FIELD_RATE) {
Some(rate) => rate,
None => panic!("the field rate is not zero"),
};
#[derive(Default)]
pub struct Sound {
device: Option<MixerDeviceSink>,
player: Option<rodio::Player>,
}
impl Sound {
pub fn play(&mut self, samples: &[i16], channels: u16) -> Result<(), String> {
let channels = NonZero::new(channels).ok_or("this zone declares no channels")?;
self.stop();
let device = match &self.device {
Some(device) => device,
None => self
.device
.insert(DeviceSinkBuilder::open_default_sink().map_err(|e| e.to_string())?),
};
let player = rodio::Player::connect_new(device.mixer());
let source: Vec<f32> = samples.iter().map(|s| f32::from(*s) / 32768.0).collect();
player.append(SamplesBuffer::new(channels, RATE, source));
self.player = Some(player);
Ok(())
}
pub fn stop(&mut self) {
if let Some(player) = self.player.take() {
player.stop();
}
}
pub fn finished(&self) -> bool {
self.player.as_ref().is_none_or(rodio::Player::empty)
}
}