From eadac08d0a37d346866b9b291c48e0cf1ea55317 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 24 Jun 2017 21:30:30 +1000 Subject: [PATCH] Sounds/music volume is configurable between 0-100, instead of just ON/OFF. Fixes #320 and addresses #446 --- .../2D/Screens/Menu/ClassicOptionsScreen.cs | 29 +++++++++--- .../2D/Screens/Menu/MiscOptionsScreen.cs | 26 +++++----- ClassicalSharp/Audio/AudioPlayer.Sounds.cs | 15 +++--- ClassicalSharp/Audio/AudioPlayer.cs | 47 ++++++++++--------- ClassicalSharp/Game/Game.Properties.cs | 3 +- ClassicalSharp/Utils/Options.cs | 9 ++-- src/Client/GameProps.h | 8 ++-- src/Client/Options.h | 9 ++-- 8 files changed, 87 insertions(+), 59 deletions(-) diff --git a/ClassicalSharp/2D/Screens/Menu/ClassicOptionsScreen.cs b/ClassicalSharp/2D/Screens/Menu/ClassicOptionsScreen.cs index 682d33e59..6a05dd342 100644 --- a/ClassicalSharp/2D/Screens/Menu/ClassicOptionsScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/ClassicOptionsScreen.cs @@ -21,9 +21,9 @@ namespace ClassicalSharp.Gui.Screens { widgets = new Widget[] { // Column 1 - MakeBool(-1, -150, "Music", OptionsKey.UseMusic, - OnWidgetClick, g => g.UseMusic, - (g, v) => { g.UseMusic = v; g.AudioPlayer.SetMusic(g.UseMusic); }), + MakeVolumeBool(-1, -150, "Music", OptionsKey.MusicVolume, + g => g.MusicVolume > 0, + (g, v) => { g.MusicVolume = v ? 100 : 0; g.AudioPlayer.SetMusic(g.MusicVolume); }), MakeBool(-1, -100, "Invert mouse", OptionsKey.InvertMouse, OnWidgetClick, g => g.InvertMouse, (g, v) => g.InvertMouse = v), @@ -38,9 +38,9 @@ namespace ClassicalSharp.Gui.Screens { (g, v) => ((SinglePlayerServer)network).physics.Enabled = v), // Column 2 - MakeBool(1, -150, "Sound", OptionsKey.UseSound, - OnWidgetClick, g => g.UseSound, - (g, v) => { g.UseSound = v; g.AudioPlayer.SetSound(g.UseSound); }), + MakeVolumeBool(1, -150, "Sound", OptionsKey.SoundsVolume, + g => g.SoundsVolume > 0, + (g, v) => { g.SoundsVolume = v ? 100 : 0; g.AudioPlayer.SetSounds(g.SoundsVolume); }), MakeBool(1, -100, "Show FPS", OptionsKey.ShowFPS, OnWidgetClick, g => g.ShowFPS, (g, v) => g.ShowFPS = v), @@ -72,6 +72,23 @@ namespace ClassicalSharp.Gui.Screens { btn.SetValue = SetFPSLimitMethod; } + ButtonWidget MakeVolumeBool(int dir, int y, string text, string optKey, + ButtonBoolGetter getter, ButtonBoolSetter setter) { + string optName = text; + text = text + ": " + (getter(game) ? "ON" : "OFF"); + ButtonWidget widget = ButtonWidget.Create(game, 300, text, titleFont, OnWidgetClick) + .SetLocation(Anchor.Centre, Anchor.Centre, 160 * dir, y); + widget.Metadata = optName; + widget.GetValue = g => getter(g) ? "yes" : "no"; + + widget.SetValue = (g, v) => { + setter(g, v == "yes"); + Options.Set(optKey, v == "yes" ? 100 : 0); + widget.SetText((string)widget.Metadata + ": " + (v == "yes" ? "ON" : "OFF")); + }; + return widget; + } + void MakeValidators() { IServerConnection network = game.Server; validators = new MenuInputValidator[] { diff --git a/ClassicalSharp/2D/Screens/Menu/MiscOptionsScreen.cs b/ClassicalSharp/2D/Screens/Menu/MiscOptionsScreen.cs index 1f3cd208b..c628ced90 100644 --- a/ClassicalSharp/2D/Screens/Menu/MiscOptionsScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/MiscOptionsScreen.cs @@ -23,16 +23,16 @@ namespace ClassicalSharp.Gui.Screens { // Column 1 !network.IsSinglePlayer ? null : MakeOpt(-1, -100, "Click distance", OnWidgetClick, - g => g.LocalPlayer.ReachDistance.ToString(), - (g, v) => g.LocalPlayer.ReachDistance = Utils.ParseDecimal(v)), + g => g.LocalPlayer.ReachDistance.ToString(), + (g, v) => g.LocalPlayer.ReachDistance = Utils.ParseDecimal(v)), - MakeBool(-1, -50, "Music", OptionsKey.UseMusic, - OnWidgetClick, g => g.UseMusic, - (g, v) => { g.UseMusic = v; g.AudioPlayer.SetMusic(g.UseMusic); }), + MakeOpt(-1, -50, "Music volume", OnWidgetClick, + g => g.MusicVolume.ToString(), + (g, v) => { g.MusicVolume = Int32.Parse(v); g.AudioPlayer.SetMusic(g.MusicVolume); }), - MakeBool(-1, 0, "Sound", OptionsKey.UseSound, - OnWidgetClick, g => g.UseSound, - (g, v) => { g.UseSound = v; g.AudioPlayer.SetSound(g.UseSound); }), + MakeOpt(-1, 0, "Sounds volume", OnWidgetClick, + g => g.SoundsVolume.ToString(), + (g, v) => { g.SoundsVolume = Int32.Parse(v); g.AudioPlayer.SetSounds(g.SoundsVolume); }), MakeBool(-1, 50, "View bobbing", OptionsKey.ViewBobbing, OnWidgetClick, g => g.ViewBobbing, (g, v) => g.ViewBobbing = v), @@ -51,9 +51,9 @@ namespace ClassicalSharp.Gui.Screens { OnWidgetClick, g => g.InvertMouse, (g, v) => g.InvertMouse = v), MakeOpt(1, 50, "Mouse sensitivity", OnWidgetClick, - g => g.MouseSensitivity.ToString(), - (g, v) => { g.MouseSensitivity = Int32.Parse(v); - Options.Set(OptionsKey.Sensitivity, v); }), + g => g.MouseSensitivity.ToString(), + (g, v) => { g.MouseSensitivity = Int32.Parse(v); + Options.Set(OptionsKey.Sensitivity, v); }), MakeBack(false, titleFont, (g, w) => g.Gui.SetNewScreen(new OptionsGroupScreen(g))), @@ -65,8 +65,8 @@ namespace ClassicalSharp.Gui.Screens { IServerConnection network = game.Server; validators = new MenuInputValidator[] { network.IsSinglePlayer ? new RealValidator(1, 1024) : null, - new BooleanValidator(), - new BooleanValidator(), + new IntegerValidator(0, 100), + new IntegerValidator(0, 100), new BooleanValidator(), network.IsSinglePlayer ? new BooleanValidator() : null, diff --git a/ClassicalSharp/Audio/AudioPlayer.Sounds.cs b/ClassicalSharp/Audio/AudioPlayer.Sounds.cs index fe5e8a113..25263e32c 100644 --- a/ClassicalSharp/Audio/AudioPlayer.Sounds.cs +++ b/ClassicalSharp/Audio/AudioPlayer.Sounds.cs @@ -12,11 +12,9 @@ namespace ClassicalSharp.Audio { Soundboard digBoard, stepBoard; const int maxSounds = 6; - public void SetSound(bool enabled) { - if (enabled) - InitSound(); - else - DisposeSound(); + public void SetSounds(int volume) { + if (volume > 0) InitSound(); + else DisposeSound(); } void InitSound() { @@ -75,7 +73,7 @@ namespace ClassicalSharp.Audio { for (int i = 0; i < monoOutputs.Length; i++) { IAudioOutput output = outputs[i]; if (output == null) output = MakeSoundOutput(outputs, i); - if (!output.DoneRawAsync()) continue; + if (!output.DoneRawAsync()) continue; LastChunk l = output.Last; if (l.Channels == 0 || (l.Channels == chunk.Channels && l.BitsPerSample == chunk.BitsPerSample @@ -107,6 +105,7 @@ namespace ClassicalSharp.Audio { void PlaySound(IAudioOutput output) { try { + output.SetVolume(game.SoundsVolume / 100.0f); output.PlayRawAsync(chunk); } catch (InvalidOperationException ex) { ErrorHandler.LogError("AudioPlayer.PlayCurrentSound()", ex); @@ -115,8 +114,8 @@ namespace ClassicalSharp.Audio { else game.Chat.Add("&cAn error occured when trying to play sounds, disabling sounds."); - SetSound(false); - game.UseSound = false; + SetSounds(0); + game.SoundsVolume = 0; } } diff --git a/ClassicalSharp/Audio/AudioPlayer.cs b/ClassicalSharp/Audio/AudioPlayer.cs index ffc90e2c7..b44a308be 100644 --- a/ClassicalSharp/Audio/AudioPlayer.cs +++ b/ClassicalSharp/Audio/AudioPlayer.cs @@ -22,28 +22,34 @@ namespace ClassicalSharp.Audio { files = Directory.GetFiles(path); else files = new string[0]; - - game.UseMusic = Options.GetBool(OptionsKey.UseMusic, false); - SetMusic(game.UseMusic); - game.UseSound = Options.GetBool(OptionsKey.UseSound, false); - SetSound(game.UseSound); + + game.MusicVolume = GetVolume(OptionsKey.MusicVolume, OptionsKey.UseMusic); + SetMusic(game.MusicVolume); + game.SoundsVolume = GetVolume(OptionsKey.SoundsVolume, OptionsKey.UseSound); + SetSounds(game.SoundsVolume); game.UserEvents.BlockChanged += PlayBlockSound; } + + static int GetVolume(string volKey, string boolKey) { + int volume = Options.GetInt(volKey, 0, 100, 0); + if (volume != 0) return volume; + return Options.GetBool(boolKey, false) ? 100 : 0; + } - public void Ready(Game game) { } + public void Ready(Game game) { } public void Reset(Game game) { } public void OnNewMap(Game game) { } - public void OnNewMapLoaded(Game game) { } + public void OnNewMapLoaded(Game game) { } - public void SetMusic(bool enabled) { - if (enabled) - InitMusic(); - else - DisposeMusic(); + public void SetMusic(int volume) { + if (volume > 0) InitMusic(); + else DisposeMusic(); } const StringComparison comp = StringComparison.OrdinalIgnoreCase; void InitMusic() { + if (musicThread != null) { musicOut.SetVolume(game.MusicVolume / 100.0f); return; } + int musicCount = 0; for (int i = 0; i < files.Length; i++) { if (files[i].EndsWith(".ogg", comp)) musicCount++; @@ -54,10 +60,11 @@ namespace ClassicalSharp.Audio { if (!files[i].EndsWith(".ogg", comp)) continue; musicFiles[j] = files[i]; j++; } - + disposingMusic = false; - musicThread = MakeThread(DoMusicThread, ref musicOut, - "ClassicalSharp.DoMusic"); + musicOut = GetPlatformOut(); + musicOut.Create(10); + musicThread = MakeThread(DoMusicThread, "ClassicalSharp.DoMusic"); } EventWaitHandle musicHandle = new EventWaitHandle(false, EventResetMode.AutoReset); @@ -72,6 +79,7 @@ namespace ClassicalSharp.Audio { using (FileStream fs = File.OpenRead(path)) { OggContainer container = new OggContainer(fs); try { + musicOut.SetVolume(game.MusicVolume / 100.0f); musicOut.PlayStreaming(container); } catch (InvalidOperationException ex) { HandleMusicError(ex); @@ -95,8 +103,8 @@ namespace ClassicalSharp.Audio { else game.Chat.Add("&cAn error occured when trying to play music, disabling music."); - SetMusic(false); - game.UseMusic = false; + SetMusic(0); + game.MusicVolume = 0; } bool disposingMusic; @@ -113,10 +121,7 @@ namespace ClassicalSharp.Audio { DisposeOf(ref musicOut, ref musicThread); } - Thread MakeThread(ThreadStart func, ref IAudioOutput output, string name) { - output = GetPlatformOut(); - output.Create(10); - + Thread MakeThread(ThreadStart func, string name) { Thread thread = new Thread(func); thread.Name = name; thread.IsBackground = true; diff --git a/ClassicalSharp/Game/Game.Properties.cs b/ClassicalSharp/Game/Game.Properties.cs index 415e2f281..6615b5970 100644 --- a/ClassicalSharp/Game/Game.Properties.cs +++ b/ClassicalSharp/Game/Game.Properties.cs @@ -190,7 +190,8 @@ namespace ClassicalSharp { public bool ClickableChat = false, HideGui = false, ShowFPS = true; internal float HotbarScale = 1, ChatScale = 1, InventoryScale = 1; public bool ViewBobbing, ShowBlockInHand; - public bool UseSound, UseMusic, ModifiableLiquids; + public bool ModifiableLiquids; + public int SoundsVolume, MusicVolume; public Vector3 CurrentCameraPos; diff --git a/ClassicalSharp/Utils/Options.cs b/ClassicalSharp/Utils/Options.cs index 045a8109c..b804035f1 100644 --- a/ClassicalSharp/Utils/Options.cs +++ b/ClassicalSharp/Utils/Options.cs @@ -7,12 +7,15 @@ using ClassicalSharp.Textures; namespace ClassicalSharp { public static class OptionsKey { -#if !LAUNCHER - public const string ViewDist = "viewdist"; - public const string SingleplayerPhysics = "singleplayerphysics"; +#if !LAUNCHER public const string UseMusic = "usemusic"; public const string UseSound = "usesound"; + public const string MusicVolume = "musicvolume"; + public const string SoundsVolume = "soundsvolume"; public const string ForceOpenAL = "forceopenal"; + + public const string ViewDist = "viewdist"; + public const string SingleplayerPhysics = "singleplayerphysics"; public const string NamesMode = "namesmode"; public const string InvertMouse = "invertmouse"; public const string Sensitivity = "mousesensitivity"; diff --git a/src/Client/GameProps.h b/src/Client/GameProps.h index 0ff850309..8858820b9 100644 --- a/src/Client/GameProps.h +++ b/src/Client/GameProps.h @@ -126,10 +126,10 @@ static Real32 Game_RawInventoryScale; bool Game_ViewBobbing; /* Whether block in hand is shown in bottom right. */ bool Game_ShowBlockInHand; -/* Whether playing dig and step sounds is enabled. */ -bool Game_UseSound; -/* Whether background music playing is enabled. */ -bool Game_UseMusic; +/* Volume of dig and step sounds. 0 means disabled. */ +Int32 Game_SoundsVolume; +/* Volume of background music played. 0 means disabled */ +Int32 Game_MusicVolume; /* Whether water/lava can be placed/deleted like normal blocks. */ bool Game_ModifiableLiquids; diff --git a/src/Client/Options.h b/src/Client/Options.h index f5ff7450d..fd98c00a0 100644 --- a/src/Client/Options.h +++ b/src/Client/Options.h @@ -12,12 +12,15 @@ typedef UInt8 FpsLimitMethod; #define FpsLimitMethod_60FPS 2 #define FpsLimitMethod_120FPS 3 #define FpsLimitMethod_None 4 - -#define OptionsKey_ViewDist "viewdist" -#define OptionsKey_SingleplayerPhysics "singleplayerphysics" + #define OptionsKey_UseMusic "usemusic" #define OptionsKey_UseSound "usesound" +#define OptionsKey_MusicVolume "musicvolume" +#define OptionsKey_SoundVolume "soundvolume" #define OptionsKey_ForceOpenAL "forceopenal" + +#define OptionsKey_ViewDist "viewdist" +#define OptionsKey_SingleplayerPhysics "singleplayerphysics" #define OptionsKey_NamesMode "namesmode" #define OptionsKey_InvertMouse "invertmouse" #define OptionsKey_Sensitivity "mousesensitivity"