From d6a06f2af6f5278fca49f35f5f166ac975f3d733 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Mar 2025 13:15:57 +0900 Subject: [PATCH 1/2] Fade out pause loop sound when the game window is inactive Closes https://github.com/ppy/osu/issues/32432. --- osu.Game/Screens/Play/PauseOverlay.cs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/PauseOverlay.cs b/osu.Game/Screens/Play/PauseOverlay.cs index 3a471acba4..11f62939fb 100644 --- a/osu.Game/Screens/Play/PauseOverlay.cs +++ b/osu.Game/Screens/Play/PauseOverlay.cs @@ -5,9 +5,12 @@ using System; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Audio; +using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Framework.Localisation; +using osu.Framework.Platform; using osu.Game.Audio; using osu.Game.Input.Bindings; using osu.Game.Localisation; @@ -31,14 +34,24 @@ namespace osu.Game.Screens.Play OnResume?.Invoke(); }; + private IBindable? windowActive; + + private float targetVolume => windowActive?.Value != false && State.Value == Visibility.Visible ? 1.0f : 0; + [BackgroundDependencyLoader] - private void load() + private void load(GameHost? host) { AddInternal(pauseLoop = new SkinnableSound(new SampleInfo("Gameplay/pause-loop")) { Looping = true, Volume = { Value = 0 } }); + + if (host != null) + { + windowActive = host.IsActive.GetBoundCopy(); + windowActive.BindValueChanged(_ => Schedule(() => pauseLoop.VolumeTo(targetVolume, 1000, Easing.Out))); + } } public void StopAllSamples() @@ -53,7 +66,7 @@ namespace osu.Game.Screens.Play { base.PopIn(); - pauseLoop.VolumeTo(1.0f, TRANSITION_DURATION, Easing.InQuint); + pauseLoop.VolumeTo(targetVolume, TRANSITION_DURATION, Easing.InQuint); pauseLoop.Play(); } @@ -61,7 +74,7 @@ namespace osu.Game.Screens.Play { base.PopOut(); - pauseLoop.VolumeTo(0, TRANSITION_DURATION, Easing.OutQuad).Finally(_ => pauseLoop.Stop()); + pauseLoop.VolumeTo(targetVolume, TRANSITION_DURATION, Easing.OutQuad).Finally(_ => pauseLoop.Stop()); } public override bool OnPressed(KeyBindingPressEvent e) From c1604a797f71c5d8520f40bfbf1e3ea22bc0babc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Mar 2025 19:56:27 +0900 Subject: [PATCH 2/2] Ensure `BindValueChanged` is run after `LoadComplete` --- osu.Game/Screens/Play/PauseOverlay.cs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/PauseOverlay.cs b/osu.Game/Screens/Play/PauseOverlay.cs index 11f62939fb..18d17c1317 100644 --- a/osu.Game/Screens/Play/PauseOverlay.cs +++ b/osu.Game/Screens/Play/PauseOverlay.cs @@ -34,9 +34,9 @@ namespace osu.Game.Screens.Play OnResume?.Invoke(); }; - private IBindable? windowActive; + private readonly IBindable windowActive = new Bindable(true); - private float targetVolume => windowActive?.Value != false && State.Value == Visibility.Visible ? 1.0f : 0; + private float targetVolume => windowActive.Value && State.Value == Visibility.Visible ? 1.0f : 0; [BackgroundDependencyLoader] private void load(GameHost? host) @@ -48,10 +48,15 @@ namespace osu.Game.Screens.Play }); if (host != null) - { - windowActive = host.IsActive.GetBoundCopy(); - windowActive.BindValueChanged(_ => Schedule(() => pauseLoop.VolumeTo(targetVolume, 1000, Easing.Out))); - } + windowActive.BindTo(host.IsActive); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + // Schedule required because host.IsActive doesn't seem to always run on the update thread. + windowActive.BindValueChanged(_ => Schedule(() => pauseLoop.VolumeTo(targetVolume, 1000, Easing.Out))); } public void StopAllSamples()