diff --git a/osu.Framework/Audio/AudioManager.cs b/osu.Framework/Audio/AudioManager.cs index 91a4e37d7a..41f76e4cc2 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 BindableVolume Volume; + /// /// Volume of all samples played game-wide. /// - public readonly BindableDouble VolumeSample = new BindableDouble(1) - { - MinValue = 0, - MaxValue = 1 - }; + public readonly BindableVolume VolumeSample = new BindableVolume(); /// /// Volume of all tracks played game-wide. /// - public readonly BindableDouble VolumeTrack = new BindableDouble(1) - { - MinValue = 0, - MaxValue = 1 - }; + public readonly BindableVolume VolumeTrack = new BindableVolume(); /// /// 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 BindableVolume(base.Volume); + globalTrackStore = new Lazy(() => { var store = new TrackStore(trackStore, TrackMixer); AddItem(store); - store.AddAdjustment(AdjustableProperty.Volume, VolumeTrack); + store.AddAdjustment(AdjustableProperty.Volume, VolumeTrack.Linear); 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.Linear); return store; }); diff --git a/osu.Framework/Audio/BindableVolume.cs b/osu.Framework/Audio/BindableVolume.cs new file mode 100644 index 0000000000..decf6a6263 --- /dev/null +++ b/osu.Framework/Audio/BindableVolume.cs @@ -0,0 +1,45 @@ +// 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 sealed class BindableVolume + { + public const double MIN = -60; + public const double STEP = 0.5; + + private static readonly double k = Math.Log(10) / 20; + + public readonly BindableNumber Linear; + public readonly BindableNumber Decibel = new BindableNumber(1) + { + MinValue = MIN, + MaxValue = 0, + Precision = STEP, + }; + + private double decibelToLinear(double x) => x <= MIN ? 0 : Math.Exp(k * x); + + private double linearToDecibel(double x) => x <= 0 ? MIN : Math.Log(x) / k; + + public BindableVolume(BindableNumber? linear = null) + { + Linear = linear ?? new BindableNumber(1) { MinValue = 0, MaxValue = 1 }; + Decibel.BindValueChanged(x => Linear.Value = decibelToLinear(x.NewValue)); + } + + public void SetFromLinear(double linear) + { + Decibel.Value = linearToDecibel(linear); + } + + public void Scale() + { + Decibel.Value = linearToDecibel(Linear.Value); + Decibel.Default = linearToDecibel(Linear.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..cba54c28f7 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.Linear); + config.BindWith(FrameworkSetting.VolumeEffect, Audio.VolumeSample.Linear); + config.BindWith(FrameworkSetting.VolumeMusic, Audio.VolumeTrack.Linear); + + Audio.Volume.Scale(); + Audio.VolumeSample.Scale(); + Audio.VolumeTrack.Scale(); Shaders = new ShaderManager(Host.Renderer, new NamespacedResourceStore(Resources, @"Shaders")); dependencies.Cache(Shaders);