]> git.mxchange.org Git - simgear.git/commitdiff
Update the bad-doppler test and simplify it to only test for bad platforms.
authorErik Hofman <erik@ehofman.com>
Sun, 12 Dec 2010 13:07:44 +0000 (14:07 +0100)
committerErik Hofman <erik@ehofman.com>
Sun, 12 Dec 2010 13:07:44 +0000 (14:07 +0100)
simgear/sound/aax/soundmgr_aax.cxx [new file with mode: 0644]
simgear/sound/aax/soundmgr_aax.hxx [new file with mode: 0644]
simgear/sound/sample_group.cxx
simgear/sound/soundmgr_openal.cxx

diff --git a/simgear/sound/aax/soundmgr_aax.cxx b/simgear/sound/aax/soundmgr_aax.cxx
new file mode 100644 (file)
index 0000000..d305ee4
--- /dev/null
@@ -0,0 +1,608 @@
+// soundmgr.cxx -- Sound effect management class
+//
+// Sound manager initially written by David Findlay
+// <david_j_findlay@yahoo.com.au> 2001
+//
+// C++-ified by Curtis Olson, started March 2001.
+// Modified for the new SoundSystem by Erik Hofman, October 2009
+//
+// Copyright (C) 2001  Curtis L. Olson - http://www.flightgear.org/~curt
+// 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$
+
+#ifdef HAVE_CONFIG_H
+#  include <simgear_config.h>
+#endif
+
+#if defined( __APPLE__ )
+# include <ALUT/alut.h>
+#else
+# include <AL/alut.h>
+#endif
+
+#include <iostream>
+#include <algorithm>
+
+#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>
+
+using std::string;
+
+extern bool isNaN(float *v);
+
+#define MAX_SOURCES    128
+
+
+//
+// Sound Manager
+//
+
+int SGSoundMgr::_alut_init = 0;
+
+// constructor
+SGSoundMgr::SGSoundMgr() :
+    _working(false),
+    _active(false),
+    _changed(true),
+    _volume(0.0),
+    _device(NULL),
+    _context(NULL),
+    _absolute_pos(SGVec3d::zeros()),
+    _offset_pos(SGVec3d::zeros()),
+    _base_pos(SGVec3d::zeros()),
+    _geod_pos(SGGeod::fromCart(SGVec3d::zeros())),
+    _velocity(SGVec3d::zeros()),
+    _orientation(SGQuatd::zeros()),
+    _bad_doppler(false),
+    _renderer("unknown"),
+    _vendor("unknown")
+{
+#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++;
+#else
+  //#error ALUT 1.1 required, ALUT 1.0 is no longer supported, please upgrade
+#endif
+}
+
+// destructor
+
+SGSoundMgr::~SGSoundMgr() {
+
+    stop();
+#if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
+    _alut_init--;
+    if (_alut_init == 0) {
+        alutExit ();
+    }
+#endif
+}
+
+// initialize the sound manager
+void SGSoundMgr::init(const char *devname) {
+
+    SG_LOG( SG_GENERAL, SG_INFO, "Initializing OpenAL sound manager" );
+
+    _config = aaxDriverOpenByName(devname, AAX_MODE_WRITE_STEREO);
+    if ( testForError(C-nfig, "Audio device not available, trying default") ) {
+        _config = aaxDriverOpenDefault(AAX_MODE_WRITE_STEREO);
+        if (testForError(_config, "Default Audio device not available.") ) {
+           return;
+        }
+    }
+
+    aaxMixerInit(_config);
+    
+    aaxSensorSetGain(_config, 0.0);
+    aaxSensorSetIdentityMatrix(_config);
+
+    aaxScenerySetDopplerFactor(_config, 340.3);
+    aaxScenerySetDistanceModel(_config, AAX_AL_INVERSE_DISTANCE_CLAMPED);
+
+    // 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++) {
+        aaxEmitter source;
+
+        source = aaxEmitterCreate();
+        if ( source ) {
+            _free_sources.push_back( source );
+        }
+        else break;
+    }
+
+    if (_free_sources.size() == 0) {
+        SG_LOG(SG_GENERAL, SG_ALERT, "Unable to grab any OpenAL sources!");
+    }
+}
+
+void SGSoundMgr::activate() {
+    if ( _working ) {
+        _active = true;
+        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->activate();
+        }
+    }
+}
+
+// stop the sound manager
+void SGSoundMgr::stop() {
+
+    // first stop all sample groups
+    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->stop();
+    }
+
+    // clear all OpenAL sources
+    for (unsigned int i=0; i<_free_sources.size(); i++) {
+        aaxEmitter source = _free_sources[i];
+        aaxEmitterDestroy(source);
+    }
+    _free_sources.clear();
+
+    // clear any OpenAL buffers before shutting down
+    buffer_map_iterator buffers_current = _buffers.begin();
+    buffer_map_iterator buffers_end = _buffers.end();
+    for ( ; buffers_current != buffers_end; ++buffers_current ) {
+        refUint ref = buffers_current->second;
+        aaxBuffer buffer = ref.id;
+        aaxBufferDestroy(buffer);
+    }
+    _buffers.clear();
+
+    if (_working) {
+        _working = false;
+        _active = false;
+
+        aaxDriverClose(_config);
+        aaxDriverFree(_config);
+
+        _renderer = "unknown";
+        _vendor = "unknown";
+    }
+}
+
+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->stop();
+        }
+        _active = false;
+    }
+}
+
+void SGSoundMgr::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();
+        }
+        _active = true;
+    }
+}
+
+void SGSoundMgr::bind ()
+{
+    _free_sources.clear();
+    _free_sources.reserve( MAX_SOURCES );
+    _sources_in_use.clear();
+    _sources_in_use.reserve( MAX_SOURCES );
+}
+
+
+void SGSoundMgr::unbind ()
+{
+    _sample_groups.clear();
+
+    // delete free sources
+    for (unsigned int i=0; i<_free_sources.size(); i++) {
+        aaxEmitter source = _free_sources[i];
+        aaxEmitterDestroy(source);
+    }
+
+    _free_sources.clear();
+    _sources_in_use.clear();
+}
+
+// run the audio scheduler
+void SGSoundMgr::update( double dt ) {
+    if (_active) {
+        if (_changed) {
+            update_pos_and_orientation();
+        }
+
+        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);
+        }
+
+        if (_changed) {
+#if 0
+if (isNaN(_at_up_vec)) printf("NaN in listener orientation\n");
+if (isNaN(toVec3f(_absolute_pos).data())) printf("NaN in listener position\n");
+if (isNaN(_velocity.data())) printf("NaN in listener velocity\n");
+#endif
+
+            SGMatrix m = SGMatrix(_orientation);
+            aaxSensorSetMatrix(m.data());
+            aaxSensorSetGain(_config, _volume);
+
+            SGQuatd hlOr = SGQuatd::fromLonLat( _geod_pos );
+            SGVec3d velocity = SGVec3d::zeros();
+            if ( _velocity[0] || _velocity[1] || _velocity[2] ) {
+                velocity = hlOr.backTransform(_velocity*SG_FEET_TO_METER);
+            }
+
+            aaxSensorSetVelocity(toVec3f(velocity).data());
+
+            // TODO: altitude dependent
+            // aaxScenerySetDopplerFactor(_config, 340.3);
+            _changed = false;
+        }
+    }
+}
+
+// add a sample 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;
+    }
+
+    if (_active) sgrp->activate();
+    _sample_groups[refname] = sgrp;
+
+    return true;
+}
+
+
+// remove a sound effect, return true if successful
+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( sample_grp_it );
+
+    return true;
+}
+
+
+// return true of the specified sound exists in the sound manager system
+bool SGSoundMgr::exists( 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;
+    }
+
+    return true;
+}
+
+
+// return a pointer to the SGSampleGroup if the specified sound exists
+// in the sound manager system, otherwise 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);
+            add( sgrp, refname );
+            return sgrp;
+        }
+        else 
+            return NULL;
+    }
+
+    return sample_grp_it->second;
+}
+
+
+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;
+
+    if (_free_sources.size() > 0) {
+       source = _free_sources.back();
+       _free_sources.pop_back();
+       _sources_in_use.push_back(source);
+    }
+    else
+       SG_LOG( SG_GENERAL, SG_INFO, "No more free sources available\n");
+
+    return source;
+}
+
+// Free up a source id for further use
+void SGSoundMgr::release_source( unsigned int source )
+{
+    vector<ALuint>::iterator it;
+
+    it = std::find(_sources_in_use.begin(), _sources_in_use.end(), source);
+    if ( it != _sources_in_use.end() ) {
+        ALint result;
+
+        result = aaxEmitterGetStatus(source);
+        if ( result == AAX_STATUS_PLAYING ) {
+            aaxMixerDeregisterEmitter(_config, source);
+            aaxEmitterDestroy(source);
+        }
+
+        _free_sources.push_back( source );
+        _sources_in_use.erase( it );
+    }
+}
+
+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();
+        void *sample_data = NULL;
+
+        // see if the sample name is already cached
+        buffer_map_iterator buffer_it = _buffers.find( sample_name );
+        if ( buffer_it != _buffers.end() ) {
+            buffer_it->second.refctr++;
+            buffer = buffer_it->second.id;
+            sample->set_buffer( buffer );
+            return buffer;
+        }
+
+        // sample name was not found in the buffer cache.
+        if ( sample->is_file() ) {
+            int freq, format;
+            size_t size;
+            bool res;
+
+            res = load(sample_name, &sample_data, &format, &size, &freq);
+            if (res == false) return buffer;
+
+            sample->set_frequency( freq );
+            sample->set_format( format );
+            sample->set_size( size );
+        }
+        else
+            sample_data = sample->get_data();
+
+        // create a buffer handle
+        unsigned long size = sample->get_size();
+        unsigned int freq = sample->get_frequency();
+        enum aaxFormat fmt = sample->get_format();
+        buffer = aaxBufferCreate(_config, sample_data, size, fmt, tracks);
+        aaxBufferSetFrequency(buffer, frequency);
+
+        if ( sample->is_file() ) free(sample_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) {
+        aaxBuffer buffer = buffer_it->second.id;
+        aaxBufferDestory(buffer);
+        _buffers.erase( buffer_it );
+        testForALError("release buffer");
+    }
+}
+
+void SGSoundMgr::update_pos_and_orientation() {
+    /**
+     * 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.
+     *
+     * This is in the same coordinate system as OpenGL; y=up, z=back, x=right.
+     */
+    SGVec3d sgv_at = _orientation.backTransform(-SGVec3d::e3());
+    SGVec3d sgv_up = _orientation.backTransform(SGVec3d::e2());
+    _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];
+
+    // static const SGQuatd q(-0.5, -0.5, 0.5, 0.5);
+    // SGQuatd hlOr = SGQuatd::fromLonLat(SGGeod::fromCart(_base_pos));
+    // SGQuatd ec2body = hlOr*_orientation;
+    _absolute_pos = _base_pos; // + ec2body.backTransform( _offset_pos );
+}
+
+bool SGSoundMgr::load(string &samplepath, void **dbuf, int *fmt,
+                                          size_t *sz, int *frq )
+{
+    if ( !_working ) return false;
+
+    ALenum format;
+    ALsizei size;
+    ALsizei freq;
+    ALvoid *data;
+
+#if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
+    ALfloat freqf;
+    // ignore previous errors to prevent the system from halting on silly errors
+    alGetError();
+    alcGetError(_device);
+    data = alutLoadMemoryFromFile(samplepath.c_str(), &format, &size, &freqf );
+    freq = (ALsizei)freqf;
+    int error = alutGetError();
+    if (data == NULL || 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
+    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 =  alGetError();
+    if ( error != AL_NO_ERROR ) {
+        string msg = "Failed to load wav file: ";
+        const ALchar *errorString = alGetString(error);
+        if (errorString) {
+            msg.append(errorString);
+        } else {
+            // alGetString returns NULL when an unexpected or OS specific error
+            // occurs: e.g. -43 on Mac when file is not found.
+            // In this case, alGetString() sets 'Invalid Enum' error, so
+            // showing with the original error number is helpful.
+            stringstream ss;
+            ss << alGetString(alGetError()) << "(" << error << ")";
+            msg.append(ss.str());
+        }
+        throw sg_io_exception(msg.c_str(), sg_location(samplepath));
+        return false;
+    }
+#endif
+
+    *dbuf = (void *)data;
+    *fmt = (int)format;
+    *sz = (size_t)size;
+    *frq = (int)freq;
+
+    return true;
+}
+
+vector<const char*> SGSoundMgr::get_available_devices()
+{
+    vector<const char*> devices;
+    unsigned int x, max;
+    char *s;
+
+    max = aaxDriverGetCount();
+    for (x=0; x<max; x++)
+    {
+        aaxConfig cfg = aaxDriverGetByNumber(x);
+        if (cfg) {
+            unsigned int y, max_device;
+            const char *d;
+
+            d = aaxDriverGetName(cfg);
+            max_device = aaxDriverGetDeviceCount(cfg);
+            for (y=0; y<max_device; y++) {
+                const char *r = aaxDriverGetDeviceNameByPos(cfg, y);
+                printf("   '%s on %s'\n", d, r);
+                devices.push_back(s);
+            }
+            aaxDriverFree(cfg);
+        }
+    }
+    return devices;
+}
+
+
+bool SGSoundMgr::testForError(void *p, string s)
+{
+   if (p == NULL) {
+      SG_LOG( SG_GENERAL, SG_ALERT, "Error: " << s);
+      return true;
+   }
+   return false;
+}
+
+
+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) {
+        SG_LOG( SG_GENERAL, SG_ALERT, "ALUT Error (sound manager): "
+                                       << alutGetErrorString(error) << " at "
+                                       << s);
+        return true;
+    }
+#endif
+    return false;
+}
diff --git a/simgear/sound/aax/soundmgr_aax.hxx b/simgear/sound/aax/soundmgr_aax.hxx
new file mode 100644 (file)
index 0000000..3834ef9
--- /dev/null
@@ -0,0 +1,313 @@
+// soundmgr.hxx -- Sound effect management class
+//
+// Sound manager initially written by David Findlay
+// <david_j_findlay@yahoo.com.au> 2001
+//
+// C++-ified by Curtis Olson, started March 2001.
+// Modified for the new SoundSystem by Erik Hofman, October 2009
+//
+// Copyright (C) 2001  Curtis L. Olson - http://www.flightgear.org/~curt
+// 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 soundmgr.hxx
+ * Provides a sound manager class to keep track of
+ * multiple sounds and manage playing them with different effects and
+ * timings.
+ */
+
+#ifndef _SG_SOUNDMGR_AAX_HXX
+#define _SG_SOUNDMGR_AAX_HXX 1
+
+#include <string>
+#include <vector>
+#include <map>
+
+#include <aax.h>
+
+#include <simgear/compiler.h>
+#include <simgear/structure/subsystem_mgr.hxx>
+#include <simgear/math/SGMathFwd.hxx>
+
+#include "sample_group.hxx"
+
+struct refUint {
+    unsigned int refctr;
+    ALuint id;
+
+    refUint() { refctr = 0; id = (ALuint)-1; };
+    refUint(ALuint i) { refctr = 1; id = i; };
+    ~refUint() {};
+};
+
+typedef std::map < std::string, refUint > buffer_map;
+typedef buffer_map::iterator buffer_map_iterator;
+typedef buffer_map::const_iterator  const_buffer_map_iterator;
+
+typedef std::map < std::string, SGSharedPtr<SGSampleGroup> > sample_group_map;
+typedef sample_group_map::iterator sample_group_map_iterator;
+typedef sample_group_map::const_iterator const_sample_group_map_iterator;
+
+/**
+ * Manage a collection of SGSampleGroup instances
+ */
+class SGSoundMgr : public SGSubsystem
+{
+public:
+
+    SGSoundMgr();
+    ~SGSoundMgr();
+
+    void init(const char *devname = NULL);
+    void bind();
+    void unbind();
+    void update(double dt);
+    
+    void suspend();
+    void resume();
+    void stop();
+
+    inline void reinit() { stop(); init(); }
+
+    /**
+     * Test is the sound manager is in a working condition.
+     * @return true is the sound manager is working
+     */
+    inline bool is_working() const { return _working; }
+
+    /**
+     * Set the sound manager to a  working condition.
+     */
+    void activate();
+
+    /**
+     * Test is the sound manager is in an active and working condition.
+     * @return true is the sound manager is active
+     */
+    inline bool is_active() const { return _active; }
+
+    /**
+     * Register a sample group to the sound manager.
+     * @para sgrp Pointer to a sample group to add
+     * @param refname Reference name of the sample group
+     * @return true if successful, false otherwise
+     */
+    bool add( SGSampleGroup *sgrp, const std::string& refname );
+
+    /** 
+     * Remove a sample group from the sound manager.
+     * @param refname Reference name of the sample group to remove
+     * @return true if successful, false otherwise
+     */
+    bool remove( const std::string& refname );
+
+    /**
+     * Test if a specified sample group is registered at the sound manager
+     * @param refname Reference name of the sample group test for
+     * @return true if the specified sample group exists
+     */
+    bool exists( const std::string& refname );
+
+    /**
+     * Find a specified sample group in the sound manager
+     * @param refname Reference name of the sample group to find
+     * @return A pointer to the SGSampleGroup
+     */
+    SGSampleGroup *find( const string& refname, bool create = false );
+
+    /**
+     * Set the Cartesian position of the sound manager.
+     * @param pos listener position
+     */
+    void set_position( const SGVec3d& pos, const SGGeod& pos_geod ) {
+        _base_pos = pos; _geod_pos = pos_geod; _changed = true;
+    }
+
+    void set_position_offset( const SGVec3d& pos ) {
+        _offset_pos = pos; _changed = true;
+    }
+
+    /**
+     * Get the position of the sound manager.
+     * This is in the same coordinate system as OpenGL; y=up, z=back, x=right
+     * @return listener position
+     */
+    SGVec3d& get_position() { return _absolute_pos; }
+
+    /**
+     * Set the velocity vector (in meters per second) of the sound manager
+     * This is the horizontal local frame; x=north, y=east, z=down
+     * @param Velocity vector
+     */
+    void set_velocity( const SGVec3d& vel ) {
+        _velocity = vel; _changed = true;
+    }
+
+    /**
+     * Get the velocity vector of the sound manager
+     * This is in the same coordinate system as OpenGL; y=up, z=back, x=right.
+     * @return Velocity vector of the listener
+     */
+    inline SGVec3f get_velocity() { return toVec3f(_velocity); }
+
+    /**
+     * Set the orientation of the sound manager
+     * @param ori Quaternation containing the orientation information
+     */
+    void set_orientation( const SGQuatd& ori ) {
+        _orientation = ori; _changed = true;
+    }
+
+    /**
+     * Get the orientation of the sound manager
+     * @return Quaternation containing the orientation information
+     */
+    inline const SGQuatd& get_orientation() { return _orientation; }
+
+    /**
+     * Get the direction vector of the sound manager
+     * This is in the same coordinate system as OpenGL; y=up, z=back, x=right.
+     * @return Look-at direction of the listener
+     */
+    SGVec3f get_direction() {
+        return SGVec3f(_at_up_vec[0], _at_up_vec[1], _at_up_vec[2]);
+    }
+
+    enum {
+        NO_SOURCE = (unsigned int)-1,
+        NO_BUFFER = (unsigned int)-1
+    };
+
+    /**
+     * Set the master volume.
+     * @param vol Volume (must be between 0.0 and 1.0)
+     */
+    void set_volume( float vol );
+
+    /**
+     * Get the master volume.
+     * @return Volume (must be between 0.0 and 1.0)
+     */
+    inline float get_volume() { return _volume; }
+
+    /**
+     * Get a free source-id
+     * @return NO_SOURCE if no source is available
+     */
+    unsigned int request_source();
+
+    /**
+     * Free an source-id for future use
+     * @param source source-id to free
+     */
+    void release_source( unsigned int source );
+
+    /**
+     * Get a free buffer-id
+     * The buffer-id will be asigned to the sample by calling this function.
+     * @param sample Pointer to an audio sample to assign the buffer-id to
+     * @return NO_BUFFER if loading of the buffer failed.
+     */
+    unsigned int request_buffer(SGSoundSample *sample);
+
+    /**
+     * Free an buffer-id for this sample
+     * @param sample Pointer to an audio sample for which to free the buffer
+     */
+    void release_buffer( SGSoundSample *sample );
+
+    /**
+     * Test if the position of the sound manager has changed.
+     * The value will be set to false upon the next call to update_late()
+     * @return true if the position has changed
+     */
+    inline bool has_changed() { return _changed; }
+
+    /**
+     * Some implementations seem to need the velocity miltyplied by a
+     * factor of 100 to make them distinct. I've not found if this is
+     * a problem in the implementation or in out code. Until then
+     * this function is used to detect the problematic implementations.
+     */
+    inline bool bad_doppler_effect() { return _bad_doppler; }
+
+    /**
+     * Load a sample file and return it's configuration and data.
+     * @param samplepath Path to the file to load
+     * @param data Pointer to a variable that points to the allocated data
+     * @param format Pointer to a vairable that gets the format
+     * @param size Pointer to a vairable that gets the sample size in bytes
+     * @param freq Pointer to a vairable that gets the sample frequency in Herz
+     * @return true if succesful, false on error
+     */
+    bool load(string &samplepath, void **data, int *format,
+                                         size_t *size, int *freq );
+
+    /**
+     * Get a list of available playback devices.
+     */
+    std::vector<const char*> get_available_devices();
+
+    /**
+     * Get the current vendor or rendering backend.
+     */
+    const std::string& get_vendor() { return _vendor; }
+    const std::string& get_renderer() { return _renderer; }
+
+private:
+    static int _alut_init;
+
+    bool _working;
+    bool _active;
+    bool _changed;
+    float _volume;
+
+    aaxConfig _config;
+
+    // Position of the listener.
+    SGVec3d _absolute_pos;
+    SGVec3d _offset_pos;
+    SGVec3d _base_pos;
+    SGGeod _geod_pos;
+
+    // Velocity of the listener.
+    SGVec3d _velocity;
+
+    // Orientation of the listener. 
+    // first 3 elements are "at" vector, second 3 are "up" vector
+    SGQuatd _orientation;
+
+    sample_group_map _sample_groups;
+    buffer_map _buffers;
+
+    std::vector<aaxEmitter> _free_sources;
+    std::vector<aaxEmitter> _sources_in_use;
+
+    bool _bad_doppler;
+    std::string _renderer;
+    std::string _vendor;
+
+    void update_pos_and_orientation();
+    void update_sample_config( SGSampleGroup *sound );
+};
+
+
+#endif // _SG_SOUNDMGR_AAX_HXX
+
+
index 26da0f937f8bce37e787d967025474150ae8d642..1610d088fbfabb3871d290ad5670866ee36e81fa 100644 (file)
@@ -273,7 +273,6 @@ SGSampleGroup::stop ()
             ALint source = sample->get_source();
             if ( sample->is_playing() ) {
                 alSourceStop( source );
-                alSourcei( source, AL_BUFFER, 0 );
             }
             _smgr->release_source( source );
             sample->no_valid_source();
