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; }