Skip to main content

goud_engine/assets/audio_manager/
controls.rs

1//! Per-sink and global volume/speed controls.
2
3use super::AudioManager;
4
5impl AudioManager {
6    /// Returns the global volume (0.0 to 1.0).
7    ///
8    /// # Example
9    ///
10    /// ```no_run
11    /// use goud_engine::assets::AudioManager;
12    ///
13    /// let audio_manager = AudioManager::new().unwrap();
14    /// assert_eq!(audio_manager.global_volume(), 1.0);
15    /// ```
16    pub fn global_volume(&self) -> f32 {
17        *self.global_volume.lock().unwrap()
18    }
19
20    /// Sets the global volume (0.0 to 1.0).
21    ///
22    /// All currently playing and future audio will use this volume.
23    /// Values outside the range are clamped.
24    ///
25    /// # Arguments
26    ///
27    /// * `volume` - Volume level (0.0 = mute, 1.0 = full volume)
28    ///
29    /// # Example
30    ///
31    /// ```no_run
32    /// use goud_engine::assets::AudioManager;
33    ///
34    /// let mut audio_manager = AudioManager::new().unwrap();
35    /// audio_manager.set_global_volume(0.5);
36    /// assert_eq!(audio_manager.global_volume(), 0.5);
37    /// ```
38    pub fn set_global_volume(&mut self, volume: f32) {
39        let clamped = volume.clamp(0.0, 1.0);
40        *self.global_volume.lock().unwrap() = clamped;
41
42        // Update volume for all active players
43        let players = self.players.lock().unwrap();
44        for player in players.values() {
45            player.set_volume(clamped);
46        }
47    }
48
49    /// Sets the volume for a specific sink.
50    ///
51    /// # Arguments
52    ///
53    /// * `sink_id` - ID returned from `play()`
54    /// * `volume` - Volume level (0.0-1.0, will be clamped)
55    ///
56    /// # Returns
57    ///
58    /// `true` if the sink was found and volume set, `false` otherwise.
59    pub fn set_sink_volume(&self, sink_id: u64, volume: f32) -> bool {
60        let players = self.players.lock().unwrap();
61        if let Some(player) = players.get(&sink_id) {
62            let clamped = volume.clamp(0.0, 1.0);
63            player.set_volume(clamped);
64            true
65        } else {
66            false
67        }
68    }
69
70    /// Sets the playback speed (and pitch) for a specific sink.
71    ///
72    /// Note: This only works for sinks that haven't started playing yet.
73    /// For real-time speed adjustment, the sink needs to be recreated.
74    ///
75    /// # Arguments
76    ///
77    /// * `sink_id` - ID returned from `play()`
78    /// * `speed` - Speed multiplier (0.1-10.0, will be clamped)
79    ///
80    /// # Returns
81    ///
82    /// `true` if the sink was found and speed set, `false` otherwise.
83    pub fn set_sink_speed(&self, sink_id: u64, speed: f32) -> bool {
84        let players = self.players.lock().unwrap();
85        if let Some(player) = players.get(&sink_id) {
86            let clamped = speed.clamp(0.1, 10.0);
87            player.set_speed(clamped);
88            true
89        } else {
90            false
91        }
92    }
93
94    /// Returns whether a sink has finished playing.
95    ///
96    /// # Arguments
97    ///
98    /// * `sink_id` - ID returned from `play()`
99    ///
100    /// # Returns
101    ///
102    /// `true` if the sink exists but has no more audio to play,
103    /// `false` if the sink does not exist or is still playing.
104    pub fn is_finished(&self, sink_id: u64) -> bool {
105        let players = self.players.lock().unwrap();
106        if let Some(player) = players.get(&sink_id) {
107            player.empty()
108        } else {
109            false
110        }
111    }
112
113    /// Allocates a new unique player ID.
114    pub(super) fn allocate_player_id(&self) -> u64 {
115        let mut next_id = self.next_player_id.lock().unwrap();
116        let id = *next_id;
117        *next_id = next_id.wrapping_add(1);
118        id
119    }
120}