simple_game_utils/
sound_effect.rs1use crate::error::GameUtilError;
2use crate::timing::Timing;
3use audio_engine::{AudioEngine, Sound, WavDecoder};
4use std::fmt::{Debug, Formatter};
5use std::io::Cursor;
6
7pub struct SoundEffect {
31 sound: Sound,
33 is_playing: bool,
35 duration: f64,
37 next_play_in: f64,
39 loops: bool,
41}
42
43impl Debug for SoundEffect {
44 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
45 write!(
46 f,
47 "Sound: is_playing: {}, duration: {:.1}s, loops: {}",
48 self.is_playing, self.duration, self.loops
49 )
50 }
51}
52
53pub trait NewSoundEffect {
54 fn load_from_bytes(
55 &self,
56 bytes: &'static [u8],
57 duration: f64,
58 ) -> Result<SoundEffect, GameUtilError>;
59}
60
61impl NewSoundEffect for AudioEngine {
62 fn load_from_bytes(
63 &self,
64 bytes: &'static [u8],
65 duration: f64,
66 ) -> Result<SoundEffect, GameUtilError> {
67 let decoder =
68 WavDecoder::new(Cursor::new(bytes)).map_err(GameUtilError::SoundEffectInvalid)?;
69 let sound = self
70 .new_sound(decoder)
71 .map_err(GameUtilError::SoundEffectInit)?;
72 Ok(SoundEffect::new(sound, duration))
73 }
74}
75
76impl SoundEffect {
77 pub fn new(sound: Sound, duration: f64) -> Self {
78 Self {
79 sound,
80 is_playing: false,
81 duration,
82 next_play_in: 0.0,
83 loops: false,
84 }
85 }
86
87 pub fn play(&mut self) {
89 if !self.is_playing {
90 self.sound.play();
91 self.is_playing = true;
92 self.next_play_in = self.duration;
93 }
94 }
95
96 pub fn reset(&mut self) {
98 self.sound.stop();
99 self.is_playing = false;
100 self.next_play_in = 0.0;
101 }
102
103 pub fn set_loop(&mut self, loops: bool) {
105 self.loops = loops;
106 self.sound.set_loop(loops)
107 }
108
109 pub fn set_volume(&mut self, volume: f32) {
110 self.sound.set_volume(volume);
111 }
112
113 pub fn can_play(&self) -> bool {
115 !self.is_playing && self.next_play_in < 0.0
116 }
117
118 pub fn update(&mut self, timing: &Timing) {
120 self.update_secs(timing.fixed_time_step)
121 }
122
123 pub fn update_secs(&mut self, delta: f64) {
125 if !self.loops && self.is_playing && self.next_play_in < 0.0 {
126 self.reset();
127 }
128 self.next_play_in -= delta;
129 }
130
131 pub fn is_playing(&self) -> bool {
133 self.is_playing
134 }
135
136 pub fn duration(&self) -> f64 {
138 self.duration
139 }
140
141 pub fn loops(&self) -> bool {
143 self.loops
144 }
145}