Skip to main content

euv_engine/audio/
impl.rs

1use crate::*;
2
3/// Implements audio context management for `GameAudioContext`.
4impl GameAudioContext {
5    /// Creates a new audio context with default master volume.
6    ///
7    /// # Returns
8    ///
9    /// - `GameAudioContext` - The new audio context.
10    pub fn create() -> GameAudioContext {
11        let context: AudioContext = AudioContext::new().expect("should create audio context");
12        let master_gain: GainNode = context
13            .create_gain()
14            .expect("should create master gain node");
15        let _ = master_gain.connect_with_audio_node(&context.destination());
16        master_gain.gain().set_value(AUDIO_DEFAULT_VOLUME as f32);
17        GameAudioContext::new(context, master_gain, AUDIO_DEFAULT_VOLUME)
18    }
19
20    /// Sets the master volume for all audio output.
21    ///
22    /// # Arguments
23    ///
24    /// - `f64` - The volume level in the range 0.0 to 1.0.
25    pub fn apply_master_volume(&self, volume: f64) {
26        let clamped: f64 = Numeric::clamp(volume, 0.0, 1.0);
27        self.get_master_gain().gain().set_value(clamped as f32);
28    }
29
30    /// Resumes the audio context if it was suspended.
31    pub fn resume(&self) {
32        let _ = self.get_context().resume();
33    }
34
35    /// Suspends the audio context, temporarily halting all audio processing.
36    pub fn suspend(&self) {
37        let _ = self.get_context().suspend();
38    }
39
40    /// Closes the audio context and releases all resources.
41    pub fn close(&self) {
42        let _ = self.get_context().close();
43    }
44
45    /// Returns the current sample rate of the audio context in Hz.
46    ///
47    /// # Returns
48    ///
49    /// - `f64` - The sample rate.
50    pub fn sample_rate(&self) -> f64 {
51        self.get_context().sample_rate() as f64
52    }
53
54    /// Returns the current playback time in seconds.
55    ///
56    /// # Returns
57    ///
58    /// - `f64` - The current time.
59    pub fn current_time(&self) -> f64 {
60        self.get_context().current_time()
61    }
62}
63
64/// Implements `Default` for `GameAudioContext` as a new context.
65impl Default for GameAudioContext {
66    fn default() -> GameAudioContext {
67        GameAudioContext::create()
68    }
69}
70
71/// Implements playback control for `AudioClip`.
72impl AudioClip {
73    /// Creates a new audio clip from a decoded buffer.
74    ///
75    /// # Arguments
76    ///
77    /// - `AudioBuffer` - The decoded audio data.
78    /// - `String` - The clip name.
79    ///
80    /// # Returns
81    ///
82    /// - `AudioClip` - The new clip.
83    pub fn create(buffer: AudioBuffer, name: String) -> AudioClip {
84        AudioClip::new(
85            buffer,
86            name,
87            AudioPlayState::Stopped,
88            AUDIO_DEFAULT_LOOP,
89            AUDIO_DEFAULT_VOLUME,
90            AUDIO_DEFAULT_PLAYBACK_RATE,
91        )
92    }
93
94    /// Plays this clip through the given audio context.
95    ///
96    /// Creates a new `AudioBufferSourceNode`, connects it through a gain node
97    /// to the master gain, and starts playback. If already playing, does nothing.
98    ///
99    /// # Arguments
100    ///
101    /// - `&GameAudioContext` - The audio context to play through.
102    pub fn play(&mut self, audio_context: &GameAudioContext) {
103        if self.get_state() == AudioPlayState::Playing {
104            return;
105        }
106        let source: AudioBufferSourceNode = audio_context
107            .get_context()
108            .create_buffer_source()
109            .expect("should create buffer source");
110        source.set_buffer(Some(self.get_buffer()));
111        source.set_loop(self.get_looping());
112        source
113            .playback_rate()
114            .set_value(self.get_playback_rate() as f32);
115        let gain: GainNode = audio_context
116            .get_context()
117            .create_gain()
118            .expect("should create gain node");
119        gain.gain().set_value(self.get_volume() as f32);
120        let _ = source.connect_with_audio_node(&gain);
121        let _ = gain.connect_with_audio_node(audio_context.get_master_gain());
122        let _ = source.start();
123        self.set_source_node(Some(source));
124        self.set_state(AudioPlayState::Playing);
125    }
126
127    /// Stops playback of this clip and releases the source node.
128    pub fn stop(&mut self) {
129        if let Some(source) = self.get_mut_source_node().take() {
130            let scheduled: &AudioScheduledSourceNode = source.as_ref();
131            let _ = scheduled.stop_with_when(0.0);
132            let _ = source.disconnect();
133        }
134        self.set_state(AudioPlayState::Stopped);
135    }
136
137    /// Sets whether the clip should loop.
138    ///
139    /// # Arguments
140    ///
141    /// - `bool` - True to enable looping.
142    pub fn update_looping(&mut self, looping: bool) {
143        self.set_looping(looping);
144        if let Some(source) = self.get_mut_source_node() {
145            source.set_loop(looping);
146        }
147    }
148
149    /// Sets the volume of this clip.
150    ///
151    /// # Arguments
152    ///
153    /// - `f64` - The volume in the range 0.0 to 1.0.
154    pub fn update_volume(&mut self, volume: f64) {
155        self.set_volume(Numeric::clamp(volume, 0.0, 1.0));
156    }
157
158    /// Sets the playback rate multiplier.
159    ///
160    /// # Arguments
161    ///
162    /// - `f64` - The playback rate (1.0 = normal speed).
163    pub fn update_playback_rate(&mut self, rate: f64) {
164        self.set_playback_rate(rate);
165        if let Some(source) = self.get_mut_source_node() {
166            source.playback_rate().set_value(rate as f32);
167        }
168    }
169
170    /// Returns the duration of the audio buffer in seconds.
171    ///
172    /// # Returns
173    ///
174    /// - `f64` - The duration.
175    pub fn duration(&self) -> f64 {
176        self.get_buffer().duration()
177    }
178
179    /// Returns the number of channels in the audio buffer.
180    ///
181    /// # Returns
182    ///
183    /// - `u32` - The channel count.
184    pub fn channel_count(&self) -> u32 {
185        self.get_buffer().number_of_channels()
186    }
187}