From 0c0c36ef6cf3010cb96b5020c012d95b5fc19b13 Mon Sep 17 00:00:00 2001 From: Liam Gallagher Date: Thu, 16 Feb 2023 20:25:19 +1300 Subject: [PATCH 01/16] Global Volume --- crates/bevy_audio/src/audio.rs | 30 +++++++++++++++++++++++++++ crates/bevy_audio/src/audio_output.rs | 8 ++++--- crates/bevy_audio/src/lib.rs | 3 ++- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/crates/bevy_audio/src/audio.rs b/crates/bevy_audio/src/audio.rs index d7ac8d615795b..88d62869b7ab1 100644 --- a/crates/bevy_audio/src/audio.rs +++ b/crates/bevy_audio/src/audio.rs @@ -128,6 +128,8 @@ pub struct PlaybackSettings { pub repeat: bool, /// Volume to play at. pub volume: f32, + /// Ignore global volume + pub absolue_volume: bool, /// Speed to play at. pub speed: f32, } @@ -143,6 +145,7 @@ impl PlaybackSettings { pub const ONCE: PlaybackSettings = PlaybackSettings { repeat: false, volume: 1.0, + absolue_volume: false, speed: 1.0, }; @@ -150,6 +153,7 @@ impl PlaybackSettings { pub const LOOP: PlaybackSettings = PlaybackSettings { repeat: true, volume: 1.0, + absolue_volume: false, speed: 1.0, }; @@ -164,6 +168,12 @@ impl PlaybackSettings { self.speed = speed; self } + + /// Helper to set if the volume sould ignore the global volume. + pub const fn with_absolute_volume(mut self, absolue_volume: bool) -> Self { + self.absolue_volume = absolue_volume; + self + } } #[derive(Clone)] @@ -188,3 +198,23 @@ where .finish() } } + +/// Use this [`Resource`] to control the global volume of all non-absolute audio. +#[derive(Resource)] +pub struct GlobalVolume { + /// The global volume of all audio. + pub volume: f32, +} + +impl Default for GlobalVolume { + fn default() -> Self { + Self { volume: 1.0 } + } +} + +impl GlobalVolume { + /// Create a new [`GlobalVolume`] with the given volume. + pub const fn new(volume: f32) -> Self { + Self { volume } + } +} diff --git a/crates/bevy_audio/src/audio_output.rs b/crates/bevy_audio/src/audio_output.rs index 31ee5f503adc3..93f11707de309 100644 --- a/crates/bevy_audio/src/audio_output.rs +++ b/crates/bevy_audio/src/audio_output.rs @@ -1,4 +1,4 @@ -use crate::{Audio, AudioSource, Decodable}; +use crate::{Audio, AudioSource, Decodable, GlobalVolume}; use bevy_asset::{Asset, Assets}; use bevy_ecs::system::{Res, ResMut, Resource}; use bevy_reflect::TypeUuid; @@ -70,6 +70,7 @@ where audio_sources: &Assets, audio: &mut Audio, sinks: &mut Assets, + global_volume: &GlobalVolume, ) { let mut queue = audio.queue.write(); let len = queue.len(); @@ -79,7 +80,7 @@ where if let Some(audio_source) = audio_sources.get(&config.source_handle) { if let Some(sink) = self.play_source(audio_source, config.settings.repeat) { sink.set_speed(config.settings.speed); - sink.set_volume(config.settings.volume); + sink.set_volume(config.settings.volume * global_volume.volume); // don't keep the strong handle. there is no way to return it to the user here as it is async let _ = sinks.set(config.sink_handle, AudioSink { sink: Some(sink) }); @@ -97,11 +98,12 @@ where pub fn play_queued_audio_system( audio_output: Res>, audio_sources: Option>>, + global_volume: Res, mut audio: ResMut>, mut sinks: ResMut>, ) { if let Some(audio_sources) = audio_sources { - audio_output.try_play_queued(&*audio_sources, &mut *audio, &mut sinks); + audio_output.try_play_queued(&*audio_sources, &mut *audio, &mut sinks, &*global_volume); }; } diff --git a/crates/bevy_audio/src/lib.rs b/crates/bevy_audio/src/lib.rs index 14b410135df52..d0111d1dba996 100644 --- a/crates/bevy_audio/src/lib.rs +++ b/crates/bevy_audio/src/lib.rs @@ -29,7 +29,7 @@ mod audio_source; #[allow(missing_docs)] pub mod prelude { #[doc(hidden)] - pub use crate::{Audio, AudioOutput, AudioSource, Decodable, PlaybackSettings}; + pub use crate::{Audio, AudioOutput, AudioSource, Decodable, GlobalVolume, PlaybackSettings}; } pub use audio::*; @@ -56,6 +56,7 @@ impl Plugin for AudioPlugin { .add_asset::() .add_asset::() .init_resource::>() + .init_resource::() .add_system(play_queued_audio_system::.in_base_set(CoreSet::PostUpdate)); #[cfg(any(feature = "mp3", feature = "flac", feature = "wav", feature = "vorbis"))] From ffd02ea30061dac6b45bd124be959214d3a37ab3 Mon Sep 17 00:00:00 2001 From: Liam Gallagher Date: Thu, 16 Feb 2023 20:43:39 +1300 Subject: [PATCH 02/16] Fix failing CI --- crates/bevy_audio/src/audio_output.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_audio/src/audio_output.rs b/crates/bevy_audio/src/audio_output.rs index 93f11707de309..4233a0a571192 100644 --- a/crates/bevy_audio/src/audio_output.rs +++ b/crates/bevy_audio/src/audio_output.rs @@ -103,7 +103,7 @@ pub fn play_queued_audio_system( mut sinks: ResMut>, ) { if let Some(audio_sources) = audio_sources { - audio_output.try_play_queued(&*audio_sources, &mut *audio, &mut sinks, &*global_volume); + audio_output.try_play_queued(&*audio_sources, &mut *audio, &mut sinks, &global_volume); }; } From f373a51ed9017dae809145bc275b40f469ba8637 Mon Sep 17 00:00:00 2001 From: Liam Gallagher Date: Fri, 17 Feb 2023 07:59:02 +1300 Subject: [PATCH 03/16] Using absolute flag, typo fixes --- crates/bevy_audio/src/audio.rs | 13 +++++++------ crates/bevy_audio/src/audio_output.rs | 6 +++++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/crates/bevy_audio/src/audio.rs b/crates/bevy_audio/src/audio.rs index 88d62869b7ab1..81c74463825c5 100644 --- a/crates/bevy_audio/src/audio.rs +++ b/crates/bevy_audio/src/audio.rs @@ -129,7 +129,7 @@ pub struct PlaybackSettings { /// Volume to play at. pub volume: f32, /// Ignore global volume - pub absolue_volume: bool, + pub absolute_volume: bool, /// Speed to play at. pub speed: f32, } @@ -145,7 +145,7 @@ impl PlaybackSettings { pub const ONCE: PlaybackSettings = PlaybackSettings { repeat: false, volume: 1.0, - absolue_volume: false, + absolute_volume: false, speed: 1.0, }; @@ -153,7 +153,7 @@ impl PlaybackSettings { pub const LOOP: PlaybackSettings = PlaybackSettings { repeat: true, volume: 1.0, - absolue_volume: false, + absolute_volume: false, speed: 1.0, }; @@ -169,9 +169,9 @@ impl PlaybackSettings { self } - /// Helper to set if the volume sould ignore the global volume. - pub const fn with_absolute_volume(mut self, absolue_volume: bool) -> Self { - self.absolue_volume = absolue_volume; + /// Helper to set if the volume should ignore the global volume. + pub const fn with_absolute_volume(mut self, absolute_volume: bool) -> Self { + self.absolute_volume = absolute_volume; self } } @@ -200,6 +200,7 @@ where } /// Use this [`Resource`] to control the global volume of all non-absolute audio. +/// Non-abosolute being any audio source that doesn't have [`absolute_volume`](PlaybackSettings::absolute_volume) set to `true`. #[derive(Resource)] pub struct GlobalVolume { /// The global volume of all audio. diff --git a/crates/bevy_audio/src/audio_output.rs b/crates/bevy_audio/src/audio_output.rs index 4233a0a571192..caf6bd4c017e6 100644 --- a/crates/bevy_audio/src/audio_output.rs +++ b/crates/bevy_audio/src/audio_output.rs @@ -80,7 +80,11 @@ where if let Some(audio_source) = audio_sources.get(&config.source_handle) { if let Some(sink) = self.play_source(audio_source, config.settings.repeat) { sink.set_speed(config.settings.speed); - sink.set_volume(config.settings.volume * global_volume.volume); + if config.settings.absolute_volume { + sink.set_volume(config.settings.volume); + } else { + sink.set_volume(config.settings.volume * global_volume.volume); + } // don't keep the strong handle. there is no way to return it to the user here as it is async let _ = sinks.set(config.sink_handle, AudioSink { sink: Some(sink) }); From f9bf48ca9767948de03da39ab42a0c2e7e66b9cd Mon Sep 17 00:00:00 2001 From: Liam Gallagher Date: Thu, 16 Feb 2023 11:50:01 -0800 Subject: [PATCH 04/16] Update crates/bevy_audio/src/audio.rs Co-authored-by: Alice Cecile --- crates/bevy_audio/src/audio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_audio/src/audio.rs b/crates/bevy_audio/src/audio.rs index 81c74463825c5..902dce1d46eaa 100644 --- a/crates/bevy_audio/src/audio.rs +++ b/crates/bevy_audio/src/audio.rs @@ -200,7 +200,7 @@ where } /// Use this [`Resource`] to control the global volume of all non-absolute audio. -/// Non-abosolute being any audio source that doesn't have [`absolute_volume`](PlaybackSettings::absolute_volume) set to `true`. +/// Sources can be set to ignore this setting by setting the `absolute_volume` field on [`PlaybackSettings`] to `true`. #[derive(Resource)] pub struct GlobalVolume { /// The global volume of all audio. From 306b8a063c13710d318367e8fb52241bbc5cb3db Mon Sep 17 00:00:00 2001 From: Liam Gallagher Date: Fri, 17 Feb 2023 16:15:12 +1300 Subject: [PATCH 05/16] Volume enum, global volume as plugin field --- crates/bevy_audio/src/audio.rs | 53 +++++++++++++++++++-------- crates/bevy_audio/src/audio_output.rs | 10 ++--- crates/bevy_audio/src/lib.rs | 7 +++- 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/crates/bevy_audio/src/audio.rs b/crates/bevy_audio/src/audio.rs index 902dce1d46eaa..668d4759886b0 100644 --- a/crates/bevy_audio/src/audio.rs +++ b/crates/bevy_audio/src/audio.rs @@ -121,15 +121,46 @@ where } } +/// Defines the volume to play an audio source at. +#[derive(Clone, Debug)] +pub enum Volume { + /// A volume level relative to the global volume. + Relative(VolumeLevel), + /// A volume level that ignores the global volume. + Absolute(VolumeLevel), +} + +impl Default for Volume { + fn default() -> Self { + Self::Relative(VolumeLevel::default()) + } +} + +/// A volume level equivalent to a positive only float. +#[derive(Clone, Debug)] +pub struct VolumeLevel(pub(crate) f32); + +impl Default for VolumeLevel { + fn default() -> Self { + Self(1.0) + } +} + +impl VolumeLevel { + /// Create a new volume level. + pub fn new(volume: f32) -> Self { + debug_assert!(volume >= 0.0); + Self(volume) + } +} + /// Settings to control playback from the start. #[derive(Clone, Debug)] pub struct PlaybackSettings { /// Play in repeat pub repeat: bool, /// Volume to play at. - pub volume: f32, - /// Ignore global volume - pub absolute_volume: bool, + pub volume: Volume, /// Speed to play at. pub speed: f32, } @@ -144,21 +175,19 @@ impl PlaybackSettings { /// Will play the associate audio source once. pub const ONCE: PlaybackSettings = PlaybackSettings { repeat: false, - volume: 1.0, - absolute_volume: false, + volume: Volume::Relative(VolumeLevel(1.0)), speed: 1.0, }; /// Will play the associate audio source in a loop. pub const LOOP: PlaybackSettings = PlaybackSettings { repeat: true, - volume: 1.0, - absolute_volume: false, + volume: Volume::Relative(VolumeLevel(1.0)), speed: 1.0, }; /// Helper to set the volume from start of playback. - pub const fn with_volume(mut self, volume: f32) -> Self { + pub const fn with_volume(mut self, volume: Volume) -> Self { self.volume = volume; self } @@ -168,12 +197,6 @@ impl PlaybackSettings { self.speed = speed; self } - - /// Helper to set if the volume should ignore the global volume. - pub const fn with_absolute_volume(mut self, absolute_volume: bool) -> Self { - self.absolute_volume = absolute_volume; - self - } } #[derive(Clone)] @@ -201,7 +224,7 @@ where /// Use this [`Resource`] to control the global volume of all non-absolute audio. /// Sources can be set to ignore this setting by setting the `absolute_volume` field on [`PlaybackSettings`] to `true`. -#[derive(Resource)] +#[derive(Resource, Clone, Copy)] pub struct GlobalVolume { /// The global volume of all audio. pub volume: f32, diff --git a/crates/bevy_audio/src/audio_output.rs b/crates/bevy_audio/src/audio_output.rs index caf6bd4c017e6..d81a3fba9b870 100644 --- a/crates/bevy_audio/src/audio_output.rs +++ b/crates/bevy_audio/src/audio_output.rs @@ -1,4 +1,4 @@ -use crate::{Audio, AudioSource, Decodable, GlobalVolume}; +use crate::{Audio, AudioSource, Decodable, GlobalVolume, Volume}; use bevy_asset::{Asset, Assets}; use bevy_ecs::system::{Res, ResMut, Resource}; use bevy_reflect::TypeUuid; @@ -80,10 +80,10 @@ where if let Some(audio_source) = audio_sources.get(&config.source_handle) { if let Some(sink) = self.play_source(audio_source, config.settings.repeat) { sink.set_speed(config.settings.speed); - if config.settings.absolute_volume { - sink.set_volume(config.settings.volume); - } else { - sink.set_volume(config.settings.volume * global_volume.volume); + + match config.settings.volume { + Volume::Relative(vol) => sink.set_volume(vol.0 * global_volume.volume), + Volume::Absolute(vol) => sink.set_volume(vol.0), } // don't keep the strong handle. there is no way to return it to the user here as it is async diff --git a/crates/bevy_audio/src/lib.rs b/crates/bevy_audio/src/lib.rs index d0111d1dba996..98aec5f82cf58 100644 --- a/crates/bevy_audio/src/lib.rs +++ b/crates/bevy_audio/src/lib.rs @@ -48,7 +48,10 @@ use bevy_ecs::prelude::*; /// /// Use the [`Audio`] resource to play audio. #[derive(Default)] -pub struct AudioPlugin; +pub struct AudioPlugin { + /// The global volume for all audio sources with a [`Volume::Relative] volume. + global_volume: GlobalVolume, +} impl Plugin for AudioPlugin { fn build(&self, app: &mut App) { @@ -56,7 +59,7 @@ impl Plugin for AudioPlugin { .add_asset::() .add_asset::() .init_resource::>() - .init_resource::() + .insert_resource(self.global_volume) .add_system(play_queued_audio_system::.in_base_set(CoreSet::PostUpdate)); #[cfg(any(feature = "mp3", feature = "flac", feature = "wav", feature = "vorbis"))] From bf56b30eb1bd310c3f846c59a2a698af91f966bf Mon Sep 17 00:00:00 2001 From: Liam Gallagher Date: Fri, 17 Feb 2023 16:31:48 +1300 Subject: [PATCH 06/16] Volume constructor methods + fix doc tests --- crates/bevy_audio/src/audio.rs | 15 +++++++++++++-- crates/bevy_audio/src/lib.rs | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/crates/bevy_audio/src/audio.rs b/crates/bevy_audio/src/audio.rs index 668d4759886b0..c1070d6b0a722 100644 --- a/crates/bevy_audio/src/audio.rs +++ b/crates/bevy_audio/src/audio.rs @@ -94,12 +94,12 @@ where /// ``` /// # use bevy_ecs::system::Res; /// # use bevy_asset::AssetServer; - /// # use bevy_audio::Audio; + /// # use bevy_audio::{Audio, Volume}; /// # use bevy_audio::PlaybackSettings; /// fn play_audio_system(asset_server: Res, audio: Res