OpenAL buffer management; add a buffer cache to prevent loading the same sample in memory twice. Especially useful to save memory for multi-aircraft configurations and (later) for AI models.

This commit is contained in:
ehofman
2009-10-09 09:00:53 +00:00
committed by Tim Moore
parent 4cc6bd69ae
commit 968f5d7693
4 changed files with 133 additions and 76 deletions

View File

@@ -76,6 +76,7 @@ SGSampleGroup::~SGSampleGroup ()
if ( sample->is_valid_source() && sample->is_playing() ) {
sample->no_valid_source();
_smgr->release_source( sample->get_source() );
_smgr->release_buffer( sample );
}
}
@@ -97,40 +98,8 @@ void SGSampleGroup::update( double dt ) {
//
// a request to start playing a sound has been filed.
//
ALboolean looping = sample->get_looping() ? AL_TRUE : AL_FALSE;
if ( !sample->is_valid_buffer() ) {
// sample was not yet loaded or removed again
// TODO: Create a buffer cache that checks whether a file is already present
// as an OpenAL buffer since buffers can be shared among sources.
load_file(sample);
if ( testForALError("load sample") ) {
throw sg_exception("Failed to load sound sample.");
continue;
}
// create an OpenAL buffer handle
ALuint buffer;
alGenBuffers(1, &buffer);
if ( testForALError("generate buffer") ) {
throw sg_exception("Failed to generate OpenAL buffer.");
continue;
}
// Copy data to the internal OpenAL buffer
const ALvoid *data = sample->get_data();
ALenum format = sample->get_format();
ALsizei size = sample->get_size();
ALsizei freq = sample->get_frequency();
alBufferData( buffer, format, data, size, freq );
sample->free_data();
if ( testForALError("buffer add data") ) {
continue;
}
sample->set_buffer(buffer);
}
if ( _smgr->request_buffer(sample) == SGSoundMgr::NO_BUFFER )
continue;
if ( _tied_to_listener && _smgr->has_changed() ) {
sample->set_base_position( _smgr->get_position_vec() );
@@ -139,6 +108,7 @@ void SGSampleGroup::update( double dt ) {
}
// start playing the sample
ALboolean looping = sample->get_looping() ? AL_TRUE : AL_FALSE;
ALuint buffer = sample->get_buffer();
ALuint source = _smgr->request_source();
if (alIsSource(source) == AL_TRUE && alIsBuffer(buffer) == AL_TRUE)
@@ -186,7 +156,6 @@ void SGSampleGroup::update( double dt ) {
sample->no_valid_source();
sample->stop();
_smgr->release_source( source );
}
}
testForALError("update");
@@ -216,7 +185,10 @@ bool SGSampleGroup::remove( const string &refname ) {
return false;
}
_samples.erase( sample_it );
// remove the sources buffer
_smgr->release_buffer( sample_it->second );
_samples.erase( refname );
return true;
}
@@ -397,23 +369,6 @@ void SGSampleGroup::update_sample_config( SGSoundSample *sample ) {
}
}
ALvoid
SGSampleGroup::load_file(SGSoundSample *sample) {
if (sample->is_file()) {
unsigned int size;
int freq, format;
void *data;
string sample_name = sample->get_sample_name();
_smgr->load(sample_name, &data, &format, &size, &freq);
sample->set_data( (unsigned char *)data );
sample->set_frequency( freq );
sample->set_format( format );
sample->set_size( size );
}
}
void SGSampleGroup::set_volume( float vol )
{
_volume = vol;

View File

@@ -151,11 +151,6 @@ public:
*/
void set_orientation( SGVec3f ori );
/**
* load the data of the sound sample
*/
void load_file(SGSoundSample *sound);
inline void tie_to_listener() { _tied_to_listener = true; }

View File

@@ -34,6 +34,7 @@
#endif
#include <iostream>
#include <algorithm>
#include "soundmgr_openal.hxx"
@@ -77,6 +78,7 @@ SGSoundMgr::SGSoundMgr() :
// destructor
SGSoundMgr::~SGSoundMgr() {
stop();
#if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
_alut_init--;
@@ -151,6 +153,16 @@ void SGSoundMgr::stop() {
if (_working) {
_working = false;
// clear any OpenAL buffers before shutting down
buffer_map_iterator buffers_current = _buffers.begin();
buffer_map_iterator buffers_end = _buffers.end();
for ( ; buffers_current != buffers_end; ++buffers_current ) {
refUint ref = buffers_current->second;
ALuint buffer = ref.id;
alDeleteBuffers(1, &buffer);
_buffers.erase( buffers_current );
}
_context = alcGetCurrentContext();
_device = alcGetContextsDevice(_context);
alcMakeContextCurrent(NULL);
@@ -196,7 +208,7 @@ void SGSoundMgr::unbind ()
void SGSoundMgr::update( double dt )
{
// nothing to do in the regular update,e verything is done on the following
// nothing to do in the regular update, everything is done on the following
// function
}
@@ -325,7 +337,6 @@ unsigned int SGSoundMgr::request_source()
if (_free_sources.size() > 0) {
source = _free_sources.back();
_free_sources.pop_back();
_sources_in_use.push_back(source);
}
@@ -335,21 +346,93 @@ unsigned int SGSoundMgr::request_source()
// Free up a source id for further use
void SGSoundMgr::release_source( unsigned int source )
{
for (unsigned int i = 0; i<_sources_in_use.size(); i++) {
if ( _sources_in_use[i] == source ) {
ALint result;
vector<ALuint>::iterator it;
alGetSourcei( source, AL_SOURCE_STATE, &result );
if ( result == AL_PLAYING ) {
alSourceStop( source );
}
testForALError("release source");
it = std::find(_sources_in_use.begin(), _sources_in_use.end(), source);
if ( it != _sources_in_use.end() ) {
ALint result;
_free_sources.push_back(source);
_sources_in_use.erase(_sources_in_use.begin()+i,
_sources_in_use.begin()+i+1);
break;
alGetSourcei( source, AL_SOURCE_STATE, &result );
if ( result == AL_PLAYING )
alSourceStop( source );
testForALError("release source");
_free_sources.push_back(source);
_sources_in_use.erase(it, it+1);
}
}
unsigned int SGSoundMgr::request_buffer(SGSoundSample *sample)
{
ALuint buffer = NO_BUFFER;
if ( !sample->is_valid_buffer() ) {
// sample was not yet loaded or removed again
string sample_name = sample->get_sample_name();
// see if the sample name is already cached
buffer_map_iterator buffer_it = _buffers.find( sample_name );
if ( buffer_it != _buffers.end() ) {
buffer_it->second.refctr++;
buffer = buffer_it->second.id;
sample->set_buffer( buffer );
return buffer;
}
// sample name was not found in the buffer cache.
if ( sample->is_file() ) {
unsigned int size;
int freq, format;
void *data;
load(sample_name, &data, &format, &size, &freq);
sample->set_data( (unsigned char *)data );
sample->set_frequency( freq );
sample->set_format( format );
sample->set_size( size );
}
// create an OpenAL buffer handle
alGenBuffers(1, &buffer);
if ( !testForALError("generate buffer") ) {
// Copy data to the internal OpenAL buffer
const ALvoid *data = sample->get_data();
ALenum format = sample->get_format();
ALsizei size = sample->get_size();
ALsizei freq = sample->get_frequency();
alBufferData( buffer, format, data, size, freq );
sample->free_data();
if ( !testForALError("buffer add data") ) {
sample->set_buffer(buffer);
_buffers[sample_name] = refUint(buffer);
}
}
}
else
buffer = sample->get_buffer();
return buffer;
}
void SGSoundMgr::release_buffer(SGSoundSample *sample)
{
string sample_name = sample->get_sample_name();
buffer_map_iterator buffer_it = _buffers.find( sample_name );
if ( buffer_it == _buffers.end() ) {
// buffer was not found
return;
}
sample->no_valid_buffer();
buffer_it->second.refctr--;
if (buffer_it->second.refctr == 0) {
ALuint buffer = buffer_it->second.id;
_buffers.erase( buffer_it );
alDeleteBuffers(1, &buffer);
testForALError("release buffer");
}
}

View File

@@ -60,14 +60,25 @@
#include "sample_group.hxx"
#include "sample_openal.hxx"
using std::map;
using std::string;
typedef map < string, SGSharedPtr<SGSampleGroup> > sample_group_map;
struct refUint {
unsigned int refctr;
ALuint id;
refUint() { refctr = 0; id = (ALuint)-1; };
refUint(ALuint i) { refctr = 1; id = i; };
~refUint() {};
};
typedef std::map < string, refUint > buffer_map;
typedef buffer_map::iterator buffer_map_iterator;
typedef buffer_map::const_iterator const_buffer_map_iterator;
typedef std::map < string, SGSharedPtr<SGSampleGroup> > sample_group_map;
typedef sample_group_map::iterator sample_group_map_iterator;
typedef sample_group_map::const_iterator const_sample_group_map_iterator;
/**
* Manage a collection of SGSampleGroup instances
*/
@@ -156,7 +167,7 @@ public:
/**
* get a new OpenAL source id
* returns NO_SOURCE is no source is available
* returns NO_SOURCE if no source is available
*/
unsigned int request_source();
@@ -165,6 +176,18 @@ public:
*/
void release_source( unsigned int source );
/**
* get a new OpenAL buffer id
* returns NO_BUFFER if loading of the buffer failed.
*/
unsigned int request_buffer(SGSoundSample *sample);
/**
* give back an OpenAL source id for further use.
*/
void release_buffer( SGSoundSample *sample );
/**
* returns true if the position has changed
@@ -197,6 +220,7 @@ private:
ALfloat _listener_ori[6];
sample_group_map _sample_groups;
buffer_map _buffers;
vector<ALuint> _free_sources;
vector<ALuint> _sources_in_use;