use raylib::audio::RaylibAudio; type Music = raylib::audio::Music<'static>; macro_rules! load_audio { ($handle:expr, $filepath:expr) => {{ let mut audio = if cfg!(any(feature = "static", target_arch = "wasm32")) { let bytes = include_bytes!(concat!("../../../", $filepath)); let vec = Vec::from(bytes); $handle.new_music_from_memory(".wav", &vec)? } else { $handle.new_music($filepath)? }; audio.looping = true; audio }}; } pub trait Channel { fn stop(&self); fn play(&self); fn update(&self); fn is_playing(&self) -> bool; fn set_volume(&self, volume: f32); fn set_pitch(&self, pitch: f32); } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum DutyCycle { Percent12, Percent25, Percent50, Percent25Neg, } pub struct PulseChannel { pulse_12: Music, pulse_25: Music, pulse_50: Music, pulse_75: Music, duty: DutyCycle, } impl PulseChannel { pub fn load(handle: &'static RaylibAudio) -> crate::Result { Ok(Self { pulse_12: load_audio!(handle, "assets/pulse_12.wav"), pulse_25: load_audio!(handle, "assets/pulse_25.wav"), pulse_50: load_audio!(handle, "assets/pulse_50.wav"), pulse_75: load_audio!(handle, "assets/pulse_50.wav"), duty: DutyCycle::Percent50, }) } pub fn set_duty(&mut self, duty: DutyCycle) { self.duty = duty; if self.is_playing() { self.stop(); self.play(); } } } impl Channel for PulseChannel { fn stop(&self) { self.pulse_12.stop_stream(); self.pulse_25.stop_stream(); self.pulse_50.stop_stream(); self.pulse_75.stop_stream(); } fn play(&self) { use DutyCycle as D; match self.duty { D::Percent12 => self.pulse_12.play_stream(), D::Percent25 => self.pulse_25.play_stream(), D::Percent50 => self.pulse_50.play_stream(), D::Percent25Neg => self.pulse_75.play_stream(), } } fn update(&self) { self.pulse_12.update_stream(); self.pulse_25.update_stream(); self.pulse_50.update_stream(); self.pulse_75.update_stream(); } fn is_playing(&self) -> bool { self.pulse_12.is_stream_playing() || self.pulse_25.is_stream_playing() || self.pulse_50.is_stream_playing() || self.pulse_75.is_stream_playing() } fn set_volume(&self, volume: f32) { self.pulse_12.set_volume(volume); self.pulse_25.set_volume(volume); self.pulse_50.set_volume(volume); self.pulse_75.set_volume(volume); } fn set_pitch(&self, pitch: f32) { self.pulse_12.set_pitch(pitch); self.pulse_25.set_pitch(pitch); self.pulse_50.set_pitch(pitch); self.pulse_75.set_pitch(pitch); } } pub struct TriangleChannel { inner: Music, } impl TriangleChannel { pub fn load(handle: &'static RaylibAudio) -> crate::Result { Ok(Self { inner: load_audio!(handle, "assets/triangle.wav"), }) } } impl Channel for TriangleChannel { fn stop(&self) { self.inner.stop_stream(); } fn play(&self) { self.inner.play_stream(); } fn update(&self) { self.inner.update_stream(); } fn is_playing(&self) -> bool { self.inner.is_stream_playing() } fn set_volume(&self, volume: f32) { self.inner.set_volume(volume); } fn set_pitch(&self, pitch: f32) { self.inner.set_pitch(pitch); } } pub struct NoiseChannel { noise_0: Music, noise_1: Music, mode: bool, } impl NoiseChannel { pub fn load(handle: &'static RaylibAudio) -> crate::Result { Ok(Self { noise_0: load_audio!(handle, "assets/noise_0.wav"), noise_1: load_audio!(handle, "assets/noise_1.wav"), mode: false, }) } pub fn set_mode(&mut self, mode: bool) { self.mode = mode; if self.is_playing() { self.stop(); self.play(); } } } impl Channel for NoiseChannel { fn stop(&self) { self.noise_0.stop_stream(); self.noise_1.stop_stream(); } fn play(&self) { if self.mode { self.noise_1.play_stream(); } else { self.noise_0.play_stream(); } } fn update(&self) { self.noise_0.update_stream(); self.noise_0.update_stream(); } fn is_playing(&self) -> bool { self.noise_0.is_stream_playing() || self.noise_1.is_stream_playing() } fn set_volume(&self, volume: f32) { self.noise_0.set_volume(volume); self.noise_1.set_volume(volume); } fn set_pitch(&self, pitch: f32) { self.noise_0.set_pitch(pitch); self.noise_1.set_pitch(pitch); } }