From 6808b9a6dd9a729531c4b22261c494b6fc872f79 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Sun, 15 Jun 2014 06:07:11 +0200 Subject: [PATCH] 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. --- src/audio.cpp | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/src/audio.cpp b/src/audio.cpp index 0a757d5..a2c21f1 100644 --- a/src/audio.cpp +++ b/src/audio.cpp @@ -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 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);