- Explicitly set distance attenuation model.

- Mute sounds that exceed a certain distance from the listener.
This commit is contained in:
Thilo Schulz 2006-11-03 08:22:38 +00:00
parent 90208be35a
commit b57a970034
2 changed files with 137 additions and 64 deletions

4
README
View file

@ -116,8 +116,12 @@ New cvars
s_alDopplerSpeed - the value passed to alDopplerVelocity
s_alMinDistance - the value of AL_REFERENCE_DISTANCE for
each source
s_alMaxDistance - the maximum distance before sounds start
to become inaudible.
s_alRolloff - the value of AL_ROLLOFF_FACTOR for each
source
s_alGraceDistance - after having passed MaxDistance, length
until sounds are completely inaudible.
s_alMaxSpeakerDistance - ET_SPEAKERS beyond this distance are
culled
s_alDriver - which OpenAL library to use

View file

@ -36,7 +36,9 @@ cvar_t *s_alSources;
cvar_t *s_alDopplerFactor;
cvar_t *s_alDopplerSpeed;
cvar_t *s_alMinDistance;
cvar_t *s_alMaxDistance;
cvar_t *s_alRolloff;
cvar_t *s_alGraceDistance;
cvar_t *s_alDriver;
cvar_t *s_alDevice;
cvar_t *s_alAvailableDevices;
@ -464,6 +466,9 @@ typedef struct src_s
int isLooping; // Is this a looping effect (attached to an entity)
int isTracking; // Is this object tracking it's owner
float curGain; // gain employed if source is within maxdistance.
float scaleGain; // Last gain value for this source. 0 if muted.
qboolean local; // Is this local (relative to the cam)
} src_t;
@ -511,6 +516,50 @@ static void _S_AL_SanitiseVector( vec3_t v, int line )
#define AL_THIRD_PERSON_THRESHOLD_SQ (48.0f*48.0f)
/*
=================
S_AL_ScaleGain
Adapt the gain if necessary to get a quicker fadeout when the source is too far away.
=================
*/
static void S_AL_ScaleGain(src_t *chksrc, vec3_t origin)
{
float distance;
if(chksrc->local)
distance = VectorLength(origin);
else
distance = Distance(origin, lastListenerOrigin);
// If we exceed a certain distance, scale the gain linearly until the sound
// vanishes into nothingness.
if((distance -= s_alMaxDistance->value) > 0)
{
float scaleFactor;
if(distance >= s_alGraceDistance->value)
scaleFactor = 0.0f;
else
scaleFactor = 1.0f - distance / s_alGraceDistance->value;
scaleFactor *= chksrc->curGain;
if(chksrc->scaleGain != scaleFactor);
{
chksrc->scaleGain = scaleFactor;
// if(scaleFactor > 0.0f)
// Com_Printf("%f\n", scaleFactor);
qalSourcef(chksrc->alSource, AL_GAIN, chksrc->scaleGain);
}
}
else if(chksrc->scaleGain != chksrc->curGain)
{
chksrc->scaleGain = chksrc->curGain;
qalSourcef(chksrc->alSource, AL_GAIN, chksrc->scaleGain);
}
}
/*
=================
S_AL_HearingThroughEntity
@ -616,41 +665,46 @@ static void S_AL_SrcSetup(srcHandle_t src, sfxHandle_t sfx, alSrcPriority_t prio
int entity, int channel, qboolean local)
{
ALuint buffer;
src_t *curSource;
// Mark the SFX as used, and grab the raw AL buffer
S_AL_BufferUse(sfx);
buffer = S_AL_BufferGet(sfx);
// Set up src struct
srcList[src].lastUsedTime = Sys_Milliseconds();
srcList[src].sfx = sfx;
srcList[src].priority = priority;
srcList[src].entity = entity;
srcList[src].channel = channel;
srcList[src].isActive = qtrue;
srcList[src].isLocked = qfalse;
srcList[src].isLooping = qfalse;
srcList[src].isTracking = qfalse;
srcList[src].local = local;
curSource = &srcList[src];
curSource->lastUsedTime = Sys_Milliseconds();
curSource->sfx = sfx;
curSource->priority = priority;
curSource->entity = entity;
curSource->channel = channel;
curSource->isActive = qtrue;
curSource->isLocked = qfalse;
curSource->isLooping = qfalse;
curSource->isTracking = qfalse;
curSource->curGain = s_alGain->value * s_volume->value;
curSource->scaleGain = curSource->curGain;
curSource->local = local;
// Set up OpenAL source
qalSourcei(srcList[src].alSource, AL_BUFFER, buffer);
qalSourcef(srcList[src].alSource, AL_PITCH, 1.0f);
qalSourcef(srcList[src].alSource, AL_GAIN, s_alGain->value * s_volume->value);
qalSourcefv(srcList[src].alSource, AL_POSITION, vec3_origin);
qalSourcefv(srcList[src].alSource, AL_VELOCITY, vec3_origin);
qalSourcei(srcList[src].alSource, AL_LOOPING, AL_FALSE);
qalSourcef(srcList[src].alSource, AL_REFERENCE_DISTANCE, s_alMinDistance->value);
qalSourcei(curSource->alSource, AL_BUFFER, buffer);
qalSourcef(curSource->alSource, AL_PITCH, 1.0f);
qalSourcef(curSource->alSource, AL_GAIN, curSource->curGain);
qalSourcefv(curSource->alSource, AL_POSITION, vec3_origin);
qalSourcefv(curSource->alSource, AL_VELOCITY, vec3_origin);
qalSourcei(curSource->alSource, AL_LOOPING, AL_FALSE);
qalSourcef(curSource->alSource, AL_REFERENCE_DISTANCE, s_alMinDistance->value);
if(local)
{
qalSourcei(srcList[src].alSource, AL_SOURCE_RELATIVE, AL_TRUE);
qalSourcef(srcList[src].alSource, AL_ROLLOFF_FACTOR, 0.0f);
qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_TRUE);
qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, 0.0f);
}
else
{
qalSourcei(srcList[src].alSource, AL_SOURCE_RELATIVE, AL_FALSE);
qalSourcef(srcList[src].alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value);
qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_FALSE);
qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value);
}
}
@ -887,6 +941,7 @@ void S_AL_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx
S_AL_SanitiseVector( sorigin );
qalSourcefv( srcList[ src ].alSource, AL_POSITION, sorigin );
S_AL_ScaleGain(&srcList[src], sorigin);
// Start it playing
qalSourcePlay(srcList[src].alSource);
@ -918,6 +973,7 @@ static void S_AL_SrcLoop( alSrcPriority_t priority, sfxHandle_t sfx,
{
int src;
sentity_t *sent = &entityList[ entityNum ];
src_t *curSource;
// Do we need to allocate a new source for this entity
if( !sent->srcAllocated )
@ -945,28 +1001,33 @@ static void S_AL_SrcLoop( alSrcPriority_t priority, sfxHandle_t sfx,
// If this is not set then the looping sound is removed
sent->loopAddedThisFrame = qtrue;
curSource = &srcList[src];
// UGH
// These lines should be called via S_AL_SrcSetup, but we
// can't call that yet as it buffers sfxes that may change
// with subsequent calls to S_AL_SrcLoop
srcList[ src ].entity = entityNum;
srcList[ src ].isLooping = qtrue;
srcList[ src ].isActive = qtrue;
curSource->entity = entityNum;
curSource->isLooping = qtrue;
curSource->isActive = qtrue;
if( S_AL_HearingThroughEntity( entityNum ) )
{
srcList[ src ].local = qtrue;
curSource->local = qtrue;
qalSourcefv( srcList[ src ].alSource, AL_POSITION, vec3_origin );
qalSourcefv( srcList[ src ].alSource, AL_VELOCITY, vec3_origin );
qalSourcefv( curSource->alSource, AL_POSITION, vec3_origin );
qalSourcefv( curSource->alSource, AL_VELOCITY, vec3_origin );
}
else
{
srcList[ src ].local = qfalse;
curSource->local = qfalse;
qalSourcefv( srcList[ src ].alSource, AL_POSITION, (ALfloat *)sent->origin );
qalSourcefv( srcList[ src ].alSource, AL_VELOCITY, (ALfloat *)velocity );
qalSourcefv( curSource->alSource, AL_POSITION, (ALfloat *)sent->origin );
qalSourcefv( curSource->alSource, AL_VELOCITY, (ALfloat *)velocity );
}
S_AL_ScaleGain(curSource, sent->origin);
}
/*
@ -1028,63 +1089,65 @@ void S_AL_SrcUpdate( void )
int i;
int entityNum;
ALint state;
src_t *curSource;
for(i = 0; i < srcCount; i++)
{
entityNum = srcList[i].entity;
curSource = &srcList[i];
if(srcList[i].isLocked)
if(curSource->isLocked)
continue;
if(!srcList[i].isActive)
if(!curSource->isActive)
continue;
// Update source parameters
if((s_alGain->modified)||(s_volume->modified))
qalSourcef(srcList[i].alSource, AL_GAIN, s_alGain->value * s_volume->value);
if((s_alRolloff->modified)&&(!srcList[i].local))
qalSourcef(srcList[i].alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value);
curSource->curGain = s_alGain->value * s_volume->value;
if((s_alRolloff->modified)&&(!curSource->local))
qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value);
if(s_alMinDistance->modified)
qalSourcef(srcList[i].alSource, AL_REFERENCE_DISTANCE, s_alMinDistance->value);
qalSourcef(curSource->alSource, AL_REFERENCE_DISTANCE, s_alMinDistance->value);
if( srcList[ i ].isLooping )
if(curSource->isLooping)
{
sentity_t *sent = &entityList[ entityNum ];
// If a looping effect hasn't been touched this frame, kill it
if( sent->loopAddedThisFrame )
if(sent->loopAddedThisFrame)
{
// The sound has changed without an intervening removal
if( srcList[ i ].isActive && !sent->startLoopingSound &&
srcList[ i ].sfx != sent->loopSfx )
if(curSource->isActive && !sent->startLoopingSound &&
curSource->sfx != sent->loopSfx)
{
qalSourceStop( srcList[ i ].alSource );
qalSourcei( srcList[ i ].alSource, AL_BUFFER, 0 );
qalSourceStop(curSource->alSource);
qalSourcei(curSource->alSource, AL_BUFFER, 0);
sent->startLoopingSound = qtrue;
}
// Ths sound hasn't been started yet
if( sent->startLoopingSound )
// The sound hasn't been started yet
if(sent->startLoopingSound)
{
S_AL_SrcSetup( i, sent->loopSfx, sent->loopPriority,
entityNum, -1, srcList[ i ].local );
srcList[ i ].isLooping = qtrue;
qalSourcei( srcList[ i ].alSource, AL_LOOPING, AL_TRUE );
qalSourcePlay( srcList[ i ].alSource );
S_AL_SrcSetup(i, sent->loopSfx, sent->loopPriority,
entityNum, -1, curSource->local);
curSource->isLooping = qtrue;
qalSourcei(curSource->alSource, AL_LOOPING, AL_TRUE);
qalSourcePlay(curSource->alSource);
sent->startLoopingSound = qfalse;
}
// Update locality
if( srcList[ i ].local)
if(curSource->local)
{
qalSourcei( srcList[ i ].alSource, AL_SOURCE_RELATIVE, AL_TRUE );
qalSourcef( srcList[ i ].alSource, AL_ROLLOFF_FACTOR, 0.0f );
qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_TRUE);
qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, 0.0f);
}
else
{
qalSourcei( srcList[ i ].alSource, AL_SOURCE_RELATIVE, AL_FALSE );
qalSourcef( srcList[ i ].alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value );
qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_FALSE);
qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value);
}
}
else
@ -1093,20 +1156,23 @@ void S_AL_SrcUpdate( void )
continue;
}
// Query relativity of source, don't move if it's true
qalGetSourcei( srcList[ i ].alSource, AL_SOURCE_RELATIVE, &state );
// See if it needs to be moved
if( srcList[ i ].isTracking && !state )
qalSourcefv(srcList[i].alSource, AL_POSITION, entityList[entityNum].origin);
// Check if it's done, and flag it
qalGetSourcei(srcList[i].alSource, AL_SOURCE_STATE, &state);
qalGetSourcei(curSource->alSource, AL_SOURCE_STATE, &state);
if(state == AL_STOPPED)
{
S_AL_SrcKill(i);
continue;
}
// Query relativity of source, don't move if it's true
qalGetSourcei(curSource->alSource, AL_SOURCE_RELATIVE, &state);
// See if it needs to be moved
if(curSource->isTracking && !state)
{
qalSourcefv(curSource->alSource, AL_POSITION, entityList[entityNum].origin);
S_AL_ScaleGain(curSource, entityList[entityNum].origin);
}
}
}
@ -1775,7 +1841,9 @@ qboolean S_AL_Init( soundInterface_t *si )
s_alDopplerFactor = Cvar_Get( "s_alDopplerFactor", "1.0", CVAR_ARCHIVE );
s_alDopplerSpeed = Cvar_Get( "s_alDopplerSpeed", "2200", CVAR_ARCHIVE );
s_alMinDistance = Cvar_Get( "s_alMinDistance", "120", CVAR_CHEAT );
s_alRolloff = Cvar_Get( "s_alRolloff", "0.8", CVAR_CHEAT );
s_alMaxDistance = Cvar_Get("s_alMaxDistance", "1024", CVAR_CHEAT);
s_alRolloff = Cvar_Get( "s_alRolloff", "2", CVAR_CHEAT);
s_alGraceDistance = Cvar_Get("s_alGraceDistance", "512", CVAR_CHEAT);
s_alMaxSpeakerDistance = Cvar_Get( "s_alMaxSpeakerDistance", "1024", CVAR_ARCHIVE );
s_alDriver = Cvar_Get( "s_alDriver", ALDRIVER_DEFAULT, CVAR_ARCHIVE );
@ -1787,7 +1855,7 @@ qboolean S_AL_Init( soundInterface_t *si )
return qfalse;
}
// Device enumeration support (extension currently only exists for windows).
// Device enumeration support (extension is implemented reasonably only on Windows right now).
if((enumsupport = qalcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")))
{
char devicenames[1024] = "";
@ -1863,6 +1931,7 @@ qboolean S_AL_Init( soundInterface_t *si )
S_AL_SrcInit( );
// Set up OpenAL parameters (doppler, etc)
qalDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
qalDopplerFactor( s_alDopplerFactor->value );
qalDopplerVelocity( s_alDopplerSpeed->value );