comfy_core/
audio.rs

1use std::collections::hash_map::Entry;
2
3use crate::*;
4
5pub fn play_sound_ex(id: &str, params: PlaySoundParams) {
6    play_sound_id_ex(sound_id(id), params);
7}
8
9pub fn play_sound_id_ex(sound: Sound, _params: PlaySoundParams) {
10    play_sound_id(sound);
11}
12
13pub fn play_music_id_ex(sound: Sound, params: PlaySoundParams) {
14    if params.looped {
15        // TODO ??
16        println!("looped music not supported yet");
17    }
18    play_sound_id(sound);
19}
20
21pub fn play_sound(id: &str) {
22    play_sound_id(sound_id(id));
23}
24
25pub fn play_voice(id: &str) {
26    play_sound_id(sound_id(id));
27}
28
29pub fn play_random_sound_ex(
30    base_id: &str,
31    amount: i32,
32    settings: StaticSoundSettings,
33) {
34    let mut assets = ASSETS.borrow_mut();
35    let id = format!("{}-{}", base_id, gen_range(1, amount + 1));
36
37    AudioSystem::play_sound(
38        &mut assets,
39        sound_id(&id),
40        Some(settings),
41        AudioTrack::None,
42    );
43}
44
45pub fn play_random_sound(base_id: &str, amount: i32) {
46    let id = format!("{}-{}", base_id, gen_range(1, amount + 1));
47    play_sound_id(sound_id(&id));
48}
49
50pub fn play_music(id: &str) {
51    play_sound_id(sound_id(id));
52}
53
54pub fn play_sound_id(sound: Sound) {
55    GLOBAL_STATE.borrow_mut().play_sound_queue.push(sound);
56}
57
58pub fn stop_sound(sound: &str) {
59    stop_sound_id(sound_id(sound));
60}
61
62pub fn stop_sound_id(sound: Sound) {
63    GLOBAL_STATE.borrow_mut().stop_sound_queue.push(sound);
64}
65
66
67#[derive(Copy, Clone, Debug, Default)]
68pub struct PlaySoundParams {
69    pub looped: bool,
70}
71
72pub struct PlaySoundCommand {
73    pub sound: Sound,
74    pub settings: StaticSoundSettings,
75}
76
77thread_local! {
78    pub static AUDIO_SYSTEM: Lazy<RefCell<AudioSystem>> =
79        Lazy::new(|| RefCell::new(AudioSystem::new()));
80}
81
82pub fn change_master_volume(change: f64) {
83    AUDIO_SYSTEM.with(|audio| {
84        if let Some(system) = audio.borrow_mut().system.as_mut() {
85            system.master_volume =
86                (system.master_volume + change).clamp(0.0, 1.0);
87
88            system
89                .master_track
90                // .manager
91                // .main_track()
92                .set_volume(
93                    Volume::Amplitude(system.master_volume),
94                    kira::tween::Tween::default(),
95                )
96                .unwrap();
97        }
98    });
99}
100
101pub fn set_master_volume(value: f64) {
102    AUDIO_SYSTEM.with(|audio| {
103        if let Some(system) = audio.borrow_mut().system.as_mut() {
104            system.master_volume = value.clamp(0.0, 1.0);
105
106            system
107                .master_track
108                // .manager
109                // .main_track()
110                .set_volume(
111                    Volume::Amplitude(system.master_volume),
112                    kira::tween::Tween::default(),
113                )
114                .unwrap();
115        }
116    });
117}
118
119pub fn master_volume() -> f64 {
120    AUDIO_SYSTEM.with(|audio| {
121        if let Some(system) = audio.borrow_mut().system.as_ref() {
122            system.master_volume
123        } else {
124            0.0
125        }
126    })
127}
128
129
130pub enum AudioTrack {
131    None,
132    Filter,
133}
134
135pub struct AudioSystemImpl {
136    pub manager: AudioManager,
137    pub master_track: TrackHandle,
138    pub filter_track: TrackHandle,
139    pub filter_handle: FilterHandle,
140
141    pub master_volume: f64,
142}
143
144impl AudioSystemImpl {
145    pub fn new(mut manager: AudioManager) -> Self {
146        let mut builder = TrackBuilder::new();
147        let filter_handle =
148            builder.add_effect(FilterBuilder::new().cutoff(100.0));
149
150        // builder.add_effect(ReverbBuilder::new().damping(0.8).feedback(0.9).mix(0.1));
151
152        let filter_track =
153            manager.add_sub_track(builder).expect("Failed to add filter track");
154
155        let master_track = manager
156            .add_sub_track(TrackBuilder::new())
157            .expect("Failed to add master track");
158
159        Self {
160            manager,
161            master_track,
162            filter_track,
163            filter_handle,
164            master_volume: 1.0,
165        }
166    }
167
168    pub fn play_sound(
169        &mut self,
170        assets: &mut Assets,
171        sound: Sound,
172        settings: Option<StaticSoundSettings>,
173        track: AudioTrack,
174        // ) -> Option<impl DerefMut<Target = StaticSoundHandle>> {
175    ) {
176        // TODO: get rid of excessive locking while processing a queue
177        let sounds = assets.sounds.lock();
178
179        if let Some(mut sound_data) = sounds.get(&sound).cloned() {
180            // TODO: don't ignore settings
181            if let Some(_settings) = settings {
182                match track {
183                    AudioTrack::None => {}
184                    AudioTrack::Filter => {
185                        sound_data.settings = sound_data
186                            .settings
187                            .output_destination(&self.filter_track);
188                    }
189                }
190            } else {
191                sound_data.settings =
192                    sound_data.settings.output_destination(&self.master_track);
193            }
194
195            sound_data.settings =
196                sound_data.settings.output_destination(&self.master_track);
197
198            match self.manager.play(sound_data) {
199                Ok(handle) => {
200                    match assets.sound_handles.entry(sound) {
201                        Entry::Occupied(mut entry) => {
202                            entry
203                                .get_mut()
204                                .stop(kira::tween::Tween::default())
205                                .log_err();
206
207                            entry.insert(handle);
208                        }
209                        Entry::Vacant(entry) => {
210                            entry.insert(handle);
211                        }
212                    }
213                }
214                Err(err) => {
215                    error!("Failed to play sound: {:?}", err);
216                }
217            }
218        } else {
219            error!("No sound data for {:?}", sound);
220        }
221    }
222
223    pub fn process_sounds(&mut self) {}
224}
225
226pub struct AudioSystem {
227    pub system: Option<AudioSystemImpl>,
228}
229
230impl AudioSystem {
231    pub fn new() -> Self {
232        // AudioManager::<kira::manager::backend::mock::MockBackend>::new(AudioManagerSettings::default())
233        let manager =
234            AudioManager::<kira::manager::backend::cpal::CpalBackend>::new(
235                AudioManagerSettings::default(),
236            )
237            .map_err(|err| {
238                error!("Failed to initialize audio manager: {:?}", err);
239                err
240            })
241            .ok();
242
243        let system = manager.map(AudioSystemImpl::new);
244
245        Self { system }
246    }
247
248    pub fn process_sounds() {
249        let _span = span!("process_sounds");
250
251        let mut assets = ASSETS.borrow_mut();
252
253        let stop_sound_queue =
254            GLOBAL_STATE.borrow_mut().stop_sound_queue.drain(..).collect_vec();
255
256        for sound in stop_sound_queue {
257            match assets.sound_handles.entry(sound) {
258                Entry::Occupied(mut entry) => {
259                    entry
260                        .get_mut()
261                        .stop(kira::tween::Tween::default())
262                        .log_err();
263                    entry.remove();
264                }
265                Entry::Vacant(_) => {}
266            }
267        }
268
269        let play_sound_queue =
270            GLOBAL_STATE.borrow_mut().play_sound_queue.drain(..).collect_vec();
271
272        for sound in play_sound_queue {
273            AudioSystem::play_sound(&mut assets, sound, None, AudioTrack::None);
274        }
275    }
276
277    pub fn play_sound(
278        assets: &mut Assets,
279        sound: Sound,
280        settings: Option<StaticSoundSettings>,
281        track: AudioTrack,
282    ) {
283        AUDIO_SYSTEM.with(|audio| {
284            if let Some(system) = audio.borrow_mut().system.as_mut() {
285                system.play_sound(assets, sound, settings, track);
286            }
287        });
288    }
289}