mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-11-29 07:32:25 +00:00
Several OpenAL improvements
- s_scaleDownAndClamp CVar so the clamping and scaling down of all sounds (that is done to prevent clipping) can be disabled (enabled by default) - s_alOutputLimiter CVar to allow configuring ALC_SOFT_output_limiter which (if enabled) reduces the overall volume if it gets too loud, to avoid clipping (defaults to -1 = "let OpenAL decide") - s_alHRTF to allow enabling or disabling HRTF, requires ALC_SOFT_HRTF (defaults to -1 = "let OpenAL decide") Those CVars can be changed at runtime and are applied immediately (in case of s_alHRTF and s_alOutputLimiter by resetting the OpenAL device, just like we do when a disconnect is detected)
This commit is contained in:
parent
7b6fdc845a
commit
2c58845d28
3 changed files with 164 additions and 22 deletions
|
@ -46,6 +46,38 @@ If you have questions concerning this license or the applicable additional terms
|
|||
typedef ALCboolean (ALC_APIENTRY*LPALCRESETDEVICESOFT)(ALCdevice *device, const ALCint *attribs);
|
||||
#endif
|
||||
|
||||
// DG: ALC_SOFT_output_mode is pretty new, provide compatibility..
|
||||
#ifndef ALC_SOFT_output_mode
|
||||
#define ALC_SOFT_output_mode
|
||||
#define ALC_OUTPUT_MODE_SOFT 0x19AC
|
||||
#define ALC_ANY_SOFT 0x19AD
|
||||
|
||||
#define ALC_STEREO_BASIC_SOFT 0x19AE
|
||||
#define ALC_STEREO_UHJ_SOFT 0x19AF
|
||||
#define ALC_STEREO_HRTF_SOFT 0x19B2
|
||||
|
||||
#define ALC_SURROUND_5_1_SOFT 0x1504
|
||||
#define ALC_SURROUND_6_1_SOFT 0x1505
|
||||
#define ALC_SURROUND_7_1_SOFT 0x1506
|
||||
#endif
|
||||
// the following formats are defined in https://openal-soft.org/openal-extensions/SOFT_output_mode.txt
|
||||
// but commented out in OpenAL Softs current AL/alext.h
|
||||
#ifndef ALC_MONO_SOFT
|
||||
#define ALC_MONO_SOFT 0x1500
|
||||
#endif
|
||||
#ifndef ALC_STEREO_SOFT
|
||||
#define ALC_STEREO_SOFT 0x1501
|
||||
#endif
|
||||
#ifndef ALC_QUAD_SOFT
|
||||
#define ALC_QUAD_SOFT 0x1503
|
||||
#endif
|
||||
|
||||
// DG: in case ALC_SOFT_output_limiter is not available in some headers..
|
||||
#ifndef ALC_SOFT_output_limiter
|
||||
#define ALC_SOFT_output_limiter
|
||||
#define ALC_OUTPUT_LIMITER_SOFT 0x199A
|
||||
#endif
|
||||
|
||||
#include "framework/UsercmdGen.h"
|
||||
#include "sound/efxlib.h"
|
||||
#include "sound/sound.h"
|
||||
|
@ -709,6 +741,9 @@ public:
|
|||
// otherwise it will try to recover the device and return false while it's gone
|
||||
// (display audio sound devices sometimes disappear for a few seconds when switching resolution)
|
||||
bool CheckDeviceAndRecoverIfNeeded();
|
||||
// resets the OpenAL device, applying the settings of s_alHRTF and s_alOutputLimiter
|
||||
// returns false if that failed, or the necessary OpenAL extension isn't available
|
||||
bool ResetALDevice();
|
||||
|
||||
idSoundCache * soundCache;
|
||||
|
||||
|
@ -767,6 +802,12 @@ public:
|
|||
// mark available during initialization, or through an explicit test
|
||||
static int EFXAvailable;
|
||||
|
||||
static bool alHRTFavailable; // needs ALC_SOFT_HRTF extension
|
||||
static bool alOutputLimiterAvailable; // needs ALC_SOFT_output_limiter extension (+ HRTF extension)
|
||||
static bool alEnumerateAllAvailable; // needs ALC_ENUMERATE_ALL_EXT
|
||||
static bool alIsDisconnectAvailable; // needs ALC_EXT_disconnect
|
||||
static bool alOutputModeAvailable; // needs ALC_SOFT_output_mode
|
||||
|
||||
// DG: for CheckDeviceAndRecoverIfNeeded()
|
||||
LPALCRESETDEVICESOFT alcResetDeviceSOFT; // needs ALC_SOFT_HRTF extension
|
||||
int resetRetryCount;
|
||||
|
@ -803,6 +844,10 @@ public:
|
|||
|
||||
static idCVar s_alReverbGain;
|
||||
|
||||
static idCVar s_scaleDownAndClamp;
|
||||
static idCVar s_alOutputLimiter;
|
||||
static idCVar s_alHRTF;
|
||||
|
||||
static idCVar s_slowAttenuate;
|
||||
|
||||
static idCVar s_enviroSuitCutoffFreq;
|
||||
|
|
|
@ -80,12 +80,53 @@ idCVar idSoundSystemLocal::s_decompressionLimit( "s_decompressionLimit", "6", CV
|
|||
|
||||
idCVar idSoundSystemLocal::s_alReverbGain( "s_alReverbGain", "0.5", CVAR_SOUND | CVAR_FLOAT | CVAR_ARCHIVE, "reduce reverb strength (0.0 to 1.0)", 0.0f, 1.0f );
|
||||
|
||||
idCVar idSoundSystemLocal::s_scaleDownAndClamp( "s_scaleDownAndClamp", "1", CVAR_SOUND | CVAR_BOOL | CVAR_ARCHIVE, "Clamp and reduce volume of all sounds to prevent clipping or temporary downscaling by OpenAL. When disabling this, you probably want to explicitly disable s_alOutputLimiter" );
|
||||
idCVar idSoundSystemLocal::s_alOutputLimiter( "s_alOutputLimiter", "-1", CVAR_SOUND | CVAR_INTEGER | CVAR_ARCHIVE, "Configure OpenAL's output-limiter. 0: Disable, 1: Enable, -1: Let OpenAL decide (default)" );
|
||||
idCVar idSoundSystemLocal::s_alHRTF( "s_alHRTF", "-1", CVAR_SOUND | CVAR_INTEGER | CVAR_ARCHIVE, "Enable HRTF for better surround sound with stereo *headphones*. 0: Disable, 1: Enable, -1: Let OpenAL decide (default)" );
|
||||
|
||||
bool idSoundSystemLocal::useEFXReverb = false;
|
||||
int idSoundSystemLocal::EFXAvailable = -1;
|
||||
|
||||
bool idSoundSystemLocal::alHRTFavailable = false;
|
||||
bool idSoundSystemLocal::alOutputLimiterAvailable = false;
|
||||
bool idSoundSystemLocal::alEnumerateAllAvailable = false;
|
||||
bool idSoundSystemLocal::alIsDisconnectAvailable = false;
|
||||
bool idSoundSystemLocal::alOutputModeAvailable = false;
|
||||
|
||||
|
||||
idSoundSystemLocal soundSystemLocal;
|
||||
idSoundSystem *soundSystem = &soundSystemLocal;
|
||||
|
||||
enum { D3_ALC_ATTRLIST_LEN = 6 }; // currently we set at most two setting-pairs + terminating 0, 0
|
||||
|
||||
static ALCint cvarToAlcBoolish( const idCVar& cvar )
|
||||
{
|
||||
int val = cvar.GetInteger();
|
||||
return (val < 0) ? ALC_DONT_CARE_SOFT : ( (val > 0) ? ALC_TRUE : ALC_FALSE );
|
||||
}
|
||||
|
||||
// initialize attrList for alcCreateContext() or alcResetDeviceSOFT(),
|
||||
// based on s_alHRTF and s_alOutputLimiter
|
||||
static void SetAlcAttrList( ALCint attrList[D3_ALC_ATTRLIST_LEN] )
|
||||
{
|
||||
int idx = 0;
|
||||
// ALC_HRTF_SOFT, ALC_TRUE // or ALC_FALSE or ALC_DONT_CARE_SOFT
|
||||
if ( idSoundSystemLocal::alHRTFavailable ) {
|
||||
attrList[idx++] = ALC_HRTF_SOFT;
|
||||
attrList[idx++] = cvarToAlcBoolish( idSoundSystemLocal::s_alHRTF );
|
||||
}
|
||||
// TODO: ALC_HRTF_ID_SOFT, index // to select an HRTF model?
|
||||
|
||||
// ALC_OUTPUT_LIMITER_SOFT, ALC_FALSE // or ALC_FALSE or ALC_DONT_CARE_SOFT
|
||||
if ( idSoundSystemLocal::alOutputLimiterAvailable ) {
|
||||
attrList[idx++] = ALC_OUTPUT_LIMITER_SOFT;
|
||||
attrList[idx++] = cvarToAlcBoolish( idSoundSystemLocal::s_alOutputLimiter );
|
||||
}
|
||||
// terminating 0, 0
|
||||
attrList[idx++] = 0;
|
||||
attrList[idx++] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SoundReloadSounds_f
|
||||
|
@ -347,7 +388,8 @@ void idSoundSystemLocal::Init() {
|
|||
else if (!idStr::Icmp(device, "default"))
|
||||
device = NULL;
|
||||
|
||||
if ( alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ) {
|
||||
alEnumerateAllAvailable = alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT");
|
||||
if ( alEnumerateAllAvailable ) {
|
||||
const char *devs = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
|
||||
bool found = false;
|
||||
|
||||
|
@ -381,7 +423,32 @@ void idSoundSystemLocal::Init() {
|
|||
common->Printf( "OpenAL: failed to open default device (0x%x), disabling sound\n", alGetError() );
|
||||
openalContext = NULL;
|
||||
} else {
|
||||
openalContext = alcCreateContext( openalDevice, NULL );
|
||||
// DG: extensions needed for CheckDeviceAndRecoverIfNeeded(), HRTF, output-limiter, the info in the settings menu, ...
|
||||
alHRTFavailable = alcIsExtensionPresent( openalDevice, "ALC_SOFT_HRTF" ) != AL_FALSE;
|
||||
alIsDisconnectAvailable = alcIsExtensionPresent( openalDevice, "ALC_EXT_disconnect" ) != AL_FALSE;
|
||||
if ( alHRTFavailable ) {
|
||||
common->Printf( "OpenAL: found extension for HRTF\n" );
|
||||
alcResetDeviceSOFT = (LPALCRESETDEVICESOFT)alcGetProcAddress( openalDevice, "alcResetDeviceSOFT" );
|
||||
if ( alIsDisconnectAvailable ) {
|
||||
common->Printf( "OpenAL: found extensions for resetting disconnected devices\n" );
|
||||
}
|
||||
alOutputLimiterAvailable = alcIsExtensionPresent( openalDevice, "ALC_SOFT_output_limiter" ) != AL_FALSE;
|
||||
if ( alOutputLimiterAvailable ) {
|
||||
common->Printf( "OpenAL: found extension to control output-limiter\n" );
|
||||
}
|
||||
} else {
|
||||
alOutputLimiterAvailable = false;
|
||||
alcResetDeviceSOFT = NULL;
|
||||
}
|
||||
alOutputModeAvailable = alcIsExtensionPresent( openalDevice, "ALC_SOFT_output_mode" );
|
||||
|
||||
ALCint attrList[D3_ALC_ATTRLIST_LEN] = {};
|
||||
SetAlcAttrList( attrList );
|
||||
|
||||
s_alHRTF.ClearModified();
|
||||
s_alOutputLimiter.ClearModified();
|
||||
|
||||
openalContext = alcCreateContext( openalDevice, attrList );
|
||||
if ( openalContext == NULL ) {
|
||||
common->Printf( "OpenAL: failed to create context (0x%x), disabling sound\n", alcGetError(openalDevice) );
|
||||
alcCloseDevice( openalDevice );
|
||||
|
@ -404,14 +471,6 @@ void idSoundSystemLocal::Init() {
|
|||
common->Printf( "OpenAL renderer: %s\n", alGetString(AL_RENDERER) );
|
||||
common->Printf( "OpenAL version: %s\n", alGetString(AL_VERSION) );
|
||||
|
||||
// DG: extensions needed for CheckDeviceAndRecoverIfNeeded()
|
||||
bool hasAlcExtDisconnect = alcIsExtensionPresent( openalDevice, "ALC_EXT_disconnect" ) != AL_FALSE;
|
||||
bool hasAlcSoftHrtf = alcIsExtensionPresent( openalDevice, "ALC_SOFT_HRTF" ) != AL_FALSE;
|
||||
if ( hasAlcExtDisconnect && hasAlcSoftHrtf ) {
|
||||
common->Printf( "OpenAL: found extensions for resetting disconnected devices\n" );
|
||||
alcResetDeviceSOFT = (LPALCRESETDEVICESOFT)alcGetProcAddress( openalDevice, "alcResetDeviceSOFT" );
|
||||
}
|
||||
|
||||
// try to obtain EFX extensions
|
||||
if (alcIsExtensionPresent(openalDevice, "ALC_EXT_EFX")) {
|
||||
common->Printf( "OpenAL: found EFX extension\n" );
|
||||
|
@ -599,6 +658,37 @@ bool idSoundSystemLocal::ShutdownHW() {
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idSoundSystemLocal::ResetALDevice
|
||||
|
||||
DG: resets the OpenAL device, applying the settings of s_alHRTF and s_alOutputLimiter
|
||||
returns false if that failed, or the necessary OpenAL extension isn't available
|
||||
===============
|
||||
*/
|
||||
bool idSoundSystemLocal::ResetALDevice()
|
||||
{
|
||||
s_alHRTF.ClearModified();
|
||||
s_alOutputLimiter.ClearModified();
|
||||
|
||||
if ( alcResetDeviceSOFT == NULL ) {
|
||||
common->Warning( "Can't reset OpenAL device, because OpenAL Extension (ALC_SOFT_HRTF) is missing!\nConsider using (a recent-ish version of) OpenAL-Soft!" );
|
||||
return false;
|
||||
}
|
||||
|
||||
ALCint attrList[D3_ALC_ATTRLIST_LEN] = {};
|
||||
SetAlcAttrList( attrList );
|
||||
|
||||
if ( alcResetDeviceSOFT( openalDevice, attrList ) ) {
|
||||
common->Printf( "OpenAL: resetting device succeeded!\n" );
|
||||
resetRetryCount = 0;
|
||||
return true;
|
||||
} else if ( resetRetryCount == 0 ) {
|
||||
common->Warning( "OpenAL: resetting device FAILED!\n" );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
|
@ -607,6 +697,8 @@ idSoundSystemLocal::CheckDeviceAndRecoverIfNeeded
|
|||
DG: returns true if openalDevice is still available,
|
||||
otherwise it will try to recover the device and return false while it's gone
|
||||
(display audio sound devices sometimes disappear for a few seconds when switching resolution)
|
||||
As this is called every frame, it now also checks if s_alHRTF or s_alOutputLimiter are
|
||||
modified and if they are, resets the device to apply the change
|
||||
===============
|
||||
*/
|
||||
bool idSoundSystemLocal::CheckDeviceAndRecoverIfNeeded()
|
||||
|
@ -617,6 +709,12 @@ bool idSoundSystemLocal::CheckDeviceAndRecoverIfNeeded()
|
|||
return true; // we can't check or reset, just pretend everything is fine..
|
||||
}
|
||||
|
||||
if ( s_alOutputLimiter.IsModified() || s_alHRTF.IsModified() ) {
|
||||
common->Printf( "%s is modified, trying to reset OpenAL device to apply that change\n",
|
||||
s_alOutputLimiter.IsModified() ? "s_alOutputLimiter" : "s_alHRTF" );
|
||||
return ResetALDevice();
|
||||
}
|
||||
|
||||
unsigned int curTime = Sys_Milliseconds();
|
||||
if ( curTime - lastCheckTime >= 1000 ) // check once per second
|
||||
{
|
||||
|
@ -643,9 +741,7 @@ bool idSoundSystemLocal::CheckDeviceAndRecoverIfNeeded()
|
|||
return false;
|
||||
}
|
||||
|
||||
if ( alcResetDeviceSOFT( openalDevice, NULL ) ) {
|
||||
common->Printf( "OpenAL: resetting device succeeded!\n" );
|
||||
resetRetryCount = 0;
|
||||
if ( ResetALDevice() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1799,7 +1799,7 @@ void idSoundWorldLocal::AddChannelContribution( idSoundEmitterLocal *sound, idSo
|
|||
// I guess this happens because the loud sounds mixed together are too loud so
|
||||
// OpenAL just makes *everything* quiter or sth like that.
|
||||
// See also https://github.com/dhewm/dhewm3/issues/179
|
||||
|
||||
if( soundSystemLocal.s_scaleDownAndClamp.GetBool() ) {
|
||||
// First clamp it to 1.0 - that's done anyway when setting AL_GAIN below,
|
||||
// for consistency it must be done before scaling, because many player-weapon
|
||||
// sounds have a too high volume defined and only sound right (relative to
|
||||
|
@ -1810,6 +1810,7 @@ void idSoundWorldLocal::AddChannelContribution( idSoundEmitterLocal *sound, idSo
|
|||
}
|
||||
|
||||
volume *= 0.333f; // (0.333 worked fine, 0.5 didn't)
|
||||
}
|
||||
|
||||
// global volume scale - DG: now done after clamping to 1.0, so reducing the
|
||||
// global volume doesn't cause the different weapon volume issues described above
|
||||
|
|
Loading…
Reference in a new issue