From aecff68a4d78154ac5f9a48b12fed79716f204f0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Apr 2015 12:13:21 +0200 Subject: [PATCH] - cleanup of sound system startup and menu handling: * added global functions that check whether FMod and OpenAL are present, without initializing the sound backend. * make sound init code more fault tolerant. It will now try to switch between FMod and OpenAL if the currently active one cannot be found but the other one can. * added 'ifoption' checks for sound backend to menu code. * only show sound backends which are present and hide the options for the ones which are not. --- src/menu/menudef.cpp | 21 +++++++++++++-- src/sound/fmodsound.cpp | 54 +++++++++++++++++++++++++++++++------ src/sound/i_sound.cpp | 57 ++++++++++++++++++++++++++++++++------- src/sound/i_sound.h | 3 +++ src/sound/oalsound.cpp | 39 ++++++++++++++++++++++----- wadsrc/static/menudef.txt | 44 +++++++++++++++++++++++++++--- 6 files changed, 188 insertions(+), 30 deletions(-) diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index b1db3cf2e..819ba96ba 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -49,6 +49,7 @@ #include "i_music.h" #include "m_joy.h" #include "gi.h" +#include "i_sound.h" #include "optionmenuitems.h" @@ -170,6 +171,14 @@ static bool CheckSkipOptionBlock(FScanner &sc) filter = true; #endif } + else if (sc.Compare("OpenAL")) + { + filter |= IsOpenALPresent(); + } + else if (sc.Compare("FModEx")) + { + filter |= IsFModExPresent(); + } } while (sc.CheckString(",")); sc.MustGetStringName(")"); @@ -591,7 +600,11 @@ static void ParseOptionSettings(FScanner &sc) while (!sc.CheckString("}")) { sc.MustGetString(); - if (sc.Compare("ifgame")) + if (sc.Compare("else")) + { + SkipSubBlock(sc); + } + else if (sc.Compare("ifgame")) { if (!CheckSkipGameBlock(sc)) { @@ -628,7 +641,11 @@ static void ParseOptionMenuBody(FScanner &sc, FOptionMenuDescriptor *desc) while (!sc.CheckString("}")) { sc.MustGetString(); - if (sc.Compare("ifgame")) + if (sc.Compare("else")) + { + SkipSubBlock(sc); + } + else if (sc.Compare("ifgame")) { if (!CheckSkipGameBlock(sc)) { diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 9559e2b70..73e419555 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -671,14 +671,8 @@ bool FMODSoundRenderer::Init() Printf("I_InitSound: Initializing FMOD\n"); - HMODULE a = GetModuleHandle("fmodex.dll"); - - // Create a System object and initialize. - __try - { - result = FMOD::System_Create(&Sys); - } - __except(CheckException(GetExceptionCode())) + // This is just for safety. Normally this should never be called if FMod Ex cannot be found. + if (!IsFModExPresent()) { Sys = NULL; Printf(TEXTCOLOR_ORANGE"Failed to load fmodex" @@ -688,6 +682,9 @@ bool FMODSoundRenderer::Init() ".dll\n"); return false; } + + // Create a System object and initialize. + result = FMOD::System_Create(&Sys); if (result != FMOD_OK) { Sys = NULL; @@ -3177,3 +3174,44 @@ FMOD_RESULT FMODSoundRenderer::SetSystemReverbProperties(const REVERB_PROPERTIES } #endif // NO_FMOD + + +//========================================================================== +// +// IsFModExPresent +// +// Check if FMod can be used +// +//========================================================================== + +bool IsFModExPresent() +{ +#ifdef NO_FMOD + return false; +#elif !defined _WIN32 + return true; // on non-Windows we cannot delay load the library so it has to be present. +#else + static bool cached_result; + static bool done = false; + + if (!done) + { + done = true; + + FMOD::System *Sys; + FMOD_RESULT result; + __try + { + result = FMOD::System_Create(&Sys); + } + __except (CheckException(GetExceptionCode())) + { + // FMod could not be delay loaded + return false; + } + if (result == FMOD_OK) Sys->release(); + cached_result = true; + } + return cached_result; +#endif +} diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index 04643dcba..0a14adc29 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -83,13 +83,15 @@ CVAR (Int, snd_buffersize, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (String, snd_output, "default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) #ifndef NO_FMOD -CVAR (String, snd_backend, "fmod", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +#define DEF_BACKEND "fmod" #elif !defined(NO_OPENAL) -CVAR (String, snd_backend, "openal", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +#define DEF_BACKEND "openal" #else -CVAR (String, snd_backend, "null", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +#define DEF_BACKEND "null" #endif +CVAR(String, snd_backend, DEF_BACKEND, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) + // killough 2/21/98: optionally use varying pitched sounds CVAR (Bool, snd_pitched, false, CVAR_ARCHIVE) @@ -256,6 +258,7 @@ void I_InitSound () nosound = !!Args->CheckParm ("-nosound"); nosfx = !!Args->CheckParm ("-nosfx"); + GSnd = NULL; if (nosound) { GSnd = new NullSoundRenderer; @@ -263,16 +266,50 @@ void I_InitSound () return; } - if(stricmp(snd_backend, "null") == 0) + // This has been extended to allow falling back from FMod to OpenAL and vice versa if the currently active sound system cannot be found. + if (stricmp(snd_backend, "null") == 0) + { GSnd = new NullSoundRenderer; -#ifndef NO_FMOD + } else if(stricmp(snd_backend, "fmod") == 0) - GSnd = new FMODSoundRenderer; -#endif -#ifndef NO_OPENAL + { + #ifndef NO_FMOD + if (IsFModExPresent()) + { + GSnd = new FMODSoundRenderer; + } + #endif + #ifndef NO_OPENAL + if ((!GSnd || !GSnd->IsValid()) && IsOpenALPresent()) + { + Printf (TEXTCOLOR_RED"FMod Ex Sound init failed. Trying OpenAL.\n"); + GSnd = new OpenALSoundRenderer; + snd_backend = "openal"; + } + #endif + } else if(stricmp(snd_backend, "openal") == 0) - GSnd = new OpenALSoundRenderer; -#endif + { + #ifndef NO_OPENAL + if (IsOpenALPresent()) + { + GSnd = new OpenALSoundRenderer; + } + #endif + #ifndef NO_FMOD + if ((!GSnd || !GSnd->IsValid()) && IsFModExPresent()) + { + Printf (TEXTCOLOR_RED"OpenAL Sound init failed. Trying FMod Ex.\n"); + GSnd = new FMODSoundRenderer; + snd_backend = "fmod"; + } + #endif + } + else + { + Printf (TEXTCOLOR_RED"%s: Unknown sound system specified\n", *snd_backend); + snd_backend = "null"; + } if (!GSnd || !GSnd->IsValid ()) { I_CloseSound(); diff --git a/src/sound/i_sound.h b/src/sound/i_sound.h index cf60e5464..153fe3863 100644 --- a/src/sound/i_sound.h +++ b/src/sound/i_sound.h @@ -175,4 +175,7 @@ FISoundChannel *S_GetChannel(void *syschan); extern ReverbContainer *DefaultEnvironments[26]; +bool IsFModExPresent(); +bool IsOpenALPresent(); + #endif diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 5745f9798..6d7cb210e 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -59,6 +59,36 @@ CVAR (String, snd_aldevice, "Default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, snd_efx, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +bool IsOpenALPresent() +{ +#ifdef NO_OPENAL + return false; +#elif !defined _WIN32 + return true; // on non-Windows we cannot delay load the library so it has to be present. +#else + static bool cached_result; + static bool done = false; + + if (!done) + { + done = true; + + __try + { + // just call one function from the API to force loading the DLL + alcGetError(NULL); + } + __except (CheckException(GetExceptionCode())) + { + // FMod could not be delay loaded + return false; + } + cached_result = true; + } + return cached_result; +#endif +} + void I_BuildALDeviceList(FOptionValues *opt) { opt->mValues.Resize(1); @@ -66,7 +96,7 @@ void I_BuildALDeviceList(FOptionValues *opt) opt->mValues[0].Text = "Default"; #ifndef NO_OPENAL - __try + if (IsOpenALPresent()) { const ALCchar *names = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ? alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) : @@ -82,9 +112,6 @@ void I_BuildALDeviceList(FOptionValues *opt) names += strlen(names) + 1; } } - __except (CheckException(GetExceptionCode())) - { - } #endif } @@ -601,7 +628,7 @@ static float GetRolloff(const FRolloffInfo *rolloff, float distance) ALCdevice *OpenALSoundRenderer::InitDevice() { ALCdevice *device = NULL; - __try + if (IsOpenALPresent()) { if(strcmp(snd_aldevice, "Default") != 0) { @@ -619,7 +646,7 @@ ALCdevice *OpenALSoundRenderer::InitDevice() } } } - __except(CheckException(GetExceptionCode())) + else { Printf(TEXTCOLOR_ORANGE"Failed to load openal32.dll\n"); } diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index c7ce861d5..f15f91dff 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1450,11 +1450,22 @@ OptionString Resamplers OptionString SoundBackends { - "fmod", "FMOD" + "fmod", "FMOD Ex" "openal", "OpenAL" "null", "No Sound" } +OptionString SoundBackendsFModOnly +{ + "fmod", "FMOD Ex" + "null", "No Sound" +} + +OptionString SoundBackendsOpenALOnly +{ + "openal", "OpenAL" + "null", "No Sound" +} OptionMenu FMODSoundItems { @@ -1507,9 +1518,34 @@ OptionMenu SoundOptions Option "Randomize pitches", "snd_pitched", "OnOff" Slider "Sound channels", "snd_channels", 8, 256, 8, 0 StaticText " " - Option "Sound backend", "snd_backend", "SoundBackends" - Submenu "FMOD options", "FMODSoundItems" - Submenu "OpenAL options", "OpenALSoundItems" + + ifoption(fmodex) + { + ifoption(openal) + { + Option "Sound backend", "snd_backend", "SoundBackends" + } + else + { + Option "Sound backend", "snd_backend", "SoundBackendsFModOnly" + } + } + else + { + ifoption(openal) + { + Option "Sound backend", "snd_backend", "SoundBackendsOpenALOnly" + } + } + + ifoption(fmodex) + { + Submenu "FMOD options", "FMODSoundItems" + } + ifoption(openal) + { + Submenu "OpenAL options", "OpenALSoundItems" + } StaticText " " Command "Restart sound", "snd_reset"