Allocate OpenAL sources when opening the device

This allows sources to be more efficiently retrieved and returned
This commit is contained in:
Chris Robinson 2012-03-19 07:11:01 -07:00
parent 8f9d4ff841
commit ae8218bf03
2 changed files with 119 additions and 51 deletions

View File

@ -17,6 +17,13 @@ namespace MWSound
static void fail(const std::string &msg) static void fail(const std::string &msg)
{ throw std::runtime_error("OpenAL exception: " + msg); } { throw std::runtime_error("OpenAL exception: " + msg); }
static void throwALCerror(ALCdevice *device)
{
ALCenum err = alcGetError(device);
if(err != ALC_NO_ERROR)
fail(alcGetString(device, err));
}
static void throwALerror() static void throwALerror()
{ {
ALenum err = alGetError(); ALenum err = alGetError();
@ -70,14 +77,14 @@ class OpenAL_SoundStream : public Sound
volatile bool mIsFinished; volatile bool mIsFinished;
public: public:
OpenAL_SoundStream(OpenAL_Output &output, DecoderPtr decoder); OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder);
virtual ~OpenAL_SoundStream(); virtual ~OpenAL_SoundStream();
virtual void stop(); virtual void stop();
virtual bool isPlaying(); virtual bool isPlaying();
virtual void update(const float *pos); virtual void update(const float *pos);
void play(float volume, float pitch); void play();
bool process(); bool process();
}; };
@ -144,25 +151,13 @@ struct OpenAL_Output::StreamThread {
}; };
OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, DecoderPtr decoder) OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder)
: mOutput(output), mDecoder(decoder), mIsFinished(true) : mOutput(output), mSource(src), mDecoder(decoder), mIsFinished(true)
{ {
throwALerror(); throwALerror();
alGenSources(1, &mSource); alGenBuffers(sNumBuffers, mBuffers);
throwALerror(); throwALerror();
try
{
alGenBuffers(sNumBuffers, mBuffers);
throwALerror();
}
catch(std::exception &e)
{
alDeleteSources(1, &mSource);
alGetError();
throw;
}
try try
{ {
int srate; int srate;
@ -178,7 +173,7 @@ OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, DecoderPtr decoder
} }
catch(std::exception &e) catch(std::exception &e)
{ {
alDeleteSources(1, &mSource); mOutput.mFreeSources.push_back(mSource);
alDeleteBuffers(sNumBuffers, mBuffers); alDeleteBuffers(sNumBuffers, mBuffers);
alGetError(); alGetError();
throw; throw;
@ -188,21 +183,22 @@ OpenAL_SoundStream::~OpenAL_SoundStream()
{ {
mOutput.mStreamThread->remove(this); mOutput.mStreamThread->remove(this);
alDeleteSources(1, &mSource); alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0);
mOutput.mFreeSources.push_back(mSource);
alDeleteBuffers(sNumBuffers, mBuffers); alDeleteBuffers(sNumBuffers, mBuffers);
alGetError(); alGetError();
mDecoder->close(); mDecoder->close();
} }
void OpenAL_SoundStream::play(float volume, float pitch) void OpenAL_SoundStream::play()
{ {
std::vector<char> data(mBufferSize); std::vector<char> data(mBufferSize);
alSourceStop(mSource); alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0); alSourcei(mSource, AL_BUFFER, 0);
alSourcef(mSource, AL_GAIN, volume);
alSourcef(mSource, AL_PITCH, pitch);
throwALerror(); throwALerror();
for(ALuint i = 0;i < sNumBuffers;i++) for(ALuint i = 0;i < sNumBuffers;i++)
@ -297,11 +293,12 @@ bool OpenAL_SoundStream::process()
// //
class OpenAL_Sound : public Sound class OpenAL_Sound : public Sound
{ {
OpenAL_Output &mOutput;
ALuint mSource; ALuint mSource;
ALuint mBuffer; ALuint mBuffer;
public: public:
OpenAL_Sound(ALuint src, ALuint buf); OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf);
virtual ~OpenAL_Sound(); virtual ~OpenAL_Sound();
virtual void stop(); virtual void stop();
@ -330,19 +327,22 @@ ALuint OpenAL_Sound::LoadBuffer(DecoderPtr decoder)
} }
data.resize(total); data.resize(total);
ALuint buf; ALuint buf=0;
alGenBuffers(1, &buf); alGenBuffers(1, &buf);
alBufferData(buf, format, &data[0], total, srate); alBufferData(buf, format, &data[0], total, srate);
return buf; return buf;
} }
OpenAL_Sound::OpenAL_Sound(ALuint src, ALuint buf) OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf)
: mSource(src), mBuffer(buf) : mOutput(output), mSource(src), mBuffer(buf)
{ {
} }
OpenAL_Sound::~OpenAL_Sound() OpenAL_Sound::~OpenAL_Sound()
{ {
alDeleteSources(1, &mSource); alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0);
mOutput.mFreeSources.push_back(mSource);
alDeleteBuffers(1, &mBuffer); alDeleteBuffers(1, &mBuffer);
alGetError(); alGetError();
} }
@ -391,13 +391,37 @@ void OpenAL_Output::init(const std::string &devname)
alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED); alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
throwALerror(); throwALerror();
ALCint maxmono, maxstereo;
alcGetIntegerv(mDevice, ALC_MONO_SOURCES, 1, &maxmono);
alcGetIntegerv(mDevice, ALC_STEREO_SOURCES, 1, &maxstereo);
throwALCerror(mDevice);
mFreeSources.resize(std::min(maxmono+maxstereo, 256));
for(size_t i = 0;i < mFreeSources.size();i++)
{
ALuint src;
alGenSources(1, &src);
if(alGetError() != AL_NO_ERROR)
{
mFreeSources.resize(i);
break;
}
mFreeSources[i] = src;
}
if(mFreeSources.size() == 0)
fail("Could not allocate any sources");
} }
void OpenAL_Output::deinit() void OpenAL_Output::deinit()
{ {
if(mStreamThread.get() != 0) mStreamThread->removeAll();
mStreamThread->removeAll();
if(!mFreeSources.empty())
{
alDeleteSources(mFreeSources.size(), mFreeSources.data());
mFreeSources.clear();
}
alcMakeContextCurrent(0); alcMakeContextCurrent(0);
if(mContext) if(mContext)
alcDestroyContext(mContext); alcDestroyContext(mContext);
@ -412,28 +436,33 @@ Sound* OpenAL_Output::playSound(const std::string &fname, float volume, float pi
{ {
throwALerror(); throwALerror();
DecoderPtr decoder = mManager.getDecoder(); std::auto_ptr<OpenAL_Sound> sound;
decoder->open(fname);
ALuint src=0, buf=0; ALuint src=0, buf=0;
if(mFreeSources.empty())
fail("No free sources");
src = mFreeSources.back();
mFreeSources.pop_back();
try try
{ {
DecoderPtr decoder = mManager.getDecoder();
decoder->open(fname);
buf = OpenAL_Sound::LoadBuffer(decoder); buf = OpenAL_Sound::LoadBuffer(decoder);
decoder->close();
alGenSources(1, &src);
throwALerror(); throwALerror();
decoder->close();
sound.reset(new OpenAL_Sound(*this, src, buf));
} }
catch(std::exception &e) catch(std::exception &e)
{ {
if(alIsSource(src)) mFreeSources.push_back(src);
alDeleteSources(1, &src);
if(alIsBuffer(buf)) if(alIsBuffer(buf))
alDeleteBuffers(1, &buf); alDeleteBuffers(1, &buf);
alGetError(); alGetError();
throw; throw;
} }
std::auto_ptr<OpenAL_Sound> sound(new OpenAL_Sound(src, buf));
alSource3f(src, AL_POSITION, 0.0f, 0.0f, 0.0f); alSource3f(src, AL_POSITION, 0.0f, 0.0f, 0.0f);
alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f); alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f); alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
@ -461,28 +490,33 @@ Sound* OpenAL_Output::playSound3D(const std::string &fname, const float *pos, fl
{ {
throwALerror(); throwALerror();
DecoderPtr decoder = mManager.getDecoder(); std::auto_ptr<OpenAL_Sound> sound;
decoder->open(fname);
ALuint src=0, buf=0; ALuint src=0, buf=0;
if(mFreeSources.empty())
fail("No free sources");
src = mFreeSources.back();
mFreeSources.pop_back();
try try
{ {
DecoderPtr decoder = mManager.getDecoder();
decoder->open(fname);
buf = OpenAL_Sound::LoadBuffer(decoder); buf = OpenAL_Sound::LoadBuffer(decoder);
decoder->close();
alGenSources(1, &src);
throwALerror(); throwALerror();
decoder->close();
sound.reset(new OpenAL_Sound(*this, src, buf));
} }
catch(std::exception &e) catch(std::exception &e)
{ {
if(alIsSource(src)) mFreeSources.push_back(src);
alDeleteSources(1, &src);
if(alIsBuffer(buf)) if(alIsBuffer(buf))
alDeleteBuffers(1, &buf); alDeleteBuffers(1, &buf);
alGetError(); alGetError();
throw; throw;
} }
std::auto_ptr<OpenAL_Sound> sound(new OpenAL_Sound(src, buf));
alSource3f(src, AL_POSITION, pos[0], pos[2], -pos[1]); alSource3f(src, AL_POSITION, pos[0], pos[2], -pos[1]);
alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f); alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f); alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
@ -508,14 +542,44 @@ Sound* OpenAL_Output::playSound3D(const std::string &fname, const float *pos, fl
Sound* OpenAL_Output::streamSound(const std::string &fname, float volume, float pitch) Sound* OpenAL_Output::streamSound(const std::string &fname, float volume, float pitch)
{ {
throwALerror();
std::auto_ptr<OpenAL_SoundStream> sound; std::auto_ptr<OpenAL_SoundStream> sound;
ALuint src;
DecoderPtr decoder = mManager.getDecoder(); if(mFreeSources.empty())
decoder->open(fname); fail("No free sources");
src = mFreeSources.back();
mFreeSources.pop_back();
sound.reset(new OpenAL_SoundStream(*this, decoder)); try
sound->play(volume, pitch); {
DecoderPtr decoder = mManager.getDecoder();
decoder->open(fname);
sound.reset(new OpenAL_SoundStream(*this, src, decoder));
}
catch(std::exception &e)
{
mFreeSources.push_back(src);
throw;
}
alSource3f(src, AL_POSITION, 0.0f, 0.0f, 0.0f);
alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
alSourcef(src, AL_REFERENCE_DISTANCE, 1.0f);
alSourcef(src, AL_MAX_DISTANCE, 1000.0f);
alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f);
alSourcef(src, AL_GAIN, volume);
alSourcef(src, AL_PITCH, pitch);
alSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE);
alSourcei(src, AL_LOOPING, AL_FALSE);
throwALerror();
sound->play();
return sound.release(); return sound.release();
} }
@ -540,7 +604,6 @@ OpenAL_Output::OpenAL_Output(SoundManager &mgr)
OpenAL_Output::~OpenAL_Output() OpenAL_Output::~OpenAL_Output()
{ {
mStreamThread.reset();
deinit(); deinit();
} }

View File

@ -2,6 +2,7 @@
#define GAME_SOUND_OPENAL_OUTPUT_H #define GAME_SOUND_OPENAL_OUTPUT_H
#include <string> #include <string>
#include <vector>
#include "alc.h" #include "alc.h"
#include "al.h" #include "al.h"
@ -18,6 +19,9 @@ namespace MWSound
ALCdevice *mDevice; ALCdevice *mDevice;
ALCcontext *mContext; ALCcontext *mContext;
typedef std::vector<ALuint> IDVec;
IDVec mFreeSources;
virtual void init(const std::string &devname=""); virtual void init(const std::string &devname="");
virtual void deinit(); virtual void deinit();
@ -35,6 +39,7 @@ namespace MWSound
class StreamThread; class StreamThread;
std::auto_ptr<StreamThread> mStreamThread; std::auto_ptr<StreamThread> mStreamThread;
friend class OpenAL_Sound;
friend class OpenAL_SoundStream; friend class OpenAL_SoundStream;
friend class SoundManager; friend class SoundManager;
}; };