//! The `audio` crate stores all audio assets that need to be loaded during runtime use raylib::audio::RaylibAudio; use std::time::{Duration, Instant}; use channel::{Channel, NoiseChannel, PulseChannel, TriangleChannel}; use data::Data; mod channel; mod data; mod parse; mod program; /// The `Error` type used within this crate pub type Error = Box; /// The `Result` type used witin this crate pub type Result = std::result::Result; const AUDIO_FPS: u32 = 60; const TIME_SLICE: Duration = Duration::from_millis(1000 / AUDIO_FPS as u64); /// Holds each audio channel pub struct Channels { pub pulse_a: PulseChannel, pub pulse_b: PulseChannel, pub triangle: TriangleChannel, pub noise: NoiseChannel, } impl Channels { pub(crate) fn load() -> crate::Result { // Phantom handle to the raylib audio subsystem // Raylib doesnt use a handle, but the rust bindings // have one to ensure memory safety. // // We must leak this handle after allocating it, // if we dont then all audio will be unloaded :( // // NOTE: would this cause issues if `Audio::load` was // called multiple times? let handle = Box::leak(Box::new(RaylibAudio::init_audio_device()?)); let pulse_a = PulseChannel::load(handle)?; pulse_a.set_volume(0.0); pulse_a.play(); let pulse_b = PulseChannel::load(handle)?; pulse_b.set_volume(0.0); pulse_b.play(); let triangle = TriangleChannel::load(handle)?; triangle.set_volume(0.0); triangle.play(); let noise = NoiseChannel::load(handle)?; noise.set_volume(0.0); noise.play(); Ok(Self { pulse_a, pulse_b, triangle, noise, }) } } /// The `Audio` container initalizes the audio subsystem /// for raylib, leaks it (to gurentee audio is statically loaded), /// then loads all needed audio samples pub struct Audio { channels: Channels, last: Instant, pub data: Data, } impl Audio { pub fn load() -> crate::Result { let channels = Channels::load()?; let last = Instant::now(); let data = Data::load()?; Ok(Self { channels, last, data, }) } pub fn update(&mut self) { if self.last.elapsed() >= TIME_SLICE { self.data.explore.exec(&mut self.channels); self.data.megalovania.exec(&mut self.channels); self.last = Instant::now(); } self.channels.pulse_a.update(); self.channels.pulse_b.update(); self.channels.triangle.update(); self.channels.noise.update(); } }