index c3eda45a0568e7cb2e9037a23b0f9a8cc9af6fb0..3a0b2979c3a4d841caf11cdddd67518fcd44e8e1 100644 (file)
@@ -174,11 +174,11 @@ void SGSoundMgr::init(const char *devname) {
 
     _vendor = (const char *)alGetString(AL_VENDOR);
     _renderer = (const char *)alGetString(AL_RENDERER);
-    if ( (_vendor != "Adalin" && _vendor != "Apple Computer Inc.") &&
-          (_vendor != "OpenAL Community" || (_renderer != "Software" &&
-                        _renderer != "OpenAL Sample Implementation"))
-       )
-    {
+
+    if (_vendor == "Creative Labs Inc.") {
+       _bad_doppler = true;
+
+    } else if (_vendor == "OpenAL Community" && _renderer == "OpenAL Soft") {
        _bad_doppler = true;
     }
 
@@ -438,11 +438,12 @@ void SGSoundMgr::release_source( unsigned int source )
         ALint result;
 
         alGetSourcei( source, AL_SOURCE_STATE, &result );
-        if ( result == AL_PLAYING )
+        if ( result == AL_PLAYING ) {
             alSourceStop( source );
-        testForALError("release source");
+        }
 
-        alSourcei( source, AL_BUFFER, 0 );
+        alSourcei( source, AL_BUFFER, 0 );     // detach the associated buffer
+        testForALError("release_source");
         _free_sources.push_back( source );
         _sources_in_use.erase( it );
     }
@@ -473,18 +474,20 @@ unsigned int SGSoundMgr::request_buffer(SGSoundSample *sample)
 
             try {
               bool res = load(sample_name, &sample_data, &format, &size, &freq);
-              if (res == false) return buffer;
+              if (res == false) return NO_BUFFER;
             } catch (sg_exception& e) {
-              SG_LOG(SG_GENERAL, SG_ALERT, "failed to load sound buffer:" << e.getFormattedMessage());
+              SG_LOG(SG_GENERAL, SG_ALERT,
+                     "failed to load sound buffer:" << e.getFormattedMessage());
               return NO_BUFFER;
             }
             
             sample->set_frequency( freq );
             sample->set_format( format );
             sample->set_size( size );
-        }
-        else
+
+        } else {
             sample_data = sample->get_data();
+        }
 
         // create an OpenAL buffer handle
         alGenBuffers(1, &buffer);
