Skip to main content

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}