]> git.mxchange.org Git - simgear.git/commitdiff
Initial commit of the new sound system, expect more updates to follow
authorehofman <ehofman>
Sun, 4 Oct 2009 13:52:27 +0000 (13:52 +0000)
committerTim Moore <timoore@redhat.com>
Tue, 6 Oct 2009 05:22:06 +0000 (07:22 +0200)
14 files changed:
simgear/environment/visual_enviro.cxx
simgear/environment/visual_enviro.hxx
simgear/sound/Makefile.am
simgear/sound/jet.wav
simgear/sound/openal_test2.cxx
simgear/sound/sample_group.cxx [new file with mode: 0644]
simgear/sound/sample_group.hxx [new file with mode: 0644]
simgear/sound/sample_openal.cxx
simgear/sound/sample_openal.hxx
simgear/sound/soundmgr_openal.cxx
simgear/sound/soundmgr_openal.hxx
simgear/sound/xmlsound.cxx
simgear/sound/xmlsound.hxx
simgear/structure/SGAtomic.cxx

index 42b61fd0f6993e6d5b8889dd628060a058b3d179..71a0c5eaee71b2405ae1392bc9b032afd9ae0e9a 100644 (file)
@@ -30,7 +30,7 @@
 #include <simgear/math/sg_geodesy.hxx>
 #include <simgear/math/point3d.hxx>
 #include <simgear/math/polar3d.hxx>
-#include <simgear/sound/soundmgr_openal.hxx>
+#include <simgear/sound/sample_group.hxx>
 #include <simgear/scene/sky/cloudfield.hxx>
 #include <simgear/scene/sky/newcloud.hxx>
 #include <simgear/props/props.hxx>
@@ -175,7 +175,7 @@ SGEnviro::SGEnviro() :
        lightning_enable_state(false),
        elapsed_time(0.0),
        dt(0.0),
-       soundMgr(NULL),
+       sampleGroup(NULL),
        snd_active(false),
        snd_dist(0.0),
        min_time_before_lt(0.0),