@@ -496,17 +499,17 @@ unsigned int SGSoundMgr::request_buffer(SGSoundSample *sample)
             ALsizei freq = sample->get_frequency();
             alBufferData( buffer, format, sample_data, size, freq );
 
-            if ( sample->is_file() ) free(sample_data);
-
             if ( !testForALError("buffer add data") ) {
                 sample->set_buffer(buffer);
                 _buffers[sample_name] = refUint(buffer);
             }
         }
+
+        if ( sample->is_file() ) free(sample_data);
     }
     else {
         buffer = sample->get_buffer();
-}
+    }
 
     return buffer;
 }
@@ -554,10 +557,7 @@ void SGSoundMgr::update_pos_and_orientation() {
     _at_up_vec[4] = sgv_up[1];
     _at_up_vec[5] = sgv_up[2];
 
-    // static const SGQuatd q(-0.5, -0.5, 0.5, 0.5);
-    // SGQuatd hlOr = SGQuatd::fromLonLat(SGGeod::fromCart(_base_pos));
-    // SGQuatd ec2body = hlOr*_orientation;
-    _absolute_pos = _base_pos; // + ec2body.backTransform( _offset_pos );
+    _absolute_pos = _base_pos;
 }
 
 bool SGSoundMgr::load(string &samplepath, void **dbuf, int *fmt,