- 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.
This commit is contained in:
Christoph Oelckers 2015-04-26 12:13:21 +02:00
parent 8e70a9b894
commit aecff68a4d
6 changed files with 188 additions and 30 deletions

View file

@ -49,6 +49,7 @@
#include "i_music.h" #include "i_music.h"
#include "m_joy.h" #include "m_joy.h"
#include "gi.h" #include "gi.h"
#include "i_sound.h"
#include "optionmenuitems.h" #include "optionmenuitems.h"
@ -170,6 +171,14 @@ static bool CheckSkipOptionBlock(FScanner &sc)
filter = true; filter = true;
#endif #endif
} }
else if (sc.Compare("OpenAL"))
{
filter |= IsOpenALPresent();
}
else if (sc.Compare("FModEx"))
{
filter |= IsFModExPresent();
}
} }
while (sc.CheckString(",")); while (sc.CheckString(","));
sc.MustGetStringName(")"); sc.MustGetStringName(")");
@ -591,7 +600,11 @@ static void ParseOptionSettings(FScanner &sc)
while (!sc.CheckString("}")) while (!sc.CheckString("}"))
{ {
sc.MustGetString(); sc.MustGetString();
if (sc.Compare("ifgame")) if (sc.Compare("else"))
{
SkipSubBlock(sc);
}
else if (sc.Compare("ifgame"))
{ {
if (!CheckSkipGameBlock(sc)) if (!CheckSkipGameBlock(sc))
{ {
@ -628,7 +641,11 @@ static void ParseOptionMenuBody(FScanner &sc, FOptionMenuDescriptor *desc)
while (!sc.CheckString("}")) while (!sc.CheckString("}"))
{ {
sc.MustGetString(); sc.MustGetString();
if (sc.Compare("ifgame")) if (sc.Compare("else"))
{
SkipSubBlock(sc);
}
else if (sc.Compare("ifgame"))
{ {
if (!CheckSkipGameBlock(sc)) if (!CheckSkipGameBlock(sc))
{ {

View file

@ -671,14 +671,8 @@ bool FMODSoundRenderer::Init()
Printf("I_InitSound: Initializing FMOD\n"); Printf("I_InitSound: Initializing FMOD\n");
HMODULE a = GetModuleHandle("fmodex.dll"); // This is just for safety. Normally this should never be called if FMod Ex cannot be found.
if (!IsFModExPresent())
// Create a System object and initialize.
__try
{
result = FMOD::System_Create(&Sys);
}
__except(CheckException(GetExceptionCode()))
{ {
Sys = NULL; Sys = NULL;
Printf(TEXTCOLOR_ORANGE"Failed to load fmodex" Printf(TEXTCOLOR_ORANGE"Failed to load fmodex"
@ -688,6 +682,9 @@ bool FMODSoundRenderer::Init()
".dll\n"); ".dll\n");
return false; return false;
} }
// Create a System object and initialize.
result = FMOD::System_Create(&Sys);
if (result != FMOD_OK) if (result != FMOD_OK)
{ {
Sys = NULL; Sys = NULL;
@ -3177,3 +3174,44 @@ FMOD_RESULT FMODSoundRenderer::SetSystemReverbProperties(const REVERB_PROPERTIES
} }
#endif // NO_FMOD #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
}

View file

@ -83,13 +83,15 @@ CVAR (Int, snd_buffersize, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (String, snd_output, "default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (String, snd_output, "default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
#ifndef NO_FMOD #ifndef NO_FMOD
CVAR (String, snd_backend, "fmod", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) #define DEF_BACKEND "fmod"
#elif !defined(NO_OPENAL) #elif !defined(NO_OPENAL)
CVAR (String, snd_backend, "openal", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) #define DEF_BACKEND "openal"
#else #else
CVAR (String, snd_backend, "null", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) #define DEF_BACKEND "null"
#endif #endif
CVAR(String, snd_backend, DEF_BACKEND, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
// killough 2/21/98: optionally use varying pitched sounds // killough 2/21/98: optionally use varying pitched sounds
CVAR (Bool, snd_pitched, false, CVAR_ARCHIVE) CVAR (Bool, snd_pitched, false, CVAR_ARCHIVE)
@ -256,6 +258,7 @@ void I_InitSound ()
nosound = !!Args->CheckParm ("-nosound"); nosound = !!Args->CheckParm ("-nosound");
nosfx = !!Args->CheckParm ("-nosfx"); nosfx = !!Args->CheckParm ("-nosfx");
GSnd = NULL;
if (nosound) if (nosound)
{ {
GSnd = new NullSoundRenderer; GSnd = new NullSoundRenderer;
@ -263,16 +266,50 @@ void I_InitSound ()
return; return;
} }
// 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) if (stricmp(snd_backend, "null") == 0)
{
GSnd = new NullSoundRenderer; GSnd = new NullSoundRenderer;
#ifndef NO_FMOD }
else if(stricmp(snd_backend, "fmod") == 0) else if(stricmp(snd_backend, "fmod") == 0)
{
#ifndef NO_FMOD
if (IsFModExPresent())
{
GSnd = new FMODSoundRenderer; GSnd = new FMODSoundRenderer;
}
#endif #endif
#ifndef NO_OPENAL #ifndef NO_OPENAL
else if(stricmp(snd_backend, "openal") == 0) if ((!GSnd || !GSnd->IsValid()) && IsOpenALPresent())
{
Printf (TEXTCOLOR_RED"FMod Ex Sound init failed. Trying OpenAL.\n");
GSnd = new OpenALSoundRenderer; GSnd = new OpenALSoundRenderer;
snd_backend = "openal";
}
#endif #endif
}
else if(stricmp(snd_backend, "openal") == 0)
{
#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 ()) if (!GSnd || !GSnd->IsValid ())
{ {
I_CloseSound(); I_CloseSound();

View file

@ -175,4 +175,7 @@ FISoundChannel *S_GetChannel(void *syschan);
extern ReverbContainer *DefaultEnvironments[26]; extern ReverbContainer *DefaultEnvironments[26];
bool IsFModExPresent();
bool IsOpenALPresent();
#endif #endif

View file

@ -59,6 +59,36 @@ CVAR (String, snd_aldevice, "Default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, snd_efx, true, 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) void I_BuildALDeviceList(FOptionValues *opt)
{ {
opt->mValues.Resize(1); opt->mValues.Resize(1);
@ -66,7 +96,7 @@ void I_BuildALDeviceList(FOptionValues *opt)
opt->mValues[0].Text = "Default"; opt->mValues[0].Text = "Default";
#ifndef NO_OPENAL #ifndef NO_OPENAL
__try if (IsOpenALPresent())
{ {
const ALCchar *names = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ? const ALCchar *names = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ?
alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) : alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) :
@ -82,9 +112,6 @@ void I_BuildALDeviceList(FOptionValues *opt)
names += strlen(names) + 1; names += strlen(names) + 1;
} }
} }
__except (CheckException(GetExceptionCode()))
{
}
#endif #endif
} }
@ -601,7 +628,7 @@ static float GetRolloff(const FRolloffInfo *rolloff, float distance)
ALCdevice *OpenALSoundRenderer::InitDevice() ALCdevice *OpenALSoundRenderer::InitDevice()
{ {
ALCdevice *device = NULL; ALCdevice *device = NULL;
__try if (IsOpenALPresent())
{ {
if(strcmp(snd_aldevice, "Default") != 0) 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"); Printf(TEXTCOLOR_ORANGE"Failed to load openal32.dll\n");
} }

View file

@ -1450,11 +1450,22 @@ OptionString Resamplers
OptionString SoundBackends OptionString SoundBackends
{ {
"fmod", "FMOD" "fmod", "FMOD Ex"
"openal", "OpenAL" "openal", "OpenAL"
"null", "No Sound" "null", "No Sound"
} }
OptionString SoundBackendsFModOnly
{
"fmod", "FMOD Ex"
"null", "No Sound"
}
OptionString SoundBackendsOpenALOnly
{
"openal", "OpenAL"
"null", "No Sound"
}
OptionMenu FMODSoundItems OptionMenu FMODSoundItems
{ {
@ -1507,9 +1518,34 @@ OptionMenu SoundOptions
Option "Randomize pitches", "snd_pitched", "OnOff" Option "Randomize pitches", "snd_pitched", "OnOff"
Slider "Sound channels", "snd_channels", 8, 256, 8, 0 Slider "Sound channels", "snd_channels", 8, 256, 8, 0
StaticText " " StaticText " "
ifoption(fmodex)
{
ifoption(openal)
{
Option "Sound backend", "snd_backend", "SoundBackends" 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" Submenu "FMOD options", "FMODSoundItems"
}
ifoption(openal)
{
Submenu "OpenAL options", "OpenALSoundItems" Submenu "OpenAL options", "OpenALSoundItems"
}
StaticText " " StaticText " "
Command "Restart sound", "snd_reset" Command "Restart sound", "snd_reset"