goud_engine/assets/audio_manager/spatial_playback.rs
1//! Spatial audio playback: distance-based attenuation for positioned audio sources.
2
3use crate::assets::loaders::AudioAsset;
4use crate::core::error::GoudResult;
5use crate::core::math::Vec2;
6
7use super::{spatial::spatial_attenuation, AudioManager};
8
9impl AudioManager {
10 /// Plays audio with spatial positioning (2D).
11 ///
12 /// Applies distance-based attenuation using the given parameters.
13 /// Volume is calculated as: base_volume * attenuation_factor
14 ///
15 /// # Arguments
16 ///
17 /// * `asset` - Reference to the audio asset to play
18 /// * `source_position` - Position of the audio source in world space
19 /// * `listener_position` - Position of the listener (typically camera or player)
20 /// * `max_distance` - Maximum distance for audio (0 volume beyond this)
21 /// * `rolloff` - Rolloff factor for attenuation (1.0 = linear, 2.0 = quadratic)
22 ///
23 /// # Returns
24 ///
25 /// A unique ID for this audio playback instance, or an error if playback fails.
26 ///
27 /// # Example
28 ///
29 /// ```no_run
30 /// use goud_engine::assets::AudioManager;
31 /// use goud_engine::core::math::Vec2;
32 ///
33 /// let mut audio_manager = AudioManager::new().unwrap();
34 /// // let audio_asset = ...; // Loaded AudioAsset
35 /// // let sink_id = audio_manager.play_spatial(
36 /// // &audio_asset,
37 /// // Vec2::new(100.0, 50.0), // Sound source position
38 /// // Vec2::new(0.0, 0.0), // Listener position
39 /// // 200.0, // Max distance
40 /// // 1.0 // Linear rolloff
41 /// // ).unwrap();
42 /// ```
43 pub fn play_spatial(
44 &mut self,
45 asset: &AudioAsset,
46 source_position: Vec2,
47 listener_position: Vec2,
48 max_distance: f32,
49 rolloff: f32,
50 ) -> GoudResult<u64> {
51 let attenuation =
52 spatial_attenuation(source_position, listener_position, max_distance, rolloff);
53 self.play_with_settings(asset, attenuation, 1.0, false)
54 }
55
56 /// Updates spatial audio volume for an existing sink.
57 ///
58 /// Recalculates attenuation based on new positions and updates the sink volume.
59 /// This should be called when either the source or listener moves.
60 ///
61 /// # Arguments
62 ///
63 /// * `sink_id` - ID returned from `play_spatial()`
64 /// * `source_position` - Current position of the audio source
65 /// * `listener_position` - Current position of the listener
66 /// * `max_distance` - Maximum distance for audio
67 /// * `rolloff` - Rolloff factor for attenuation
68 ///
69 /// # Returns
70 ///
71 /// `true` if the sink was found and volume updated, `false` otherwise.
72 ///
73 /// # Example
74 ///
75 /// ```no_run
76 /// use goud_engine::assets::AudioManager;
77 /// use goud_engine::core::math::Vec2;
78 ///
79 /// let mut audio_manager = AudioManager::new().unwrap();
80 /// // let sink_id = ...; // From play_spatial()
81 /// // audio_manager.update_spatial_volume(
82 /// // sink_id,
83 /// // Vec2::new(150.0, 75.0), // New source position
84 /// // Vec2::new(50.0, 25.0), // New listener position
85 /// // 200.0,
86 /// // 1.0
87 /// // );
88 /// ```
89 pub fn update_spatial_volume(
90 &self,
91 sink_id: u64,
92 source_position: Vec2,
93 listener_position: Vec2,
94 max_distance: f32,
95 rolloff: f32,
96 ) -> bool {
97 let attenuation =
98 spatial_attenuation(source_position, listener_position, max_distance, rolloff);
99 self.set_sink_volume(sink_id, attenuation)
100 }
101}