@@ -189,6 +189,8 @@ SGEnviro::SGEnviro() :
 }
 
 SGEnviro::~SGEnviro(void) {
+       if (sampleGroup) delete sampleGroup;
+
   // OSGFIXME
   return;
        list_of_lightning::iterator iLightning;
@@ -530,8 +532,8 @@ void SGEnviro::drawRain(double pitch, double roll, double heading, double hspeed
 
 }
 
-void SGEnviro::set_soundMgr(SGSoundMgr *mgr) {
-       soundMgr = mgr;
+void SGEnviro::set_sampleGroup(SGSampleGroup *sgr) {
+       sampleGroup = sgr;
 }
 
 void SGEnviro::drawPrecipitation(double rain_norm, double snow_norm, double hail_norm, double pitch, double roll, double heading, double hspeed) {
@@ -616,7 +618,7 @@ void SGLightning::lt_build(void) {
     top[PY] = alt;
     top[PZ] = 0;
     lt_build_tree_branch(0, top, 1.0, 50, top[PY] / 8.0);
-       if( ! sgEnviro.soundMgr )
+       if( ! sgEnviro.sampleGroup )
                return;
        Point3D start( sgEnviro.last_lon*SG_DEGREES_TO_RADIANS, sgEnviro.last_lat*SG_DEGREES_TO_RADIANS, 0.0 );
        Point3D dest( lon*SG_DEGREES_TO_RADIANS, lat*SG_DEGREES_TO_RADIANS, 0.0 );
@@ -751,15 +753,15 @@ void SGEnviro::drawLightning(void) {
                                double ax = 0.0, ay = 0.0;
                                ax = cos(course) * dist;
                                ay = sin(course) * dist;
-                               SGSharedPtr<SGSoundSample> snd = soundMgr->find("thunder");
+                               SGSharedPtr<SGSoundSample> snd = sampleGroup->find("thunder");
                                if( snd ) {
-                                       ALfloat pos[3]={ax, ay, -sgEnviro.last_alt };
-                                       snd->set_source_pos(pos);
+                                       SGVec3d pos = SGVec3d(ax, ay, -sgEnviro.last_alt);
+                                       snd->set_base_position(pos);
                                        snd->play_once();
                                }
                        }
                } else {
-                       if( !soundMgr->is_playing("thunder") ) {
+                       if( !sampleGroup->is_playing("thunder") ) {
                                snd_active = false;
                                snd_playing = false;
                        }
index 51a76a0692e7310f0cd954dc0a9b6d7b19f68e70..08830c0bf6b3b8be6685a47b71c3b95b1ac82568 100644 (file)
@@ -32,7 +32,7 @@ using std::vector;
 using std::string;
 
 class SGLightning;
-class SGSoundMgr;
+class SGSampleGroup;
 
 /**
  * Simulate some echo on a weather radar.
@@ -84,7 +84,7 @@ private:
        sgVec4  fog_color;
        sgMat4 transform;
        double last_lon, last_lat, last_alt;
-       SGSoundMgr      *soundMgr;
+       SGSampleGroup   *sampleGroup;
        bool            snd_active, snd_playing;
        double          snd_timer, snd_wait, snd_pos_lat, snd_pos_lon, snd_dist;
        double          min_time_before_lt;
@@ -243,7 +243,7 @@ public:
      * Forward the sound manager instance to be able to play samples.
      * @param mgr a running sound manager
      */
-       void set_soundMgr(SGSoundMgr *mgr);
+       void set_sampleGroup(SGSampleGroup *sgr);
 
        void setFOV( float w, float h );
        void getFOV( float &w, float &h );
index e421cdef5ca82e20bc200d8801bb1adae00332d2..57f3161a6dcafcda47f6f19b2f725a989dfee4e5 100644 (file)
@@ -7,11 +7,13 @@ lib_LIBRARIES = libsgsound.a
 noinst_HEADERS =
 
 include_HEADERS = \
+       sample_group.hxx \
        sample_openal.hxx \
        soundmgr_openal.hxx \
        xmlsound.hxx 
 
 libsgsound_a_SOURCES = \
+       sample_group.cxx \
        sample_openal.cxx  \
        soundmgr_openal.cxx \
        xmlsound.cxx 
@@ -27,10 +29,10 @@ libsgsound_a_SOURCES = \
 
 #openal_test2_LDADD = \
 #      libsgsound.a \
+#      $(top_builddir)/simgear/structure/libsgstructure.a \
+#      $(top_builddir)/simgear/timing/libsgtiming.a \
 #      $(top_builddir)/simgear/debug/libsgdebug.a \
 #      $(top_builddir)/simgear/misc/libsgmisc.a \
-#      $(top_builddir)/simgear/structure/libsgstructure.a \
-#      $(openal_LIBS) \
-#      -lOpenThreads
+#      $(openal_LIBS)
 
 INCLUDES = -I$(top_srcdir) -DSRC_DIR=\"$(top_srcdir)/simgear/sound\"
index 891c84d0b2064d5e66e594d65e8809b0953c8b07..a06f2afeaebc8fdea8601d67ddb935db8cffef68 100644 (file)
Binary files a/simgear/sound/jet.wav and b/simgear/sound/jet.wav differ
index da263620822fedeb0842ad0629faf6c464d8eae8..46a0f621ad640392e0158e9d3ded4d6110d84fd6 100644 (file)
@@ -7,48 +7,94 @@ static unsigned int sleep(unsigned int secs) { return 0; }
 #include <unistd.h>    // sleep()
 #endif
 
-#include "sample_openal.hxx"
+#include <simgear/debug/logstream.hxx>
+#include <simgear/misc/sg_path.hxx>
+
 #include "soundmgr_openal.hxx"
 
 
 int main( int argc, char *argv[] ) {
-    SGSoundMgr sm;
+    SGSampleGroup *sgr;
+    SGSoundMgr *smgr;
+
+    smgr = new SGSoundMgr;
+
+    smgr->bind();
+    smgr->init();
+    smgr->set_volume(0.9);
+    sgr = smgr->find("default", true);
 
-    SGSoundSample sample1( SRC_DIR, "jet.wav" );
-    sample1.set_volume(0.5);
-    sample1.set_volume(0.2);
-    sample1.play_looped();
+    SGSoundSample *sample1 = new SGSoundSample( SRC_DIR, "jet.wav" );
+    sample1->set_volume(1.0);
+    sample1->set_pitch(1.0);
+    sample1->play_looped();
+    sgr->add(sample1, "sound1");
+    smgr->update(1.0);
+    printf("playing sample1\n");
     sleep(1);
 
-    SGSoundSample sample2( SRC_DIR, "jet.wav" );
-    sample2.set_volume(0.5);
-    sample2.set_pitch(0.4);
-    sample2.play_looped();
+    SGSoundSample *sample2 = new SGSoundSample( SRC_DIR, "jet.wav" );
+    sample2->set_volume(0.5);
+    sample2->set_pitch(0.4);
+    sample2->play_looped();
+    sgr->add(sample2, "sound2");
+    smgr->update(1.0);
+    printf("playing sample2\n");
     sleep(1);
 
-    SGSoundSample sample3( SRC_DIR, "jet.wav" );
-    sample3.set_volume(0.5);
-    sample3.set_pitch(0.8);
-    sample3.play_looped();
+    SGSoundSample *sample3 = new SGSoundSample( SRC_DIR, "jet.wav" );
+    sample3->set_volume(0.5);
+    sample3->set_pitch(0.8);
+    sample3->play_looped();
+    sgr->add(sample3, "sound3");
+    smgr->update(1.0);
+    printf("playing sample3\n");
     sleep(1);
 
-    SGSoundSample sample4( SRC_DIR, "jet.wav" );
-    sample4.set_volume(0.5);
-    sample4.set_pitch(1.2);
-    sample4.play_looped();
+    SGSoundSample *sample4 = new SGSoundSample( SRC_DIR, "jet.wav" );
+    sample4->set_volume(0.5);
+    sample4->set_pitch(1.2);
+    sample4->play_looped();
+    sgr->add(sample4, "sound4");
+    smgr->update(1.0);
+    printf("playing sample4\n");
     sleep(1);
 
-    SGSoundSample sample5( SRC_DIR, "jet.wav" );
-    sample5.set_volume(0.5);
-    sample5.set_pitch(1.6);
-    sample5.play_looped();
+    SGSoundSample *sample5 = new SGSoundSample( SRC_DIR, "jet.wav" );
+    sample5->set_volume(0.5);
+    sample5->set_pitch(1.6);
+    sample5->play_looped();
+    sgr->add(sample5, "sound5");
+    smgr->update(1.0);
+    printf("playing sample5\n");
     sleep(1);
 
-    SGSoundSample sample6( SRC_DIR, "jet.wav" );
-    sample6.set_volume(0.5);
-    sample6.set_pitch(2.0);
-    sample6.play_looped();
+    SGSoundSample *sample6 = new SGSoundSample( SRC_DIR, "jet.wav" );
+    sample6->set_volume(0.5);
+    sample6->set_pitch(2.0);
+    sample6->play_looped();
+    sgr->add(sample6, "sound6");
+    smgr->update(1.0);
+    printf("playing sample6\n");
+    sleep(1);
+
+    for (int i=0; i<10; i++) {
+        sleep(1);
+        smgr->update(1);
+    }
+
+    sgr->stop("sound1");
+    sgr->stop("sound2");
+    sgr->stop("sound3");
+    sleep(0.5);
+    sgr->update(0.5);
+    sgr->stop("sound4");
+    sgr->stop("sound5");
+    sgr->stop("sound6");
+    sgr->update(1);
     sleep(1);
 
-    sleep(10);
+    smgr->unbind();
+    sleep(2);
+    delete smgr;
 }
diff --git a/simgear/sound/sample_group.cxx b/simgear/sound/sample_group.cxx
new file mode 100644 (file)
index 0000000..ffa23e6
--- /dev/null
@@ -0,0 +1,443 @@
+#ifdef HAVE_CONFIG_H
+#  include <simgear_config.h>
+#endif
+
+#include <simgear/compiler.h>
+
+#if defined (__APPLE__)
+#  ifdef __GNUC__
+#    if ( __GNUC__ >= 3 ) && ( __GNUC_MINOR__ >= 3 )
+//  #        include <math.h>
+inline int (isnan)(double r) { return !(r <= 0 || r >= 0); }
+#    else
+    // any C++ header file undefines isinf and isnan
+    // so this should be included before <iostream>
+    // the functions are STILL in libm (libSystem on mac os x)
+extern "C" int isnan (double);
+extern "C" int isinf (double);
+#    endif
+#  else
+//    inline int (isinf)(double r) { return isinf(r); }
+//    inline int (isnan)(double r) { return isnan(r); }
+#  endif
+#endif
+
+#if defined (__FreeBSD__)
+#  if __FreeBSD_version < 500000
+     extern "C" {
+       inline int isnan(double r) { return !(r <= 0 || r >= 0); }
+     }
+#  endif
+#endif
+
+#if defined (__CYGWIN__)
+#  include <ieeefp.h>
+#endif
+
+#if defined(__MINGW32__)
+#  define isnan(x) _isnan(x)
+#endif
+
+#include "soundmgr_openal.hxx"
+#include "sample_group.hxx"
+
+SGSampleGroup::SGSampleGroup () :
+    _smgr(NULL),
+    _active(false),
+    _changed(true),
+    _position_changed(true),
+    _position(SGVec3d::zeros().data()),
+    _orientation(SGVec3f::zeros().data())
+{
+    _samples.clear();
+}
+
+SGSampleGroup::SGSampleGroup ( SGSoundMgr *smgr, const string &refname ) :
+    _smgr(smgr),
+    _active(false), 
+    _changed(true),
+    _position_changed(true),
+    _position(SGVec3d::zeros().data()),
+    _orientation(SGVec3f::zeros().data())
+{
+    _smgr->add(this, refname);
+    _active = _smgr->is_working();
+    _samples.clear();
+}
+
+SGSampleGroup::~SGSampleGroup ()
+{
+    _active = false;
+
+    sample_map_iterator sample_current = _samples.begin();
+    sample_map_iterator sample_end = _samples.end();
+    for ( ; sample_current != sample_end; ++sample_current ) {
+        SGSoundSample *sample = sample_current->second;
+
+        if ( sample->is_valid_source() && sample->is_playing() ) {
+            sample->no_valid_source();
+            _smgr->release_source( sample->get_source() );
+        }
+    }
+
+    _smgr = 0;
+}
+
+void SGSampleGroup::update( double dt ) {
+
+    if ( !_active ) return;
+
+    // testForALError("start of update!!\n");
+
+    sample_map_iterator sample_current = _samples.begin();
+    sample_map_iterator sample_end = _samples.end();
+    for ( ; sample_current != sample_end; ++sample_current ) {
+        SGSoundSample *sample = sample_current->second;
+
+        if ( !sample->is_valid_source() && sample->is_playing() ) {
+            //
+            // 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);
+            }
+
+            // start playing the sample
+            ALuint buffer = sample->get_buffer();
+            ALuint source = _smgr->request_source();
+            if (alIsSource(source) == AL_TRUE && alIsBuffer(buffer) == AL_TRUE)
+            {
+                sample->set_source( source );
+                
+                alSourcei( source, AL_BUFFER, buffer );
+                testForALError("assign buffer to source");
+
+                sample->set_source( source );
+                update_sample_config( sample );
+
+                alSourcei( source, AL_SOURCE_RELATIVE, AL_FALSE );
+                alSourcei( source, AL_LOOPING, looping );
+                alSourcePlay( source );
+                testForALError("sample play");
+            } else {
+                if (alIsBuffer(buffer) == AL_FALSE) 
+                   SG_LOG( SG_GENERAL, SG_ALERT, "No such buffer!\n");
+                // sample->no_valid_source();
+                // sadly, no free source available at this time
+            }
+
+        } else if ( sample->is_valid_source() && sample->has_changed() ) {
+            if ( !sample->is_playing() ) {
+                // a request to stop playing the sound has been filed.
+
+                sample->no_valid_source();
+                sample->stop();
+                _smgr->release_source( sample->get_source() );
+            } else  {
+                update_sample_config( sample );
+            }
+
+        } else if ( sample->is_valid_source() ) {
+            // check if the sound has stopped by itself
+
+            unsigned int source = sample->get_source();
+            int result;
+
+            alGetSourcei( source, AL_SOURCE_STATE, &result );
+            if ( result == AL_STOPPED ) {
+                // sample is stoped because it wasn't looping
+                sample->no_valid_source();
+                sample->stop();
+                _smgr->release_source( source );
+
+            }
+        }
+        testForALError("update");
+    }
+}
+
+// add a sound effect, return true if successful
+bool SGSampleGroup::add( SGSoundSample *sound, const string& refname ) {
+
+    sample_map_iterator sample_it = _samples.find( refname );
+    if ( sample_it != _samples.end() ) {
+        // sample name already exists
+        return false;
+    }
+
+    _samples[refname] = sound;
+    return true;
+}
+
+
+// remove a sound effect, return true if successful
+bool SGSampleGroup::remove( const string &refname ) {
+
+    sample_map_iterator sample_it = _samples.find( refname );
+    if ( sample_it == _samples.end() ) {
+        // sample was not found
+        return false;
+    }
+
+    _samples.erase( sample_it );
+    return true;
+}
+
+
+// return true of the specified sound exists in the sound manager system
+bool SGSampleGroup::exists( const string &refname ) {
+    sample_map_iterator sample_it = _samples.find( refname );
+    if ( sample_it == _samples.end() ) {
+        // sample was not found
+        return false;
+    }
+
+    return true;
+}
+
+
+// return a pointer to the SGSoundSample if the specified sound exists
+// in the sound manager system, otherwise return NULL
+SGSoundSample *SGSampleGroup::find( const string &refname ) {
+    sample_map_iterator sample_it = _samples.find( refname );
+    if ( sample_it == _samples.end() ) {
+        // sample was not found
+        return NULL;
+    }
+
+    return sample_it->second;
+}
+
+
+// stop playing all associated samples
+void
+SGSampleGroup::suspend ()
+{
+    _active = false;
+    sample_map_iterator sample_current = _samples.begin();
+    sample_map_iterator sample_end = _samples.end();
+    for ( ; sample_current != sample_end; ++sample_current ) {
+        SGSoundSample *sample = sample_current->second;
+
+        if ( sample->is_valid_source() && sample->is_playing() ) {
+            unsigned int source = sample->get_source();
+            alSourcePause( source );
+        }
+    }
+    testForALError("suspend");
+}
+
+// resume playing all associated samples
+void
+SGSampleGroup::resume ()
+{
+    sample_map_iterator sample_current = _samples.begin();
+    sample_map_iterator sample_end = _samples.end();
+    for ( ; sample_current != sample_end; ++sample_current ) {
+        SGSoundSample *sample = sample_current->second;
+
+        if ( sample->is_valid_source() && sample->is_playing() ) {
+            unsigned int source = sample->get_source();
+            alSourcePlay( source );
+        }
+    }
+    testForALError("resume");
+    _active = true;
+}
+
+
+// tell the scheduler to play the indexed sample in a continuous loop
+bool SGSampleGroup::play( const string &refname, bool looping = false ) {
+    SGSoundSample *sample = find( refname );
+
+    if ( sample == NULL ) {
+        return false;
+    }
+
+    sample->play( looping );
+    return true;
+}
+
+
+// return true of the specified sound is currently being played
+bool SGSampleGroup::is_playing( const string& refname ) {
+    SGSoundSample *sample = find( refname );
+
+    if ( sample == NULL ) {
+        return false;
+    }
+
+    return ( sample->is_playing() ) ? true : false;
+}
+
+// immediate stop playing the sound
+bool SGSampleGroup::stop( const string& refname ) {
+    SGSoundSample *sample  = find( refname );
+
+    if ( sample == NULL ) {
+        return false;
+    }
+
+    sample->stop();
+    return true;
+}
+
+
+// set source position of all managed sounds
+void SGSampleGroup::set_position( SGVec3d pos ) {
+    if ( isnan(pos.data()[0]) || isnan(pos.data()[1]) || isnan(pos.data()[2]) )
+    {
+        SG_LOG( SG_GENERAL, SG_ALERT, "NAN's found in SampleGroup postion");
+        return;
+    }
+
+    sample_map_iterator sample_current = _samples.begin();
+    sample_map_iterator sample_end = _samples.end();
+    for ( ; sample_current != sample_end; ++sample_current ) {
+        SGSoundSample *sample = sample_current->second;
+        sample->set_base_position( pos );
+    }
+}
+
+// set source velocity of all managed sounds
+void SGSampleGroup::set_velocity( SGVec3f vel ) {
+    if ( isnan(vel.data()[0]) || isnan(vel.data()[1]) || isnan(vel.data()[2]) )
+    {
+        SG_LOG( SG_GENERAL, SG_ALERT, "NAN's found in SampleGroup velocity");
+        return;
+    }
+
+    sample_map_iterator sample_current = _samples.begin();
+    sample_map_iterator sample_end = _samples.end();
+    for ( ; sample_current != sample_end; ++sample_current ) {
+        SGSoundSample *sample = sample_current->second;
+        sample->set_velocity( vel );
+    }
+}
+
+// ste the source orientation of all managed sounds
+void SGSampleGroup::set_orientation( SGVec3f ori ) {
+    if ( isnan(ori.data()[0]) || isnan(ori.data()[1]) || isnan(ori.data()[2]) )
+    {
+        SG_LOG( SG_GENERAL, SG_ALERT, "NAN's found in SampleGroup orientation");
+        return;
+    }
+
+    sample_map_iterator sample_current = _samples.begin();
+    sample_map_iterator sample_end = _samples.end();
+    for ( ; sample_current != sample_end; ++sample_current ) {
+        SGSoundSample *sample = sample_current->second;
+        sample->set_orientation( ori );
+    }
+}
+
+void SGSampleGroup::update_sample_config( SGSoundSample *sample ) {
+    if ( sample->is_valid_source() ) {
+        unsigned int source = sample->get_source();
+
+        alSourcefv( source, AL_POSITION, sample->get_position());
+        alSourcefv( source, AL_DIRECTION, sample->get_direction() );
+        alSourcefv( source, AL_VELOCITY, sample->get_velocity() );
+        testForALError("position and orientation");
+
+        alSourcef( source, AL_PITCH, sample->get_pitch() );
+        alSourcef( source, AL_GAIN, sample->get_volume() );
+        testForALError("pitch and gain");
+
+        if ( sample->has_static_data_changed() ) {
+            alSourcef( source, AL_CONE_INNER_ANGLE, sample->get_innerangle() );
+            alSourcef( source, AL_CONE_OUTER_ANGLE, sample->get_outerangle() );
+            alSourcef( source, AL_CONE_OUTER_GAIN, sample->get_outergain() );
+            testForALError("audio cone");
+
+            alSourcef( source, AL_ROLLOFF_FACTOR, 1.0 );
+            alSourcef( source, AL_MAX_DISTANCE, sample->get_max_dist() );
+            alSourcef( source, AL_REFERENCE_DISTANCE,
+                               sample->get_reference_dist() );
+            testForALError("distance rolloff");
+        }
+    }
+}
+
+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;
+    if (_volume < 0.0) _volume = 0.0;
+    if (_volume > 1.0) _volume = 1.0;
+
+    sample_map_iterator sample_current = _samples.begin();
+    sample_map_iterator sample_end = _samples.end();
+    for ( ; sample_current != sample_end; ++sample_current ) {
+        SGSoundSample *sample = sample_current->second;
+        sample->set_master_volume( _volume );
+    }
+}
+
+bool SGSampleGroup::testForError(void *p, string s)
+{
+   if (p == NULL) {
+      SG_LOG( SG_GENERAL, SG_ALERT, "Error (sample group): " << s);
+      return true;
+   }
+   return false;
+}
+
+bool SGSampleGroup::testForALError(string s)
+{
+    ALenum error = alGetError();
+    if (error != AL_NO_ERROR)  {
+       SG_LOG( SG_GENERAL, SG_ALERT, "AL Error (sample group): "
+                                      << alGetString(error) << " at " << s);
+       return true;
+    }
+    return false;
+}
+
diff --git a/simgear/sound/sample_group.hxx b/simgear/sound/sample_group.hxx
new file mode 100644 (file)
index 0000000..3e27701
--- /dev/null
@@ -0,0 +1,181 @@
+// soundmgr.hxx -- Sound effect management class
+//
+// Sampel Group handler initially written by Erik Hofman
+//
+// Copyright (C) 2009  Erik Hofman - <erik@ehofman.com>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// $Id$
+
+/**
+ * \file sample_group.hxx
+ * sample groups contain all sounds related to one specific object and
+ * have to be added to the sound manager, otherwise they won't get processed.
+ */
+
+#ifndef _SG_SAMPLE_GROUP_OPENAL_HXX
+#define _SG_SAMPLE_GROUP_OPENAL_HXX 1
+
+#ifndef __cplusplus
+# error This library requires C++
+#endif
+
+#if defined(__APPLE__)
+# include <OpenAL/al.h>
+#else
+# include <AL/al.h>
+#endif
+
+#include <string>
+#include <map>
+
+#include <simgear/compiler.h>
+#include <simgear/math/SGMath.hxx>
+#include <simgear/structure/SGReferenced.hxx>
+#include <simgear/structure/SGSharedPtr.hxx>
+#include <simgear/structure/exception.hxx>
+
+#include "sample_openal.hxx"
+
+using std::map;
+using std::string;
+
+typedef map < string, SGSharedPtr<SGSoundSample> > sample_map;
+typedef sample_map::iterator sample_map_iterator;
+typedef sample_map::const_iterator const_sample_map_iterator;
+
+class SGSoundMgr;
+
+class SGSampleGroup : public SGReferenced
+{
+public:
+    SGSampleGroup ();
+    SGSampleGroup ( SGSoundMgr *smgr, const string &refname );
+    ~SGSampleGroup ();
+
+    virtual void update (double dt);
+
+    /**
+     * add a sound effect, return true if successful
+     */
+    bool add( SGSoundSample *sound, const string& refname );
+
+    /**
+     * remove a sound effect, return true if successful
+     */
+    bool remove( const string& refname );
+
+    /**
+     * return true of the specified sound exists in the sound manager system
+     */
+    bool exists( const string& refname );
+
+    /**
+     * return a pointer to the SGSoundSample if the specified sound
+     * exists in the sound manager system, otherwise return NULL
+     */
+    SGSoundSample *find( const string& refname );
+
+    /**
+     * request to stop playing all associated samples until further notice
+     */
+    void suspend();
+
+    /**
+     * request to resume playing all associated samples
+     */
+    void resume();
+
+
+    /**
+     * request to start playing the associated samples
+     */
+    bool play( const string& refname, bool looping );
+    
+    /**
+     * tell the scheduler to play the indexed sample in a continuous
+     * loop
+     */
+    inline bool play_looped( const string& refname ) {
+        return play( refname, true );
+    }
+
+    /**
+     * tell the scheduler to play the indexed sample once
+     */
+    inline bool play_once( const string& refname ) {
+        return play( refname, false );
+    }
+
+    /**
+     * return true of the specified sound is currently being played
+     */
+    bool is_playing( const string& refname );
+
+    /**
+     * request to stop playing the associated samples
+     */
+    bool stop( const string& refname );
+
+    /**
+     * set overall volume for the application.
+     * @param must be between 0.0 and 1.0
+     */
+    void set_volume( float vol );
+
+    /**
+     * set the positions of all managed sound sources
+     */
+    void set_position( SGVec3d pos );
+
+    /**
+     * set the velocities of all managed sound sources
+     */
+    void set_velocity( SGVec3f vel );
+
+    /**
+     * set the orientation of all managed sound sources
+     */
+    void set_orientation( SGVec3f ori );
+
+    /**
+     * load the data of the sound sample
+     */
+    void load_file(SGSoundSample *sound);
+
+protected:
+    SGSoundMgr *_smgr;
+    bool _active;
+
+private:
+    bool _changed;
+    bool _position_changed;
+
+    float _volume;
+
+    SGVec3d _position;
+    SGVec3f _orientation;
+
+    sample_map _samples;
+
+    bool testForALError(string s);
+    bool testForError(void *p, string s);
+
+    void update_sample_config( SGSoundSample *sound );
+};
+
+#endif // _SG_SAMPLE_GROUP_OPENAL_HXX
+
index 52eaea184435b00a3b4e27a5803e3cfbc1ecb526..917f0596dade294c8d7993bfbdd89cc03bb8c58f 100644 (file)
@@ -15,8 +15,8 @@
 // General Public License for more details.
 //
 // You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //
 // $Id$
 
 #  include <simgear_config.h>
 #endif
 
-#if defined( __APPLE__ )
-# define AL_ILLEGAL_ENUM AL_INVALID_ENUM
-# define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION
-# include <OpenAL/al.h>
-# include <OpenAL/alut.h>
-#else
-# include <AL/al.h>
-# include <AL/alut.h>
-#endif
-
 #include <simgear/debug/logstream.hxx>
-#include <simgear/misc/sg_path.hxx>
 #include <simgear/structure/exception.hxx>
+#include <simgear/misc/sg_path.hxx>
+#include <simgear/math/SGQuat.hxx>
 
+#include "soundmgr_openal.hxx"
 #include "sample_openal.hxx"
 
 
 // SGSoundSample
 //
 
-
-static bool print_openal_error(const string &s = "unknown") {
-    ALuint error = alGetError();
-    if ( error == AL_NO_ERROR ) {
-       return false;
-    } else if ( error == AL_INVALID_NAME ) {
-        SG_LOG( SG_GENERAL, SG_ALERT, "OpenAL error (AL_INVALID_NAME): " << s );
-    } else if ( error == AL_ILLEGAL_ENUM ) {
-        SG_LOG( SG_GENERAL, SG_ALERT, "OpenAL error (AL_ILLEGAL_ENUM): "  << s );
-    } else if ( error == AL_INVALID_VALUE ) {
-        SG_LOG( SG_GENERAL, SG_ALERT, "OpenAL error (AL_INVALID_VALUE): " << s );
-    } else if ( error == AL_ILLEGAL_COMMAND ) {
-        SG_LOG( SG_GENERAL, SG_ALERT, "OpenAL error (AL_ILLEGAL_COMMAND): " << s );
-    } else if ( error == AL_OUT_OF_MEMORY ) {
-        SG_LOG( SG_GENERAL, SG_ALERT, "OpenAL error (AL_OUT_OF_MEMORY): " << s );
-    } else {
-        SG_LOG( SG_GENERAL, SG_ALERT, "Unhandled error code = " << error );
-    }
-    return error != 0;
-}
-
 // empty constructor
 SGSoundSample::SGSoundSample() :
-    buffer(0),
-    source(0),
-    pitch(1.0),
-    volume(1.0),
-    reference_dist(500.0),
-    max_dist(3000.),
-    loop(AL_FALSE),
-#ifdef USE_SOFTWARE_DOPPLER
-    doppler_pitch_factor(1),
-    doppler_volume_factor(1),
-#endif
-    playing(false),
-    no_Doppler_effect(true)
+    _absolute_pos(SGVec3d::zeros().data()),
+    _relative_pos(SGVec3f::zeros().data()),
+    _base_pos(SGVec3d::zeros().data()),
+    _direction(SGVec3f::zeros().data()),
+    _velocity(SGVec3f::zeros().data()),
+    _sample_name(""),
+    _data(NULL),
+    _format(AL_FORMAT_MONO8),
+    _size(0),
+    _freq(0),
+    _valid_buffer(false),
+    _buffer(SGSoundMgr::NO_BUFFER),
+    _valid_source(false),
+    _source(SGSoundMgr::NO_SOURCE),
+    _inner_angle(360.0),
+    _outer_angle(360.0),
+    _outer_gain(0.0),
+    _pitch(1.0),
+    _volume(1.0),
+    _master_volume(1.0),
+    _reference_dist(500.0),
+    _max_dist(3000.0),
+    _loop(AL_FALSE),
+    _playing(false),
+    _changed(true),
+    _static_changed(true),
+    _is_file(false)
 {
 }
 
 // constructor
-SGSoundSample::SGSoundSample( const char *path, const char *file, bool _no_Doppler_effect ) :
-    buffer(0),
-    source(0),
-    pitch(1.0),
-    volume(1.0),
-    reference_dist(500.0),
-    max_dist(3000.),
-    loop(AL_FALSE),
-#ifdef USE_SOFTWARE_DOPPLER
-    doppler_pitch_factor(1),
-    doppler_volume_factor(1),
-#endif
-    playing(false),
-    no_Doppler_effect(_no_Doppler_effect)
+SGSoundSample::SGSoundSample( const char *path, const char *file ) :
+    _absolute_pos(SGVec3d::zeros().data()),
+    _relative_pos(SGVec3f::zeros().data()),
+    _base_pos(SGVec3d::zeros().data()),
+    _direction(SGVec3f::zeros().data()),
+    _velocity(SGVec3f::zeros().data()),
+    _format(AL_FORMAT_MONO8),
+    _size(0),
+    _freq(0),
+    _valid_buffer(false),
+    _buffer(SGSoundMgr::NO_BUFFER),
+    _valid_source(false),
+    _source(SGSoundMgr::NO_SOURCE),
+    _inner_angle(360.0),
+    _outer_angle(360.0),
+    _outer_gain(0.0),
+    _pitch(1.0),
+    _volume(1.0),
+    _master_volume(1.0),
+    _reference_dist(500.0),
+    _max_dist(3000.0),
+    _loop(AL_FALSE),
+    _playing(false),
+    _changed(true),
+    _static_changed(true),
+    _is_file(true)
 {
     SGPath samplepath( path );
     if ( strlen(file) ) {
         samplepath.append( file );
     }
-    sample_name = samplepath.str();
+    _sample_name = samplepath.str();
 
-    SG_LOG( SG_GENERAL, SG_DEBUG, "From file sounds sample = "
+     SG_LOG( SG_GENERAL, SG_DEBUG, "From file sounds sample = "
             << samplepath.str() );
-
-    source_pos[0] = 0.0; source_pos[1] = 0.0; source_pos[2] = 0.0;
-    offset_pos[0] = 0.0; offset_pos[1] = 0.0; offset_pos[2] = 0.0;
-    source_vel[0] = 0.0; source_vel[1] = 0.0; source_vel[2] = 0.0;
-    direction[0] = 0.0; direction[1] = 0.0; direction[2] = 0.0;
-    inner = outer = 360.0; outergain = 0.0;
-
-    // clear errors from elsewhere?
-    alGetError();
-
-    // create an OpenAL buffer handle
-    alGenBuffers(1, &buffer);
-    if ( print_openal_error("constructor (alGenBuffers)") ) {
-        throw sg_exception("Failed to gen OpenAL buffer.");
-    }
-
-    // Load the sample file
-#if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
-
-  buffer = alutCreateBufferFromFile(samplepath.c_str());
-  if (buffer == AL_NONE) {
-     ALenum error = alutGetError ();
-     print_openal_error("constructor (alutCreateBufferFromFile)");
-     throw sg_io_exception("Failed to load wav file: ",
-                        sg_location(string(alutGetErrorString (error))));
-  }
-
-#else
-        //
-       // pre 1.0 alut version
-        //
-    ALvoid* data = load_file(path, file);
-
-    // Copy data to the internal OpenAL buffer
-    alBufferData( buffer, format, data, size, freq );
-
-    if ( print_openal_error("constructor (alBufferData)") ) {
-        SG_LOG( SG_GENERAL, SG_ALERT, "Trying to use file " << file );
-        throw sg_exception("Failed to buffer data.");
-    }
-
-    alutUnloadWAV( format, data, size, freq );
-#endif
-
-    print_openal_error("constructor return");
 }
 
 // constructor
-SGSoundSample::SGSoundSample( unsigned char *_data, int len, int _freq, bool _no_Doppler_effect ) :
-    buffer(0),
-    source(0),
-    pitch(1.0),
-    volume(1.0),
-    reference_dist(500.0),
-    max_dist(3000.),
-    loop(AL_FALSE),
-#ifdef USE_SOFTWARE_DOPPLER
-    doppler_pitch_factor(1),
-    doppler_volume_factor(1),
-#endif
-    playing(false),
-    no_Doppler_effect(_no_Doppler_effect)
+SGSoundSample::SGSoundSample( unsigned char *data, int len, int freq, int format ) :
+    _absolute_pos(SGVec3d::zeros().data()),
+    _relative_pos(SGVec3f::zeros().data()),
+    _base_pos(SGVec3d::zeros().data()),
+    _direction(SGVec3f::zeros().data()),
+    _velocity(SGVec3f::zeros().data()),
+    _data(data),
+    _format(format),
+    _size(len),
+    _freq(freq),
+    _valid_buffer(false),
+    _buffer(SGSoundMgr::NO_BUFFER),
+    _valid_source(false),
+    _source(SGSoundMgr::NO_SOURCE),
+    _inner_angle(360.0),
+    _outer_angle(360.0),
+    _outer_gain(0.0),
+    _pitch(1.0),
+    _volume(1.0),
+    _master_volume(1.0),
+    _reference_dist(500.0),
+    _max_dist(3000.0),
+    _loop(AL_FALSE),
+    _playing(false),
+    _changed(true),
+    _static_changed(true),
+    _is_file(false)
 {
+    _sample_name = "unknown, data supplied by caller";
     SG_LOG( SG_GENERAL, SG_DEBUG, "In memory sounds sample" );
-
-    sample_name = "unknown, generated from data";
-
-    source_pos[0] = 0.0; source_pos[1] = 0.0; source_pos[2] = 0.0;
-    offset_pos[0] = 0.0; offset_pos[1] = 0.0; offset_pos[2] = 0.0;
-    source_vel[0] = 0.0; source_vel[1] = 0.0; source_vel[2] = 0.0;
-    direction[0] = 0.0; direction[1] = 0.0; direction[2] = 0.0;
-    inner = outer = 360.0; outergain = 0.0;
-
-    // clear errors from elsewhere?
-    alGetError();
-
-    // Load wav data into a buffer.
-    alGenBuffers(1, &buffer);
-    if ( print_openal_error("constructor (alGenBuffers)") ) {
-        throw sg_exception("Failed to gen buffer." );
-    }
-
-    format = AL_FORMAT_MONO8;
-    size = len;
-    freq = _freq;
-
-    alBufferData( buffer, format, _data, size, freq );
-    if ( print_openal_error("constructor (alBufferData)") ) {
-        throw sg_exception("Failed to buffer data.");
-    }
-
-    print_openal_error("constructor return");
 }
 
 
 // destructor
 SGSoundSample::~SGSoundSample() {
-    SG_LOG( SG_GENERAL, SG_INFO, "Deleting a sample" );
-    if (buffer)
-        alDeleteBuffers(1, &buffer);
-}
-
-
-// play the sample
-void SGSoundSample::play( bool _loop ) {
-
-    if ( source ) {
-        alSourceStop( source );
-    }
-
-    playing = bind_source();
-    if ( playing ) {
-        loop = _loop;
-    
-        alSourcei( source, AL_LOOPING, loop );
-        alSourcePlay( source );
-
-        print_openal_error("play (alSourcePlay)");
+#if 0
+    if (_data != NULL) {
+        delete[] _data;
+        _data = NULL;
     }
-}
-
-
-// stop playing the sample
-void SGSoundSample::stop() {
-    if (playing) {
-        alSourceStop( source );
-        alDeleteSources(1, &source);
-        source = 0;
-        print_openal_error("stop (alDeleteSources)");
-    }
-    playing = false;
-}
-
-// Generate sound source
-bool
-SGSoundSample::bind_source() {
-
-    if ( playing ) {
-        return true;
-    }
-    if ( buffer == 0 ) {
-        return false;
-    }
-
-    // Bind buffer with a source.
-    alGetError();
-    alGenSources(1, &source);
-    if ( print_openal_error("bind_source (alGenSources)") ) {
-        // No biggy, better luck next time.
-        SG_LOG( SG_GENERAL, SG_ALERT, "Failed to generate audio source.");
-        // SG_LOG( SG_GENERAL, SG_ALERT, "Please update your sound driver and try again.");
-        return false;
-    }
-
-    alSourcei( source, AL_BUFFER, buffer );
-#ifndef USE_SOFTWARE_DOPPLER
-    alSourcef( source, AL_PITCH, pitch );
-    alSourcef( source, AL_GAIN, volume );
-#else
-    print_openal_error("bind_sources return");
-    alSourcef( source, AL_PITCH, pitch * doppler_pitch_factor );
-    alGetError(); // ignore if the pitch is clamped by the driver
-    alSourcef( source, AL_GAIN, volume * doppler_volume_factor );
-#endif
-    alSourcefv( source, AL_POSITION, source_pos );
-    alSourcefv( source, AL_DIRECTION, direction );
-    alSourcef( source, AL_CONE_INNER_ANGLE, inner );
-    alSourcef( source, AL_CONE_OUTER_ANGLE, outer );
-    alSourcef( source, AL_CONE_OUTER_GAIN, outergain);
-#ifdef USE_OPEN_AL_DOPPLER
-    alSourcefv( source, AL_VELOCITY, source_vel );
 #endif
-    alSourcei( source, AL_LOOPING, loop );
-
-    alSourcei( source, AL_SOURCE_RELATIVE, AL_TRUE );
-    alSourcef( source, AL_REFERENCE_DISTANCE, reference_dist );
-    alSourcef( source, AL_MAX_DISTANCE, max_dist );
-
-    print_openal_error("bind_sources return");
-
-    return true;
-}
-
-void
-SGSoundSample::set_pitch( double p ) {
-    // clamp in the range of 0.01 to 2.0
-    if ( p < 0.01 ) { p = 0.01; }
-    if ( p > 2.0 ) { p = 2.0; }
-    pitch = p;
-    if (playing) {
-#ifndef USE_SOFTWARE_DOPPLER
-        alSourcef( source, AL_PITCH, pitch );
-        print_openal_error("set_pitch");
-#else
-        alSourcef( source, AL_PITCH, pitch * doppler_pitch_factor );
-        alGetError(); // ignore if the pitch is clamped by the driver
-#endif
-    }
-}
-
-void
-SGSoundSample::set_volume( double v ) {
-    volume = v;
-    if (playing) {
-#ifndef USE_SOFTWARE_DOPPLER
-        alSourcef( source, AL_GAIN, volume );
-#else
-        alSourcef( source, AL_GAIN, volume * doppler_volume_factor );
-#endif
-        print_openal_error("set_volume");
-    }
-}
-
-
-bool
-SGSoundSample::is_playing( ) {
-    if (playing) {
-        ALint result;
-        alGetSourcei( source, AL_SOURCE_STATE, &result );
-        if ( alGetError() != AL_NO_ERROR) {
-            SG_LOG( SG_GENERAL, SG_ALERT,
-                "Oops AL error in sample is_playing(): " << sample_name );
-        }
-        return (result == AL_PLAYING) ;
-    } else
-        return false;
-}
-
-void
-SGSoundSample::set_source_pos( ALfloat *pos ) {
-    source_pos[0] = pos[0];
-    source_pos[1] = pos[1];
-    source_pos[2] = pos[2];
-
-    if (playing) {
-        sgVec3 final_pos;
-        sgAddVec3( final_pos, source_pos, offset_pos );
-
-        alSourcefv( source, AL_POSITION, final_pos );
-        print_openal_error("set_source_pos");
-    }
-}
-
-void
-SGSoundSample::set_offset_pos( ALfloat *pos ) {
-    offset_pos[0] = pos[0];
-    offset_pos[1] = pos[1];
-    offset_pos[2] = pos[2];
-
-    if (playing) {
-        sgVec3 final_pos;
-        sgAddVec3( final_pos, source_pos, offset_pos );
-
-        alSourcefv( source, AL_POSITION, final_pos );
-        print_openal_error("set_offset_pos");
-    }
-}
-
-void
-SGSoundSample::set_orientation( ALfloat *dir, ALfloat inner_angle,
-                                           ALfloat outer_angle,
-                                           ALfloat outer_gain)
-{
-    inner = inner_angle;
-    outer = outer_angle;
-    outergain = outer_gain;
-    direction[0] = dir[0];
-    direction[1] = dir[1];
-    direction[2] = dir[2];
-    if (playing) {
-        alSourcefv( source, AL_DIRECTION, dir);
-        alSourcef( source, AL_CONE_INNER_ANGLE, inner );
-        alSourcef( source, AL_CONE_OUTER_ANGLE, outer );
-        alSourcef( source, AL_CONE_OUTER_GAIN, outergain );
-    }
 }
 
-void
-SGSoundSample::set_source_vel( ALfloat *vel, ALfloat *listener_vel ) {
-    if (no_Doppler_effect) {
-        source_vel[0] = listener_vel[0];
-        source_vel[1] = listener_vel[1];
-        source_vel[2] = listener_vel[2];
-    } else {
-        source_vel[0] = vel[0];
-        source_vel[1] = vel[1];
-        source_vel[2] = vel[2];
-    }
-#ifdef USE_OPEN_AL_DOPPLER
-    if (playing) {
-        alSourcefv( source, AL_VELOCITY, source_vel );
-    }
-#elif defined (USE_OPEN_AL_DOPPLER_WITH_FIXED_LISTENER)
-    if (playing) {
-        sgVec3 relative_vel;
-        sgSubVec3( relative_vel, source_vel, listener_vel );
-        alSourcefv( source, AL_VELOCITY, relative_vel );
-    }
-#else
-    if (no_Doppler_effect) {
-        doppler_pitch_factor = 1;
-        doppler_volume_factor = 1;
-        return;
-    }
-    double doppler, mfp;
-    sgVec3 final_pos;
-    sgAddVec3( final_pos, source_pos, offset_pos );
-    mfp = sgLengthVec3(final_pos);
-    if (mfp > 1e-6) {
-        double vls = -sgScalarProductVec3( listener_vel, final_pos ) / mfp;
-        double vss = -sgScalarProductVec3( source_vel, final_pos ) / mfp;
-        if (fabs(340 - vss) > 1e-6)
-        {
-            doppler = (340 - vls) / (340 - vss);
-            doppler = ( doppler > 0) ? ( ( doppler < 10) ? doppler : 10 ) : 0;
-        }
-        else
-            doppler = 0;
-    }
-    else
-        doppler = 1;
-    /* the OpenAL documentation of the Doppler calculation
-    SS: AL_SPEED_OF_SOUND = speed of sound (default value 343.3)
-    DF: AL_DOPPLER_FACTOR = Doppler factor (default 1.0)
-    vls: Listener velocity scalar (scalar, projected on source-to-listener vector)
-    vss: Source velocity scalar (scalar, projected on source-to-listener vector)
-    SL = source to listener vector
-    SV = Source Velocity vector
-    LV = Listener Velocity vector
-    vls = DotProduct(SL, LV) / Mag(SL)
-    vss = DotProduct(SL, SV) / Mag(SL)
-    Dopper Calculation:
-    vss = min(vss, SS/DF)
-    vls = min(vls, SS/DF)
-    f' = f * (SS - DF*vls) / (SS - DF*vss)
-    */
-    if (doppler > 0.1) {
-        if (doppler < 10) {
-            doppler_pitch_factor = doppler;
-            doppler_volume_factor = 1;
-        }
-        else {
-            doppler_pitch_factor = (doppler < 11) ? doppler : 11;
-            doppler_volume_factor = (doppler < 11) ? 11-doppler : 0;
-        }
-    }
-    else {
-        doppler_pitch_factor = 0.1;
-        doppler_volume_factor = (doppler > 0) ? doppler * 10 : 0;
-    }
-    if (playing) {
-        alSourcef( source, AL_GAIN, volume * doppler_volume_factor );
-        print_openal_error("set_source_vel: volume");
-        alSourcef( source, AL_PITCH, pitch * doppler_pitch_factor );
-        alGetError(); //ignore if the pitch is clamped
-    }
-#endif
+void SGSoundSample::set_base_position( SGVec3d pos ) {
+    _base_pos = pos;
+    update_absolute_position();
+    _changed = true;
 }
 
-void
-SGSoundSample::set_reference_dist( ALfloat dist ) {
-    reference_dist = dist;
-    if (playing) {
-        alSourcef( source, AL_REFERENCE_DISTANCE, reference_dist );
-    }
+void SGSoundSample::set_relative_position( SGVec3f pos ) {
+    _relative_pos = pos;
+    update_absolute_position();
+    _changed = true;
 }
 
-
-void
-SGSoundSample::set_max_dist( ALfloat dist ) {
-    max_dist = dist;
-    if (playing) {
-        alSourcef( source, AL_MAX_DISTANCE, max_dist );
-    }
+void SGSoundSample::set_orientation( SGVec3f dir ) {
+    _direction = dir;
+    update_absolute_position();
+    _changed = true;
 }
 
-ALvoid *
-SGSoundSample::load_file(const char *path, const char *file)
-{
-    ALvoid* data = 0;
-
-    SGPath samplepath( path );
-    if ( strlen(file) ) {
-        samplepath.append( file );
-    }
-
-#if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
-    ALfloat freqf;
-    data = alutLoadMemoryFromFile(samplepath.c_str(), &format, &size, &freqf );
-    if (data == NULL) {
-        throw sg_io_exception("Failed to load wav file.",
-                                       sg_location(samplepath.str()));
-    }
-    freq = (ALsizei)freqf;
-#else
-# if defined (__APPLE__)
-    alutLoadWAVFile( (ALbyte *)samplepath.c_str(),
-                     &format, &data, &size, &freq );
-# else
-    alutLoadWAVFile( (ALbyte *)samplepath.c_str(),
-                     &format, &data, &size, &freq, &loop );
-# endif
-    if ( print_openal_error("constructor (alutLoadWAVFile)") ) {
-        throw sg_io_exception("Failed to load wav file.",
-                                       sg_location(samplepath.str()));
-    }
-#endif
-
-    return data;
+void SGSoundSample::update_absolute_position() {
+    SGQuatf orient = SGQuatf::fromAngleAxis(_direction);
+    SGVec3f modified_relative_pos = orient.transform(_relative_pos);
+    _absolute_pos = _base_pos + toVec3d(modified_relative_pos);
 }
-
index 1131981bf70a61a17ed8acd65dfe5b4282c308d7..5d4baf624886ef79261f2e617a5e29b9f96339e1 100644 (file)
 # error This library requires C++
 #endif
 
-#include <simgear/compiler.h>
-
 #include <string>
 
+#include <simgear/compiler.h>
 #include <simgear/debug/logstream.hxx>
 #include <simgear/structure/SGReferenced.hxx>
 #include <simgear/structure/SGSharedPtr.hxx>
+#include <simgear/math/SGMath.hxx>
 
 #include <plib/sg.h>
 
-#if defined(__APPLE__)
-# define AL_ILLEGAL_ENUM AL_INVALID_ENUM
-# define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION
-# include <OpenAL/al.h>
-# include <OpenAL/alut.h>
-#else
-# include <AL/al.h>
-# include <AL/alut.h>
-#endif
-
-#ifndef HAVE_WINDOWS_H
- #ifdef AL_VERSION_1_2
-  #define USE_OPEN_AL_DOPPLER should work
- #else
-  #define USE_OPEN_AL_DOPPLER_WITH_FIXED_LISTENER better than nothing
- #endif
-#else
- // the Open_AL Doppler calculation seems to be buggy on windows
- #define USE_SOFTWARE_DOPPLER seem to be necessary
-#endif
-
 using std::string;
 
 /**
@@ -73,45 +52,51 @@ class SGSoundSample : public SGReferenced {
 
 private:
 
-    string sample_name;
+    // Position of the source sound.
+    SGVec3d _absolute_pos;     // absolute position
+    SGVec3f _relative_pos;     // position relative to the base position
+    SGVec3d _base_pos;         // base position
 
-    // Buffers hold sound data.
-    ALuint buffer;
+    // The orientation of the sound (direction and cut-off angles)
+    SGVec3f _direction;
 
-    // Sources are points emitting sound.
-    ALuint source;
+    // Velocity of the source sound.
+    SGVec3f _velocity;
 
-    // Position of the source sound.
-    ALfloat source_pos[3];
+    string _sample_name;
+    unsigned char *_data;
+
+    // configuration values
+    int _format;
+    int _size;
+    int _freq;
 
-    // A constant offset to be applied to the final source_pos
-    ALfloat offset_pos[3];
+    // Buffers hold sound data.
+    bool _valid_buffer;
+    unsigned int _buffer;
+
+    // Sources are points emitting sound.
+    bool _valid_source;
+    unsigned int _source;
 
     // The orientation of the sound (direction and cut-off angles)
-    ALfloat direction[3];
-    ALfloat inner, outer, outergain;
+    float _inner_angle;
+    float _outer_angle;
+    float _outer_gain;
 
-    // Velocity of the source sound.
-    ALfloat source_vel[3];
+    float _pitch;
+    float _volume;
+    float _master_volume;
+    float _reference_dist;
+    float _max_dist;
+    bool _loop;
 
-    // configuration values
-    ALenum format;
-    ALsizei size;
-    ALsizei freq;
-
-    double pitch;
-    double volume;
-#ifdef USE_SOFTWARE_DOPPLER
-    double doppler_pitch_factor;
-    double doppler_volume_factor;
-#endif
-    double reference_dist;
-    double max_dist;
-    ALboolean loop;
+    bool _playing;
+    bool _changed;
+    bool _static_changed;
+    bool _is_file;
 
-    bool playing;
-    bool bind_source();
-    bool no_Doppler_effect;
+    void update_absolute_position();
 
 public:
 
@@ -128,7 +113,7 @@ public:
        should usually be true unless you want to manipulate the data
        later.)
      */
-    SGSoundSample( const char *path, const char *file, bool no_Doppler_effect = true );
+    SGSoundSample( const char *path, const char *file );
 
     /**
      * Constructor.
@@ -139,23 +124,50 @@ public:
        should usually be true unless you want to manipulate the data
        later.)
      */
-    SGSoundSample( unsigned char *_data, int len, int _freq, bool no_Doppler_effect = true );
+    SGSoundSample( unsigned char *data, int len, int freq, int format = AL_FORMAT_MONO8 );
+
+    ~SGSoundSample ();
+
+    /**
+     * detect wheter the sample holds the information of a sound file
+     */
+    inline bool is_file() const { return _is_file; }
+
+    /**
+     * Test whether this sample has a changed configuration since the last
+     * call. (Calling this function resets the value).
+     */
+    inline bool has_changed() {
+        bool b = _changed; _changed = false; return b;
+    }
+
+    inline bool has_static_data_changed() {
+        bool b = _static_changed; _static_changed = false; return b;
+    }
 
-    ~SGSoundSample();
 
     /**
      * Start playing this sample.
      *
      * @param _loop Define whether the sound should be played in a loop.
      */
-    void play( bool _loop );
+    inline void play( bool loop ) {
+        _playing = true; _loop = loop; _changed = true;
+    }
+
+    /**
+     * Return if the sample is looping or not.
+     */
+    inline bool get_looping() { return _loop; }
 
     /**
      * Stop playing this sample.
      *
      * @param sched A pointer to the appropriate scheduler.
      */
-    void stop();
+    inline void stop() {
+        _playing = false; _changed = true;
+    }
 
     /**
      * Play this sample once.
@@ -173,77 +185,226 @@ public:
      * Test if a sample is currently playing.
      * @return true if is is playing, false otherwise.
      */
-    bool is_playing( );
+    inline bool is_playing() { return _playing; }
+
+    /**
+     * set the data associated with this sample
+     */
+    inline void set_data( unsigned char* data ) {
+        _data = data;
+    }
+
+    /**
+     * @return the data associated with this sample
+     */
+    inline void* get_data() const { return _data; }
+
+    /**
+     * free the data associated with this sample
+     */
+    inline void free_data() {
+        if (_data != NULL) { delete[] _data; _data = NULL; }
+    }
+
+    /**
+     * set the source id of this source
+     */
+    inline void set_source(unsigned int s) {
+        _source = s; _valid_source = true; _changed = true;
+    }
+
+    /**
+     * get the source id of this source
+     */
+    inline unsigned int get_source() { return _source; }
+
+    /**
+     * detect wheter the source id of the sample is valid
+     */
+    inline bool is_valid_source() const { return _valid_source; }
+
+    /**
+     * set the source id of the sample to invalid.
+     */
+    inline void no_valid_source() {
+        _valid_source = false;
+    }
+
+    /**
+     * set the buffer id of this source
+     */
+    inline void set_buffer(unsigned int b) {
+        _buffer = b; _valid_buffer = true; _changed = true;
+    } 
+
+    /**
+     * get the buffer id of this source
+     */
+    inline unsigned int get_buffer() { return _buffer; }
+
+    /**
+     * detect wheter the source id of the sample is valid
+     */
+    inline bool is_valid_buffer() const { return _valid_buffer; }
+
+    /**
+     * set the source id of the sample to invalid.
+     */
+    inline void no_valid_buffer() {
+        _valid_buffer = false;
+    }
 
     /**
      * Get the current pitch setting of this sample.
      */
-    inline double get_pitch() const { return pitch; }
+    inline float get_pitch() { return _pitch; }
 
     /**
      * Set the pitch of this sample.
      */
-    void set_pitch( double p );
+    inline void set_pitch( float p ) {
+        _pitch = p; _changed = true;
+    }
 
     /**
      * Get the current volume setting of this sample.
      */
-    inline double get_volume() const { return volume; }
+    inline float get_volume() { return _volume * _master_volume; }
+
+    /**
+     * Set the master (sampel group) volume of this sample.
+     */
+    inline void set_master_volume( float v ) {
+        _master_volume = v; _changed = true;
+    }
 
     /**
      * Set the volume of this sample.
      */
-    void set_volume( double v );
+    inline void set_volume( float v ) {
+        _volume = v; _changed = true;
+    }
+
+    /**
+     * Set the format of the sounds sample
+     */
+    inline void set_format( int format ) {
+        _format = format;
+    }
+
+    /**
+     * Returns the format of the sounds sample
+     */
+    inline int get_format() { return _format; }
+
+
+    /**
+     * Set the frequency of the sounds sample
+     */
+    inline void set_frequency( int freq ) {
+        _freq = freq; _changed = true;
+    }
+
+    /**
+     * Returns the frequency of the sounds sample
+     */
+    inline int get_frequency() { return _freq; }
 
     /**
      * Returns the size of the sounds sample
      */
-    inline int get_size() {
-        return size;
+    inline void set_size( int size ) {
+        _size = size;
     }
 
     /**
-     * Set position of sound source (uses same coordinate system as opengl)
+     * Returns the size of the sounds sample
      */
-    void set_source_pos( ALfloat *pos );
+    inline int get_size() const { return _size; }
 
     /**
-     * Set "constant" offset position of sound source (uses same
-     * coordinate system as opengl)
+     * Set position of the sound source (uses same coordinate system as opengl)
      */
-    void set_offset_pos( ALfloat *pos );
+    void set_base_position( SGVec3d pos );
+    void set_relative_position( SGVec3f pos );
+
+    /**
+     * Get position of the sound source (uses same coordinate system as opengl)
+     */
+    inline float *get_position() const { return toVec3f(_absolute_pos).data(); }
 
     /**
      * Set the orientation of the sound source, both for direction
      * and audio cut-off angles.
      */
-    void set_orientation( ALfloat *dir, ALfloat inner_angle=360.0,
-                                               ALfloat outer_angle=360.0,
-                                               ALfloat outer_gain=0.0);
+    void set_orientation( SGVec3f dir );
+
+    /**
+     * Define the audio cone parameters for directional audio
+     */
+    inline void set_audio_cone( float inner, float outer, float gain ) {
+        _inner_angle = inner;
+        _outer_angle = outer;
+        _outer_gain = gain;
+        _static_changed = true;
+    }
+
+    /**
+     * Get the orientation of the sound source, the inner or outer angle
+     * or outer gain.
+     */
+    inline float *get_orientation() { return _direction.data(); }
+    inline float *get_direction() { return _direction.data(); }
+    inline float get_innerangle() { return _inner_angle; }
+    inline float get_outerangle() { return _outer_angle; }
+    inline float get_outergain() { return _outer_gain; }
+
+    /**
+     * Set velocity of the sound source (uses same coordinate system as opengl)
+     */
+    inline void set_velocity( SGVec3f vel ) {
+        _velocity = SGVec3f(vel); _changed = true;
+    }
 
     /**
-     * Set velocity of sound source (uses same coordinate system as opengl)
+     * Get velocity of the sound source (uses same coordinate system as opengl)
      */
-    void set_source_vel( ALfloat *vel, ALfloat *listener_vel );
+    inline float *get_velocity() { return _velocity.data(); }
 
 
     /**
      * Set reference distance of sound (the distance where the gain
      * will be half.)
      */
-    void set_reference_dist( ALfloat dist );
+    inline void set_reference_dist( float dist ) {
+        _reference_dist = dist; _static_changed = true;
+    }
+
+    /**
+     * Get reference distance of sound (the distance where the gain
+     * will be half.)
+     */
+    inline float get_reference_dist() { return _reference_dist; }
 
 
     /**
      * Set maximum distance of sound (the distance where the sound is
      * no longer audible.
      */
-    void set_max_dist( ALfloat dist );
+    void set_max_dist( float dist ) {
+        _max_dist = dist; _static_changed = true;
+    }
+
+    /**
+     * Get maximum istance of sound (the distance where the sound is
+     * no longer audible.
+     */
+    inline float get_max_dist() { return _max_dist; }
 
     /**
-     * Load a sound file into a memory buffer only.
+     * Get the name of this sample
      */
-    ALvoid* load_file(const char *path, const char *file);
+    inline string get_sample_name() { return _sample_name; }
 };
 
 
index fb49d247f984d074b5d3406d0e4d34e5c9a3ec68..543960e063c39d93a3be4d865dad7182237d480e 100644 (file)
@@ -18,8 +18,8 @@
 // General Public License for more details.
 //
 // You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //
 // $Id$
 
 #  include <simgear_config.h>
 #endif
 
-#include <simgear/compiler.h>
-
-#if defined(__APPLE__)
-# include <OpenAL/al.h>
-# include <OpenAL/alc.h>
+#if defined( __APPLE__ )
+# include <OpenAL/alut.h>
 #else
-# include <AL/al.h>
-# include <AL/alc.h>
-#endif
-
-#if defined (__APPLE__)
-#  ifdef __GNUC__
-#    if ( __GNUC__ >= 3 ) && ( __GNUC_MINOR__ >= 3 )
-//  #        include <math.h>
-inline int (isnan)(double r) { return !(r <= 0 || r >= 0); }
-#    else
-    // any C++ header file undefines isinf and isnan
-    // so this should be included before <iostream>
-    // the functions are STILL in libm (libSystem on mac os x)
-extern "C" int isnan (double);
-extern "C" int isinf (double);
-#    endif
-#  else
-//    inline int (isinf)(double r) { return isinf(r); }
-//    inline int (isnan)(double r) { return isnan(r); }
-#  endif
-#endif
-
-#if defined (__FreeBSD__)
-#  if __FreeBSD_version < 500000
-     extern "C" {
-       inline int isnan(double r) { return !(r <= 0 || r >= 0); }
-     }
-#  endif
+# include <AL/alut.h>
 #endif
 
-#if defined (__CYGWIN__)
-#include <ieeefp.h>
-#endif
-
-
 #include <iostream>
 
+#include "soundmgr_openal.hxx"
+
+#include <simgear/structure/exception.hxx>
 #include <simgear/debug/logstream.hxx>
 #include <simgear/misc/sg_path.hxx>
+#include <simgear/math/SGMath.hxx>
 
-#include "soundmgr_openal.hxx"
 
-#if defined(__MINGW32__)
-#define isnan(x) _isnan(x)
-#endif
+#define MAX_SOURCES    128
 
 //
 // Sound Manager
 //
 
+int SGSoundMgr::_alut_init = 0;
+
 // constructor
-SGSoundMgr::SGSoundMgr() {
+SGSoundMgr::SGSoundMgr() :
+    _working(false),
+    _changed(true),
+    _volume(0.5),
+    _device(NULL),
+    _context(NULL),
+    _listener_pos(SGVec3d::zeros().data()),
+    _listener_vel(SGVec3f::zeros().data()),
+    _devname(NULL)
+{
+#if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
+    if (_alut_init == 0) {
+        if ( !alutInitWithoutContext(NULL, NULL) ) {
+            testForALUTError("alut initialization");
+            return;
+        }
+        _alut_init++;
+    }
+    _alut_init++;
+#endif
+}
 
-    SG_LOG( SG_GENERAL, SG_INFO, "Initializing OpenAL sound manager" );
+// destructor
 
-    // initialize OpenAL
+SGSoundMgr::~SGSoundMgr() {
+    stop();
 #if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
-    if (!alutInit(NULL, NULL))
-    {
-        ALenum error = alutGetError ();
-        SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" );
-        SG_LOG( SG_GENERAL, SG_ALERT, "   "+string(alutGetErrorString(error)));
-        working = false;
-        context = 0;
-        return;
+    _alut_init--;
+    if (_alut_init == 0) {
+        alutExit ();
     }
-    else
-    {
-        working = true;
-        context = alcGetCurrentContext();
+#endif
+}
+
+// initialize the sound manager
+void SGSoundMgr::init() {
+
+    SG_LOG( SG_GENERAL, SG_INFO, "Initializing OpenAL sound manager" );
+
+    ALCdevice *device = alcOpenDevice(_devname);
+    if ( testForError(device, "No default audio device available.") ) {
+        return;
     }
-#else
-    if ( (dev = alcOpenDevice( NULL )) != NULL
-            && ( context = alcCreateContext( dev, NULL )) != NULL ) {
-        working = true;
-        alcMakeContextCurrent( context );
-    } else {
-        working = false;
-        context = 0;
-        SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" );
+
+    ALCcontext *context = alcCreateContext(device, NULL);
+    if ( testForError(context, "Unable to create a valid context.") ) {
         return;
     }
-#endif
 
-    listener_pos[0] = 0.0;
-    listener_pos[1] = 0.0;
-    listener_pos[2] = 0.0;
-
-    listener_vel[0] = 0.0;
-    listener_vel[1] = 0.0;
-    listener_vel[2] = 0.0;
-    
-    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;
-
-    alListenerf( AL_GAIN, 0.0f );
-    alListenerfv( AL_POSITION, listener_pos );
-    alListenerfv( AL_VELOCITY, listener_vel );
-    alListenerfv( AL_ORIENTATION, listener_ori );
-    alGetError();
-    if ( alGetError() != AL_NO_ERROR) {
-        SG_LOG( SG_GENERAL, SG_ALERT,
-                "Oops AL error after audio initialization!" );
+    if ( !alcMakeContextCurrent(context) ) {
+        testForALCError("context initialization");
+        return;
     }
 
-    // exaggerate the ear candy?
+    _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;
+
+    alListenerf( AL_GAIN, 0.2f );
+    alListenerfv( AL_POSITION, toVec3f(_listener_pos).data() );
+    alListenerfv( AL_ORIENTATION, _listener_ori );
+    alListenerfv( AL_VELOCITY, _listener_vel.data() );
+
     alDopplerFactor(1.0);
-    alDopplerVelocity(340.0);  // speed of sound in meters per second.
-}
+    alDopplerVelocity(340.3);   // speed of sound in meters per second.
 
-// destructor
+    if ( alIsExtensionPresent((const ALchar*)"EXT_exponent_distance") ) {
+        alDistanceModel(AL_EXPONENT_DISTANCE);
+    } else {
+        alDistanceModel(AL_INVERSE_DISTANCE);
+    }
 
-SGSoundMgr::~SGSoundMgr() {
+    testForALError("listener initialization");
 
-#if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
-    alutExit ();
-#else
-    if (context)
-        alcDestroyContext( context );
-#endif
+    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++) {
+        ALuint source;
+        ALenum error;
+
+        alGetError();
+        alGenSources(1, &source);
+        error = alGetError();
+        if ( error == AL_NO_ERROR ) {
+            _free_sources.push_back( source );
+        }
+        else break;
+    }
 }
 
+// suspend the sound manager
+void SGSoundMgr::stop() {
+    if (_working) {
+        _working = false;
 
-// initialize the sound manager
-void SGSoundMgr::init() {
-    //
-    // Remove the samples from the sample manager.
-    //
-    samples.clear();
+        _context = alcGetCurrentContext();
+        _device = alcGetContextsDevice(_context);
+        alcMakeContextCurrent(NULL);
+        alcDestroyContext(_context);
+        alcCloseDevice(_device);
+    }
+}
+
+void SGSoundMgr::suspend() {
+    if (_working) {
+        sample_group_map_iterator sample_grp_current = _sample_groups.begin();
+        sample_group_map_iterator sample_grp_end = _sample_groups.end();
+        for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) {
+            SGSampleGroup *sgrp = sample_grp_current->second;
+            sgrp->suspend();
+        }
+    }
 }
 
 
 void SGSoundMgr::bind ()
 {
-    // no properties
+    _free_sources.clear();
+    _free_sources.reserve( MAX_SOURCES );
+    _sources_in_use.clear();
+    _sources_in_use.reserve( MAX_SOURCES );
 }
 
 
 void SGSoundMgr::unbind ()
 {
-    // no properties
+    _sample_groups.clear();
+
+    // delete free sources
+    for (unsigned int i=0; i<_free_sources.size(); i++) {
+        ALuint source = _free_sources.at( i );
+        alDeleteSources( 1 , &source );
+    }
+
+    _free_sources.clear();
+    _sources_in_use.clear();
 }
 
 
 // run the audio scheduler
 void SGSoundMgr::update( double dt ) {
-}
-
+    if (_working) {
+        sample_group_map_iterator sample_grp_current = _sample_groups.begin();
+        sample_group_map_iterator sample_grp_end = _sample_groups.end();
+        for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) {
+            SGSampleGroup *sgrp = sample_grp_current->second;
+            sgrp->update(dt);
+        }
 
-void
-SGSoundMgr::pause ()
-{
-    if (context) {
-        alcSuspendContext( context );
-        if ( alGetError() != AL_NO_ERROR) {
-            SG_LOG( SG_GENERAL, SG_ALERT,
-                    "Oops AL error after soundmgr pause()!" );
+        if (_changed) {
+            alListenerf( AL_GAIN, _volume );
+            alListenerfv( AL_VELOCITY, _listener_vel.data() );
+            alListenerfv( AL_ORIENTATION, _listener_ori );
+            alListenerfv( AL_POSITION, toVec3f(_listener_pos).data() );
+            // alDopplerVelocity(340.3);       // TODO: altitude dependent
+            testForALError("update");
+            _changed = false;
         }
     }
 }
@@ -202,151 +221,241 @@ SGSoundMgr::pause ()
 void
 SGSoundMgr::resume ()
 {
-    if (context) {
-        alcProcessContext( context );
-        if ( alGetError() != AL_NO_ERROR) {
-            SG_LOG( SG_GENERAL, SG_ALERT,
-                    "Oops AL error after soundmgr resume()!" );
+    if (_working) {
+        sample_group_map_iterator sample_grp_current = _sample_groups.begin();
+        sample_group_map_iterator sample_grp_end = _sample_groups.end();
+        for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) {
+            SGSampleGroup *sgrp = sample_grp_current->second;
+            sgrp->resume();
         }
     }
 }
 
 
-// add a sound effect, return true if successful
-bool SGSoundMgr::add( SGSoundSample *sound, const string& refname ) {
-
-    sample_map_iterator sample_it = samples.find( refname );
-    if ( sample_it != samples.end() ) {
-        // sound already exists
+// add a sampel group, return true if successful
+bool SGSoundMgr::add( SGSampleGroup *sgrp, const string& refname )
+{
+    sample_group_map_iterator sample_grp_it = _sample_groups.find( refname );
+    if ( sample_grp_it != _sample_groups.end() ) {
+        // sample group already exists
         return false;
     }
 
-    samples[refname] = sound;
+    _sample_groups[refname] = sgrp;
 
     return true;
 }
 
 
 // remove a sound effect, return true if successful
-bool SGSoundMgr::remove( const string &refname ) {
-
-    sample_map_iterator sample_it = samples.find( refname );
-    if ( sample_it != samples.end() ) {
-        // first stop the sound from playing (so we don't bomb the
-        // audio scheduler)
-        samples.erase( sample_it );
-
-        // cout << "sndmgr: removed -> " << refname << endl;
-        return true;
-    } else {
-        // cout << "sndmgr: failed remove -> " << refname << endl;
+bool SGSoundMgr::remove( const string &refname )
+{
+    sample_group_map_iterator sample_grp_it = _sample_groups.find( refname );
+    if ( sample_grp_it == _sample_groups.end() ) {
+        // sample group was not found.
         return false;
     }
+
+    _sample_groups.erase( refname );
+
+    return true;
 }
 
 
 // return true of the specified sound exists in the sound manager system
 bool SGSoundMgr::exists( const string &refname ) {
-    sample_map_iterator sample_it = samples.find( refname );
-    if ( sample_it != samples.end() ) {
-        return true;
-    } else {
+    sample_group_map_iterator sample_grp_it = _sample_groups.find( refname );
+    if ( sample_grp_it == _sample_groups.end() ) {
+        // sample group was not found.
         return false;
     }
+
+    return true;
 }
 
 
-// return a pointer to the SGSoundSample if the specified sound exists
+// return a pointer to the SGSampleGroup if the specified sound exists
 // in the sound manager system, otherwise return NULL
-SGSoundSample *SGSoundMgr::find( const string &refname ) {
-    sample_map_iterator sample_it = samples.find( refname );
-    if ( sample_it != samples.end() ) {
-        return sample_it->second;
-    } else {
-        return NULL;
+SGSampleGroup *SGSoundMgr::find( const string &refname, bool create ) {
+    sample_group_map_iterator sample_grp_it = _sample_groups.find( refname );
+    if ( sample_grp_it == _sample_groups.end() ) {
+        // sample group was not found.
+        if (create) {
+            SGSampleGroup* sgrp = new SGSampleGroup(this, refname);
+            return sgrp;
+        }
+        else 
+            return NULL;
     }
-}
 
+    return sample_grp_it->second;
+}
 
-// tell the scheduler to play the indexed sample in a continuous
-// loop
-bool SGSoundMgr::play_looped( const string &refname ) {
-    SGSoundSample *sample;
 
-    if ( (sample = find( refname )) == NULL ) {
-        return false;
-    } else {
-        sample->play( true );
-        return true;
-    }
+void SGSoundMgr::set_volume( float v )
+{
+    _volume = v;
+    if (_volume > 1.0) _volume = 1.0;
+    if (_volume < 0.0) _volume = 0.0;
+    _changed = true;
 }
 
+// Get an unused source id
+//
+// The Sound Manager should keep track of the sources in use, the distance
+// of these sources to the listener and the volume (also based on audio cone
+// and hence orientation) of the sources.
+//
+// The Sound Manager is (and should be) the only one knowing about source
+// management. Sources further away should be suspendped to free resources for
+// newly added sounds close by.
+unsigned int SGSoundMgr::request_source()
+{
+    unsigned int source = NO_SOURCE;
 
-// tell the scheduler to play the indexed sample once
-bool SGSoundMgr::play_once( const string& refname ) {
-    SGSoundSample *sample;
+    if (_free_sources.size() > 0) {
+       source = _free_sources.back();
+       _free_sources.pop_back();
 
-    if ( (sample = find( refname )) == NULL ) {
-        return false;
-    } else {
-        sample->play( false );
-        return true;
+       _sources_in_use.push_back(source);
     }
-}
-
 
-// return true of the specified sound is currently being played
-bool SGSoundMgr::is_playing( const string& refname ) {
-    SGSoundSample *sample;
+    return source;
+}
 
-    if ( (sample = find( refname )) == NULL ) {
-        return false;
-    } else {
-        return ( sample->is_playing() );
+// 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;
+
+            alGetSourcei( source, AL_SOURCE_STATE, &result );
+            if ( result == AL_PLAYING ) {
+                alSourceStop( source );
+            }
+            testForALError("free_source");
+
+            _free_sources.push_back(source);
+            _sources_in_use.erase(_sources_in_use.begin()+i,
+                                  _sources_in_use.begin()+i+1);
+            break;
+        }
     }
 }
 
+bool SGSoundMgr::load(string &samplepath, void **dbuf, int *fmt,
+                                          unsigned int *sz, int *frq )
+{
+    ALenum format = (ALenum)*fmt;
+    ALsizei size = (ALsizei)*sz;
+    ALsizei freq = (ALsizei)*frq;
+    ALvoid *data;
 
-// immediate stop playing the sound
-bool SGSoundMgr::stop( const string& refname ) {
-    SGSoundSample *sample;
+#if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
+    ALfloat freqf;
+    data = alutLoadMemoryFromFile(samplepath.c_str(), &format, &size, &freqf );
+    freq = (ALsizei)freqf;
+    if (data == NULL) {
+        int error = alutGetError();
+        string msg = "Failed to load wav file: ";
+        msg.append(alutGetErrorString(error));
+        throw sg_io_exception(msg.c_str(), sg_location(samplepath));
+        return false;
+    }
 
-    if ( (sample = find( refname )) == NULL ) {
+#else
+    ALbyte *fname = (ALbyte *)samplepath.c_str();
+# if defined (__APPLE__)
+    alutLoadWAVFile( fname, &format, &data, &size, &freq );
+# else
+    ALboolean loop;
+    alutLoadWAVFile( fname, &format, &data, &size, &freq, &loop );
+# endif
+    ALenum error =  alutGetError();
+    if ( error != ALUT_ERROR_NO_ERROR ) {
+        string msg = "Failed to load wav file: ";
+        msg.append(alutGetErrorString(error));
+        throw sg_io_exception(msg.c_str(), sg_location(samplepath));
         return false;
-    } else {
-        sample->stop();
-        return true;
     }
+#endif
+
+    *dbuf = (void *)data;
+    *fmt = (int)format;
+    *sz = (unsigned int)size;
+    *frq = (int)freq;
+
+    return true;
 }
 
 
-// set source position of all managed sounds
-void SGSoundMgr::set_source_pos_all( ALfloat *pos ) {
-    if ( isnan(pos[0]) || isnan(pos[1]) || isnan(pos[2]) ) {
-        // bail if a bad position is passed in
-        return;
+/**
+ * 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;
+}
 
-    sample_map_iterator sample_current = samples.begin();
-    sample_map_iterator sample_end = samples.end();
-    for ( ; sample_current != sample_end; ++sample_current ) {
-        SGSoundSample *sample = sample_current->second;
-        sample->set_source_pos( pos );
-    }
+
+bool SGSoundMgr::testForError(void *p, string s)
+{
+   if (p == NULL) {
+      SG_LOG( SG_GENERAL, SG_ALERT, "Error: " << s);
+      return true;
+   }
+   return false;
 }
 
 
-// set source velocity of all managed sounds
-void SGSoundMgr::set_source_vel_all( ALfloat *vel ) {
-    if ( isnan(vel[0]) || isnan(vel[1]) || isnan(vel[2]) ) {
-        // bail if a bad velocity is passed in
-        return;
+bool SGSoundMgr::testForALError(string s)
+{
+    ALenum error = alGetError();
+    if (error != AL_NO_ERROR)  {
+       SG_LOG( SG_GENERAL, SG_ALERT, "AL Error (sound manager): "
+                                      << alGetString(error) << " at " << s);
+       return true;
     }
+    return false;
+}
+
+bool SGSoundMgr::testForALCError(string s)
+{
+    ALCenum error;
+    error = alcGetError(_device);
+    if (error != ALC_NO_ERROR) {
+        SG_LOG( SG_GENERAL, SG_ALERT, "ALC Error (sound manager): "
+                                       << alcGetString(_device, error) << " at "
+                                       << s);
+        return true;
+    }
+    return false;
+}
 
-    sample_map_iterator sample_current = samples.begin();
-    sample_map_iterator sample_end = samples.end();
-    for ( ; sample_current != sample_end; ++sample_current ) {
-        SGSoundSample *sample = sample_current->second;
-        sample->set_source_vel( vel, listener_vel );
+bool SGSoundMgr::testForALUTError(string s)
+{
+    ALenum error;
+    error =  alutGetError ();
+    if (error != ALUT_ERROR_NO_ERROR) {
+        SG_LOG( SG_GENERAL, SG_ALERT, "ALUT Error (sound manager): "
+                                       << alutGetErrorString(error) << " at "
+                                       << s);
+        return true;
     }
+    return false;
 }
index 59cb24e4acf0eaa510caa1eea12a756b36fdc3e1..9610905741127772be01c33c237abb4ff91dcdef 100644 (file)
 # error This library requires C++
 #endif
 
-#include <simgear/compiler.h>
-
 #include <string>
+#include <vector>
 #include <map>
 
-#if defined( __APPLE__ )
+#if defined(__APPLE__)
+# define AL_ILLEGAL_ENUM AL_INVALID_ENUM
+# define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION
 # include <OpenAL/al.h>
-# include <OpenAL/alc.h>
+# include <OpenAL/alut.h>
 #else
 # include <AL/al.h>
-# include <AL/alc.h>
+# include <AL/alut.h>
 #endif
 
+#include <simgear/compiler.h>
+#include <simgear/structure/subsystem_mgr.hxx>
+#include <simgear/math/SGMathFwd.hxx>
+
+#include "sample_group.hxx"
 #include "sample_openal.hxx"
 
 using std::map;
 using std::string;
 
-
-typedef map < string, SGSharedPtr<SGSoundSample> > sample_map;
-typedef sample_map::iterator sample_map_iterator;
-typedef sample_map::const_iterator const_sample_map_iterator;
+typedef 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 SGSoundSample instances
+ * Manage a collection of SGSampleGroup instances
  */
-class SGSoundMgr
+class SGSoundMgr : public SGSubsystem
 {
-
-    ALCdevice *dev;
-    ALCcontext *context;
-
-    // Position of the listener.
-    ALfloat listener_pos[3];
-
-    // Velocity of the listener.
-    ALfloat listener_vel[3];
-
-    // Orientation of the listener. (first 3 elements are "at", second
-    // 3 are "up")
-    ALfloat listener_ori[6];
-
-    sample_map samples;
-
-    bool working;
-    double safety;
-
 public:
 
     SGSoundMgr();
     ~SGSoundMgr();
 
-
-    /**
-     * (re) initialize the sound manager.
-     */
     void init();
-
-
-    /**
-     * Bind properties for the sound manager.
-     */
     void bind();
-
-
-    /**
-     * Unbind properties for the sound manager.
-     */
     void unbind();
-
-
-    /**
-     * Run the audio scheduler.
-     */
     void update(double dt);
-
-
-    /**
-     * Pause all sounds.
-     */
-    void pause();
-
-
-    /**
-     * Resume all sounds.
-     */
+    
+    void suspend();
     void resume();
+    void stop();
 
+    inline void reinit() { stop(); init(); }
 
     /**
      * is audio working?
      */
-    inline bool is_working() const { return working; }
+    inline bool is_working() const { return _working; }
 
     /**
-     * reinitialize the sound manager
+     * add a sample group, return true if successful
      */
-    inline void reinit() { init(); }
-
-    /**
-     * add a sound effect, return true if successful
-     */
-    bool add( SGSoundSample *sound, const string& refname);
+    bool add( SGSampleGroup *sgrp, const string& refname );
 
     /** 
-     * remove a sound effect, return true if successful
+     * remove a sample group, return true if successful
      */
     bool remove( const string& refname );
 
@@ -153,94 +108,91 @@ public:
     bool exists( const string& refname );
 
     /**
-     * return a pointer to the SGSoundSample if the specified sound
+     * return a pointer to the SGSampleGroup if the specified sound
      * exists in the sound manager system, otherwise return NULL
      */
-    SGSoundSample *find( const string& refname );
-
-    /**
-     * tell the scheduler to play the indexed sample in a continuous
-     * loop
-     */
-    bool play_looped( const string& refname );
+    SGSampleGroup *find( const string& refname, bool create = false );
 
     /**
-     * tell the scheduler to play the indexed sample once
-     */
-    bool play_once( const string& refname );
-
-    /**
-     * return true of the specified sound is currently being played
-     */
-    bool is_playing( const string& refname );
-
-    /**
-     * immediate stop playing the sound
-     */
-    bool stop( const string& refname );
-
-    /**
-     * set overall volume for the application.
-     * @param vol 1.0 is default, must be greater than 0
+     * set the position of the listener (in opengl coordinates)
      */
-    inline void set_volume( const ALfloat vol ) {
-        if ( vol > 0.0 ) {
-            alListenerf( AL_GAIN, vol );
-        }
+    inline void set_position( SGVec3d pos ) {
+        _listener_pos = pos;
+        _changed = true;
     }
 
-    /**
-     * set the position of the listener (in opengl coordinates)
-     */
-    inline void set_listener_pos( ALfloat *pos ) {
-        listener_pos[0] = pos[0];
-        listener_pos[1] = pos[1];
-        listener_pos[2] = pos[2];
-        alListenerfv( AL_POSITION, listener_pos );
+    inline double *get_position() {
+       return _listener_pos.data();
     }
 
     /**
      * set the velocity of the listener (in opengl coordinates)
      */
-    inline void set_listener_vel( ALfloat *vel ) {
-        listener_vel[0] = vel[0];
-        listener_vel[1] = vel[1];
-        listener_vel[2] = vel[2];
-#ifdef USE_OPEN_AL_DOPPLER
-        alListenerfv( AL_VELOCITY, listener_vel );
-#endif
+    inline void set_velocity( SGVec3f vel ) {
+        _listener_vel = vel;
+        _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.
      */
-    inline void set_listener_orientation( ALfloat *ori ) {
-        listener_ori[0] = ori[0];
-        listener_ori[1] = ori[1];
-        listener_ori[2] = ori[2];
-        listener_ori[3] = ori[3];
-        listener_ori[4] = ori[4];
-        listener_ori[5] = ori[5];
-        alListenerfv( AL_ORIENTATION, listener_ori );
-    }
+    void set_orientation( SGQuatd ori );
+
+    enum {
+        NO_SOURCE = (unsigned int)-1,
+        NO_BUFFER = (unsigned int)-1
+    };
+
+    void set_volume( float v );
+    inline float get_volume() { return _volume; }
 
     /**
-     * set the positions of all managed sound sources 
+     * get a new OpenAL source id
+     * returns NO_SOURCE is no source is available
      */
-    void set_source_pos_all( ALfloat *pos );
+    unsigned int request_source();
 
     /**
-     * set the velocities of all managed sound sources 
+     * give back an OpenAL source id for further use.
      */
-    void set_source_vel_all( ALfloat *pos );
+    void release_source( unsigned int source );
+
+    bool load(string &samplepath, void **data, int *format, unsigned int*size,
+                                  int *freq );
+
+
+private:
+    static int _alut_init;
+
+    bool _working;
+    bool _changed;
+    float _volume;
+
+    ALCdevice *_device;
+    ALCcontext *_context;
+
+    // Position of the listener.
+    SGVec3d _listener_pos;
+
+    // Velocity of the listener.
+    SGVec3f _listener_vel;
+
+    // Orientation of the listener. 
+    // first 3 elements are "at" vector, second 3 are "up" vector
+    ALfloat _listener_ori[6];
+
+    sample_group_map _sample_groups;
+
+    vector<ALuint> _free_sources;
+    vector<ALuint> _sources_in_use;
+
+    char *_devname;
+
+    bool testForALError(string s);
+    bool testForALCError(string s);
+    bool testForALUTError(string s);
+    bool testForError(void *p, string s);
+    void update_sample_config( SGSampleGroup *sound );
 };
 
 
index 8dd8df9323d197e0e5e6a6395af9339200e97646..919f08371669b9f8871db20178b09d7a05fac0f7 100644 (file)
@@ -50,14 +50,11 @@ static const struct {
        const char *name;
        double (*fn)(double);
 } __sound_fn[] = {
-//     {"lin", _snd_lin},
        {"inv", _snd_inv},
        {"abs", _snd_abs},
        {"sqrt", _snd_sqrt},
        {"log", _snd_log10},
        {"ln", _snd_log},
-//     {"sqr", _snd_sqr},
-//     {"pow3", _snd_pow3},
        {"", NULL}
 };
 
@@ -84,18 +81,14 @@ SGXmlSound::~SGXmlSound()
 }
 
 void
-SGXmlSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr,
-                 const string &path)
+SGXmlSound::init(SGPropertyNode *root, SGPropertyNode *node,
+                 SGSampleGroup *sgrp, const string &path)
 {
 
    //
    // set global sound properties
    //
 
-   if (sndmgr->is_working() == false) {
-       return;
-   }
-   
    _name = node->getStringValue("name", "");
    SG_LOG(SG_GENERAL, SG_DEBUG, "Loading sound information for: " << _name );
 
@@ -236,8 +229,7 @@ SGXmlSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr,
    //
    // Relative position
    //
-   sgVec3 offset_pos;
-   sgSetVec3( offset_pos, 0.0, 0.0, 0.0 );
+   SGVec3f offset_pos = SGVec3f::zeros();
    SGPropertyNode_ptr pos = node->getChild("position");
    if ( pos != NULL ) {
        offset_pos[0] = pos->getDoubleValue("x", 0.0);
@@ -248,9 +240,8 @@ SGXmlSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr,
    //
    // Orientation
    //
-   sgVec3 dir;
+   SGVec3f dir = SGVec3f::zeros();
    float inner, outer, outer_gain;
-   sgSetVec3( dir, 0.0, 0.0, 0.0 );
    inner = outer = 360.0;
    outer_gain = 0.0;
    pos = node->getChild("orientation");
@@ -266,8 +257,8 @@ SGXmlSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr,
    //
    // Initialize the sample
    //
-   _mgr = sndmgr;
-   if ( (_sample = _mgr->find(_name)) == NULL ) {
+   _sgrp = sgrp;
+   if ( (_sample = _sgrp->find(_name)) == NULL ) {
        // FIXME: Does it make sense to overwrite a previous entry's
        // configuration just because a new entry has the same name?
        // Note that we can't match on identical "path" because we the
@@ -276,17 +267,16 @@ SGXmlSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr,
        // "alSource".  The semantics of what is going on here seems
        // confused and needs to be thought through more carefully.
         _sample = new SGSoundSample( path.c_str(),
-                                    node->getStringValue("path", ""),
-                                    false );
-
-       _mgr->add( _sample, _name );
+                                    node->getStringValue("path", "") );
+       _sgrp->add( _sample, _name );
    }
 
-   _sample->set_offset_pos( offset_pos );
-   _sample->set_orientation(dir, inner, outer, outer_gain);
-   _sample->set_volume(v);
+   _sample->set_relative_position( offset_pos );
+   _sample->set_orientation( dir );
+   _sample->set_audio_cone(inner, outer, outer_gain);
    _sample->set_reference_dist( reference_dist );
    _sample->set_max_dist( max_dist );
+   _sample->set_volume(v);
    _sample->set_pitch(p);
 }
 
@@ -316,7 +306,8 @@ SGXmlSound::update (double dt)
         )
        )
    {
-       if ((_mode != SGXmlSound::IN_TRANSIT) || (_stopping > MAX_TRANSIT_TIME)) {
+       if ((_mode != SGXmlSound::IN_TRANSIT) || (_stopping > MAX_TRANSIT_TIME))
+       {
            if (_sample->is_playing()) {
                SG_LOG(SG_GENERAL, SG_DEBUG, "Stopping audio after " << _dt_play
                       << " sec: " << _name );
index d161bbca4acf5f32035da558f38d26963d18ba22..b5bc1f9f3893ffb7a224e96c5a1a8cab9ef01c1b 100644 (file)
@@ -38,8 +38,8 @@
 #include <simgear/compiler.h>
 #include <simgear/props/condition.hxx>
 
+#include "sample_group.hxx"
 #include "sample_openal.hxx"
-#include "soundmgr_openal.hxx"
 
 static const double MAX_TRANSIT_TIME = 0.1;    // 100 ms.
 
@@ -99,10 +99,10 @@ public:
    * @param root The root node of the programs property tree.
    * @param child A pointer to the location of the current event as defined
    * in the configuration file.
-   * @param sndmgr A pointer to a pre-initialized sound manager class.
+   * @param sgrp A pointer to a pre-initialized sample group class.
    * @param path The path where the audio files remain.
    */
-  virtual void init (SGPropertyNode *, SGPropertyNode *, SGSoundMgr *,
+  virtual void init (SGPropertyNode *, SGPropertyNode *, SGSampleGroup *,
                      const string &);
 
   /**
@@ -135,7 +135,7 @@ protected:
 
 private:
 
-  SGSoundMgr * _mgr;
+  SGSampleGroup * _sgrp;
   SGSharedPtr<SGSoundSample> _sample;
 
   SGSharedPtr<SGCondition> _condition;
index ee219d84c086d7754ce7f18bbe60dbb25b84c8ad..a31478f54dc92448f534923e2e4d3d1d7e88e6a6 100644 (file)
@@ -20,7 +20,7 @@
 
 #include "SGAtomic.hxx"
 
-#if defined(SGATOMIC_USE_GCC4_BUILTINS) && defined(__i386__)
+#if !defined(SGATOMIC_USE_GCC4_BUILTINS) && defined (__i386__)
 
 // Usually the apropriate functions are inlined by gcc.
 // But if gcc is called with something aequivalent to -march=i386,