From f0a489fb82c81895a1ab85bfa7eebf8567b8d636 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Mon, 29 Jan 2024 16:49:01 -0500 Subject: [PATCH 01/10] Use volume scaling --- osu.Framework/Audio/AudioManager.cs | 23 +++++----- osu.Framework/Audio/VolumeScaler.cs | 46 +++++++++++++++++++ .../Configuration/FrameworkConfigManager.cs | 6 +-- osu.Framework/Game.cs | 10 ++-- 4 files changed, 67 insertions(+), 18 deletions(-) create mode 100644 osu.Framework/Audio/VolumeScaler.cs diff --git a/osu.Framework/Audio/AudioManager.cs b/osu.Framework/Audio/AudioManager.cs index 91a4e37d7a..3b03e0ab3d 100644 --- a/osu.Framework/Audio/AudioManager.cs +++ b/osu.Framework/Audio/AudioManager.cs @@ -90,23 +90,20 @@ public class AudioManager : AudioCollectionManager /// public readonly Bindable AudioDevice = new Bindable(); + /// + /// Volume of all audio game-wide. + /// + public new readonly VolumeScaler Volume; + /// /// Volume of all samples played game-wide. /// - public readonly BindableDouble VolumeSample = new BindableDouble(1) - { - MinValue = 0, - MaxValue = 1 - }; + public readonly VolumeScaler VolumeSample = new VolumeScaler(); /// /// Volume of all tracks played game-wide. /// - public readonly BindableDouble VolumeTrack = new BindableDouble(1) - { - MinValue = 0, - MaxValue = 1 - }; + public readonly VolumeScaler VolumeTrack = new VolumeScaler(); /// /// Whether a global mixer is being used for audio routing. @@ -179,11 +176,13 @@ public AudioManager(AudioThread audioThread, ResourceStore trackStore, R AddItem(TrackMixer = createAudioMixer(null, nameof(TrackMixer))); AddItem(SampleMixer = createAudioMixer(null, nameof(SampleMixer))); + Volume = new VolumeScaler(base.Volume); + globalTrackStore = new Lazy(() => { var store = new TrackStore(trackStore, TrackMixer); AddItem(store); - store.AddAdjustment(AdjustableProperty.Volume, VolumeTrack); + store.AddAdjustment(AdjustableProperty.Volume, VolumeTrack.Real); return store; }); @@ -191,7 +190,7 @@ public AudioManager(AudioThread audioThread, ResourceStore trackStore, R { var store = new SampleStore(sampleStore, SampleMixer); AddItem(store); - store.AddAdjustment(AdjustableProperty.Volume, VolumeSample); + store.AddAdjustment(AdjustableProperty.Volume, VolumeSample.Real); return store; }); diff --git a/osu.Framework/Audio/VolumeScaler.cs b/osu.Framework/Audio/VolumeScaler.cs new file mode 100644 index 0000000000..e128bd917b --- /dev/null +++ b/osu.Framework/Audio/VolumeScaler.cs @@ -0,0 +1,46 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Bindables; + +namespace osu.Framework.Audio +{ + public class VolumeScaler + { + public const double MIN = -60; + + private const double ln_ten = 2.302585092994045684017991454684364208; + private const double k = ln_ten * MIN / 20; + + public readonly BindableNumber Real; + public readonly BindableNumber Scaled = new BindableNumber(1) + { + MinValue = 0, + MaxValue = 1, + Precision = 0.01, + }; + + private double scaledToReal(double x) => x <= 0 ? 0 : Math.Exp(k * (1 - x)); + + private double realToScaled(double x) => x <= 0 ? 0 : 1 - Math.Log(x) / k; + + public VolumeScaler(BindableNumber? real = null) + { + Real = real ?? new BindableNumber(1) { MinValue = 0, MaxValue = 1 }; + Scaled.BindValueChanged(x => Real.Value = scaledToReal(x.NewValue)); + } + + public double Value + { + get => Real.Value; + set => Scaled.Value = realToScaled(value); + } + + public void Scale() + { + Scaled.Value = realToScaled(Real.Value); + Scaled.Default = realToScaled(Real.Default); + } + } +} diff --git a/osu.Framework/Configuration/FrameworkConfigManager.cs b/osu.Framework/Configuration/FrameworkConfigManager.cs index c38bd77d69..d2ef0fffb6 100644 --- a/osu.Framework/Configuration/FrameworkConfigManager.cs +++ b/osu.Framework/Configuration/FrameworkConfigManager.cs @@ -32,9 +32,9 @@ protected override void InitialiseDefaults() SetDefault(FrameworkSetting.WindowedPositionY, 0.5, -0.5, 1.5); SetDefault(FrameworkSetting.LastDisplayDevice, DisplayIndex.Default); SetDefault(FrameworkSetting.AudioDevice, string.Empty); - SetDefault(FrameworkSetting.VolumeUniversal, 1.0, 0.0, 1.0, 0.01); - SetDefault(FrameworkSetting.VolumeMusic, 1.0, 0.0, 1.0, 0.01); - SetDefault(FrameworkSetting.VolumeEffect, 1.0, 0.0, 1.0, 0.01); + SetDefault(FrameworkSetting.VolumeUniversal, 1.0, 0.0, 1.0); + SetDefault(FrameworkSetting.VolumeMusic, 1.0, 0.0, 1.0); + SetDefault(FrameworkSetting.VolumeEffect, 1.0, 0.0, 1.0); SetDefault(FrameworkSetting.HardwareVideoDecoder, HardwareVideoDecoder.Any); SetDefault(FrameworkSetting.SizeFullscreen, new Size(9999, 9999), new Size(320, 240)); SetDefault(FrameworkSetting.MinimiseOnFocusLossInFullscreen, RuntimeInfo.IsDesktop); diff --git a/osu.Framework/Game.cs b/osu.Framework/Game.cs index 1f7a8e827b..f48339d9df 100644 --- a/osu.Framework/Game.cs +++ b/osu.Framework/Game.cs @@ -173,9 +173,13 @@ private void load(FrameworkConfigManager config) // attach our bindables to the audio subsystem. config.BindWith(FrameworkSetting.AudioDevice, Audio.AudioDevice); - config.BindWith(FrameworkSetting.VolumeUniversal, Audio.Volume); - config.BindWith(FrameworkSetting.VolumeEffect, Audio.VolumeSample); - config.BindWith(FrameworkSetting.VolumeMusic, Audio.VolumeTrack); + config.BindWith(FrameworkSetting.VolumeUniversal, Audio.Volume.Real); + config.BindWith(FrameworkSetting.VolumeEffect, Audio.VolumeSample.Real); + config.BindWith(FrameworkSetting.VolumeMusic, Audio.VolumeTrack.Real); + + Audio.Volume.Scale(); + Audio.VolumeSample.Scale(); + Audio.VolumeTrack.Scale(); Shaders = new ShaderManager(Host.Renderer, new NamespacedResourceStore(Resources, @"Shaders")); dependencies.Cache(Shaders); From ef5a89224c1fa02dbcb5a38a68b340fa61e9699d Mon Sep 17 00:00:00 2001 From: Mike Will Date: Sun, 12 Jan 2025 20:11:11 -0500 Subject: [PATCH 02/10] Display volume in decibel format --- osu.Framework/Audio/VolumeScaler.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Framework/Audio/VolumeScaler.cs b/osu.Framework/Audio/VolumeScaler.cs index e128bd917b..c7322a00eb 100644 --- a/osu.Framework/Audio/VolumeScaler.cs +++ b/osu.Framework/Audio/VolumeScaler.cs @@ -9,21 +9,22 @@ namespace osu.Framework.Audio public class VolumeScaler { public const double MIN = -60; + public const double STEP = 0.5; private const double ln_ten = 2.302585092994045684017991454684364208; - private const double k = ln_ten * MIN / 20; + private const double k = ln_ten / 20; public readonly BindableNumber Real; public readonly BindableNumber Scaled = new BindableNumber(1) { - MinValue = 0, - MaxValue = 1, - Precision = 0.01, + MinValue = MIN, + MaxValue = 0, + Precision = STEP, }; - private double scaledToReal(double x) => x <= 0 ? 0 : Math.Exp(k * (1 - x)); + private double scaledToReal(double x) => x <= MIN ? 0 : Math.Exp(k * x); - private double realToScaled(double x) => x <= 0 ? 0 : 1 - Math.Log(x) / k; + private double realToScaled(double x) => x <= 0 ? MIN : Math.Log(x) / k; public VolumeScaler(BindableNumber? real = null) { From 41ec0a8fa822412f98112eb4d541316d9329ee91 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Mon, 13 Jan 2025 06:59:41 -0500 Subject: [PATCH 03/10] Use Math.Log(10) instead of the numeric literal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Framework/Audio/VolumeScaler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Framework/Audio/VolumeScaler.cs b/osu.Framework/Audio/VolumeScaler.cs index c7322a00eb..24527dbddd 100644 --- a/osu.Framework/Audio/VolumeScaler.cs +++ b/osu.Framework/Audio/VolumeScaler.cs @@ -11,7 +11,7 @@ public class VolumeScaler public const double MIN = -60; public const double STEP = 0.5; - private const double ln_ten = 2.302585092994045684017991454684364208; + private static readonly double ln_ten = Math.Log(10); private const double k = ln_ten / 20; public readonly BindableNumber Real; From 38e105d2335ea73d56c58811889111720df35837 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Mon, 13 Jan 2025 07:10:23 -0500 Subject: [PATCH 04/10] Further simplify the assigning of `k` `ln_ten` was really just there to clarify what the numeric literal represented. --- osu.Framework/Audio/VolumeScaler.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Framework/Audio/VolumeScaler.cs b/osu.Framework/Audio/VolumeScaler.cs index 24527dbddd..c54574cdf8 100644 --- a/osu.Framework/Audio/VolumeScaler.cs +++ b/osu.Framework/Audio/VolumeScaler.cs @@ -11,8 +11,7 @@ public class VolumeScaler public const double MIN = -60; public const double STEP = 0.5; - private static readonly double ln_ten = Math.Log(10); - private const double k = ln_ten / 20; + private const double k = Math.Log(10) / 20; public readonly BindableNumber Real; public readonly BindableNumber Scaled = new BindableNumber(1) From 2b6119883634611f2ddc8f70d73663fbfe0a5402 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Mon, 13 Jan 2025 07:18:38 -0500 Subject: [PATCH 05/10] Rename `VolumeScaler` to `BindableVolume` --- osu.Framework/Audio/AudioManager.cs | 8 ++++---- .../Audio/{VolumeScaler.cs => BindableVolume.cs} | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) rename osu.Framework/Audio/{VolumeScaler.cs => BindableVolume.cs} (92%) diff --git a/osu.Framework/Audio/AudioManager.cs b/osu.Framework/Audio/AudioManager.cs index 3b03e0ab3d..56fbbb3160 100644 --- a/osu.Framework/Audio/AudioManager.cs +++ b/osu.Framework/Audio/AudioManager.cs @@ -93,17 +93,17 @@ public class AudioManager : AudioCollectionManager /// /// Volume of all audio game-wide. /// - public new readonly VolumeScaler Volume; + public new readonly BindableVolume Volume; /// /// Volume of all samples played game-wide. /// - public readonly VolumeScaler VolumeSample = new VolumeScaler(); + public readonly BindableVolume VolumeSample = new BindableVolume(); /// /// Volume of all tracks played game-wide. /// - public readonly VolumeScaler VolumeTrack = new VolumeScaler(); + public readonly BindableVolume VolumeTrack = new BindableVolume(); /// /// Whether a global mixer is being used for audio routing. @@ -176,7 +176,7 @@ public AudioManager(AudioThread audioThread, ResourceStore trackStore, R AddItem(TrackMixer = createAudioMixer(null, nameof(TrackMixer))); AddItem(SampleMixer = createAudioMixer(null, nameof(SampleMixer))); - Volume = new VolumeScaler(base.Volume); + Volume = new BindableVolume(base.Volume); globalTrackStore = new Lazy(() => { diff --git a/osu.Framework/Audio/VolumeScaler.cs b/osu.Framework/Audio/BindableVolume.cs similarity index 92% rename from osu.Framework/Audio/VolumeScaler.cs rename to osu.Framework/Audio/BindableVolume.cs index c54574cdf8..e7557917f1 100644 --- a/osu.Framework/Audio/VolumeScaler.cs +++ b/osu.Framework/Audio/BindableVolume.cs @@ -6,7 +6,7 @@ namespace osu.Framework.Audio { - public class VolumeScaler + public class BindableVolume { public const double MIN = -60; public const double STEP = 0.5; @@ -25,7 +25,7 @@ public class VolumeScaler private double realToScaled(double x) => x <= 0 ? MIN : Math.Log(x) / k; - public VolumeScaler(BindableNumber? real = null) + public BindableVolume(BindableNumber? real = null) { Real = real ?? new BindableNumber(1) { MinValue = 0, MaxValue = 1 }; Scaled.BindValueChanged(x => Real.Value = scaledToReal(x.NewValue)); From 998f687f816e608829e0c5c307d55d99fe6c0cd4 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Mon, 13 Jan 2025 07:46:42 -0500 Subject: [PATCH 06/10] Bring back `ln_ten` as a numeric literal `ln_ten` needs to also be const in order to be assigned to `k` --- osu.Framework/Audio/BindableVolume.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Framework/Audio/BindableVolume.cs b/osu.Framework/Audio/BindableVolume.cs index e7557917f1..bfff51463a 100644 --- a/osu.Framework/Audio/BindableVolume.cs +++ b/osu.Framework/Audio/BindableVolume.cs @@ -11,7 +11,8 @@ public class BindableVolume public const double MIN = -60; public const double STEP = 0.5; - private const double k = Math.Log(10) / 20; + private const double ln_ten = 2.302585092994045684017991454684364208; + private const double k = ln_ten / 20; public readonly BindableNumber Real; public readonly BindableNumber Scaled = new BindableNumber(1) From 370a49c709047c5defeb299fc2e1d7827dbcfd6b Mon Sep 17 00:00:00 2001 From: Mike Will Date: Mon, 13 Jan 2025 11:22:08 -0500 Subject: [PATCH 07/10] Make BindableVolume a sealed class --- osu.Framework/Audio/BindableVolume.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Framework/Audio/BindableVolume.cs b/osu.Framework/Audio/BindableVolume.cs index bfff51463a..efc82b423b 100644 --- a/osu.Framework/Audio/BindableVolume.cs +++ b/osu.Framework/Audio/BindableVolume.cs @@ -6,7 +6,7 @@ namespace osu.Framework.Audio { - public class BindableVolume + public sealed class BindableVolume { public const double MIN = -60; public const double STEP = 0.5; From 590d1d02d0a990f4d80d1a80a6b85f3cbd162862 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Mon, 13 Jan 2025 11:53:02 -0500 Subject: [PATCH 08/10] Remove BindableVolume.Value Getter can be replaced with explicit calls to Real Setter should instead be a function with a clearer name. --- osu.Framework/Audio/BindableVolume.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Framework/Audio/BindableVolume.cs b/osu.Framework/Audio/BindableVolume.cs index efc82b423b..10d0fe61b8 100644 --- a/osu.Framework/Audio/BindableVolume.cs +++ b/osu.Framework/Audio/BindableVolume.cs @@ -32,10 +32,9 @@ public BindableVolume(BindableNumber? real = null) Scaled.BindValueChanged(x => Real.Value = scaledToReal(x.NewValue)); } - public double Value + public void SetFromLinear(double linear) { - get => Real.Value; - set => Scaled.Value = realToScaled(value); + Scaled.Value = realToScaled(linear); } public void Scale() From 8ea57e815080516d408cba1157859df879b85215 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Tue, 14 Jan 2025 00:59:48 -0500 Subject: [PATCH 09/10] Make `k` a static readonly so we can use Math.Log(10) --- osu.Framework/Audio/BindableVolume.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Framework/Audio/BindableVolume.cs b/osu.Framework/Audio/BindableVolume.cs index 10d0fe61b8..c26e736f66 100644 --- a/osu.Framework/Audio/BindableVolume.cs +++ b/osu.Framework/Audio/BindableVolume.cs @@ -11,8 +11,7 @@ public sealed class BindableVolume public const double MIN = -60; public const double STEP = 0.5; - private const double ln_ten = 2.302585092994045684017991454684364208; - private const double k = ln_ten / 20; + private static readonly double k = Math.Log(10) / 20; public readonly BindableNumber Real; public readonly BindableNumber Scaled = new BindableNumber(1) From 844989f6778960cc65ba6f20d989938b5d9f8666 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Tue, 14 Jan 2025 02:12:46 -0500 Subject: [PATCH 10/10] Rename `Real/Scaled` to `Linear/Decibel` --- osu.Framework/Audio/AudioManager.cs | 4 ++-- osu.Framework/Audio/BindableVolume.cs | 20 ++++++++++---------- osu.Framework/Game.cs | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/osu.Framework/Audio/AudioManager.cs b/osu.Framework/Audio/AudioManager.cs index 56fbbb3160..41f76e4cc2 100644 --- a/osu.Framework/Audio/AudioManager.cs +++ b/osu.Framework/Audio/AudioManager.cs @@ -182,7 +182,7 @@ public AudioManager(AudioThread audioThread, ResourceStore trackStore, R { var store = new TrackStore(trackStore, TrackMixer); AddItem(store); - store.AddAdjustment(AdjustableProperty.Volume, VolumeTrack.Real); + store.AddAdjustment(AdjustableProperty.Volume, VolumeTrack.Linear); return store; }); @@ -190,7 +190,7 @@ public AudioManager(AudioThread audioThread, ResourceStore trackStore, R { var store = new SampleStore(sampleStore, SampleMixer); AddItem(store); - store.AddAdjustment(AdjustableProperty.Volume, VolumeSample.Real); + store.AddAdjustment(AdjustableProperty.Volume, VolumeSample.Linear); return store; }); diff --git a/osu.Framework/Audio/BindableVolume.cs b/osu.Framework/Audio/BindableVolume.cs index c26e736f66..decf6a6263 100644 --- a/osu.Framework/Audio/BindableVolume.cs +++ b/osu.Framework/Audio/BindableVolume.cs @@ -13,33 +13,33 @@ public sealed class BindableVolume private static readonly double k = Math.Log(10) / 20; - public readonly BindableNumber Real; - public readonly BindableNumber Scaled = new BindableNumber(1) + public readonly BindableNumber Linear; + public readonly BindableNumber Decibel = new BindableNumber(1) { MinValue = MIN, MaxValue = 0, Precision = STEP, }; - private double scaledToReal(double x) => x <= MIN ? 0 : Math.Exp(k * x); + private double decibelToLinear(double x) => x <= MIN ? 0 : Math.Exp(k * x); - private double realToScaled(double x) => x <= 0 ? MIN : Math.Log(x) / k; + private double linearToDecibel(double x) => x <= 0 ? MIN : Math.Log(x) / k; - public BindableVolume(BindableNumber? real = null) + public BindableVolume(BindableNumber? linear = null) { - Real = real ?? new BindableNumber(1) { MinValue = 0, MaxValue = 1 }; - Scaled.BindValueChanged(x => Real.Value = scaledToReal(x.NewValue)); + Linear = linear ?? new BindableNumber(1) { MinValue = 0, MaxValue = 1 }; + Decibel.BindValueChanged(x => Linear.Value = decibelToLinear(x.NewValue)); } public void SetFromLinear(double linear) { - Scaled.Value = realToScaled(linear); + Decibel.Value = linearToDecibel(linear); } public void Scale() { - Scaled.Value = realToScaled(Real.Value); - Scaled.Default = realToScaled(Real.Default); + Decibel.Value = linearToDecibel(Linear.Value); + Decibel.Default = linearToDecibel(Linear.Default); } } } diff --git a/osu.Framework/Game.cs b/osu.Framework/Game.cs index f48339d9df..cba54c28f7 100644 --- a/osu.Framework/Game.cs +++ b/osu.Framework/Game.cs @@ -173,9 +173,9 @@ private void load(FrameworkConfigManager config) // attach our bindables to the audio subsystem. config.BindWith(FrameworkSetting.AudioDevice, Audio.AudioDevice); - config.BindWith(FrameworkSetting.VolumeUniversal, Audio.Volume.Real); - config.BindWith(FrameworkSetting.VolumeEffect, Audio.VolumeSample.Real); - config.BindWith(FrameworkSetting.VolumeMusic, Audio.VolumeTrack.Real); + config.BindWith(FrameworkSetting.VolumeUniversal, Audio.Volume.Linear); + config.BindWith(FrameworkSetting.VolumeEffect, Audio.VolumeSample.Linear); + config.BindWith(FrameworkSetting.VolumeMusic, Audio.VolumeTrack.Linear); Audio.Volume.Scale(); Audio.VolumeSample.Scale();