]> git.mxchange.org Git - simgear.git/commitdiff
OpenAL buffer management; add a buffer cache to prevent loading the same sample in...
authorehofman <ehofman>
Fri, 9 Oct 2009 09:00:53 +0000 (09:00 +0000)
committerTim Moore <timoore@redhat.com>
Sun, 11 Oct 2009 22:00:53 +0000 (00:00 +0200)
simgear/sound/sample_group.cxx
simgear/sound/sample_group.hxx
simgear/sound/soundmgr_openal.cxx
simgear/sound/soundmgr_openal.hxx

index 183a4894e37d2ec37ad90d678c989eff844ed4d5..dabf79bf0ea21411f1efc92dacbf2318908af3b1 100644 (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;
index e1ca92d1c16a2ab50675cd4edeb8f9c5a9e334be..b3170696389d808c14f155825e4f0a70a1e968df 100644 (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; }
 
 
index 98d7354b364f6ed1808074185d5435397795d27c..4f49416a507d627ec2f25fc26bd2ab78ca5cd4cc 100644 (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,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;
+
+        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;
+        }
 
-            _free_sources.push_back(source);
-            _sources_in_use.erase(_sources_in_use.begin()+i,
-                                  _sources_in_use.begin()+i+1);
-            break;
+        // 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");
     }
 }
 
index 24e8f1590d33f074ff0ab0ff88f5b42b2ccd163b..ef46df8f6a54a4df95f5a59d689732328cfb65f8 100644 (file)
 #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;