use crate::error::GameUtilError;
use crate::timing::Timing;
use audio_engine::{AudioEngine, Sound, WavDecoder};
use std::fmt::{Debug, Formatter};
use std::io::Cursor;
pub struct SoundEffect {
sound: Sound,
is_playing: bool,
duration: f64,
next_play_in: f64,
loops: bool,
}
impl Debug for SoundEffect {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Sound: is_playing: {}, duration: {:.1}s, loops: {}",
self.is_playing, self.duration, self.loops
)
}
}
pub trait NewSoundEffect {
fn load_from_bytes(
&self,
bytes: &'static [u8],
duration: f64,
) -> Result<SoundEffect, GameUtilError>;
}
impl NewSoundEffect for AudioEngine {
fn load_from_bytes(
&self,
bytes: &'static [u8],
duration: f64,
) -> Result<SoundEffect, GameUtilError> {
let decoder =
WavDecoder::new(Cursor::new(bytes)).map_err(GameUtilError::SoundEffectInvalid)?;
let sound = self
.new_sound(decoder)
.map_err(GameUtilError::SoundEffectInit)?;
Ok(SoundEffect::new(sound, duration))
}
}
impl SoundEffect {
pub fn new(sound: Sound, duration: f64) -> Self {
Self {
sound,
is_playing: false,
duration,
next_play_in: 0.0,
loops: false,
}
}
pub fn play(&mut self) {
if !self.is_playing {
self.sound.play();
self.is_playing = true;
self.next_play_in = self.duration;
}
}
pub fn reset(&mut self) {
self.sound.stop();
self.is_playing = false;
self.next_play_in = 0.0;
}
pub fn set_loop(&mut self, loops: bool) {
self.loops = loops;
self.sound.set_loop(loops)
}
pub fn set_volume(&mut self, volume: f32) {
self.sound.set_volume(volume);
}
pub fn can_play(&self) -> bool {
!self.is_playing && self.next_play_in < 0.0
}
pub fn update(&mut self, timing: &Timing) {
self.update_secs(timing.fixed_time_step)
}
pub fn update_secs(&mut self, delta: f64) {
if !self.loops && self.is_playing && self.next_play_in < 0.0 {
self.reset();
}
self.next_play_in -= delta;
}
pub fn is_playing(&self) -> bool {
self.is_playing
}
pub fn duration(&self) -> f64 {
self.duration
}
pub fn loops(&self) -> bool {
self.loops
}
}