forked from teamnwah/openmw-tes3coop
Cache OpenAL buffers for easy reuse
This commit is contained in:
parent
91821ccd8c
commit
6c45d6668b
2 changed files with 87 additions and 45 deletions
|
@ -313,35 +313,8 @@ public:
|
||||||
virtual void stop();
|
virtual void stop();
|
||||||
virtual bool isPlaying();
|
virtual bool isPlaying();
|
||||||
virtual void update(const float *pos);
|
virtual void update(const float *pos);
|
||||||
|
|
||||||
static ALuint LoadBuffer(DecoderPtr decoder);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ALuint OpenAL_Sound::LoadBuffer(DecoderPtr decoder)
|
|
||||||
{
|
|
||||||
int srate;
|
|
||||||
ChannelConfig chans;
|
|
||||||
SampleType type;
|
|
||||||
ALenum format;
|
|
||||||
|
|
||||||
decoder->getInfo(&srate, &chans, &type);
|
|
||||||
format = getALFormat(chans, type);
|
|
||||||
|
|
||||||
std::vector<char> data(32768);
|
|
||||||
size_t got, total = 0;
|
|
||||||
while((got=decoder->read(&data[total], data.size()-total)) > 0)
|
|
||||||
{
|
|
||||||
total += got;
|
|
||||||
data.resize(total*2);
|
|
||||||
}
|
|
||||||
data.resize(total);
|
|
||||||
|
|
||||||
ALuint buf=0;
|
|
||||||
alGenBuffers(1, &buf);
|
|
||||||
alBufferData(buf, format, &data[0], total, srate);
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf)
|
OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf)
|
||||||
: mOutput(output), mSource(src), mBuffer(buf)
|
: mOutput(output), mSource(src), mBuffer(buf)
|
||||||
{
|
{
|
||||||
|
@ -352,8 +325,7 @@ OpenAL_Sound::~OpenAL_Sound()
|
||||||
alSourcei(mSource, AL_BUFFER, 0);
|
alSourcei(mSource, AL_BUFFER, 0);
|
||||||
|
|
||||||
mOutput.mFreeSources.push_back(mSource);
|
mOutput.mFreeSources.push_back(mSource);
|
||||||
alDeleteBuffers(1, &mBuffer);
|
mOutput.bufferFinished(mBuffer);
|
||||||
alGetError();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenAL_Sound::stop()
|
void OpenAL_Sound::stop()
|
||||||
|
@ -431,6 +403,15 @@ void OpenAL_Output::deinit()
|
||||||
alDeleteSources(mFreeSources.size(), mFreeSources.data());
|
alDeleteSources(mFreeSources.size(), mFreeSources.data());
|
||||||
mFreeSources.clear();
|
mFreeSources.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mBufferRefs.clear();
|
||||||
|
mUnusedBuffers.clear();
|
||||||
|
while(!mBufferCache.empty())
|
||||||
|
{
|
||||||
|
alDeleteBuffers(1, &mBufferCache.begin()->second);
|
||||||
|
mBufferCache.erase(mBufferCache.begin());
|
||||||
|
}
|
||||||
|
|
||||||
alcMakeContextCurrent(0);
|
alcMakeContextCurrent(0);
|
||||||
if(mContext)
|
if(mContext)
|
||||||
alcDestroyContext(mContext);
|
alcDestroyContext(mContext);
|
||||||
|
@ -441,6 +422,63 @@ void OpenAL_Output::deinit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ALuint OpenAL_Output::getBuffer(const std::string &fname)
|
||||||
|
{
|
||||||
|
ALuint buf = 0;
|
||||||
|
|
||||||
|
NameMap::iterator iditer = mBufferCache.find(fname);
|
||||||
|
if(iditer != mBufferCache.end())
|
||||||
|
{
|
||||||
|
buf = iditer->second;
|
||||||
|
if(mBufferRefs[buf]++ == 0)
|
||||||
|
{
|
||||||
|
IDDq::iterator iter = std::find(mUnusedBuffers.begin(),
|
||||||
|
mUnusedBuffers.end(), buf);
|
||||||
|
if(iter != mUnusedBuffers.end())
|
||||||
|
mUnusedBuffers.erase(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
throwALerror();
|
||||||
|
|
||||||
|
int srate;
|
||||||
|
ChannelConfig chans;
|
||||||
|
SampleType type;
|
||||||
|
ALenum format;
|
||||||
|
|
||||||
|
DecoderPtr decoder = mManager.getDecoder();
|
||||||
|
decoder->open(fname);
|
||||||
|
decoder->getInfo(&srate, &chans, &type);
|
||||||
|
format = getALFormat(chans, type);
|
||||||
|
|
||||||
|
std::vector<char> data(32768);
|
||||||
|
size_t got, total = 0;
|
||||||
|
while((got=decoder->read(&data[total], data.size()-total)) > 0)
|
||||||
|
{
|
||||||
|
total += got;
|
||||||
|
data.resize(total*2);
|
||||||
|
}
|
||||||
|
data.resize(total);
|
||||||
|
decoder->close();
|
||||||
|
|
||||||
|
alGenBuffers(1, &buf);
|
||||||
|
throwALerror();
|
||||||
|
|
||||||
|
alBufferData(buf, format, &data[0], total, srate);
|
||||||
|
mBufferCache[fname] = buf;
|
||||||
|
mBufferRefs[buf] = 1;
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenAL_Output::bufferFinished(ALuint buf)
|
||||||
|
{
|
||||||
|
if(mBufferRefs.at(buf)-- == 1)
|
||||||
|
mUnusedBuffers.push_back(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Sound* OpenAL_Output::playSound(const std::string &fname, float volume, float pitch, bool loop)
|
Sound* OpenAL_Output::playSound(const std::string &fname, float volume, float pitch, bool loop)
|
||||||
{
|
{
|
||||||
throwALerror();
|
throwALerror();
|
||||||
|
@ -455,19 +493,14 @@ Sound* OpenAL_Output::playSound(const std::string &fname, float volume, float pi
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
DecoderPtr decoder = mManager.getDecoder();
|
buf = getBuffer(fname);
|
||||||
decoder->open(fname);
|
|
||||||
buf = OpenAL_Sound::LoadBuffer(decoder);
|
|
||||||
throwALerror();
|
|
||||||
decoder->close();
|
|
||||||
|
|
||||||
sound.reset(new OpenAL_Sound(*this, src, buf));
|
sound.reset(new OpenAL_Sound(*this, src, buf));
|
||||||
}
|
}
|
||||||
catch(std::exception &e)
|
catch(std::exception &e)
|
||||||
{
|
{
|
||||||
mFreeSources.push_back(src);
|
mFreeSources.push_back(src);
|
||||||
if(alIsBuffer(buf))
|
if(buf && alIsBuffer(buf))
|
||||||
alDeleteBuffers(1, &buf);
|
bufferFinished(buf);
|
||||||
alGetError();
|
alGetError();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
@ -509,19 +542,14 @@ Sound* OpenAL_Output::playSound3D(const std::string &fname, const float *pos, fl
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
DecoderPtr decoder = mManager.getDecoder();
|
buf = getBuffer(fname);
|
||||||
decoder->open(fname);
|
|
||||||
buf = OpenAL_Sound::LoadBuffer(decoder);
|
|
||||||
throwALerror();
|
|
||||||
decoder->close();
|
|
||||||
|
|
||||||
sound.reset(new OpenAL_Sound(*this, src, buf));
|
sound.reset(new OpenAL_Sound(*this, src, buf));
|
||||||
}
|
}
|
||||||
catch(std::exception &e)
|
catch(std::exception &e)
|
||||||
{
|
{
|
||||||
mFreeSources.push_back(src);
|
mFreeSources.push_back(src);
|
||||||
if(alIsBuffer(buf))
|
if(buf && alIsBuffer(buf))
|
||||||
alDeleteBuffers(1, &buf);
|
bufferFinished(buf);
|
||||||
alGetError();
|
alGetError();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
#include "alc.h"
|
#include "alc.h"
|
||||||
#include "al.h"
|
#include "al.h"
|
||||||
|
@ -22,6 +24,18 @@ namespace MWSound
|
||||||
typedef std::vector<ALuint> IDVec;
|
typedef std::vector<ALuint> IDVec;
|
||||||
IDVec mFreeSources;
|
IDVec mFreeSources;
|
||||||
|
|
||||||
|
typedef std::map<std::string,ALuint> NameMap;
|
||||||
|
NameMap mBufferCache;
|
||||||
|
|
||||||
|
typedef std::map<ALuint,ALuint> IDRefMap;
|
||||||
|
IDRefMap mBufferRefs;
|
||||||
|
|
||||||
|
typedef std::deque<ALuint> IDDq;
|
||||||
|
IDDq mUnusedBuffers;
|
||||||
|
|
||||||
|
ALuint getBuffer(const std::string &fname);
|
||||||
|
void bufferFinished(ALuint buffer);
|
||||||
|
|
||||||
virtual void init(const std::string &devname="");
|
virtual void init(const std::string &devname="");
|
||||||
virtual void deinit();
|
virtual void deinit();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue