You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

741 lines
23 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plEAXEffects - Various classes and wrappers to support EAX //
// acceleration. //
// //
//////////////////////////////////////////////////////////////////////////////
#include "HeadSpin.h"
#include "hsThread.h"
#ifndef EAX_SDK_AVAILABLE
#include "plEAXStructures.h"
#endif
#include "plEAXEffects.h"
#include "plAudioCore/plAudioCore.h"
#include "plDSoundBuffer.h"
#include "hsTemplates.h"
#include "plEAXListenerMod.h"
#include "hsStream.h"
#include "plAudioSystem.h"
#include <al.h>
#if HS_BUILD_FOR_WIN32
13 years ago
# if defined(DX_OLD_SDK) || defined(__MINGW32__)
# include <dxerr9.h>
# else
# include <dxerr.h>
# endif
#endif
#ifdef EAX_SDK_AVAILABLE
#include <eax.h>
#include <eax-util.h>
#include <eaxlegacy.h>
#endif
#include "plStatusLog/plStatusLog.h"
#define kDebugLog if( myLog != nil ) myLog->AddLineF(
#ifdef EAX_SDK_AVAILABLE
static EAXGet s_EAXGet;
static EAXSet s_EAXSet;
#endif
//// GetInstance /////////////////////////////////////////////////////////////
plEAXListener &plEAXListener::GetInstance( void )
{
static plEAXListener instance;
return instance;
}
//// Constructor/Destructor //////////////////////////////////////////////////
plEAXListener::plEAXListener()
{
fInited = false;
ClearProcessCache();
}
plEAXListener::~plEAXListener()
{
Shutdown();
}
//// Init ////////////////////////////////////////////////////////////////////
13 years ago
bool plEAXListener::Init( void )
{
#ifdef EAX_SDK_AVAILABLE
if( fInited )
return true;
if(!alIsExtensionPresent((ALchar *)"EAX4.0")) // is eax 4 supported
{
if(!alIsExtensionPresent((ALchar *) "EAX4.0Emulated")) // is an earlier version of eax supported
{
plStatusLog::AddLineS("audio.log", "EAX not supported");
return false;
}
else
{
plStatusLog::AddLineS("audio.log", "EAX 4 Emulated supported");
}
}
else
{
plStatusLog::AddLineS("audio.log", "EAX 4 available");
}
// EAX is supported
s_EAXGet = (EAXGet)alGetProcAddress((ALchar *)"EAXGet");
s_EAXSet = (EAXSet)alGetProcAddress((ALchar *)"EAXSet");
if(!s_EAXGet || ! s_EAXSet)
{
IFail( "EAX initialization failed", true );
return false;
}
fInited = true;
#if 1
try
{
// Make an EAX call here to prevent problems on WDM driver
unsigned int lRoom = -10000;
SetGlobalEAXProperty(DSPROPSETID_EAX_ListenerProperties, DSPROPERTY_EAXLISTENER_ROOM, &lRoom, sizeof( unsigned int ));
}
catch ( ... )
{
plStatusLog::AddLineS("audio.log", "Unable to set EAX Property Set, disabling EAX...");
plgAudioSys::EnableEAX(false);
return false;
}
#endif
ClearProcessCache();
return true;
#else /* !EAX_SDK_AVAILABLE */
plStatusLog::AddLineS("audio.log", "EAX disabled in this build");
return false;
#endif
}
//// Shutdown ////////////////////////////////////////////////////////////////
void plEAXListener::Shutdown( void )
{
if( !fInited )
return;
#ifdef EAX_SDK_AVAILABLE
s_EAXSet = nil;
s_EAXGet = nil;
#endif
IRelease();
}
bool plEAXListener::SetGlobalEAXProperty(GUID guid, unsigned long ulProperty, void *pData, unsigned long ulDataSize )
{
if(fInited)
{
#ifdef EAX_SDK_AVAILABLE
return s_EAXSet(&guid, ulProperty, 0, pData, ulDataSize) == AL_NO_ERROR;
#endif
}
return false;
}
bool plEAXListener::GetGlobalEAXProperty(GUID guid, unsigned long ulProperty, void *pData, unsigned long ulDataSize)
{
if(fInited)
{
#ifdef EAX_SDK_AVAILABLE
return s_EAXGet(&guid, ulProperty, 0, pData, ulDataSize) == AL_NO_ERROR;
#endif
}
return false;
}
bool plEAXSource::SetSourceEAXProperty(unsigned source, GUID guid, unsigned long ulProperty, void *pData, unsigned long ulDataSize)
{
#ifdef EAX_SDK_AVAILABLE
return s_EAXSet(&guid, ulProperty, source, pData, ulDataSize) == AL_NO_ERROR;
#else
return false;
#endif
}
bool plEAXSource::GetSourceEAXProperty(unsigned source, GUID guid, unsigned long ulProperty, void *pData, unsigned long ulDataSize)
{
#ifdef EAX_SDK_AVAILABLE
return s_EAXGet(&guid, ulProperty, source, pData, ulDataSize) == AL_NO_ERROR;
#else
return false;
#endif
}
//// IRelease ////////////////////////////////////////////////////////////////
void plEAXListener::IRelease( void )
{
fInited = false;
}
//// IFail ///////////////////////////////////////////////////////////////////
13 years ago
void plEAXListener::IFail( bool major )
{
plStatusLog::AddLineS( "audio.log", plStatusLog::kRed,
"ERROR in plEAXListener: Could not set global eax params");
if( major )
IRelease();
}
13 years ago
void plEAXListener::IFail( const char *msg, bool major )
{
plStatusLog::AddLineS( "audio.log", plStatusLog::kRed,
"ERROR in plEAXListener: %s", msg );
if( major )
IRelease();
}
//// IMuteProperties /////////////////////////////////////////////////////////
// Mutes the given properties, so if you have some props that you want
// half strength, this function will do it for ya.
void plEAXListener::IMuteProperties( EAXREVERBPROPERTIES *props, float percent )
{
// We only mute the room, roomHF and roomLF, since those control the overall effect
// application. All three are a direct linear blend as defined by eax-util.cpp, so
// this should be rather easy
float invPercent = 1.f - percent;
// The old way, as dictated by EAX sample code...
#ifdef EAX_SDK_AVAILABLE
props->lRoom = (int)( ( (float)EAXLISTENER_MINROOM * invPercent ) + ( (float)props->lRoom * percent ) );
#endif
// The new way, as suggested by EAX guys...
// props->lRoom = (int)( 2000.f * log( invPercent ) ) + props->lRoom;
// props->lRoomLF = (int)( ( (float)EAXLISTENER_MINROOMLF * invPercent ) + ( (float)props->lRoomLF * percent ) );
// props->lRoomHF = (int)( ( (float)EAXLISTENER_MINROOMHF * invPercent ) + ( (float)props->lRoomHF * percent ) );
}
//// ClearProcessCache ///////////////////////////////////////////////////////
// Clears the cache settings used to speed up ProcessMods(). Call whenever
// the list of mods changed.
void plEAXListener::ClearProcessCache( void )
{
fLastBigRegion = nil;
fLastModCount = -1;
fLastWasEmpty = false;
fLastSingleStrength = -1.f;
}
//// ProcessMods /////////////////////////////////////////////////////////////
// 9.13.02 mcn - Updated the caching method. Now fLastBigRegion will point
// to a region iff it's the only region from the last pass that had a
// strength > 0. The reason we can't do our trick before is because even if
// we have a region w/ strength 1, another region might power up from 1 and
// thus suddenly alter the total reverb settings. Thus, the only time we
// can wisely skip is if our current big region == fLastBigRegion *and*
// the total strength is the same.
void plEAXListener::ProcessMods( hsTArray<plEAXListenerMod *> &modArray )
{
#ifdef EAX_SDK_AVAILABLE
int i;
float totalStrength;
13 years ago
bool firstOne;
plEAXListenerMod *thisBigRegion = nil;
EAXLISTENERPROPERTIES finalProps;
static int oldTime = timeGetTime(); // Get starting time
int newTime;
13 years ago
bool bMorphing = false;
static plStatusLog *myLog = nil;
if( myLog == nil && plgAudioSys::AreExtendedLogsEnabled() )
myLog = plStatusLogMgr::GetInstance().CreateStatusLog( 30, "EAX Reverbs", plStatusLog::kFilledBackground | plStatusLog::kDeleteForMe | plStatusLog::kDontWriteFile );
else if( myLog != nil && !plgAudioSys::AreExtendedLogsEnabled() )
{
delete myLog;
myLog = nil;
}
if( myLog != nil )
myLog->Clear();
if( modArray.GetCount() != fLastModCount )
{
kDebugLog "Clearing cache..." );
ClearProcessCache(); // Code path changed, clear the entire cache
fLastModCount = modArray.GetCount();
}
else
{
kDebugLog "" );
}
if( modArray.GetCount() > 0 )
{
kDebugLog "%d regions to calc", modArray.GetCount() );
// Reset and find a new one if applicable
thisBigRegion = nil;
// Accumulate settings from all the active listener regions (shouldn't be too many, we hope)
totalStrength = 0.f;
firstOne = true;
for( i = 0; i < modArray.GetCount(); i++ )
{
float strength = modArray[ i ]->GetStrength();
kDebugLog "%4.2f - %s", strength, modArray[ i ]->GetKey()->GetUoid().GetObjectName() );
if( strength > 0.f )
{
// fLastBigRegion will point to a region iff it's the only region w/ strength > 0
if( totalStrength == 0.f )
thisBigRegion = modArray[ i ];
else
thisBigRegion = nil;
if( firstOne )
{
// First one, just init to it
memcpy( &finalProps, modArray[ i ]->GetListenerProps(), sizeof( finalProps ) );
totalStrength = strength;
firstOne = false;
}
else
{
float scale = strength / ( totalStrength + strength );
EAX3ListenerInterpolate( &finalProps, modArray[ i ]->GetListenerProps(), scale, &finalProps, false );
totalStrength += strength;
bMorphing = true;
}
if( totalStrength >= 1.f )
break;
}
}
if( firstOne )
{
// No regions of strength > 0, so just make it quiet
kDebugLog "Reverb should be quiet" );
if( fLastWasEmpty )
return;
memcpy( &finalProps, &EAX30_ORIGINAL_PRESETS[ ORIGINAL_GENERIC ], sizeof( EAXLISTENERPROPERTIES ) );
finalProps.lRoom = EAXLISTENER_MINROOM;
// finalProps.lRoomLF = EAXLISTENER_MINROOMLF;
// finalProps.lRoomHF = EAXLISTENER_MINROOMHF;
fLastWasEmpty = true;
fLastBigRegion = nil;
fLastSingleStrength = -1.f;
}
else
{
fLastWasEmpty = false;
if( thisBigRegion == fLastBigRegion && totalStrength == fLastSingleStrength )
// Cached values should be the same, so we can bail at this point
return;
fLastBigRegion = thisBigRegion;
fLastSingleStrength = ( thisBigRegion != nil ) ? totalStrength : -1.f;
if( totalStrength < 1.f )
{
kDebugLog "Total strength < 1; muting result" );
// All of them together is less than full strength, so mute our result
IMuteProperties( &finalProps, totalStrength );
}
}
}
else
{
kDebugLog "No regions at all; disabling reverb" );
// No regions whatsoever, so disable listener props entirely
if( fLastWasEmpty )
return;
memcpy( &finalProps, &EAX30_ORIGINAL_PRESETS[ ORIGINAL_GENERIC ], sizeof( EAXLISTENERPROPERTIES ) );
finalProps.lRoom = EAXLISTENER_MINROOM;
// finalProps.lRoomLF = EAXLISTENER_MINROOMLF;
// finalProps.lRoomHF = EAXLISTENER_MINROOMHF;
fLastWasEmpty = true;
}
// if were morphing between regions, do 10th of a second check, otherwise just let it
// change due to opt out(caching) feature.
if(bMorphing)
{
newTime = timeGetTime();
// Update, at most, ten times per second
if((newTime - oldTime) < 100) return;
oldTime = newTime; // update time
}
//finalProps.flAirAbsorptionHF *= 0.3048f; // Convert to feet
//kDebugLog "** Updating property set **" );
if(!SetGlobalEAXProperty(DSPROPSETID_EAX_ListenerProperties, DSPROPERTY_EAXLISTENER_ALLPARAMETERS, &finalProps, sizeof( finalProps )))
{
IFail( false );
}
#endif /* EAX_SDK_AVAILABLE */
}
//////////////////////////////////////////////////////////////////////////////
//// Source Settings /////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//// Constructor/Destructor //////////////////////////////////////////////////
plEAXSourceSettings::plEAXSourceSettings()
{
fDirtyParams = kAll;
Enable( false );
}
plEAXSourceSettings::~plEAXSourceSettings()
{
}
//// Read/Write/Set //////////////////////////////////////////////////////////
void plEAXSourceSettings::Read( hsStream *s )
{
fEnabled = s->ReadBool();
if( fEnabled )
{
fRoom = s->ReadLE16();
fRoomHF = s->ReadLE16();
fRoomAuto = s->ReadBool();
fRoomHFAuto = s->ReadBool();
fOutsideVolHF = s->ReadLE16();
fAirAbsorptionFactor = s->ReadLEFloat();
fRoomRolloffFactor = s->ReadLEFloat();
fDopplerFactor = s->ReadLEFloat();
fRolloffFactor = s->ReadLEFloat();
fSoftStarts.Read( s );
fSoftEnds.Read( s );
fOcclusionSoftValue = -1.f;
SetOcclusionSoftValue( s->ReadLEFloat() );
fDirtyParams = kAll;
}
else
Enable( false ); // Force init of params
}
void plEAXSourceSettings::Write( hsStream *s )
{
s->WriteBool( fEnabled );
if( fEnabled )
{
s->WriteLE16( fRoom );
s->WriteLE16( fRoomHF );
s->WriteBool( fRoomAuto );
s->WriteBool( fRoomHFAuto );
s->WriteLE16( fOutsideVolHF );
s->WriteLEFloat( fAirAbsorptionFactor );
s->WriteLEFloat( fRoomRolloffFactor );
s->WriteLEFloat( fDopplerFactor );
s->WriteLEFloat( fRolloffFactor );
fSoftStarts.Write( s );
fSoftEnds.Write( s );
s->WriteLEFloat( fOcclusionSoftValue );
}
}
13 years ago
void plEAXSourceSettings::SetRoomParams( int16_t room, int16_t roomHF, bool roomAuto, bool roomHFAuto )
{
fRoom = room;
fRoomHF = roomHF;
fRoomAuto = roomAuto;
fRoomHFAuto = roomHFAuto;
fDirtyParams |= kRoom;
}
13 years ago
void plEAXSourceSettings::Enable( bool e )
{
fEnabled = e;
if( !e )
{
#ifdef EAX_SDK_AVAILABLE
fRoom = EAXBUFFER_MINROOM;
fRoomHF = EAXBUFFER_MINROOMHF;
#else
fRoom = 0;
fRoomHF = 0;
#endif
fRoomAuto = true;
fRoomHFAuto = true;
fOutsideVolHF = 0;
fAirAbsorptionFactor = 1.f;
fRoomRolloffFactor = 0.f;
fDopplerFactor = 0.f;
fRolloffFactor = 0.f;
fOcclusionSoftValue = 0.f;
fSoftStarts.Reset();
fSoftEnds.Reset();
fCurrSoftValues.Reset();
fDirtyParams = kAll;
}
}
void plEAXSourceSettings::SetOutsideVolHF( int16_t vol )
{
fOutsideVolHF = vol;
fDirtyParams |= kOutsideVolHF;
}
void plEAXSourceSettings::SetFactors( float airAbsorption, float roomRolloff, float doppler, float rolloff )
{
fAirAbsorptionFactor = airAbsorption;
fRoomRolloffFactor = roomRolloff;
fDopplerFactor = doppler;
fRolloffFactor = rolloff;
fDirtyParams |= kFactors;
}
void plEAXSourceSettings::SetOcclusionSoftValue( float value )
{
if( fOcclusionSoftValue != value )
{
fOcclusionSoftValue = value;
IRecalcSofts( kOcclusion );
fDirtyParams |= kOcclusion;
}
}
void plEAXSourceSettings::IRecalcSofts( uint8_t whichOnes )
{
float percent, invPercent;
if( whichOnes & kOcclusion )
{
percent = fOcclusionSoftValue;
invPercent = 1.f - percent;
int16_t occ = (int16_t)( ( (float)fSoftStarts.GetOcclusion() * invPercent ) + ( (float)fSoftEnds.GetOcclusion() * percent ) );
float lfRatio = (float)( ( fSoftStarts.GetOcclusionLFRatio() * invPercent ) + ( fSoftEnds.GetOcclusionLFRatio() * percent ) );
float roomRatio = (float)( ( fSoftStarts.GetOcclusionRoomRatio() * invPercent ) + ( fSoftEnds.GetOcclusionRoomRatio() * percent ) );
float directRatio = (float)( ( fSoftStarts.GetOcclusionDirectRatio() * invPercent ) + ( fSoftEnds.GetOcclusionDirectRatio() * percent ) );
fCurrSoftValues.SetOcclusion( occ, lfRatio, roomRatio, directRatio );
}
}
//////////////////////////////////////////////////////////////////////////////
//// Source Soft Settings ////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
void plEAXSourceSoftSettings::Reset( void )
{
fOcclusion = 0;
fOcclusionLFRatio = 0.25f;
fOcclusionRoomRatio = 1.5f;
fOcclusionDirectRatio = 1.f;
}
void plEAXSourceSoftSettings::Read( hsStream *s )
{
s->ReadLE( &fOcclusion );
s->ReadLE( &fOcclusionLFRatio );
s->ReadLE( &fOcclusionRoomRatio );
s->ReadLE( &fOcclusionDirectRatio );
}
void plEAXSourceSoftSettings::Write( hsStream *s )
{
s->WriteLE( fOcclusion );
s->WriteLE( fOcclusionLFRatio );
s->WriteLE( fOcclusionRoomRatio );
s->WriteLE( fOcclusionDirectRatio );
}
void plEAXSourceSoftSettings::SetOcclusion( int16_t occ, float lfRatio, float roomRatio, float directRatio )
{
fOcclusion = occ;
fOcclusionLFRatio = lfRatio;
fOcclusionRoomRatio = roomRatio;
fOcclusionDirectRatio = directRatio;
}
//// Constructor/Destructor //////////////////////////////////////////////////
plEAXSource::plEAXSource()
{
fInit = false;
}
plEAXSource::~plEAXSource()
{
Release();
}
//// Init/Release ////////////////////////////////////////////////////////////
void plEAXSource::Init( plDSoundBuffer *parent )
{
fInit = true;
// Init some default params
plEAXSourceSettings defaultParams;
SetFrom( &defaultParams, parent->GetSource() );
}
void plEAXSource::Release( void )
{
fInit = false;
}
13 years ago
bool plEAXSource::IsValid( void ) const
{
return true;
}
//// SetFrom /////////////////////////////////////////////////////////////////
13 years ago
void plEAXSource::SetFrom( plEAXSourceSettings *settings, unsigned source, bool force )
{
uint32_t dirtyParams;
if(source == 0 || !fInit)
return;
if( force )
dirtyParams = plEAXSourceSettings::kAll;
else
dirtyParams = settings->fDirtyParams;
// Do the params
#ifdef EAX_SDK_AVAILABLE
if( dirtyParams & plEAXSourceSettings::kRoom )
{
SetSourceEAXProperty(source, DSPROPSETID_EAX_BufferProperties, DSPROPERTY_EAXBUFFER_ROOM, &settings->fRoom, sizeof(settings->fRoom));
SetSourceEAXProperty(source, DSPROPSETID_EAX_BufferProperties, DSPROPERTY_EAXBUFFER_ROOMHF, &settings->fRoomHF, sizeof(settings->fRoomHF));
}
if( dirtyParams & plEAXSourceSettings::kOutsideVolHF )
{
SetSourceEAXProperty(source, DSPROPSETID_EAX_BufferProperties, DSPROPERTY_EAXBUFFER_OUTSIDEVOLUMEHF, &settings->fOutsideVolHF, sizeof(settings->fOutsideVolHF));
}
if( dirtyParams & plEAXSourceSettings::kFactors )
{
SetSourceEAXProperty(source, DSPROPSETID_EAX_BufferProperties, DSPROPERTY_EAXBUFFER_DOPPLERFACTOR, &settings->fDopplerFactor, sizeof(settings->fDopplerFactor));
SetSourceEAXProperty(source, DSPROPSETID_EAX_BufferProperties, DSPROPERTY_EAXBUFFER_ROLLOFFFACTOR, &settings->fRolloffFactor, sizeof(settings->fRolloffFactor));
SetSourceEAXProperty(source, DSPROPSETID_EAX_BufferProperties, DSPROPERTY_EAXBUFFER_ROOMROLLOFFFACTOR, &settings->fRoomRolloffFactor, sizeof(settings->fRoomRolloffFactor));
SetSourceEAXProperty(source, DSPROPSETID_EAX_BufferProperties, DSPROPERTY_EAXBUFFER_AIRABSORPTIONFACTOR, &settings->fAirAbsorptionFactor, sizeof(settings->fAirAbsorptionFactor));
}
if( dirtyParams & plEAXSourceSettings::kOcclusion )
{
SetSourceEAXProperty(source, DSPROPSETID_EAX_BufferProperties, DSPROPERTY_EAXBUFFER_OCCLUSION, &settings->GetCurrSofts().fOcclusion, sizeof(settings->GetCurrSofts().fOcclusion));
SetSourceEAXProperty(source, DSPROPSETID_EAX_BufferProperties, DSPROPERTY_EAXBUFFER_OCCLUSIONLFRATIO, &settings->GetCurrSofts().fOcclusionLFRatio, sizeof(settings->GetCurrSofts().fOcclusionLFRatio));
SetSourceEAXProperty(source, DSPROPSETID_EAX_BufferProperties, DSPROPERTY_EAXBUFFER_OCCLUSIONROOMRATIO, &settings->GetCurrSofts().fOcclusionRoomRatio, sizeof(settings->GetCurrSofts().fOcclusionRoomRatio));
SetSourceEAXProperty(source, DSPROPSETID_EAX_BufferProperties, DSPROPERTY_EAXBUFFER_OCCLUSIONDIRECTRATIO, &settings->GetCurrSofts().fOcclusionDirectRatio, sizeof(settings->GetCurrSofts().fOcclusionDirectRatio));
}
#endif /* EAX_SDK_AVAILABLE */
settings->ClearDirtyParams();
// Do all the flags in one pass
#ifdef EAX_SDK_AVAILABLE
DWORD flags;
if( GetSourceEAXProperty( source, DSPROPSETID_EAX_BufferProperties, DSPROPERTY_EAXBUFFER_FLAGS, &flags, sizeof( DWORD )) )
{
if( settings->GetRoomAuto() )
flags |= EAXBUFFERFLAGS_ROOMAUTO;
else
flags &= ~EAXBUFFERFLAGS_ROOMAUTO;
if( settings->GetRoomHFAuto() )
flags |= EAXBUFFERFLAGS_ROOMHFAUTO;
else
flags &= ~EAXBUFFERFLAGS_ROOMHFAUTO;
if( SetSourceEAXProperty( source, DSPROPSETID_EAX_BufferProperties, DSPROPERTY_EAXBUFFER_FLAGS, &flags, sizeof( DWORD ) ) )
{
return; // All worked, return here
}
// Flag setting failed somehow
hsAssert( false, "Unable to set EAX buffer flags" );
}
#endif /* EAX_SDK_AVAILABLE */
}