mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-09-28 14:41:06 -04:00
Allocate OpenAL sources when opening the device
This allows sources to be more efficiently retrieved and returned
This commit is contained in:
parent
8f9d4ff841
commit
ae8218bf03
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user