1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-01 07:45:36 +00:00

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)
{ 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()
{
ALenum err = alGetError();
@ -70,14 +77,14 @@ class OpenAL_SoundStream : public Sound
volatile bool mIsFinished;
public:
OpenAL_SoundStream(OpenAL_Output &output, DecoderPtr decoder);
OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder);
virtual ~OpenAL_SoundStream();
virtual void stop();
virtual bool isPlaying();
virtual void update(const float *pos);
void play(float volume, float pitch);
void play();
bool process();
};
@ -144,25 +151,13 @@ struct OpenAL_Output::StreamThread {
};
OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, DecoderPtr decoder)
: mOutput(output), mDecoder(decoder), mIsFinished(true)
OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder)
: mOutput(output), mSource(src), mDecoder(decoder), mIsFinished(true)
{
throwALerror();
alGenSources(1, &mSource);
alGenBuffers(sNumBuffers, mBuffers);
throwALerror();
try
{
alGenBuffers(sNumBuffers, mBuffers);
throwALerror();
}
catch(std::exception &e)
{
alDeleteSources(1, &mSource);
alGetError();
throw;
}
try
{
int srate;
@ -178,7 +173,7 @@ OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, DecoderPtr decoder
}
catch(std::exception &e)
{
alDeleteSources(1, &mSource);
mOutput.mFreeSources.push_back(mSource);
alDeleteBuffers(sNumBuffers, mBuffers);
alGetError();
throw;
@ -188,21 +183,22 @@ OpenAL_SoundStream::~OpenAL_SoundStream()
{
mOutput.mStreamThread->remove(this);
alDeleteSources(1, &mSource);
alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0);
mOutput.mFreeSources.push_back(mSource);
alDeleteBuffers(sNumBuffers, mBuffers);
alGetError();
mDecoder->close();
}
void OpenAL_SoundStream::play(float volume, float pitch)
void OpenAL_SoundStream::play()
{
std::vector<char> data(mBufferSize);
alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0);
alSourcef(mSource, AL_GAIN, volume);
alSourcef(mSource, AL_PITCH, pitch);
throwALerror();
for(ALuint i = 0;i < sNumBuffers;i++)
@ -297,11 +293,12 @@ bool OpenAL_SoundStream::process()
//
class OpenAL_Sound : public Sound
{
OpenAL_Output &mOutput;
ALuint mSource;
ALuint mBuffer;
public:
OpenAL_Sound(ALuint src, ALuint buf);
OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf);
virtual ~OpenAL_Sound();
virtual void stop();
@ -330,19 +327,22 @@ ALuint OpenAL_Sound::LoadBuffer(DecoderPtr decoder)
}
data.resize(total);
ALuint buf;
ALuint buf=0;
alGenBuffers(1, &buf);
alBufferData(buf, format, &data[0], total, srate);
return buf;
}
OpenAL_Sound::OpenAL_Sound(ALuint src, ALuint buf)
: mSource(src), mBuffer(buf)
OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf)
: mOutput(output), mSource(src), mBuffer(buf)
{
}
OpenAL_Sound::~OpenAL_Sound()
{
alDeleteSources(1, &mSource);
alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0);
mOutput.mFreeSources.push_back(mSource);
alDeleteBuffers(1, &mBuffer);
alGetError();
}
@ -391,13 +391,37 @@ void OpenAL_Output::init(const std::string &devname)
alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
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()
{
if(mStreamThread.get() != 0)
mStreamThread->removeAll();
mStreamThread->removeAll();
if(!mFreeSources.empty())
{
alDeleteSources(mFreeSources.size(), mFreeSources.data());
mFreeSources.clear();
}
alcMakeContextCurrent(0);
if(mContext)
alcDestroyContext(mContext);
@ -412,28 +436,33 @@ Sound* OpenAL_Output::playSound(const std::string &fname, float volume, float pi
{
throwALerror();
DecoderPtr decoder = mManager.getDecoder();
decoder->open(fname);
std::auto_ptr<OpenAL_Sound> sound;
ALuint src=0, buf=0;
if(mFreeSources.empty())
fail("No free sources");
src = mFreeSources.back();
mFreeSources.pop_back();
try
{
DecoderPtr decoder = mManager.getDecoder();
decoder->open(fname);
buf = OpenAL_Sound::LoadBuffer(decoder);
decoder->close();
alGenSources(1, &src);
throwALerror();
decoder->close();
sound.reset(new OpenAL_Sound(*this, src, buf));
}
catch(std::exception &e)
{
if(alIsSource(src))
alDeleteSources(1, &src);
mFreeSources.push_back(src);
if(alIsBuffer(buf))
alDeleteBuffers(1, &buf);
alGetError();
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_DIRECTION, 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();
DecoderPtr decoder = mManager.getDecoder();
decoder->open(fname);
std::auto_ptr<OpenAL_Sound> sound;
ALuint src=0, buf=0;
if(mFreeSources.empty())
fail("No free sources");
src = mFreeSources.back();
mFreeSources.pop_back();
try
{
DecoderPtr decoder = mManager.getDecoder();
decoder->open(fname);
buf = OpenAL_Sound::LoadBuffer(decoder);
decoder->close();
alGenSources(1, &src);
throwALerror();
decoder->close();
sound.reset(new OpenAL_Sound(*this, src, buf));
}
catch(std::exception &e)
{
if(alIsSource(src))
alDeleteSources(1, &src);
mFreeSources.push_back(src);
if(alIsBuffer(buf))
alDeleteBuffers(1, &buf);
alGetError();
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_DIRECTION, 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)
{
throwALerror();
std::auto_ptr<OpenAL_SoundStream> sound;
ALuint src;
DecoderPtr decoder = mManager.getDecoder();
decoder->open(fname);
if(mFreeSources.empty())
fail("No free sources");
src = mFreeSources.back();
mFreeSources.pop_back();
sound.reset(new OpenAL_SoundStream(*this, decoder));
sound->play(volume, pitch);
try
{
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();
}
@ -540,7 +604,6 @@ OpenAL_Output::OpenAL_Output(SoundManager &mgr)
OpenAL_Output::~OpenAL_Output()
{
mStreamThread.reset();
deinit();
}

View file

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