SoundEmitter: Optimize source allocation strategy
Before, we would blindly rotate through the sources (like a revolver through its chambers), which worked great if one assumed all sounds to be relatively short and therefore oldest use == most likely to be free, but breaks if there is one long sound playing, which would be stopped and overtaken if we rotated back to it even though there might be other free sources available. Instead, keep an ascending priority list of sources with last used == highest priorty that is iterated through for the first free one, and only if none is found overtake the one with lowest priority. This also ensures we're always able to play 'SE_SOURCES' sounds at once independently of their length. Fixes #37.
This commit is contained in:
parent
282d547ad4
commit
6808b9a6dd
|
@ -143,6 +143,18 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
/* Before: [a][b][c][d], After (index=1): [a][c][d][b] */
|
||||
static void
|
||||
arrayPushBack(size_t array[], size_t size, size_t index)
|
||||
{
|
||||
size_t v = array[index];
|
||||
|
||||
for (size_t t = index; t < size-1; ++t)
|
||||
array[t] = array[t+1];
|
||||
|
||||
array[size-1] = v;
|
||||
}
|
||||
|
||||
struct SoundEmitter
|
||||
{
|
||||
typedef BoostHash<std::string, SoundBuffer*> BufferHash;
|
||||
|
@ -155,17 +167,18 @@ struct SoundEmitter
|
|||
|
||||
AL::Source::ID alSrcs[SE_SOURCES];
|
||||
SoundBuffer *atchBufs[SE_SOURCES];
|
||||
/* Index of next source to be used */
|
||||
int srcIndex;
|
||||
|
||||
/* Indices of sources, sorted by priority (lowest first) */
|
||||
size_t srcPrio[SE_SOURCES];
|
||||
|
||||
SoundEmitter()
|
||||
: bufferBytes(0),
|
||||
srcIndex(0)
|
||||
: bufferBytes(0)
|
||||
{
|
||||
for (int i = 0; i < SE_SOURCES; ++i)
|
||||
{
|
||||
alSrcs[i] = AL::Source::gen();
|
||||
atchBufs[i] = 0;
|
||||
srcPrio[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,20 +207,30 @@ struct SoundEmitter
|
|||
|
||||
SoundBuffer *buffer = allocateBuffer(filename);
|
||||
|
||||
int soundIndex = srcIndex++;
|
||||
if (srcIndex > SE_SOURCES-1)
|
||||
srcIndex = 0;
|
||||
/* Try to find first free source */
|
||||
size_t i;
|
||||
for (i = 0; i < SE_SOURCES; ++i)
|
||||
if (AL::Source::getState(alSrcs[srcPrio[i]]) != AL_PLAYING)
|
||||
break;
|
||||
|
||||
AL::Source::ID src = alSrcs[soundIndex];
|
||||
/* If we didn't find any, overtake the one with lowest priority */
|
||||
if (i == SE_SOURCES)
|
||||
i = 0;
|
||||
|
||||
/* Push the used source to the back of the priority list */
|
||||
size_t srcIndex = srcPrio[i];
|
||||
arrayPushBack(srcPrio, SE_SOURCES, i);
|
||||
|
||||
AL::Source::ID src = alSrcs[srcIndex];
|
||||
AL::Source::stop(src);
|
||||
AL::Source::detachBuffer(src);
|
||||
|
||||
SoundBuffer *old = atchBufs[soundIndex];
|
||||
SoundBuffer *old = atchBufs[srcIndex];
|
||||
|
||||
if (old)
|
||||
SoundBuffer::deref(old);
|
||||
|
||||
atchBufs[soundIndex] = SoundBuffer::ref(buffer);
|
||||
atchBufs[srcIndex] = SoundBuffer::ref(buffer);
|
||||
|
||||
AL::Source::attachBuffer(src, buffer->alBuffer);
|
||||
|
||||
|
|
Loading…
Reference in New Issue