1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
use crate::*; use rodio::Device; use std::{collections::HashMap, sync::Mutex, time::Instant}; /// The Riddle audio system core state. /// /// Manages underlying audio device and riddle audio objects' states. The recommended /// way to use this type is to let the `riddle` crate initialize and manage it for you. /// /// It is possible to manage the audio system state independantly - the most important /// thing to note is that [`AudioSystem::process_frame`] must be called periodically /// for [`ClipPlayer`] to work properly. This is **not** something that needs doing if /// using the `riddle` crate to manage the [`AudioSystem`] automatically. pub struct AudioSystem { weak_self: AudioSystemWeak, pub(super) device: Device, fades: Mutex<HashMap<FadeKey, Fade>>, } define_handles!(<AudioSystem>::weak_self, pub AudioSystemHandle, pub AudioSystemWeak); impl AudioSystem { /// Create the audio system, connected to the default audio output device. pub fn new() -> Result<AudioSystemHandle> { let device = rodio::default_output_device().ok_or(AudioError::InitFailed { cause: "Failed to get rodio output device", })?; Ok(AudioSystemHandle::new(|weak_self| AudioSystem { weak_self, device, fades: Mutex::new(HashMap::new()), })) } /// Update the system's state. /// /// Updates all [`ClipPlayer`] fades. This must be called periodically for the [`AudioSystem`] /// to function. **Do not** call this if the `riddle` crate is being used. /// /// # Example /// ```no_run /// # use riddle_audio::*; fn main() -> Result<(), AudioError> { /// let audio_system = AudioSystem::new()?; /// /// // Tick the audio system every 100ms /// let start_time = std::time::Instant::now(); /// while std::time::Instant::now() - start_time < std::time::Duration::from_secs(2) { /// audio_system.process_frame(); /// std::thread::sleep(std::time::Duration::from_millis(100)); /// } /// # Ok(()) } /// ``` pub fn process_frame(&self) { let now = Instant::now(); self.tick_fades(now); } pub(crate) fn register_fade(&self, fade: Fade) { let mut fades = self.fades.lock().unwrap(); let existing = fades.remove(&fade.key()); match existing { Some(old) => fades.insert(fade.key(), Fade::merge_pair(old, fade)), None => fades.insert(fade.key(), fade), }; } fn tick_fades(&self, now: Instant) { let mut fades = self.fades.lock().unwrap(); fades.retain(|_, f| f.update(now)); } }