From 73808a3902c89ee8cac8051b99cc2dc67eb873e0 Mon Sep 17 00:00:00 2001 From: Nils Hasenbanck Date: Mon, 6 Jan 2025 19:09:44 +0100 Subject: [PATCH] Migrate to kira 0.10 --- Cargo.lock | 131 +++++++++++++--------- Cargo.toml | 2 +- korangar_audio/src/lib.rs | 224 +++++++++++++++++++------------------- 3 files changed, 194 insertions(+), 163 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e9a1b583..3464cb84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -133,9 +133,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "approx" @@ -190,6 +190,12 @@ dependencies = [ "libloading", ] +[[package]] +name = "atomic-arena" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73e8ed45f88ed32e6827a96b62d8fd4086d72defc754c5c6bd08470c1aaf648e" + [[package]] name = "atomic-waker" version = "1.1.2" @@ -323,9 +329,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.11.1" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786a307d683a5bf92e6fd5fd69a7eb613751668d1d8d67d802846dfe367c62c8" +checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" dependencies = [ "memchr", "serde", @@ -409,9 +415,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.5" +version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" +checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7" dependencies = [ "jobserver", "libc", @@ -1024,9 +1030,9 @@ checksum = "f2e102e6eb644d3e0b186fc161e4460417880a0a0b87d235f2e5b8fb30f2e9e0" [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "glow" @@ -1573,15 +1579,16 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" [[package]] name = "kira" -version = "0.9.6" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a9f9dff5e262540b628b00d5e1a772270a962d6869f8695bb24832ff3b394" +checksum = "50679def12511d0a12c261ecffad7bf0c39d83250b62a3f905fa52343613ca77" dependencies = [ + "atomic-arena", "cpal", "glam", "mint", "paste", - "ringbuf", + "rtrb", "send_wrapper", "symphonia", "triple_buffer", @@ -1746,9 +1753,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "litemap" @@ -2524,18 +2531,18 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" +checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" +checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" dependencies = [ "proc-macro2", "quote", @@ -2544,9 +2551,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -2673,9 +2680,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -2903,9 +2910,9 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "reqwest" -version = "0.12.9" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" dependencies = [ "base64 0.22.1", "bytes", @@ -2936,6 +2943,7 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", + "tower", "tower-service", "url", "wasm-bindgen", @@ -2965,15 +2973,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "ringbuf" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79abed428d1fd2a128201cec72c5f6938e2da607c6f3745f769fabea399d950a" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "ron" version = "0.8.1" @@ -2992,6 +2991,12 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" +[[package]] +name = "rtrb" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8388ea1a9e0ea807e442e8263a699e7edcb320ecbcd21b4fa8ff859acce3ba" + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -3012,9 +3017,9 @@ checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustix" -version = "0.38.42" +version = "0.38.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" dependencies = [ "bitflags 2.6.0", "errno 0.3.10", @@ -3143,9 +3148,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.13.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" dependencies = [ "core-foundation-sys", "libc", @@ -3165,18 +3170,18 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", @@ -3185,9 +3190,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.135" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" dependencies = [ "itoa", "memchr", @@ -3451,9 +3456,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.90" +version = "2.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a" dependencies = [ "proc-macro2", "quote", @@ -3531,12 +3536,13 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.14.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", "fastrand", + "getrandom", "once_cell", "rustix", "windows-sys 0.59.0", @@ -3715,6 +3721,27 @@ dependencies = [ "winnow", ] +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + [[package]] name = "tower-service" version = "0.3.3" @@ -4624,9 +4651,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winit" -version = "0.30.6" +version = "0.30.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3d72dfa0f47e429290cd0d236884ca02f22dbd5dd33a43ad2b8bf4d79b6c18" +checksum = "f5d74280aabb958072864bff6cfbcf9025cf8bfacdde5e32b5e12920ef703b0f" dependencies = [ "ahash", "android-activity", @@ -4676,9 +4703,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.20" +version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980" dependencies = [ "memchr", ] @@ -4760,9 +4787,9 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" [[package]] name = "xml-rs" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea8b391c9a790b496184c29f7f93b9ed5b16abb306c05415b68bcc16e4d06432" +checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4" [[package]] name = "yoke" diff --git a/Cargo.toml b/Cargo.toml index 38e6b211..22cf4e04 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ flate2 = { version = "1", default-features = false } glidesort = "0.1" hashbrown = "0.15" image = { version = "0.25", default-features = false } -kira = { version = "0.9", default-features = false } +kira = { version = "0.10", default-features = false } korangar_audio = { path = "korangar_audio" } korangar_debug = { path = "korangar_debug" } korangar_interface = { path = "korangar_interface" } diff --git a/korangar_audio/src/lib.rs b/korangar_audio/src/lib.rs index 78c92be3..64cace40 100644 --- a/korangar_audio/src/lib.rs +++ b/korangar_audio/src/lib.rs @@ -15,17 +15,13 @@ use std::time::{Duration, Instant}; use cgmath::{InnerSpace, Matrix3, Point3, Quaternion, Vector3}; use cpal::BufferSize; -use kira::manager::backend::cpal::{CpalBackend, CpalBackendSettings}; -use kira::manager::{AudioManager, AudioManagerSettings, Capacities}; +use kira::backend::cpal::{CpalBackend, CpalBackendSettings}; +use kira::listener::ListenerHandle; use kira::sound::static_sound::{StaticSoundData, StaticSoundHandle}; use kira::sound::streaming::{StreamingSoundData, StreamingSoundHandle}; use kira::sound::{FromFileError, PlaybackState}; -use kira::spatial::emitter::{EmitterDistances, EmitterHandle, EmitterSettings}; -use kira::spatial::listener::{ListenerHandle, ListenerSettings}; -use kira::spatial::scene::{SpatialSceneHandle, SpatialSceneSettings}; -use kira::track::{TrackBuilder, TrackHandle}; -use kira::tween::{Easing, Tween, Value}; -use kira::{Frame, Volume}; +use kira::track::{MainTrackBuilder, SpatialTrackBuilder, SpatialTrackDistances, SpatialTrackHandle, TrackBuilder, TrackHandle}; +use kira::{AudioManager, AudioManagerSettings, Capacities, Decibels, Easing, Frame, Tween}; #[cfg(feature = "debug")] use korangar_debug::logging::{print_debug, Colorize}; use korangar_util::collision::{KDTree, Sphere}; @@ -65,11 +61,12 @@ struct QueuedSoundEffect { struct AmbientSoundConfig { sound_effect_key: SoundEffectKey, bounds: Sphere, - volume: f32, + volume: Decibels, cycle: Option, } struct PlayingAmbient { + key: AmbientKey, data: StaticSoundData, handle: StaticSoundHandle, cycle: f32, @@ -106,7 +103,7 @@ pub struct AudioEngine { } struct EngineContext { - active_emitters: HashMap, + active_spatial_tracks: HashMap, spatial_listener: ListenerHandle, ambient_sound: SimpleSlab, spatial_sound_effect_track: TrackHandle, @@ -127,7 +124,6 @@ struct EngineContext { query_result: Vec, queued_background_music_track: Option, queued_sound_effect: Vec, - scene: SpatialSceneHandle, scratchpad: Vec, sound_effect_paths: GenerationalSlab, sound_effect_track: TrackHandle, @@ -138,7 +134,8 @@ impl AudioEngine { pub fn new(game_file_loader: Arc) -> AudioEngine { let mut manager = AudioManager::::new(AudioManagerSettings { capacities: Capacities::default(), - main_track_builder: TrackBuilder::default(), + main_track_builder: MainTrackBuilder::default(), + internal_buffer_size: 128, backend_settings: CpalBackendSettings { device: None, // At sampling rate of 48 kHz 1200 frames take 25 ms. @@ -146,9 +143,6 @@ impl AudioEngine { }, }) .expect("Can't initialize audio backend"); - let mut scene = manager - .add_spatial_scene(SpatialSceneSettings::default()) - .expect("Can't create spatial scene"); let background_music_track = manager .add_sub_track(TrackBuilder::new()) .expect("Can't create background music track"); @@ -158,11 +152,8 @@ impl AudioEngine { .expect("Can't create spatial sound effect track"); let position = Vector3::new(0.0, 0.0, 0.0); let orientation = Quaternion::new(0.0, 0.0, 0.0, 0.0); - let spatial_listener = scene - .add_listener(position, orientation, ListenerSettings { - track: spatial_sound_effect_track.id(), - }) - .expect("Can't create ambient listener"); + let spatial_listener = manager.add_listener(position, orientation).expect("Can't create spatial listener"); + let loading_sound_effect = HashSet::new(); let cache = SimpleCache::new( NonZeroU32::new(MAX_CACHE_COUNT).unwrap(), @@ -175,7 +166,7 @@ impl AudioEngine { let object_kdtree = KDTree::empty(); let engine_context = Mutex::new(EngineContext { - active_emitters: HashMap::default(), + active_spatial_tracks: HashMap::default(), spatial_listener, ambient_sound: SimpleSlab::default(), spatial_sound_effect_track, @@ -196,7 +187,6 @@ impl AudioEngine { query_result: Vec::default(), queued_background_music_track: None, queued_sound_effect: Vec::default(), - scene, scratchpad: Vec::default(), sound_effect_paths: GenerationalSlab::default(), sound_effect_track, @@ -206,11 +196,10 @@ impl AudioEngine { /// Mutes or unmutes the audio. pub fn mute(&self, enable: bool) { - let mut volume = Volume::Amplitude(1.0); - if enable { - volume = Volume::Amplitude(0.0); - } - self.set_main_volume(volume); + match enable { + true => self.set_main_volume(0.0), + false => self.set_main_volume(1.0), + }; } /// This function needs the full file path with the file extension. @@ -261,23 +250,32 @@ impl AudioEngine { } /// Sets the global volume. - pub fn set_main_volume(&self, volume: impl Into>) { - self.engine_context.lock().unwrap().set_main_volume(volume) + pub fn set_main_volume(&self, volume: f32) { + self.engine_context.lock().unwrap().set_main_volume(linear_to_decibel(volume)) } /// Sets the volume of the background music. - pub fn set_background_music_volume(&self, volume: impl Into>) { - self.engine_context.lock().unwrap().set_background_music_volume(volume) + pub fn set_background_music_volume(&self, volume: f32) { + self.engine_context + .lock() + .unwrap() + .set_background_music_volume(linear_to_decibel(volume)) } /// Sets the volume of sound effect. - pub fn set_sound_effect_volume(&self, volume: impl Into>) { - self.engine_context.lock().unwrap().set_sound_effect_volume(volume) + pub fn set_sound_effect_volume(&self, volume: f32) { + self.engine_context + .lock() + .unwrap() + .set_sound_effect_volume(linear_to_decibel(volume)) } /// Sets the volume of spatial sound effects. - pub fn set_spatial_sound_effect_volume(&self, volume: impl Into>) { - self.engine_context.lock().unwrap().set_spatial_sound_effect_volume(volume) + pub fn set_spatial_sound_effect_volume(&self, volume: f32) { + self.engine_context + .lock() + .unwrap() + .set_spatial_sound_effect_volume(linear_to_decibel(volume)) } /// Plays the background music track. Fades out the currently playing @@ -329,10 +327,10 @@ impl AudioEngine { self.engine_context .lock() .unwrap() - .add_ambient_sound(sound_effect_key, position, range, volume, cycle) + .add_ambient_sound(sound_effect_key, position, range, linear_to_decibel(volume), cycle) } - /// Removes all ambient sound emitters from the spatial scene. + /// Removes all ambient-sound tracks. pub fn clear_ambient_sound(&self) { self.engine_context.lock().unwrap().clear_ambient_sound() } @@ -350,28 +348,28 @@ impl AudioEngine { } impl EngineContext { - fn set_main_volume(&mut self, volume: impl Into>) { + fn set_main_volume(&mut self, volume: Decibels) { self.manager.main_track().set_volume(volume, Tween { duration: Duration::from_millis(500), ..Default::default() }); } - fn set_background_music_volume(&mut self, volume: impl Into>) { + fn set_background_music_volume(&mut self, volume: Decibels) { self.background_music_track.set_volume(volume, Tween { duration: Duration::from_millis(500), ..Default::default() }); } - fn set_sound_effect_volume(&mut self, volume: impl Into>) { + fn set_sound_effect_volume(&mut self, volume: Decibels) { self.sound_effect_track.set_volume(volume, Tween { duration: Duration::from_millis(500), ..Default::default() }); } - fn set_spatial_sound_effect_volume(&mut self, volume: impl Into>) { + fn set_spatial_sound_effect_volume(&mut self, volume: Decibels) { self.spatial_sound_effect_track.set_volume(volume, Tween { duration: Duration::from_millis(500), ..Default::default() @@ -418,8 +416,7 @@ impl EngineContext { .get(&sound_effect_key) .map(|cached_sound_effect| cached_sound_effect.0.clone()) { - let data = data.output_destination(&self.sound_effect_track); - if let Err(_error) = self.manager.play(data.clone()) { + if let Err(_error) = self.sound_effect_track.play(data.clone()) { #[cfg(feature = "debug")] print_debug!("[{}] can't play sound effect: {:?}", "error".red(), _error); } @@ -446,28 +443,27 @@ impl EngineContext { .get(&sound_effect_key) .map(|cached_sound_effect| cached_sound_effect.0.clone()) { - let settings = EmitterSettings { - distances: EmitterDistances { + let spatial_track = SpatialTrackBuilder::new() + .persist_until_sounds_finish(true) + .distances(SpatialTrackDistances { min_distance: 5.0, max_distance: range, - }, - attenuation_function: Some(Easing::Linear), - enable_spatialization: true, - persist_until_sounds_finish: true, - }; + }) + .attenuation_function(Easing::Linear); - match self.scene.add_emitter(position, settings) { - Ok(emitter_handle) => { - let data = adjust_ambient_sound(data, &emitter_handle, 1.0); - - if let Err(_error) = self.manager.play(data) { + match self + .spatial_sound_effect_track + .add_spatial_sub_track(&self.spatial_listener, position, spatial_track) + { + Ok(mut spatial_track_handle) => { + if let Err(_error) = spatial_track_handle.play(data) { #[cfg(feature = "debug")] print_debug!("[{}] can't play sound effect: {:?}", "error".red(), _error); } } Err(_error) => { #[cfg(feature = "debug")] - print_debug!("[{}] can't add spatial sound emitter: {:?}", "error".red(), _error); + print_debug!("[{}] can't add spatial sound track: {:?}", "error".red(), _error); } }; } @@ -502,23 +498,27 @@ impl EngineContext { // Kira uses a RH coordinate system, so we need to convert our LH vectors. let position = sound_config.bounds.center(); let position = Vector3::new(position.x, position.y, -position.z); - let emitter_settings = EmitterSettings { - distances: EmitterDistances { + + let spatial_track = SpatialTrackBuilder::new() + .persist_until_sounds_finish(true) + .distances(SpatialTrackDistances { min_distance: 5.0, max_distance: sound_config.bounds.radius(), - }, - attenuation_function: Some(Easing::Linear), - enable_spatialization: true, - persist_until_sounds_finish: true, - }; - let emitter_handle = match self.scene.add_emitter(position, emitter_settings) { - Ok(emitter_handle) => emitter_handle, - Err(_error) => { - #[cfg(feature = "debug")] - print_debug!("[{}] can't add ambient sound emitter: {:?}", "error".red(), _error); - continue; - } - }; + }) + .attenuation_function(Easing::Linear); + + let mut spatial_track_handle = + match self + .spatial_sound_effect_track + .add_spatial_sub_track(&self.spatial_listener, position, spatial_track) + { + Ok(spatial_track_handle) => spatial_track_handle, + Err(_error) => { + #[cfg(feature = "debug")] + print_debug!("[{}] can't add ambient sound track: {:?}", "error".red(), _error); + continue; + } + }; let sound_effect_key = sound_config.sound_effect_key; if let Some(data) = self @@ -526,11 +526,12 @@ impl EngineContext { .get(&sound_effect_key) .map(|cached_sound_effect| cached_sound_effect.0.clone()) { - let data = adjust_ambient_sound(data, &emitter_handle, sound_config.volume); - match self.manager.play(data.clone()) { + let data = data.volume(sound_config.volume); + match spatial_track_handle.play(data.clone()) { Ok(handle) => { if let Some(cycle) = sound_config.cycle { self.cycling_ambient.insert(ambient_key, PlayingAmbient { + key: ambient_key, data, handle, cycle, @@ -554,13 +555,13 @@ impl EngineContext { ); } - self.active_emitters.insert(ambient_key, emitter_handle); + self.active_spatial_tracks.insert(ambient_key, spatial_track_handle); } // Remove ambient sound that are out of reach. difference(&mut self.previous_query_result, &mut self.query_result, &mut self.scratchpad); for ambient_key in self.scratchpad.iter() { - let _ = self.active_emitters.remove(ambient_key); + let _ = self.active_spatial_tracks.remove(ambient_key); let _ = self.cycling_ambient.remove(ambient_key); } @@ -597,7 +598,7 @@ impl EngineContext { sound_effect_key: SoundEffectKey, position: Point3, range: f32, - volume: f32, + volume: Decibels, cycle: Option, ) -> AmbientKey { self.ambient_sound @@ -616,7 +617,7 @@ impl EngineContext { self.scratchpad.clear(); self.ambient_sound.clear(); - self.active_emitters.clear(); + self.active_spatial_tracks.clear(); self.cycling_ambient.clear(); } @@ -703,46 +704,46 @@ impl EngineContext { match queued.sound_type { QueuedSoundEffectType::Sound => { - if let Err(_error) = self.manager.play(data.output_destination(&self.sound_effect_track)) { + if let Err(_error) = self.sound_effect_track.play(data) { #[cfg(feature = "debug")] print_debug!("[{}] can't play sound effect: {:?}", "error".red(), _error); } } QueuedSoundEffectType::SpatialSound { position, range } => { - let settings = EmitterSettings { - distances: EmitterDistances { + let spatial_track = SpatialTrackBuilder::new() + .persist_until_sounds_finish(true) + .distances(SpatialTrackDistances { min_distance: 5.0, max_distance: range, - }, - attenuation_function: Some(Easing::Linear), - enable_spatialization: true, - persist_until_sounds_finish: true, - }; + }) + .attenuation_function(Easing::Linear); - match self.scene.add_emitter(position, settings) { - Ok(emitter_handle) => { - let data = adjust_ambient_sound(data, &emitter_handle, 1.0); - - if let Err(_error) = self.manager.play(data) { + match self + .spatial_sound_effect_track + .add_spatial_sub_track(&self.spatial_listener, position, spatial_track) + { + Ok(mut spatial_track_handle) => { + if let Err(_error) = spatial_track_handle.play(data) { #[cfg(feature = "debug")] print_debug!("[{}] can't play sound effect: {:?}", "error".red(), _error); } } Err(_error) => { #[cfg(feature = "debug")] - print_debug!("[{}] can't add spatial sound emitter: {:?}", "error".red(), _error); + print_debug!("[{}] can't add spatial sound track: {:?}", "error".red(), _error); } }; } QueuedSoundEffectType::AmbientSound { ambient_key } => { - if let Some(emitter_handle) = self.active_emitters.get(&ambient_key) + if let Some(spatial_track_handle) = self.active_spatial_tracks.get_mut(&ambient_key) && let Some(sound_config) = self.ambient_sound.get(ambient_key) { - let data = adjust_ambient_sound(data, emitter_handle, sound_config.volume); - match self.manager.play(data.clone()) { + let data = data.volume(sound_config.volume); + match spatial_track_handle.play(data.clone()) { Ok(handle) => { if let Some(cycle) = sound_config.cycle { self.cycling_ambient.insert(ambient_key, PlayingAmbient { + key: ambient_key, data, handle, cycle, @@ -770,15 +771,17 @@ impl EngineContext { for (_, playing) in self.cycling_ambient.iter_mut().filter(|(_, playing)| { playing.handle.state() != PlaybackState::Playing && now.duration_since(playing.last_start).as_secs_f32() >= playing.cycle }) { - playing.last_start = now; + if let Some(spatial_track) = self.active_spatial_tracks.get_mut(&playing.key) { + playing.last_start = now; - match self.manager.play(playing.data.clone()) { - Ok(handle) => { - playing.handle = handle; - } - Err(_error) => { - #[cfg(feature = "debug")] - print_debug!("[{}] can't play ambient sound effect: {:?}", "error".red(), _error); + match spatial_track.play(playing.data.clone()) { + Ok(handle) => { + playing.handle = handle; + } + Err(_error) => { + #[cfg(feature = "debug")] + print_debug!("[{}] can't play ambient sound effect: {:?}", "error".red(), _error); + } } } } @@ -806,9 +809,8 @@ impl EngineContext { // the music again. let duration = data.duration().as_secs_f64() - 0.05; let data = data.loop_region(..duration); - let data = data.output_destination(&self.background_music_track); - let handle = match self.manager.play(data) { + let handle = match self.background_music_track.play(data) { Ok(handle) => handle, Err(_error) => { #[cfg(feature = "debug")] @@ -824,12 +826,6 @@ impl EngineContext { } } -fn adjust_ambient_sound(mut data: StaticSoundData, emitter_handle: &EmitterHandle, volume: f32) -> StaticSoundData { - // Kira does the volume mapping from linear to logarithmic for us. - data.settings.volume = Volume::Amplitude(volume as f64).into(); - data.output_destination(emitter_handle) -} - fn queue_sound_effect_playback( game_file_loader: Arc, async_response_sender: Sender, @@ -966,6 +962,14 @@ fn difference(vector_1: &mut [T], vector_2: &mut [T], result: &mu result.extend_from_slice(&vector_1[i..]); } +fn linear_to_decibel(linear: f32) -> Decibels { + if linear <= 0.0 { + Decibels::SILENCE + } else { + Decibels::from(20.0 * linear.log10()) + } +} + #[cfg(test)] mod tests { use crate::difference;