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}