]> git.mxchange.org Git - simgear.git/blobdiff - simgear/sound/soundmgr_openal.cxx
add a debugging statement
[simgear.git] / simgear / sound / soundmgr_openal.cxx
index b204aa13fbc4418cf52ad40fbad452a29147c68d..450b5714d0cc98811747c9b72241c0807663ac5b 100644 (file)
@@ -34,6 +34,7 @@
 #endif
 
 #include <iostream>
+#include <algorithm>
 
 #include "soundmgr_openal.hxx"
 
@@ -58,8 +59,9 @@ SGSoundMgr::SGSoundMgr() :
     _volume(0.0),
     _device(NULL),
     _context(NULL),
-    _listener_pos(SGVec3d::zeros().data()),
-    _listener_vel(SGVec3f::zeros().data()),
+    _position(SGVec3d::zeros()),
+    _velocity(SGVec3d::zeros()),
+    _orientation(SGQuatd::zeros()),
     _devname(NULL)
 {
 #if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
@@ -77,6 +79,7 @@ SGSoundMgr::SGSoundMgr() :
 // destructor
 
 SGSoundMgr::~SGSoundMgr() {
+
     stop();
 #if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
     _alut_init--;
@@ -98,24 +101,27 @@ void SGSoundMgr::init() {
 
     ALCcontext *context = alcCreateContext(device, NULL);
     if ( testForError(context, "Unable to create a valid context.") ) {
+        alcCloseDevice (device);
         return;
     }
 
     if ( !alcMakeContextCurrent(context) ) {
         testForALCError("context initialization");
+        alcDestroyContext (context);
+        alcCloseDevice (device);
         return;
     }
 
     _context = context;
     _working = true;
 
-    _listener_ori[0] = 0.0; _listener_ori[1] = 0.0; _listener_ori[2] = -1.0;
-    _listener_ori[3] = 0.0; _listener_ori[4] = 1.0; _listener_ori[5] = 0.0;
+    _at_up_vec[0] = 0.0; _at_up_vec[1] = 0.0; _at_up_vec[2] = -1.0;
+    _at_up_vec[3] = 0.0; _at_up_vec[4] = 1.0; _at_up_vec[5] = 0.0;
 
     alListenerf( AL_GAIN, 0.2f );
-    alListenerfv( AL_POSITION, toVec3f(_listener_pos).data() );
-    alListenerfv( AL_ORIENTATION, _listener_ori );
-    alListenerfv( AL_VELOCITY, _listener_vel.data() );
+    alListenerfv( AL_ORIENTATION, _at_up_vec );
+    alListenerfv( AL_POSITION, SGVec3f::zeros().data() );
+    alListenerfv( AL_VELOCITY, SGVec3f::zeros().data() );
 
     alDopplerFactor(1.0);
     alDopplerVelocity(340.3);   // speed of sound in meters per second.
@@ -128,8 +134,6 @@ void SGSoundMgr::init() {
 
     testForALError("listener initialization");
 
-    alGetError(); // clear any undetetced error, just to be sure
-
     // get a free source one at a time
     // if an error is returned no more (hardware) sources are available
     for (unsigned int i=0; i<MAX_SOURCES; i++) {
@@ -144,6 +148,10 @@ void SGSoundMgr::init() {
         }
         else break;
     }
+
+    if (_free_sources.size() == 0) {
+        SG_LOG(SG_GENERAL, SG_ALERT, "Unable to grab any OpenAL sources!");
+    }
 }
 
 // suspend the sound manager
@@ -151,6 +159,16 @@ void SGSoundMgr::stop() {
     if (_working) {
         _working = false;
 
+        // clear any OpenAL buffers before shutting down
+        buffer_map_iterator buffers_current;
+        while(_buffers.size()){
+            buffers_current = _buffers.begin();
+            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 +214,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
 }
 
@@ -204,7 +222,7 @@ void SGSoundMgr::update( double dt )
 // run the audio scheduler
 void SGSoundMgr::update_late( double dt ) {
     if (_working) {
-        // alcSuspendContext(_context);
+        alcSuspendContext(_context);
 
         sample_group_map_iterator sample_grp_current = _sample_groups.begin();
         sample_group_map_iterator sample_grp_end = _sample_groups.end();
@@ -215,14 +233,14 @@ void SGSoundMgr::update_late( double dt ) {
 
         if (_changed) {
             alListenerf( AL_GAIN, _volume );
-            alListenerfv( AL_VELOCITY, _listener_vel.data() );
-            alListenerfv( AL_ORIENTATION, _listener_ori );
-            alListenerfv( AL_POSITION, toVec3f(_listener_pos).data() );
+            alListenerfv( AL_ORIENTATION, _at_up_vec );
+            alListenerfv( AL_POSITION, toVec3f(_position).data() );
+            alListenerfv( AL_VELOCITY, toVec3f(_velocity).data() );
             // alDopplerVelocity(340.3);       // TODO: altitude dependent
             testForALError("update");
             _changed = false;
         }
-        // alcProcessContext(_context);
+        alcProcessContext(_context);
     }
 }
 
@@ -309,6 +327,32 @@ void SGSoundMgr::set_volume( float v )
     _changed = true;
 }
 
+/**
+ * set the orientation of the listener (in opengl coordinates)
+ *
+ * Description: ORIENTATION is a pair of 3-tuples representing the
+ * 'at' direction vector and 'up' direction of the Object in
+ * Cartesian space. AL expects two vectors that are orthogonal to
+ * each other. These vectors are not expected to be normalized. If
+ * one or more vectors have zero length, implementation behavior
+ * is undefined. If the two vectors are linearly dependent,
+ * behavior is undefined.
+ */
+void SGSoundMgr::set_orientation( SGQuatd ori )
+{
+    _orientation = ori;
+
+    SGVec3d sgv_up = ori.rotate(SGVec3d::e2());
+    SGVec3d sgv_at = ori.rotate(SGVec3d::e3());
+    _at_up_vec[0] = sgv_at[0];
+    _at_up_vec[1] = sgv_at[1];
+    _at_up_vec[2] = sgv_at[2];
+    _at_up_vec[3] = sgv_up[0];
+    _at_up_vec[4] = sgv_up[1];
+    _at_up_vec[5] = sgv_up[2];
+    _changed = true;
+}
+
 // Get an unused source id
 //
 // The Sound Manager should keep track of the sources in use, the distance
@@ -325,7 +369,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,22 +378,94 @@ 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");
+    }
 }
 
 bool SGSoundMgr::load(string &samplepath, void **dbuf, int *fmt,
@@ -399,29 +514,6 @@ bool SGSoundMgr::load(string &samplepath, void **dbuf, int *fmt,
 }
 
 
-/**
- * set the orientation of the listener (in opengl coordinates)
- *
- * Description: ORIENTATION is a pair of 3-tuples representing the
- * 'at' direction vector and 'up' direction of the Object in
- * Cartesian space. AL expects two vectors that are orthogonal to
- * each other. These vectors are not expected to be normalized. If
- * one or more vectors have zero length, implementation behavior
- * is undefined. If the two vectors are linearly dependent,
- * behavior is undefined.
- */
-void SGSoundMgr::set_orientation( SGQuatd ori )
-{
-    SGVec3d sgv_up = ori.rotate(SGVec3d::e2());
-    SGVec3d sgv_at = ori.rotate(SGVec3d::e3());
-    for (int i=0; i<3; i++) {
-       _listener_ori[i] = sgv_at[i];
-       _listener_ori[i+3] = sgv_up[i];
-    }
-    _changed = true;
-}
-
-
 bool SGSoundMgr::testForError(void *p, string s)
 {
    if (p == NULL) {
@@ -458,6 +550,7 @@ bool SGSoundMgr::testForALCError(string s)
 
 bool SGSoundMgr::testForALUTError(string s)
 {
+#if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
     ALenum error;
     error =  alutGetError ();
     if (error != ALUT_ERROR_NO_ERROR) {
@@ -466,5 +559,6 @@ bool SGSoundMgr::testForALUTError(string s)
                                        << s);
         return true;
     }
+#endif
     return false;
 }