From 1d23ac0f2db355914a45affc9491970eeec39248 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 5 Sep 2021 12:54:21 +0900 Subject: [PATCH 1/3] Initial clean up pass on notification logic --- osu.Game/Graphics/UserInterface/HoverSounds.cs | 3 +-- osu.Game/Overlays/NotificationOverlay.cs | 9 +++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/HoverSounds.cs b/osu.Game/Graphics/UserInterface/HoverSounds.cs index c0ef5cb3fc..7db1efc75f 100644 --- a/osu.Game/Graphics/UserInterface/HoverSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverSounds.cs @@ -6,7 +6,6 @@ using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Extensions; using osu.Framework.Graphics; -using osu.Game.Configuration; using osu.Framework.Utils; namespace osu.Game.Graphics.UserInterface @@ -28,7 +27,7 @@ namespace osu.Game.Graphics.UserInterface } [BackgroundDependencyLoader] - private void load(AudioManager audio, SessionStatics statics) + private void load(AudioManager audio) { sampleHover = audio.Samples.Get($@"UI/{SampleSet.GetDescription()}-hover") ?? audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-hover"); diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 2175e17da9..f5b0bf2a7d 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -98,14 +98,16 @@ namespace osu.Game.Overlays private int runningDepth; - private void notificationClosed() => updateCounts(); - private readonly Scheduler postScheduler = new Scheduler(); public override bool IsPresent => base.IsPresent || postScheduler.HasPendingTasks; private bool processingPosts = true; + /// + /// Post a new notification for display. + /// + /// The notification to display. public void Post(Notification notification) => postScheduler.Add(() => { ++runningDepth; @@ -129,6 +131,7 @@ namespace osu.Game.Overlays protected override void Update() { base.Update(); + if (processingPosts) postScheduler.Update(); } @@ -151,6 +154,8 @@ namespace osu.Game.Overlays this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint); } + private void notificationClosed() => updateCounts(); + private void updateCounts() { UnreadCount.Value = sections.Select(c => c.UnreadCount).Sum(); From 473e15e8f3ba1a35419bc0bbb0f72034715a2e80 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 5 Sep 2021 13:22:37 +0900 Subject: [PATCH 2/3] Add debounce to notification sample playback logic --- osu.Game/Overlays/NotificationOverlay.cs | 25 +++++++++++++++- .../Overlays/Notifications/Notification.cs | 29 ++++--------------- .../Notifications/NotificationSection.cs | 7 +---- .../Notifications/ProgressNotification.cs | 4 +-- .../Notifications/SimpleErrorNotification.cs | 2 +- 5 files changed, 34 insertions(+), 33 deletions(-) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index f5b0bf2a7d..fcb8692010 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -9,6 +9,7 @@ using osu.Game.Overlays.Notifications; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Containers; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Localisation; using osu.Framework.Threading; @@ -29,6 +30,9 @@ namespace osu.Game.Overlays private FlowContainer sections; + [Resolved] + private AudioManager audio { get; set; } + [BackgroundDependencyLoader] private void load() { @@ -104,6 +108,8 @@ namespace osu.Game.Overlays private bool processingPosts = true; + private double? lastSamplePlayback; + /// /// Post a new notification for display. /// @@ -126,6 +132,7 @@ namespace osu.Game.Overlays Show(); updateCounts(); + playDebouncedSample(notification.PopInSampleName); }); protected override void Update() @@ -154,7 +161,23 @@ namespace osu.Game.Overlays this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint); } - private void notificationClosed() => updateCounts(); + private void notificationClosed() + { + updateCounts(); + + // this debounce is currently shared between popin/popout sounds, which means one could potentially not play when the user is expecting it. + // popout is constant across all notification types, and should therefore be handled using playback concurrency instead, but seems broken at the moment. + playDebouncedSample("UI/overlay-pop-out"); + } + + private void playDebouncedSample(string sampleName) + { + if (lastSamplePlayback == null || Time.Current - lastSamplePlayback > 50) + { + audio.Samples.Get(sampleName)?.Play(); + lastSamplePlayback = Time.Current; + } + } private void updateCounts() { diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index d1a97c74b2..44203e8ee7 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -3,20 +3,18 @@ using System; using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; -using osu.Game.Graphics; -using osuTK; -using osuTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; +using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Overlays.Notifications { @@ -42,10 +40,7 @@ namespace osu.Game.Overlays.Notifications /// public virtual bool DisplayOnTop => true; - private Sample samplePopIn; - private Sample samplePopOut; - protected virtual string PopInSampleName => "UI/notification-pop-in"; - protected virtual string PopOutSampleName => "UI/overlay-pop-out"; // TODO: replace with a unique sample? + public virtual string PopInSampleName => "UI/notification-pop-in"; protected NotificationLight Light; private readonly CloseButton closeButton; @@ -114,7 +109,7 @@ namespace osu.Game.Overlays.Notifications closeButton = new CloseButton { Alpha = 0, - Action = () => Close(), + Action = Close, Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, Margin = new MarginPadding @@ -127,13 +122,6 @@ namespace osu.Game.Overlays.Notifications }); } - [BackgroundDependencyLoader] - private void load(AudioManager audio) - { - samplePopIn = audio.Samples.Get(PopInSampleName); - samplePopOut = audio.Samples.Get(PopOutSampleName); - } - protected override bool OnHover(HoverEvent e) { closeButton.FadeIn(75); @@ -158,8 +146,6 @@ namespace osu.Game.Overlays.Notifications { base.LoadComplete(); - samplePopIn?.Play(); - this.FadeInFromZero(200); NotificationContent.MoveToX(DrawSize.X); NotificationContent.MoveToX(0, 500, Easing.OutQuint); @@ -167,15 +153,12 @@ namespace osu.Game.Overlays.Notifications public bool WasClosed; - public virtual void Close(bool playSound = true) + public virtual void Close() { if (WasClosed) return; WasClosed = true; - if (playSound) - samplePopOut?.Play(); - Closed?.Invoke(); this.FadeOut(100); Expire(); diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs index 2316199049..a23ff07a64 100644 --- a/osu.Game/Overlays/Notifications/NotificationSection.cs +++ b/osu.Game/Overlays/Notifications/NotificationSection.cs @@ -110,12 +110,7 @@ namespace osu.Game.Overlays.Notifications private void clearAll() { - bool first = true; - notifications.Children.ForEach(c => - { - c.Close(first); - first = false; - }); + notifications.Children.ForEach(c => c.Close()); } protected override void Update() diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 703c14af2b..3105ecd742 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -150,12 +150,12 @@ namespace osu.Game.Overlays.Notifications colourCancelled = colours.Red; } - public override void Close(bool playSound = true) + public override void Close() { switch (State) { case ProgressNotificationState.Cancelled: - base.Close(playSound); + base.Close(); break; case ProgressNotificationState.Active: diff --git a/osu.Game/Overlays/Notifications/SimpleErrorNotification.cs b/osu.Game/Overlays/Notifications/SimpleErrorNotification.cs index 13c9c5a02d..faab4ed472 100644 --- a/osu.Game/Overlays/Notifications/SimpleErrorNotification.cs +++ b/osu.Game/Overlays/Notifications/SimpleErrorNotification.cs @@ -7,7 +7,7 @@ namespace osu.Game.Overlays.Notifications { public class SimpleErrorNotification : SimpleNotification { - protected override string PopInSampleName => "UI/error-notification-pop-in"; + public override string PopInSampleName => "UI/error-notification-pop-in"; public SimpleErrorNotification() { From ab1c64591f2a9b224cec05919606836edccd5c21 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 5 Sep 2021 13:25:10 +0900 Subject: [PATCH 3/3] Move sample playback debounce time to central `const` --- .../Graphics/UserInterface/HoverSampleDebounceComponent.cs | 7 +------ osu.Game/OsuGameBase.cs | 5 +++++ osu.Game/Overlays/NotificationOverlay.cs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs b/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs index 55f43cfe46..1fd03a34e7 100644 --- a/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs +++ b/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs @@ -15,11 +15,6 @@ namespace osu.Game.Graphics.UserInterface /// public abstract class HoverSampleDebounceComponent : CompositeDrawable { - /// - /// Length of debounce for hover sound playback, in milliseconds. - /// - public double HoverDebounceTime { get; } = 20; - private Bindable lastPlaybackTime; [BackgroundDependencyLoader] @@ -34,7 +29,7 @@ namespace osu.Game.Graphics.UserInterface if (e.HasAnyButtonPressed) return false; - bool enoughTimePassedSinceLastPlayback = !lastPlaybackTime.Value.HasValue || Time.Current - lastPlaybackTime.Value >= HoverDebounceTime; + bool enoughTimePassedSinceLastPlayback = !lastPlaybackTime.Value.HasValue || Time.Current - lastPlaybackTime.Value >= OsuGameBase.SAMPLE_DEBOUNCE_TIME; if (enoughTimePassedSinceLastPlayback) { diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 69f6bc1b7b..762216e93c 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -56,6 +56,11 @@ namespace osu.Game public const int SAMPLE_CONCURRENCY = 6; + /// + /// Length of debounce (in milliseconds) for commonly occuring sample playbacks that could stack. + /// + public const int SAMPLE_DEBOUNCE_TIME = 20; + /// /// The maximum volume at which audio tracks should playback. This can be set lower than 1 to create some head-room for sound effects. /// diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index fcb8692010..8809dec642 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -172,7 +172,7 @@ namespace osu.Game.Overlays private void playDebouncedSample(string sampleName) { - if (lastSamplePlayback == null || Time.Current - lastSamplePlayback > 50) + if (lastSamplePlayback == null || Time.Current - lastSamplePlayback > OsuGameBase.SAMPLE_DEBOUNCE_TIME) { audio.Samples.Get(sampleName)?.Play(); lastSamplePlayback = Time.Current;