1use super::{Audio, AudioManager, AudioSource};
4use crate::prelude::*;
5use kira;
6use kira::{
7 sound::{static_sound::StaticSoundSettings, PlaybackState},
8 tween,
9 tween::Tween,
10 Volume,
11};
12use std::collections::VecDeque;
13use std::time::Duration;
14use tracing::warn;
15
16#[derive(HasSchema)]
18#[schema(no_clone)]
19pub struct AudioCenter {
20 events: VecDeque<AudioEvent>,
22 music: Option<Audio>,
24 main_volume_scale: f32,
26 music_volume_scale: f32,
28 effects_volume_scale: f32,
30 music_fade_duration: Duration,
32 sounds_fade_duration: Duration,
34}
35
36impl Default for AudioCenter {
37 fn default() -> Self {
38 Self {
39 events: VecDeque::with_capacity(16),
40 music: None,
41 main_volume_scale: 1.0,
42 music_volume_scale: 1.0,
43 effects_volume_scale: 1.0,
44 music_fade_duration: Duration::from_millis(500),
45 sounds_fade_duration: Duration::from_millis(500),
46 }
47 }
48}
49
50impl AudioCenter {
51 pub fn push_event(&mut self, event: AudioEvent) {
53 self.events.push_back(event);
54 }
55
56 pub fn music(&self) -> Option<&Audio> {
58 self.music.as_ref()
59 }
60
61 pub fn music_state(&self) -> Option<PlaybackState> {
63 self.music().map(|m| m.handle.state())
64 }
65
66 pub fn play_sound(&mut self, sound_source: Handle<AudioSource>, volume: f64) {
70 self.events.push_back(AudioEvent::PlaySound {
71 sound_source,
72 volume,
73 })
74 }
75
76 pub fn play_music(&mut self, sound_source: Handle<AudioSource>, volume: f64, loop_music: bool) {
79 let clamped_volume = volume.clamp(0.0, 1.0);
80 let mut settings = StaticSoundSettings::new().volume(Volume::Amplitude(clamped_volume));
81
82 if loop_music {
83 settings = settings.loop_region(kira::sound::Region {
84 start: 0.0.into(),
85 end: kira::sound::EndPosition::EndOfAudio,
86 });
87 }
88
89 self.events.push_back(AudioEvent::PlayMusic {
90 sound_source,
91 sound_settings: Box::new(settings),
92 force_restart: true,
93 });
94 }
95
96 #[allow(clippy::too_many_arguments)]
109 pub fn play_music_advanced(
110 &mut self,
111 sound_source: Handle<AudioSource>,
112 volume: f64,
113 loop_music: bool,
114 reverse: bool,
115 start_position: f64,
116 playback_rate: f64,
117 skip_restart: bool,
118 ) {
119 let clamped_volume = volume.clamp(0.0, 1.0);
120 let mut settings = StaticSoundSettings::new()
121 .volume(Volume::Amplitude(clamped_volume))
122 .start_position(kira::sound::PlaybackPosition::Seconds(start_position))
123 .reverse(reverse)
124 .playback_rate(playback_rate);
125
126 if loop_music {
127 settings = settings.loop_region(kira::sound::Region {
128 start: 0.0.into(),
129 end: kira::sound::EndPosition::EndOfAudio,
130 });
131 }
132
133 self.events.push_back(AudioEvent::PlayMusic {
134 sound_source,
135 sound_settings: Box::new(settings),
136 force_restart: !skip_restart,
137 });
138 }
139
140 pub fn play_music_custom(
143 &mut self,
144 sound_source: Handle<AudioSource>,
145 sound_settings: StaticSoundSettings,
146 skip_restart: bool,
147 ) {
148 self.events.push_back(AudioEvent::PlayMusic {
149 sound_source,
150 sound_settings: Box::new(sound_settings),
151 force_restart: !skip_restart,
152 });
153 }
154
155 pub fn set_main_volume_scale(&mut self, main: f32) {
158 self.main_volume_scale = main.clamp(0.0, 1.0);
159 }
160
161 pub fn set_music_volume_scale(&mut self, music: f32) {
163 self.music_volume_scale = music.clamp(0.0, 1.0);
164 }
165
166 pub fn set_effects_volume_scale(&mut self, effects: f32) {
168 self.effects_volume_scale = effects.clamp(0.0, 1.0);
169 }
170
171 pub fn set_volume_scales(&mut self, main: f32, music: f32, effects: f32) {
173 self.set_main_volume_scale(main);
174 self.set_music_volume_scale(music);
175 self.set_effects_volume_scale(effects);
176 self.events.push_back(AudioEvent::VolumeScaleUpdate {
177 main_volume_scale: self.main_volume_scale,
178 music_volume_scale: self.music_volume_scale,
179 effects_volume_scale: self.effects_volume_scale,
180 });
181 }
182
183 pub fn main_volume_scale(&self) -> f32 {
185 self.main_volume_scale
186 }
187
188 pub fn music_volume_scale(&self) -> f32 {
190 self.music_volume_scale
191 }
192
193 pub fn effects_volume_scale(&self) -> f32 {
195 self.effects_volume_scale
196 }
197
198 pub fn music_fade_duration(&self) -> Duration {
200 self.music_fade_duration
201 }
202
203 pub fn set_music_fade_duration(&mut self, duration: Duration) {
205 self.music_fade_duration = duration;
206 }
207
208 pub fn sounds_fade_duration(&self) -> Duration {
210 self.sounds_fade_duration
211 }
212
213 pub fn set_sounds_fade_duration(&mut self, duration: Duration) {
215 self.sounds_fade_duration = duration;
216 }
217
218 pub fn stop_music(&mut self, fade_out: bool) {
221 self.events.push_back(AudioEvent::StopMusic { fade_out });
222 }
223
224 pub fn stop_all_sounds(&mut self, fade_out: bool) {
227 self.events
228 .push_back(AudioEvent::StopAllSounds { fade_out });
229 }
230}
231
232#[derive(Clone, Debug)]
235pub enum AudioEvent {
236 VolumeScaleUpdate {
239 main_volume_scale: f32,
241 music_volume_scale: f32,
243 effects_volume_scale: f32,
245 },
246 PlayMusic {
250 sound_source: Handle<AudioSource>,
252 sound_settings: Box<StaticSoundSettings>,
254 force_restart: bool,
256 },
257 StopMusic {
259 fade_out: bool,
261 },
262 PlaySound {
264 sound_source: Handle<AudioSource>,
266 volume: f64,
268 },
269 StopAllSounds {
271 fade_out: bool,
273 },
274}
275
276pub fn _process_audio_events(
278 mut audio_manager: ResMut<AudioManager>,
279 mut audio_center: ResMut<AudioCenter>,
280 assets: ResInit<AssetServer>,
281 mut entities: ResMut<Entities>,
282 mut audios: CompMut<Audio>,
283) {
284 for event in audio_center.events.drain(..).collect::<Vec<_>>() {
285 match event {
286 AudioEvent::VolumeScaleUpdate {
287 main_volume_scale,
288 music_volume_scale,
289 effects_volume_scale,
290 } => {
291 let tween = Tween::default();
292 if let Some(music) = &mut audio_center.music {
294 let volume =
295 (main_volume_scale as f64) * (music_volume_scale as f64) * music.volume;
296 music.handle.set_volume(volume, tween);
297 }
298 for audio in audios.iter_mut() {
300 let volume =
301 (main_volume_scale as f64) * (effects_volume_scale as f64) * audio.volume;
302 audio.handle.set_volume(volume, tween);
303 }
304 }
305 AudioEvent::PlayMusic {
306 sound_source,
307 mut sound_settings,
308 force_restart,
309 } => {
310 let should_play = force_restart
311 || audio_center
312 .music
313 .as_ref()
314 .is_none_or(|current_music| sound_source != current_music.bones_handle);
315
316 if should_play {
317 if let Some(mut music) = audio_center.music.take() {
319 let tween = Tween {
320 start_time: kira::StartTime::Immediate,
321 duration: audio_center.music_fade_duration,
322 easing: tween::Easing::Linear,
323 };
324 music.handle.stop(tween);
325 }
326 let volume = match sound_settings.volume {
328 tween::Value::Fixed(vol) => vol.as_amplitude(),
329 _ => 1.0,
330 };
331 let scaled_volume = (audio_center.main_volume_scale as f64)
332 * (audio_center.music_volume_scale as f64)
333 * volume;
334 sound_settings.volume = tween::Value::Fixed(Volume::Amplitude(scaled_volume));
335 let sound_data = assets.get(sound_source).with_settings(*sound_settings);
337 match audio_manager.play(sound_data) {
338 Err(err) => warn!("Error playing music: {err}"),
339 Ok(handle) => {
340 audio_center.music = Some(Audio {
341 handle,
342 volume,
343 bones_handle: sound_source,
344 })
345 }
346 }
347 }
348 }
349 AudioEvent::StopMusic { fade_out } => {
350 if let Some(mut music) = audio_center.music.take() {
351 if fade_out {
352 let tween = Tween {
353 start_time: kira::StartTime::Immediate,
354 duration: audio_center.music_fade_duration,
355 easing: tween::Easing::Linear,
356 };
357 music.handle.stop(tween);
358 } else {
359 music.handle.stop(Tween::default());
360 }
361 }
362 }
363 AudioEvent::StopAllSounds { fade_out } => {
364 let tween = if fade_out {
365 Tween {
366 start_time: kira::StartTime::Immediate,
367 duration: audio_center.sounds_fade_duration,
368 easing: tween::Easing::Linear,
369 }
370 } else {
371 Tween::default()
372 };
373
374 for (_, audio) in entities.iter_with(&mut audios) {
375 audio.handle.stop(tween);
376 }
377 }
378 AudioEvent::PlaySound {
379 sound_source,
380 volume,
381 } => {
382 let scaled_volume = (audio_center.main_volume_scale as f64)
383 * (audio_center.effects_volume_scale as f64)
384 * volume;
385 let sound_data = assets
386 .get(sound_source)
387 .with_settings(StaticSoundSettings::default().volume(scaled_volume));
388 match audio_manager.play(sound_data) {
389 Err(err) => warn!("Error playing sound: {err}"),
390 Ok(handle) => {
391 let audio_ent = entities.create();
392 audios.insert(
393 audio_ent,
394 Audio {
395 handle,
396 volume,
397 bones_handle: sound_source,
398 },
399 );
400 }
401 }
402 }
403 }
404 }
405}
406
407pub fn _kill_finished_audios(entities: Res<Entities>, audios: Comp<Audio>, mut commands: Commands) {
410 for (audio_ent, audio) in entities.iter_with(&audios) {
411 if audio.handle.state() == PlaybackState::Stopped {
412 commands.add(move |mut entities: ResMut<Entities>| entities.kill(audio_ent));
413 }
414 }
415}