From 68c5e6a4311080716624c1114e1b63a90c2dd74f Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 1 Jul 2021 20:41:30 +0900 Subject: [PATCH 1/9] Add audio feedback to changing volume --- osu.Game/Overlays/Volume/VolumeMeter.cs | 35 ++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index a15076581e..2251be03c6 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -4,6 +4,8 @@ using System; using System.Globalization; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -36,6 +38,10 @@ namespace osu.Game.Overlays.Volume private OsuSpriteText text; private BufferedContainer maxGlow; + private bool firstUpdate = true; + private Sample sample; + private double sampleLastPlaybackTime; + public VolumeMeter(string name, float circleSize, Color4 meterColour) { this.circleSize = circleSize; @@ -46,8 +52,11 @@ namespace osu.Game.Overlays.Volume } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, AudioManager audio) { + sample = audio.Samples.Get(@"UI/notch-tick"); + sampleLastPlaybackTime = Time.Current; + Color4 backgroundColour = colours.Gray1; CircularProgress bgProgress; @@ -202,6 +211,7 @@ namespace osu.Game.Overlays.Volume get => displayVolume; set { + bool displayVolumeChanged = Math.Round(displayVolume * 100) != Math.Round(value * 100); displayVolume = value; if (displayVolume >= 0.995f) @@ -217,6 +227,29 @@ namespace osu.Game.Overlays.Volume volumeCircle.Current.Value = displayVolume * 0.75f; volumeCircleGlow.Current.Value = displayVolume * 0.75f; + + Schedule(() => + { + const int sfx_debounce_time = 30; + + if (firstUpdate || + !displayVolumeChanged || + Time.Current - sampleLastPlaybackTime <= sfx_debounce_time) + { + firstUpdate = false; + return; + } + + var channel = sample.Play(); + + channel.Frequency.Value = 1 + displayVolume * 0.1f + RNG.NextDouble(0.02f); + if (displayVolume < 0.005f) + channel.Frequency.Value -= 0.5f; + else if (displayVolume > 0.995f) + channel.Frequency.Value -= 0.5f; + + sampleLastPlaybackTime = Time.Current; + }); } } From dad28b28265ddec8f6c478041b8aee4317f43c22 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 1 Jul 2021 20:45:29 +0900 Subject: [PATCH 2/9] Update OsuSliderBar to use new notch-tick sample and tweak pitch ramping --- osu.Game/Graphics/UserInterface/OsuSliderBar.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index ae16169123..1433f0c38b 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -15,6 +15,7 @@ using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Framework.Localisation; +using osu.Framework.Utils; namespace osu.Game.Graphics.UserInterface { @@ -99,7 +100,7 @@ namespace osu.Game.Graphics.UserInterface [BackgroundDependencyLoader] private void load(AudioManager audio, OsuColour colours) { - sample = audio.Samples.Get(@"UI/sliderbar-notch"); + sample = audio.Samples.Get(@"UI/notch-tick"); AccentColour = colours.Pink; } @@ -149,7 +150,7 @@ namespace osu.Game.Graphics.UserInterface private void playSample(T value) { - if (Clock == null || Clock.CurrentTime - lastSampleTime <= 50) + if (Clock == null || Clock.CurrentTime - lastSampleTime <= 30) return; if (value.Equals(lastSampleValue)) @@ -160,11 +161,11 @@ namespace osu.Game.Graphics.UserInterface var channel = sample.Play(); - channel.Frequency.Value = 1 + NormalizedValue * 0.2f; + channel.Frequency.Value = 1 + NormalizedValue * 0.2f + RNG.NextDouble(0.02f); if (NormalizedValue == 0) - channel.Frequency.Value -= 0.4f; + channel.Frequency.Value -= 0.5f; else if (NormalizedValue == 1) - channel.Frequency.Value += 0.4f; + channel.Frequency.Value -= 0.5f; } private void updateTooltipText(T value) From f1c11243e92be087d5977bbd5e8a10d2a19a42b6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Jul 2021 22:06:59 +0900 Subject: [PATCH 3/9] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 481ddc118f..b2b48f5de8 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 589afb86be..42eb2ad1d8 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index a8bf0e4ab2..67993049f2 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -71,7 +71,7 @@ - + From 69b13477304ce77d9003cbceac394cf3f571dd88 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Jul 2021 15:29:51 +0900 Subject: [PATCH 4/9] Tidy up weird bind logic --- osu.Game/Overlays/Volume/VolumeMeter.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index 2251be03c6..6a26de204c 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -187,13 +187,7 @@ namespace osu.Game.Overlays.Volume } }; - Bindable.ValueChanged += volume => - { - this.TransformTo("DisplayVolume", - volume.NewValue, - 400, - Easing.OutQuint); - }; + Bindable.ValueChanged += volume => { this.TransformTo(nameof(DisplayVolume), volume.NewValue, 400, Easing.OutQuint); }; bgProgress.Current.Value = 0.75f; } From 13254d51fc93a33dbe67921d4a62b112bd4ae2ae Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Jul 2021 15:44:35 +0900 Subject: [PATCH 5/9] Remove usage of `bool` for initial playback Also refactors the whole method to generally clean things up. One more important fix is setting the frequency on the channel before starting playback, so avoid the frequency potentially being adjusted after the playback is already started. --- osu.Game/Overlays/Volume/VolumeMeter.cs | 63 +++++++++++++------------ 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index 6a26de204c..3321dcf329 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -38,7 +38,6 @@ namespace osu.Game.Overlays.Volume private OsuSpriteText text; private BufferedContainer maxGlow; - private bool firstUpdate = true; private Sample sample; private double sampleLastPlaybackTime; @@ -187,16 +186,12 @@ namespace osu.Game.Overlays.Volume } }; - Bindable.ValueChanged += volume => { this.TransformTo(nameof(DisplayVolume), volume.NewValue, 400, Easing.OutQuint); }; + Bindable.BindValueChanged(volume => { this.TransformTo(nameof(DisplayVolume), volume.NewValue, 400, Easing.OutQuint); }, true); bgProgress.Current.Value = 0.75f; } - protected override void LoadComplete() - { - base.LoadComplete(); - Bindable.TriggerChange(); - } + private int displayVolumeInt; private double displayVolume; @@ -205,9 +200,16 @@ namespace osu.Game.Overlays.Volume get => displayVolume; set { - bool displayVolumeChanged = Math.Round(displayVolume * 100) != Math.Round(value * 100); + if (value == displayVolume) + return; + displayVolume = value; + int intValue = (int)Math.Round(displayVolume * 100); + bool intVolumeChanged = intValue != displayVolumeInt; + + displayVolumeInt = intValue; + if (displayVolume >= 0.995f) { text.Text = "MAX"; @@ -216,37 +218,36 @@ namespace osu.Game.Overlays.Volume else { maxGlow.EffectColour = Color4.Transparent; - text.Text = Math.Round(displayVolume * 100).ToString(CultureInfo.CurrentCulture); + text.Text = displayVolumeInt.ToString(CultureInfo.CurrentCulture); } volumeCircle.Current.Value = displayVolume * 0.75f; volumeCircleGlow.Current.Value = displayVolume * 0.75f; - Schedule(() => - { - const int sfx_debounce_time = 30; - - if (firstUpdate || - !displayVolumeChanged || - Time.Current - sampleLastPlaybackTime <= sfx_debounce_time) - { - firstUpdate = false; - return; - } - - var channel = sample.Play(); - - channel.Frequency.Value = 1 + displayVolume * 0.1f + RNG.NextDouble(0.02f); - if (displayVolume < 0.005f) - channel.Frequency.Value -= 0.5f; - else if (displayVolume > 0.995f) - channel.Frequency.Value -= 0.5f; - - sampleLastPlaybackTime = Time.Current; - }); + if (intVolumeChanged && IsLoaded) + Scheduler.AddOnce(playTickSound); } } + private void playTickSound() + { + const int tick_debounce_time = 30; + + if (Time.Current - sampleLastPlaybackTime <= tick_debounce_time) + return; + + var channel = sample.GetChannel(); + + channel.Frequency.Value = 1 + displayVolume * 0.1f + RNG.NextDouble(0.02f); + + if (displayVolumeInt == 0) + channel.Frequency.Value -= 0.5f; + else if (displayVolumeInt == 100) channel.Frequency.Value -= 0.5f; + + channel.Play(); + sampleLastPlaybackTime = Time.Current; + } + public double Volume { get => Bindable.Value; From bd6664d5414532a384563128581f81a46663d64d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Jul 2021 15:45:50 +0900 Subject: [PATCH 6/9] Add note about intentional downward pitch, against expectations --- osu.Game/Overlays/Volume/VolumeMeter.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index 3321dcf329..7428c6a7f6 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -242,7 +242,9 @@ namespace osu.Game.Overlays.Volume if (displayVolumeInt == 0) channel.Frequency.Value -= 0.5f; - else if (displayVolumeInt == 100) channel.Frequency.Value -= 0.5f; + else if (displayVolumeInt == 100) + // intentionally pitched down, even when hitting max. + channel.Frequency.Value -= 0.5f; channel.Play(); sampleLastPlaybackTime = Time.Current; From 910fe3e9f8bde8135cb7f8caabad32b0511bca48 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 2 Jul 2021 15:39:43 +0900 Subject: [PATCH 7/9] Center pitch randomisation around base pitch --- osu.Game/Graphics/UserInterface/OsuSliderBar.cs | 7 +++---- osu.Game/Overlays/Volume/VolumeMeter.cs | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index 1433f0c38b..386e081e6f 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -161,10 +161,9 @@ namespace osu.Game.Graphics.UserInterface var channel = sample.Play(); - channel.Frequency.Value = 1 + NormalizedValue * 0.2f + RNG.NextDouble(0.02f); - if (NormalizedValue == 0) - channel.Frequency.Value -= 0.5f; - else if (NormalizedValue == 1) + channel.Frequency.Value = 0.99f + RNG.NextDouble(0.02f) + NormalizedValue * 0.2f; + + if (NormalizedValue == 0 || NormalizedValue == 1) channel.Frequency.Value -= 0.5f; } diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index 7428c6a7f6..3300d8ee17 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -238,7 +238,7 @@ namespace osu.Game.Overlays.Volume var channel = sample.GetChannel(); - channel.Frequency.Value = 1 + displayVolume * 0.1f + RNG.NextDouble(0.02f); + channel.Frequency.Value = 0.99f + RNG.NextDouble(0.02f) + displayVolume * 0.1f; if (displayVolumeInt == 0) channel.Frequency.Value -= 0.5f; From 63d2ac66d2e3a20863a2d60761d49f357b257f54 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Jul 2021 15:52:20 +0900 Subject: [PATCH 8/9] Fix one more instance of incorrect playback/frequency set order --- osu.Game/Graphics/UserInterface/OsuSliderBar.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index 386e081e6f..0ae77071fb 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -159,12 +159,14 @@ namespace osu.Game.Graphics.UserInterface lastSampleValue = value; lastSampleTime = Clock.CurrentTime; - var channel = sample.Play(); + var channel = sample.GetChannel(); channel.Frequency.Value = 0.99f + RNG.NextDouble(0.02f) + NormalizedValue * 0.2f; if (NormalizedValue == 0 || NormalizedValue == 1) channel.Frequency.Value -= 0.5f; + + channel.Play(); } private void updateTooltipText(T value) From 35f79669223a8f6564589fa1069b3ee4a5b9ca29 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Jul 2021 15:55:20 +0900 Subject: [PATCH 9/9] Merge conditionals in line with other case of same logic --- osu.Game/Graphics/UserInterface/OsuSliderBar.cs | 1 + osu.Game/Overlays/Volume/VolumeMeter.cs | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index 0ae77071fb..f85f9327fa 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -163,6 +163,7 @@ namespace osu.Game.Graphics.UserInterface channel.Frequency.Value = 0.99f + RNG.NextDouble(0.02f) + NormalizedValue * 0.2f; + // intentionally pitched down, even when hitting max. if (NormalizedValue == 0 || NormalizedValue == 1) channel.Frequency.Value -= 0.5f; diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index 3300d8ee17..532b0f4a81 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -240,10 +240,8 @@ namespace osu.Game.Overlays.Volume channel.Frequency.Value = 0.99f + RNG.NextDouble(0.02f) + displayVolume * 0.1f; - if (displayVolumeInt == 0) - channel.Frequency.Value -= 0.5f; - else if (displayVolumeInt == 100) - // intentionally pitched down, even when hitting max. + // intentionally pitched down, even when hitting max. + if (displayVolumeInt == 0 || displayVolumeInt == 100) channel.Frequency.Value -= 0.5f; channel.Play();