From 8180d34765efa2af7b9cf409b3d5d2f1b0421546 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 18 Apr 2017 16:42:28 +0200 Subject: [PATCH] - added user configurable menus where soundfonts, patch sets or Timidity EXEs can be selected from lists being stored in the config file to reduce the hassle of testing MIDIs with different settings. --- src/menu/menu.cpp | 11 +++ src/menu/menu.h | 1 + src/menu/menudef.cpp | 89 +++++++++++++++++++ src/s_sound.cpp | 10 +-- src/sound/i_soundinternal.h | 12 ++- src/sound/music_midi_base.cpp | 53 ++++------- wadsrc/static/language.enu | 1 + wadsrc/static/menudef.txt | 27 ++++++ .../static/zscript/menu/optionmenuitems.txt | 17 ++-- 9 files changed, 167 insertions(+), 54 deletions(-) diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 54bc8af07..4ea76fe65 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -1165,6 +1165,17 @@ DMenuItemBase * CreateOptionMenuItemControl(const char *label, FName cmd, FKeyBi return (DMenuItemBase*)p; } +DMenuItemBase * CreateOptionMenuItemCommand(const char *label, FName cmd, bool centered) +{ + auto c = PClass::FindClass("OptionMenuItemCommand"); + auto p = c->CreateNew(); + FString namestr = label; + VMValue params[] = { p, &namestr, cmd.GetIndex(), centered }; + auto f = dyn_cast(c->FindSymbol("Init", false)); + VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); + return (DMenuItemBase*)p; +} + DMenuItemBase * CreateListMenuItemPatch(double x, double y, int height, int hotkey, FTextureID tex, FName command, int param) { auto c = PClass::FindClass("ListMenuItemPatchItem"); diff --git a/src/menu/menu.h b/src/menu/menu.h index 5c40b7f7b..7e985df6d 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -355,5 +355,6 @@ DMenuItemBase * CreateOptionMenuItemControl(const char *label, FName cmd, FKeyBi DMenuItemBase * CreateOptionMenuItemJoyConfigMenu(const char *label, IJoystickConfig *joy); DMenuItemBase * CreateListMenuItemPatch(double x, double y, int height, int hotkey, FTextureID tex, FName command, int param); DMenuItemBase * CreateListMenuItemText(double x, double y, int height, int hotkey, const char *text, FFont *font, PalEntry color1, PalEntry color2, FName command, int param); +DMenuItemBase * CreateOptionMenuItemCommand(const char *label, FName cmd, bool centered = false); #endif diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index d3a2ee49f..12df3d65f 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -53,6 +53,7 @@ #include "cmdlib.h" #include "vm.h" #include "types.h" +#include "gameconfigfile.h" @@ -1283,6 +1284,93 @@ static void InitCrosshairsList() } } +//============================================================================= +// +// Initialize the music configuration submenus +// +//============================================================================= +static void InitMusicMenus() +{ + DMenuDescriptor **advmenu = MenuDescriptors.CheckKey("AdvSoundOptions"); + DMenuDescriptor **gusmenu = MenuDescriptors.CheckKey("GusConfigMenu"); + DMenuDescriptor **timiditymenu = MenuDescriptors.CheckKey("TimidityExeMenu"); + DMenuDescriptor **wildmidimenu = MenuDescriptors.CheckKey("WildMidiConfigMenu"); + DMenuDescriptor **fluidmenu = MenuDescriptors.CheckKey("FluidPatchsetMenu"); + + const char *key, *value; + if (GameConfig->SetSection("SoundFonts")) + { + while (GameConfig->NextInSection(key, value)) + { + if (FileExists(value)) + { + if (fluidmenu != nullptr) + { + auto it = CreateOptionMenuItemCommand(key, FStringf("fluid_patchset %s", NicePath(value)), true); + static_cast(*fluidmenu)->mItems.Push(it); + } + } + } + } + else if (advmenu != nullptr) + { + // Remove the item for this submenu + auto d = static_cast(*advmenu); + auto it = d->GetItem("FluidPatchsetMenu"); + if (it != nullptr) d->mItems.Delete(d->mItems.Find(it)); + } + if (GameConfig->SetSection("PatchSets")) + { + while (GameConfig->NextInSection(key, value)) + { + if (FileExists(value)) + { + if (gusmenu != nullptr) + { + auto it = CreateOptionMenuItemCommand(key, FStringf("midi_config %s", NicePath(value)), true); + static_cast(*gusmenu)->mItems.Push(it); + } + if (wildmidimenu != nullptr) + { + auto it = CreateOptionMenuItemCommand(key, FStringf("wildmidi_config %s", NicePath(value)), true); + static_cast(*wildmidimenu)->mItems.Push(it); + } + } + } + } + else if (advmenu != nullptr) + { + // Remove the item for this submenu + auto d = static_cast(*advmenu); + auto it = d->GetItem("GusConfigMenu"); + if (it != nullptr) d->mItems.Delete(d->mItems.Find(it)); + it = d->GetItem("WildMidiConfigMenu"); + if (it != nullptr) d->mItems.Delete(d->mItems.Find(it)); + } +#ifdef _WIN32 // Different Timidity paths only make sense if they can be stored in arbitrary paths with local configs (i.e. not if things are done the Linux way) + if (GameConfig->SetSection("TimidityExes")) + { + while (GameConfig->NextInSection(key, value)) + { + if (FileExists(value)) + { + if (timiditymenu != nullptr) + { + auto it = CreateOptionMenuItemCommand(key, FStringf("timidity_exe %s", NicePath(value)), true); + static_cast(*timiditymenu)->mItems.Push(it); + } + } + } + } + else + { + auto d = static_cast(*advmenu); + auto it = d->GetItem("TimidityExeMenu"); + if (it != nullptr) d->mItems.Delete(d->mItems.Find(it)); + } +#endif +} + //============================================================================= // // With the current workings of the menu system this cannot be done any longer @@ -1332,6 +1420,7 @@ void M_CreateMenus() BuildEpisodeMenu(); BuildPlayerclassMenu(); InitCrosshairsList(); + InitMusicMenus(); InitKeySections(); FOptionValues **opt = OptionValues.CheckKey(NAME_Mididevices); diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 3d678b7d2..48139da4e 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -109,14 +109,6 @@ // TYPES ------------------------------------------------------------------- -struct MusPlayingInfo -{ - FString name; - MusInfo *handle; - int baseorder; - bool loop; -}; - enum { SOURCE_None, // Sound is always on top of the listener. @@ -151,7 +143,7 @@ static void S_SetListener(SoundListener &listener, AActor *listenactor); static bool SoundPaused; // whether sound is paused static bool MusicPaused; // whether music is paused -static MusPlayingInfo mus_playing; // music currently being played +MusPlayingInfo mus_playing; // music currently being played static FString LastSong; // last music that was played static FPlayList *PlayList; static int RestartEvictionsAt; // do not restart evicted channels before this level.time diff --git a/src/sound/i_soundinternal.h b/src/sound/i_soundinternal.h index f5f49f560..aa91d73ae 100644 --- a/src/sound/i_soundinternal.h +++ b/src/sound/i_soundinternal.h @@ -3,7 +3,7 @@ #include -#include "basictypes.h" +#include "doomtype.h" #include "vectors.h" #include "tarray.h" @@ -161,5 +161,15 @@ enum EMidiDevice MDEV_WILDMIDI = 6, }; +class MusInfo; +struct MusPlayingInfo +{ + FString name; + MusInfo *handle; + int baseorder; + bool loop; +}; + + #endif diff --git a/src/sound/music_midi_base.cpp b/src/sound/music_midi_base.cpp index b7af50d6a..c437af696 100644 --- a/src/sound/music_midi_base.cpp +++ b/src/sound/music_midi_base.cpp @@ -41,6 +41,7 @@ #include "gameconfigfile.h" #include "cmdlib.h" #include "m_misc.h" +#include "s_sound.h" #include "templates.h" #include "v_text.h" @@ -55,42 +56,6 @@ static bool nummididevicesset; #define NUM_DEF_DEVICES 5 #endif -//Provide some lists from which the user can choose the music resources in the menu instead of having to type them in manually -// These lists have to be maintained manually for the moment. -TArray SoundFonts; -TArray PatchSets; -TArray TimidityExes; - -static void ReadSoundFonts() -{ - const char *key, *value; - // Do not check for missing files here so that they will be saved back. - // Deletion should be done explicitly im the menu, equivalent to how the savegame menu works. - if (GameConfig->SetSection("SoundFonts")) - { - while (GameConfig->NextInSection(key, value)) - { - if (FileExists(value)) SoundFonts.Push(value); - } - } - if (GameConfig->SetSection("PatchSets")) - { - while (GameConfig->NextInSection(key, value)) - { - if (FileExists(value)) PatchSets.Push(value); - } - } -#ifdef _WIN32 // Different Timidity paths only make sense if they can be stored in arbitrary paths with local configs (i.e. not if things are done the Linux way) - if (GameConfig->SetSection("TimidityExes")) - { - while (GameConfig->NextInSection(key, value)) - { - if (FileExists(value)) PatchSets.Push(value); - } - } -#endif -} - static void AddDefaultMidiDevices(FOptionValues *opt) { int p; @@ -115,6 +80,8 @@ static void AddDefaultMidiDevices(FOptionValues *opt) } +extern MusPlayingInfo mus_playing; + void MIDIDeviceChanged(int newdev, bool force) { static int oldmididev = INT_MIN; @@ -127,8 +94,18 @@ void MIDIDeviceChanged(int newdev, bool force) MusInfo *song = currSong; if (song->m_Status == MusInfo::STATE_Playing) { - song->Stop(); - song->Start(song->m_Looping); + if (song->GetDeviceType() == MDEV_FLUIDSYNTH && force) + { + // FluidSynth must reload the song to change the patch set. + auto mi = mus_playing; + S_StopMusic(true); + S_ChangeMusic(mi.name, mi.baseorder, mi.loop); + } + else + { + song->Stop(); + song->Start(song->m_Looping); + } } } else diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 8e8572b2f..ca45cd1ef 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2161,6 +2161,7 @@ ADVSNDMNU_TIMIDITYCHORUS = "Chorus"; ADVSNDMNU_TIMIDITYVOLUME = "Relative volume"; ADVSNDMNU_WILDMIDI = "WildMidi"; ADVSNDMNU_WILDMIDICONFIG = "WildMidi config file"; +ADVSNDMNU_SELCONFIG = "Select configuration"; // Module Replayer Options MODMNU_TITLE = "MODULE REPLAYER OPTIONS"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index c5e3820af..1fb0172c5 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1637,12 +1637,14 @@ OptionMenu AdvSoundOptions StaticText " " StaticText "$ADVSNDMNU_GUSEMULATION", 1 TextField "$ADVSNDMNU_GUSCONFIG", "midi_config" + SubMenu "$ADVSNDMNU_SELCONFIG", "GusConfigMenu" Slider "$ADVSNDMNU_MIDIVOICES", "midi_voices", 16, 256, 4, 0 Option "$ADVSNDMNU_DMXGUS", "midi_dmxgus", "OnOff" Option "$ADVSNDMNU_GUSMEMSIZE", "gus_memsize", "GusMemory" StaticText " " StaticText "$ADVSNDMNU_FLUIDSYNTH", 1 TextField "$ADVSNDMNU_FLUIDPATCHSET", "fluid_patchset" + SubMenu "$ADVSNDMNU_SELCONFIG", "FluidPatchsetMenu" Slider "$ADVSNDMNU_FLUIDGAIN", "fluid_gain", 0, 10, 0.5, 1 Option "$ADVSNDMNU_REVERB", "fluid_reverb", "OnOff" Slider "$ADVSNDMNU_FLUIDVOICES", "fluid_voices", 16, 4096, 16, 1 @@ -1650,15 +1652,40 @@ OptionMenu AdvSoundOptions StaticText " " StaticText "$ADVSNDMNU_TIMIDITY", 1 TextField "$ADVSNDMNU_TIMIDITYEXE", "timidity_exe" + IfOption(Windows) + { + SubMenu "$ADVSNDMNU_SELCONFIG", "TimidityExeMenu" + } Option "$ADVSNDMNU_REVERB", "timidity_reverb", "OnOff" Option "$ADVSNDMNU_TIMIDITYCHORUS", "timidity_chorus", "OnOff" Slider "$ADVSNDMNU_TIMIDITYVOLUME", "timidity_mastervolume", 0, 4, 0.2, 1 StaticText " " StaticText "$ADVSNDMNU_WILDMIDI", 1 TextField "$ADVSNDMNU_WILDMIDICONFIG", "wildmidi_config" + SubMenu "$ADVSNDMNU_SELCONFIG", "WildMidiConfigMenu" Option "$ADVSNDMNU_REVERB", "wildmidi_reverb", "OnOff" } +OptionMenu GusConfigMenu +{ + Title "$ADVSNDMNU_SELCONFIG" +} + +OptionMenu WildMidiConfigMenu +{ + Title "$ADVSNDMNU_SELCONFIG" +} + +OptionMenu TimidityExeMenu +{ + Title "$ADVSNDMNU_SELCONFIG" +} + +OptionMenu FluidPatchsetMenu +{ + Title "$ADVSNDMNU_SELCONFIG" +} + /*======================================= * * Module Replayer Options Menu diff --git a/wadsrc/static/zscript/menu/optionmenuitems.txt b/wadsrc/static/zscript/menu/optionmenuitems.txt index 04d2023a2..4ec0fcc6a 100644 --- a/wadsrc/static/zscript/menu/optionmenuitems.txt +++ b/wadsrc/static/zscript/menu/optionmenuitems.txt @@ -44,7 +44,7 @@ class OptionMenuItem : MenuItemBase mCentered = center; } - protected void drawLabel(int indent, int y, int color, bool grayed = false) + protected int drawLabel(int indent, int y, int color, bool grayed = false) { String label = Stringtable.Localize(mLabel); @@ -55,6 +55,7 @@ class OptionMenuItem : MenuItemBase if (!mCentered) x = indent - w; else x = (screen.GetWidth() - w) / 2; screen.DrawText (SmallFont, color, x, y, label, DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay); + return x; } int CursorSpace() @@ -92,16 +93,20 @@ class OptionMenuItem : MenuItemBase class OptionMenuItemSubmenu : OptionMenuItem { int mParam; - OptionMenuItemSubmenu Init(String label, Name command, int param = 0) + OptionMenuItemSubmenu Init(String label, Name command, int param = 0, bool centered = false) { - Super.init(label, command); + Super.init(label, command, centered); mParam = param; return self; } override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected) { - drawLabel(indent, y, selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColorMore); + int x = drawLabel(indent, y, selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColorMore); + if (mCentered) + { + return x - 16*CleanXfac_1; + } return indent; } @@ -121,9 +126,9 @@ class OptionMenuItemSubmenu : OptionMenuItem class OptionMenuItemCommand : OptionMenuItemSubmenu { - OptionMenuItemCommand Init(String label, Name command) + OptionMenuItemCommand Init(String label, Name command, bool centered = false) { - Super.Init(label, command); + Super.Init(label, command, 0, centered); return self; }