[quake3-commits] r1712 - trunk/code/client
DONOTREPLY at icculus.org
DONOTREPLY at icculus.org
Tue Oct 27 07:13:36 EDT 2009
Author: thilo
Date: 2009-10-27 07:13:33 -0400 (Tue, 27 Oct 2009)
New Revision: 1712
Modified:
trunk/code/client/snd_openal.c
Log:
New batch of fixes for the OpenAL part:
- Don't play sources outside the listening range (Thanks Kpaxian for bringing this to my attention)
- Handle previously unhandled errors for old OpenAL sample implementation which does not support AL_SEC_OFFSET (sounds won't be synchronized then),
thanks to Tequila from SmokingGuns for reporting this.
Modified: trunk/code/client/snd_openal.c
===================================================================
--- trunk/code/client/snd_openal.c 2009-10-26 23:20:05 UTC (rev 1711)
+++ trunk/code/client/snd_openal.c 2009-10-27 11:13:33 UTC (rev 1712)
@@ -110,8 +110,10 @@
if( quiet )
return;
if(error != AL_NO_ERROR)
+ {
Com_Printf(S_COLOR_YELLOW "WARNING: unhandled AL error: %s\n",
S_AL_ErrorMsg(error));
+ }
}
@@ -515,6 +517,7 @@
#endif
static src_t srcList[MAX_SRC];
static int srcCount = 0;
+static int srcActiveCnt = 0;
static qboolean alSourcesInitialised = qfalse;
static vec3_t lastListenerOrigin = { 0.0f, 0.0f, 0.0f };
@@ -637,6 +640,7 @@
// Clear the sources data structure
memset(srcList, 0, sizeof(srcList));
srcCount = 0;
+ srcActiveCnt = 0;
// Cap s_alSources to MAX_SRC
limit = s_alSources->integer;
@@ -670,6 +674,7 @@
void S_AL_SrcShutdown( void )
{
int i;
+ src_t *curSource;
if(!alSourcesInitialised)
return;
@@ -677,9 +682,14 @@
// Destroy all the sources
for(i = 0; i < srcCount; i++)
{
- if(srcList[i].isLocked)
+ curSource = &srcList[i];
+
+ if(curSource->isLocked)
Com_DPrintf( S_COLOR_YELLOW "WARNING: Source %d is locked\n", i);
+ if(curSource->entity > 0)
+ entityList[curSource->entity].srcAllocated = qfalse;
+
qalSourceStop(srcList[i].alSource);
qalDeleteSources(1, &srcList[i].alSource);
}
@@ -712,7 +722,6 @@
curSource->priority = priority;
curSource->entity = entity;
curSource->channel = channel;
- curSource->isActive = qtrue;
curSource->isPlaying = qfalse;
curSource->isLocked = qfalse;
curSource->isLooping = qfalse;
@@ -749,6 +758,36 @@
=================
*/
+static void S_AL_SaveLoopPos(src_t *dest, ALuint alSource)
+{
+ int error;
+
+ S_AL_ClearError(qfalse);
+
+ qalGetSourcef(alSource, AL_SEC_OFFSET, &dest->lastTimePos);
+ if((error = qalGetError()) != AL_NO_ERROR)
+ {
+ // Old OpenAL implementations don't support AL_SEC_OFFSET
+
+ if(error != AL_INVALID_ENUM)
+ {
+ Com_Printf(S_COLOR_YELLOW "WARNING: Could not get time offset for alSource %d: %s\n",
+ alSource, S_AL_ErrorMsg(error));
+ }
+
+ dest->lastTimePos = -1;
+ }
+ else
+ dest->lastSampleTime = Sys_Milliseconds();
+}
+
+/*
+=================
+S_AL_NewLoopMaster
+Remove given source as loop master if it is the master and hand off master status to another source in this case.
+=================
+*/
+
static void S_AL_NewLoopMaster(src_t *rmSource, qboolean iskilled)
{
int index;
@@ -764,8 +803,17 @@
if(curSfx->loopCnt)
{
- if(rmSource == &srcList[curSfx->masterLoopSrc])
+ if(rmSource->priority == SRCPRI_ENTITY)
{
+ if(!iskilled && rmSource->isPlaying)
+ {
+ // only sync ambient loops...
+ // It makes more sense to have sounds for weapons/projectiles unsynced
+ S_AL_SaveLoopPos(rmSource, rmSource->alSource);
+ }
+ }
+ else if(rmSource == &srcList[curSfx->masterLoopSrc])
+ {
int firstInactive = -1;
// Only if rmSource was the master and if there are still playing loops for
@@ -778,7 +826,7 @@
curSource = &srcList[index];
if(curSource->sfx == rmSource->sfx && curSource != rmSource &&
- curSource->isActive && curSource->isLooping)
+ curSource->isActive && curSource->isLooping && curSource->priority == SRCPRI_AMBIENT)
{
if(curSource->isPlaying)
{
@@ -794,15 +842,22 @@
if(!curSfx->loopActiveCnt)
{
if(firstInactive < 0)
- curSource = rmSource;
+ {
+ if(iskilled)
+ {
+ curSfx->masterLoopSrc = -1;
+ return;
+ }
+ else
+ curSource = rmSource;
+ }
else
curSource = &srcList[firstInactive];
if(rmSource->isPlaying)
{
// this was the last not stopped source, save last sample position + time
- qalGetSourcef(rmSource->alSource, AL_SEC_OFFSET, &curSource->lastTimePos);
- curSource->lastSampleTime = Sys_Milliseconds();
+ S_AL_SaveLoopPos(curSource, rmSource->alSource);
}
else
{
@@ -865,7 +920,11 @@
curSource->priority = 0;
curSource->entity = -1;
curSource->channel = -1;
- curSource->isActive = qfalse;
+ if(curSource->isActive)
+ {
+ curSource->isActive = qfalse;
+ srcActiveCnt--;
+ }
curSource->isLocked = qfalse;
curSource->isTracking = qfalse;
curSource->local = qfalse;
@@ -884,6 +943,7 @@
int weakest = -1;
int weakest_time = Sys_Milliseconds();
int weakest_pri = 999;
+ float weakest_gain = 1000.0;
qboolean weakest_isplaying = qtrue;
int weakest_numloops = 0;
src_t *curSource;
@@ -906,11 +966,15 @@
if(curSource->isPlaying)
{
if(weakest_isplaying && curSource->priority < priority &&
- (curSource->priority < weakest_pri || curSource->lastUsedTime < weakest_time))
+ (curSource->priority < weakest_pri ||
+ (!curSource->isLooping && (curSource->scaleGain < weakest_gain || curSource->lastUsedTime < weakest_time))))
{
- // If it's older or has lower priority, flag it as weak
+ // If it has lower priority, is fainter or older, flag it as weak
+ // the last two values are only compared if it's not a looping sound, because we want to prevent two
+ // loops (loops are added EVERY frame) fighting for a slot
weakest_pri = curSource->priority;
weakest_time = curSource->lastUsedTime;
+ weakest_gain = curSource->scaleGain;
weakest = i;
}
}
@@ -918,7 +982,8 @@
{
weakest_isplaying = qfalse;
- if(knownSfx[curSource->sfx].loopCnt > weakest_numloops ||
+ if(weakest < 0 ||
+ knownSfx[curSource->sfx].loopCnt > weakest_numloops ||
curSource->priority < weakest_pri ||
curSource->lastUsedTime < weakest_time)
{
@@ -928,7 +993,6 @@
weakest_time = curSource->lastUsedTime;
weakest_numloops = knownSfx[curSource->sfx].loopCnt;
weakest = i;
- weakest_isplaying = qfalse;
}
}
@@ -945,22 +1009,17 @@
#endif
}
- // Do we have an empty one?
- if(empty != -1)
+ if(empty == -1)
+ empty = weakest;
+
+ if(empty >= 0)
{
- S_AL_SrcKill( empty );
- return empty;
+ S_AL_SrcKill(empty);
+ srcList[empty].isActive = qtrue;
+ srcActiveCnt++;
}
- // No. How about an overridable one?
- if(weakest != -1)
- {
- S_AL_SrcKill(weakest);
- return weakest;
- }
-
- // Nothing. Return failure (cries...)
- return -1;
+ return empty;
}
/*
@@ -1040,7 +1099,7 @@
static qboolean S_AL_CheckInput(int entityNum, sfxHandle_t sfx)
{
if (entityNum < 0 || entityNum > MAX_GENTITIES)
- Com_Error(ERR_DROP, "S_StartSound: bad entitynum %i", entityNum);
+ Com_Error(ERR_DROP, "ERROR: S_AL_CheckInput: bad entitynum %i", entityNum);
if (sfx < 0 || sfx >= numSfx)
{
@@ -1087,49 +1146,61 @@
Play a one-shot sound effect
=================
*/
-static
-void S_AL_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx )
+static void S_AL_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx )
{
vec3_t sorigin;
srcHandle_t src;
+ src_t *curSource;
- if(S_AL_CheckInput(origin ? 0 : entnum, sfx))
+ if(origin)
+ {
+ if(S_AL_CheckInput(0, sfx))
+ return;
+
+ VectorCopy(origin, sorigin);
+ }
+ else
+ {
+ if(S_AL_CheckInput(entnum, sfx))
+ return;
+
+ if(S_AL_HearingThroughEntity(entnum))
+ {
+ S_AL_StartLocalSound(sfx, entchannel);
+ return;
+ }
+
+ VectorCopy(entityList[entnum].origin, sorigin);
+ }
+
+ S_AL_SanitiseVector(sorigin);
+
+ if((srcActiveCnt > 5 * srcCount / 3) &&
+ (DistanceSquared(sorigin, lastListenerOrigin) >=
+ (s_alMaxDistance->value + s_alGraceDistance->value) * (s_alMaxDistance->value + s_alGraceDistance->value)))
+ {
+ // We're getting tight on sources and source is not within hearing distance so don't add it
return;
+ }
// Try to grab a source
src = S_AL_SrcAlloc(SRCPRI_ONESHOT, entnum, entchannel);
if(src == -1)
return;
- // Set up the effect
- if( origin == NULL )
- {
- if( S_AL_HearingThroughEntity( entnum ) )
- {
- // Where the entity is the local player, play a local sound
- S_AL_SrcSetup( src, sfx, SRCPRI_ONESHOT, entnum, entchannel, qtrue );
- VectorClear( sorigin );
- }
- else
- {
- S_AL_SrcSetup( src, sfx, SRCPRI_ONESHOT, entnum, entchannel, qfalse );
- VectorCopy( entityList[ entnum ].origin, sorigin );
- }
- srcList[ src ].isTracking = qtrue;
- }
- else
- {
- S_AL_SrcSetup( src, sfx, SRCPRI_ONESHOT, entnum, entchannel, qfalse );
- VectorCopy( origin, sorigin );
- }
+ S_AL_SrcSetup(src, sfx, SRCPRI_ONESHOT, entnum, entchannel, qfalse);
+
+ curSource = &srcList[src];
- S_AL_SanitiseVector( sorigin );
- qalSourcefv( srcList[ src ].alSource, AL_POSITION, sorigin );
- S_AL_ScaleGain(&srcList[src], sorigin);
+ if(!origin)
+ curSource->isTracking = qtrue;
+
+ qalSourcefv(curSource->alSource, AL_POSITION, sorigin );
+ S_AL_ScaleGain(curSource, sorigin);
// Start it playing
- srcList[src].isPlaying = qtrue;
- qalSourcePlay(srcList[src].alSource);
+ curSource->isPlaying = qtrue;
+ qalSourcePlay(curSource->alSource);
}
/*
@@ -1176,10 +1247,18 @@
return;
}
+ curSource = &srcList[src];
+
sent->startLoopingSound = qtrue;
+
+ curSource->lastTimePos = -1.0;
+ curSource->lastSampleTime = Sys_Milliseconds();
}
else
+ {
src = sent->srcIndex;
+ curSource = &srcList[src];
+ }
sent->srcAllocated = qtrue;
sent->srcIndex = src;
@@ -1190,15 +1269,12 @@
// If this is not set then the looping sound is stopped.
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
curSource->entity = entityNum;
curSource->isLooping = qtrue;
- curSource->isActive = qtrue;
if( S_AL_HearingThroughEntity( entityNum ) )
{
@@ -1280,8 +1356,8 @@
int i;
int entityNum;
ALint state;
- src_t *curSource;
-
+ src_t *curSource;
+
for(i = 0; i < srcCount; i++)
{
entityNum = srcList[i].entity;
@@ -1346,48 +1422,68 @@
curSource->isPlaying = qfalse;
}
else if(!curSfx->loopActiveCnt && curSfx->masterLoopSrc < 0)
- {
- // There are no loops yet, make this one master
- curSource->lastTimePos = 0;
- curSource->lastSampleTime = Sys_Milliseconds();
-
curSfx->masterLoopSrc = i;
- }
continue;
}
if(!curSource->isPlaying)
{
- // If there are other looping sources with the same sound,
- // make sure the sound of these sources are in sync.
-
- if(curSfx->loopActiveCnt)
+ if(curSource->priority == SRCPRI_AMBIENT)
{
- int offset;
+ // If there are other ambient looping sources with the same sound,
+ // make sure the sound of these sources are in sync.
+
+ if(curSfx->loopActiveCnt)
+ {
+ int offset, error;
- // we already have a master loop playing, get buffer position.
- qalGetSourcei(srcList[curSfx->masterLoopSrc].alSource, AL_SAMPLE_OFFSET, &offset);
- qalSourcei(curSource->alSource, AL_SAMPLE_OFFSET, offset);
+ // we already have a master loop playing, get buffer position.
+ S_AL_ClearError(qfalse);
+ qalGetSourcei(srcList[curSfx->masterLoopSrc].alSource, AL_SAMPLE_OFFSET, &offset);
+ if((error = qalGetError()) != AL_NO_ERROR)
+ {
+ if(error != AL_INVALID_ENUM)
+ {
+ Com_Printf(S_COLOR_YELLOW "WARNING: Cannot get sample offset from source %d: "
+ "%s\n", i, S_AL_ErrorMsg(error));
+ }
+ }
+ else
+ qalSourcei(curSource->alSource, AL_SAMPLE_OFFSET, offset);
+ }
+ else if(curSfx->loopCnt && curSfx->masterLoopSrc >= 0)
+ {
+ float secofs;
+
+ src_t *master = &srcList[curSfx->masterLoopSrc];
+ // This loop sound used to be played, but all sources are stopped. Use last sample position/time
+ // to calculate offset so the player thinks the sources continued playing while they were inaudible.
+
+ if(master->lastTimePos >= 0)
+ {
+ secofs = master->lastTimePos + (Sys_Milliseconds() - master->lastSampleTime) / 1000.0f;
+ secofs = fmodf(secofs, (float) curSfx->info.samples / curSfx->info.rate);
+
+ qalSourcef(curSource->alSource, AL_SEC_OFFSET, secofs);
+ }
+
+ // I be the master now
+ curSfx->masterLoopSrc = i;
+ }
+ else
+ curSfx->masterLoopSrc = i;
}
- else if(curSfx->loopCnt && curSfx->masterLoopSrc >= 0)
+ else if(curSource->lastTimePos >= 0)
{
float secofs;
- src_t *master = &srcList[curSfx->masterLoopSrc];
- // This loop sound used to be played, but all sources are stopped. Use last sample position/time
- // to calculate offset so the player thinks the sources continued playing while they were inaudible.
+ // For unsynced loops (SRCPRI_ENTITY) just carry on playing as if the sound was never stopped
- secofs = master->lastTimePos + (Sys_Milliseconds() - master->lastSampleTime) / 1000.0f;
+ secofs = curSource->lastTimePos + (Sys_Milliseconds() - curSource->lastSampleTime) / 1000.0f;
secofs = fmodf(secofs, (float) curSfx->info.samples / curSfx->info.rate);
-
qalSourcef(curSource->alSource, AL_SEC_OFFSET, secofs);
-
- // I be the master now
- curSfx->masterLoopSrc = i;
}
- else
- curSfx->masterLoopSrc = i;
curSfx->loopActiveCnt++;
More information about the quake3-commits
mailing list