Initial commit of the new sound system, expect more updates to follow
This commit is contained in:
@@ -30,7 +30,7 @@
|
|||||||
#include <simgear/math/sg_geodesy.hxx>
|
#include <simgear/math/sg_geodesy.hxx>
|
||||||
#include <simgear/math/point3d.hxx>
|
#include <simgear/math/point3d.hxx>
|
||||||
#include <simgear/math/polar3d.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/cloudfield.hxx>
|
||||||
#include <simgear/scene/sky/newcloud.hxx>
|
#include <simgear/scene/sky/newcloud.hxx>
|
||||||
#include <simgear/props/props.hxx>
|
#include <simgear/props/props.hxx>
|
||||||
@@ -175,7 +175,7 @@ SGEnviro::SGEnviro() :
|
|||||||
lightning_enable_state(false),
|
lightning_enable_state(false),
|
||||||
elapsed_time(0.0),
|
elapsed_time(0.0),
|
||||||
dt(0.0),
|
dt(0.0),
|
||||||
soundMgr(NULL),
|
sampleGroup(NULL),
|
||||||
snd_active(false),
|
snd_active(false),
|
||||||
snd_dist(0.0),
|
snd_dist(0.0),
|
||||||
min_time_before_lt(0.0),
|
min_time_before_lt(0.0),
|
||||||
@@ -189,6 +189,8 @@ SGEnviro::SGEnviro() :
|
|||||||
}
|
}
|
||||||
|
|
||||||
SGEnviro::~SGEnviro(void) {
|
SGEnviro::~SGEnviro(void) {
|
||||||
|
if (sampleGroup) delete sampleGroup;
|
||||||
|
|
||||||
// OSGFIXME
|
// OSGFIXME
|
||||||
return;
|
return;
|
||||||
list_of_lightning::iterator iLightning;
|
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) {
|
void SGEnviro::set_sampleGroup(SGSampleGroup *sgr) {
|
||||||
soundMgr = mgr;
|
sampleGroup = sgr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SGEnviro::drawPrecipitation(double rain_norm, double snow_norm, double hail_norm, double pitch, double roll, double heading, double hspeed) {
|
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[PY] = alt;
|
||||||
top[PZ] = 0;
|
top[PZ] = 0;
|
||||||
lt_build_tree_branch(0, top, 1.0, 50, top[PY] / 8.0);
|
lt_build_tree_branch(0, top, 1.0, 50, top[PY] / 8.0);
|
||||||
if( ! sgEnviro.soundMgr )
|
if( ! sgEnviro.sampleGroup )
|
||||||
return;
|
return;
|
||||||
Point3D start( sgEnviro.last_lon*SG_DEGREES_TO_RADIANS, sgEnviro.last_lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
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 );
|
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;
|
double ax = 0.0, ay = 0.0;
|
||||||
ax = cos(course) * dist;
|
ax = cos(course) * dist;
|
||||||
ay = sin(course) * dist;
|
ay = sin(course) * dist;
|
||||||
SGSharedPtr<SGSoundSample> snd = soundMgr->find("thunder");
|
SGSharedPtr<SGSoundSample> snd = sampleGroup->find("thunder");
|
||||||
if( snd ) {
|
if( snd ) {
|
||||||
ALfloat pos[3]={ax, ay, -sgEnviro.last_alt };
|
SGVec3d pos = SGVec3d(ax, ay, -sgEnviro.last_alt);
|
||||||
snd->set_source_pos(pos);
|
snd->set_base_position(pos);
|
||||||
snd->play_once();
|
snd->play_once();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if( !soundMgr->is_playing("thunder") ) {
|
if( !sampleGroup->is_playing("thunder") ) {
|
||||||
snd_active = false;
|
snd_active = false;
|
||||||
snd_playing = false;
|
snd_playing = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ using std::vector;
|
|||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
class SGLightning;
|
class SGLightning;
|
||||||
class SGSoundMgr;
|
class SGSampleGroup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simulate some echo on a weather radar.
|
* Simulate some echo on a weather radar.
|
||||||
@@ -84,7 +84,7 @@ private:
|
|||||||
sgVec4 fog_color;
|
sgVec4 fog_color;
|
||||||
sgMat4 transform;
|
sgMat4 transform;
|
||||||
double last_lon, last_lat, last_alt;
|
double last_lon, last_lat, last_alt;
|
||||||
SGSoundMgr *soundMgr;
|
SGSampleGroup *sampleGroup;
|
||||||
bool snd_active, snd_playing;
|
bool snd_active, snd_playing;
|
||||||
double snd_timer, snd_wait, snd_pos_lat, snd_pos_lon, snd_dist;
|
double snd_timer, snd_wait, snd_pos_lat, snd_pos_lon, snd_dist;
|
||||||
double min_time_before_lt;
|
double min_time_before_lt;
|
||||||
@@ -243,7 +243,7 @@ public:
|
|||||||
* Forward the sound manager instance to be able to play samples.
|
* Forward the sound manager instance to be able to play samples.
|
||||||
* @param mgr a running sound manager
|
* @param mgr a running sound manager
|
||||||
*/
|
*/
|
||||||
void set_soundMgr(SGSoundMgr *mgr);
|
void set_sampleGroup(SGSampleGroup *sgr);
|
||||||
|
|
||||||
void setFOV( float w, float h );
|
void setFOV( float w, float h );
|
||||||
void getFOV( float &w, float &h );
|
void getFOV( float &w, float &h );
|
||||||
|
|||||||
@@ -7,11 +7,13 @@ lib_LIBRARIES = libsgsound.a
|
|||||||
noinst_HEADERS =
|
noinst_HEADERS =
|
||||||
|
|
||||||
include_HEADERS = \
|
include_HEADERS = \
|
||||||
|
sample_group.hxx \
|
||||||
sample_openal.hxx \
|
sample_openal.hxx \
|
||||||
soundmgr_openal.hxx \
|
soundmgr_openal.hxx \
|
||||||
xmlsound.hxx
|
xmlsound.hxx
|
||||||
|
|
||||||
libsgsound_a_SOURCES = \
|
libsgsound_a_SOURCES = \
|
||||||
|
sample_group.cxx \
|
||||||
sample_openal.cxx \
|
sample_openal.cxx \
|
||||||
soundmgr_openal.cxx \
|
soundmgr_openal.cxx \
|
||||||
xmlsound.cxx
|
xmlsound.cxx
|
||||||
@@ -27,10 +29,10 @@ libsgsound_a_SOURCES = \
|
|||||||
|
|
||||||
#openal_test2_LDADD = \
|
#openal_test2_LDADD = \
|
||||||
# libsgsound.a \
|
# libsgsound.a \
|
||||||
|
# $(top_builddir)/simgear/structure/libsgstructure.a \
|
||||||
|
# $(top_builddir)/simgear/timing/libsgtiming.a \
|
||||||
# $(top_builddir)/simgear/debug/libsgdebug.a \
|
# $(top_builddir)/simgear/debug/libsgdebug.a \
|
||||||
# $(top_builddir)/simgear/misc/libsgmisc.a \
|
# $(top_builddir)/simgear/misc/libsgmisc.a \
|
||||||
# $(top_builddir)/simgear/structure/libsgstructure.a \
|
# $(openal_LIBS)
|
||||||
# $(openal_LIBS) \
|
|
||||||
# -lOpenThreads
|
|
||||||
|
|
||||||
INCLUDES = -I$(top_srcdir) -DSRC_DIR=\"$(top_srcdir)/simgear/sound\"
|
INCLUDES = -I$(top_srcdir) -DSRC_DIR=\"$(top_srcdir)/simgear/sound\"
|
||||||
|
|||||||
Binary file not shown.
@@ -7,48 +7,94 @@ static unsigned int sleep(unsigned int secs) { return 0; }
|
|||||||
#include <unistd.h> // sleep()
|
#include <unistd.h> // sleep()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "sample_openal.hxx"
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
|
||||||
#include "soundmgr_openal.hxx"
|
#include "soundmgr_openal.hxx"
|
||||||
|
|
||||||
|
|
||||||
int main( int argc, char *argv[] ) {
|
int main( int argc, char *argv[] ) {
|
||||||
SGSoundMgr sm;
|
SGSampleGroup *sgr;
|
||||||
|
SGSoundMgr *smgr;
|
||||||
|
|
||||||
SGSoundSample sample1( SRC_DIR, "jet.wav" );
|
smgr = new SGSoundMgr;
|
||||||
sample1.set_volume(0.5);
|
|
||||||
sample1.set_volume(0.2);
|
smgr->bind();
|
||||||
sample1.play_looped();
|
smgr->init();
|
||||||
|
smgr->set_volume(0.9);
|
||||||
|
sgr = smgr->find("default", true);
|
||||||
|
|
||||||
|
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);
|
sleep(1);
|
||||||
|
|
||||||
SGSoundSample sample2( SRC_DIR, "jet.wav" );
|
SGSoundSample *sample2 = new SGSoundSample( SRC_DIR, "jet.wav" );
|
||||||
sample2.set_volume(0.5);
|
sample2->set_volume(0.5);
|
||||||
sample2.set_pitch(0.4);
|
sample2->set_pitch(0.4);
|
||||||
sample2.play_looped();
|
sample2->play_looped();
|
||||||
|
sgr->add(sample2, "sound2");
|
||||||
|
smgr->update(1.0);
|
||||||
|
printf("playing sample2\n");
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|
||||||
SGSoundSample sample3( SRC_DIR, "jet.wav" );
|
SGSoundSample *sample3 = new SGSoundSample( SRC_DIR, "jet.wav" );
|
||||||
sample3.set_volume(0.5);
|
sample3->set_volume(0.5);
|
||||||
sample3.set_pitch(0.8);
|
sample3->set_pitch(0.8);
|
||||||
sample3.play_looped();
|
sample3->play_looped();
|
||||||
|
sgr->add(sample3, "sound3");
|
||||||
|
smgr->update(1.0);
|
||||||
|
printf("playing sample3\n");
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|
||||||
SGSoundSample sample4( SRC_DIR, "jet.wav" );
|
SGSoundSample *sample4 = new SGSoundSample( SRC_DIR, "jet.wav" );
|
||||||
sample4.set_volume(0.5);
|
sample4->set_volume(0.5);
|
||||||
sample4.set_pitch(1.2);
|
sample4->set_pitch(1.2);
|
||||||
sample4.play_looped();
|
sample4->play_looped();
|
||||||
|
sgr->add(sample4, "sound4");
|
||||||
|
smgr->update(1.0);
|
||||||
|
printf("playing sample4\n");
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|
||||||
SGSoundSample sample5( SRC_DIR, "jet.wav" );
|
SGSoundSample *sample5 = new SGSoundSample( SRC_DIR, "jet.wav" );
|
||||||
sample5.set_volume(0.5);
|
sample5->set_volume(0.5);
|
||||||
sample5.set_pitch(1.6);
|
sample5->set_pitch(1.6);
|
||||||
sample5.play_looped();
|
sample5->play_looped();
|
||||||
|
sgr->add(sample5, "sound5");
|
||||||
|
smgr->update(1.0);
|
||||||
|
printf("playing sample5\n");
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|
||||||
SGSoundSample sample6( SRC_DIR, "jet.wav" );
|
SGSoundSample *sample6 = new SGSoundSample( SRC_DIR, "jet.wav" );
|
||||||
sample6.set_volume(0.5);
|
sample6->set_volume(0.5);
|
||||||
sample6.set_pitch(2.0);
|
sample6->set_pitch(2.0);
|
||||||
sample6.play_looped();
|
sample6->play_looped();
|
||||||
|
sgr->add(sample6, "sound6");
|
||||||
|
smgr->update(1.0);
|
||||||
|
printf("playing sample6\n");
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|
||||||
sleep(10);
|
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);
|
||||||
|
|
||||||
|
smgr->unbind();
|
||||||
|
sleep(2);
|
||||||
|
delete smgr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
+109
-454
@@ -15,8 +15,8 @@
|
|||||||
// General Public License for more details.
|
// General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program; if not, write to the Free Software
|
// along with this program; if not, write to the Free Software Foundation,
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
//
|
//
|
||||||
// $Id$
|
// $Id$
|
||||||
|
|
||||||
@@ -24,20 +24,12 @@
|
|||||||
# include <simgear_config.h>
|
# include <simgear_config.h>
|
||||||
#endif
|
#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/debug/logstream.hxx>
|
||||||
#include <simgear/misc/sg_path.hxx>
|
|
||||||
#include <simgear/structure/exception.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"
|
#include "sample_openal.hxx"
|
||||||
|
|
||||||
|
|
||||||
@@ -45,477 +37,140 @@
|
|||||||
// SGSoundSample
|
// 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
|
// empty constructor
|
||||||
SGSoundSample::SGSoundSample() :
|
SGSoundSample::SGSoundSample() :
|
||||||
buffer(0),
|
_absolute_pos(SGVec3d::zeros().data()),
|
||||||
source(0),
|
_relative_pos(SGVec3f::zeros().data()),
|
||||||
pitch(1.0),
|
_base_pos(SGVec3d::zeros().data()),
|
||||||
volume(1.0),
|
_direction(SGVec3f::zeros().data()),
|
||||||
reference_dist(500.0),
|
_velocity(SGVec3f::zeros().data()),
|
||||||
max_dist(3000.),
|
_sample_name(""),
|
||||||
loop(AL_FALSE),
|
_data(NULL),
|
||||||
#ifdef USE_SOFTWARE_DOPPLER
|
_format(AL_FORMAT_MONO8),
|
||||||
doppler_pitch_factor(1),
|
_size(0),
|
||||||
doppler_volume_factor(1),
|
_freq(0),
|
||||||
#endif
|
_valid_buffer(false),
|
||||||
playing(false),
|
_buffer(SGSoundMgr::NO_BUFFER),
|
||||||
no_Doppler_effect(true)
|
_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
|
// constructor
|
||||||
SGSoundSample::SGSoundSample( const char *path, const char *file, bool _no_Doppler_effect ) :
|
SGSoundSample::SGSoundSample( const char *path, const char *file ) :
|
||||||
buffer(0),
|
_absolute_pos(SGVec3d::zeros().data()),
|
||||||
source(0),
|
_relative_pos(SGVec3f::zeros().data()),
|
||||||
pitch(1.0),
|
_base_pos(SGVec3d::zeros().data()),
|
||||||
volume(1.0),
|
_direction(SGVec3f::zeros().data()),
|
||||||
reference_dist(500.0),
|
_velocity(SGVec3f::zeros().data()),
|
||||||
max_dist(3000.),
|
_format(AL_FORMAT_MONO8),
|
||||||
loop(AL_FALSE),
|
_size(0),
|
||||||
#ifdef USE_SOFTWARE_DOPPLER
|
_freq(0),
|
||||||
doppler_pitch_factor(1),
|
_valid_buffer(false),
|
||||||
doppler_volume_factor(1),
|
_buffer(SGSoundMgr::NO_BUFFER),
|
||||||
#endif
|
_valid_source(false),
|
||||||
playing(false),
|
_source(SGSoundMgr::NO_SOURCE),
|
||||||
no_Doppler_effect(_no_Doppler_effect)
|
_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 );
|
SGPath samplepath( path );
|
||||||
if ( strlen(file) ) {
|
if ( strlen(file) ) {
|
||||||
samplepath.append( 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() );
|
<< 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
|
// constructor
|
||||||
SGSoundSample::SGSoundSample( unsigned char *_data, int len, int _freq, bool _no_Doppler_effect ) :
|
SGSoundSample::SGSoundSample( unsigned char *data, int len, int freq, int format ) :
|
||||||
buffer(0),
|
_absolute_pos(SGVec3d::zeros().data()),
|
||||||
source(0),
|
_relative_pos(SGVec3f::zeros().data()),
|
||||||
pitch(1.0),
|
_base_pos(SGVec3d::zeros().data()),
|
||||||
volume(1.0),
|
_direction(SGVec3f::zeros().data()),
|
||||||
reference_dist(500.0),
|
_velocity(SGVec3f::zeros().data()),
|
||||||
max_dist(3000.),
|
_data(data),
|
||||||
loop(AL_FALSE),
|
_format(format),
|
||||||
#ifdef USE_SOFTWARE_DOPPLER
|
_size(len),
|
||||||
doppler_pitch_factor(1),
|
_freq(freq),
|
||||||
doppler_volume_factor(1),
|
_valid_buffer(false),
|
||||||
#endif
|
_buffer(SGSoundMgr::NO_BUFFER),
|
||||||
playing(false),
|
_valid_source(false),
|
||||||
no_Doppler_effect(_no_Doppler_effect)
|
_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" );
|
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
|
// destructor
|
||||||
SGSoundSample::~SGSoundSample() {
|
SGSoundSample::~SGSoundSample() {
|
||||||
SG_LOG( SG_GENERAL, SG_INFO, "Deleting a sample" );
|
#if 0
|
||||||
if (buffer)
|
if (_data != NULL) {
|
||||||
alDeleteBuffers(1, &buffer);
|
delete[] _data;
|
||||||
}
|
_data = NULL;
|
||||||
|
|
||||||
|
|
||||||
// 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)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void SGSoundSample::set_base_position( SGVec3d pos ) {
|
||||||
SGSoundSample::set_reference_dist( ALfloat dist ) {
|
_base_pos = pos;
|
||||||
reference_dist = dist;
|
update_absolute_position();
|
||||||
if (playing) {
|
_changed = true;
|
||||||
alSourcef( source, AL_REFERENCE_DISTANCE, reference_dist );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SGSoundSample::set_relative_position( SGVec3f pos ) {
|
||||||
void
|
_relative_pos = pos;
|
||||||
SGSoundSample::set_max_dist( ALfloat dist ) {
|
update_absolute_position();
|
||||||
max_dist = dist;
|
_changed = true;
|
||||||
if (playing) {
|
|
||||||
alSourcef( source, AL_MAX_DISTANCE, max_dist );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ALvoid *
|
void SGSoundSample::set_orientation( SGVec3f dir ) {
|
||||||
SGSoundSample::load_file(const char *path, const char *file)
|
_direction = dir;
|
||||||
{
|
update_absolute_position();
|
||||||
ALvoid* data = 0;
|
_changed = true;
|
||||||
|
|
||||||
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);
|
||||||
|
}
|
||||||
|
|||||||
+240
-79
@@ -32,37 +32,16 @@
|
|||||||
# error This library requires C++
|
# error This library requires C++
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
#include <simgear/structure/SGReferenced.hxx>
|
#include <simgear/structure/SGReferenced.hxx>
|
||||||
#include <simgear/structure/SGSharedPtr.hxx>
|
#include <simgear/structure/SGSharedPtr.hxx>
|
||||||
|
#include <simgear/math/SGMath.hxx>
|
||||||
|
|
||||||
#include <plib/sg.h>
|
#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;
|
using std::string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -73,45 +52,51 @@ class SGSoundSample : public SGReferenced {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
string sample_name;
|
|
||||||
|
|
||||||
// Buffers hold sound data.
|
|
||||||
ALuint buffer;
|
|
||||||
|
|
||||||
// Sources are points emitting sound.
|
|
||||||
ALuint source;
|
|
||||||
|
|
||||||
// Position of the source sound.
|
// Position of the source sound.
|
||||||
ALfloat source_pos[3];
|
SGVec3d _absolute_pos; // absolute position
|
||||||
|
SGVec3f _relative_pos; // position relative to the base position
|
||||||
// A constant offset to be applied to the final source_pos
|
SGVec3d _base_pos; // base position
|
||||||
ALfloat offset_pos[3];
|
|
||||||
|
|
||||||
// The orientation of the sound (direction and cut-off angles)
|
// The orientation of the sound (direction and cut-off angles)
|
||||||
ALfloat direction[3];
|
SGVec3f _direction;
|
||||||
ALfloat inner, outer, outergain;
|
|
||||||
|
|
||||||
// Velocity of the source sound.
|
// Velocity of the source sound.
|
||||||
ALfloat source_vel[3];
|
SGVec3f _velocity;
|
||||||
|
|
||||||
|
string _sample_name;
|
||||||
|
unsigned char *_data;
|
||||||
|
|
||||||
// configuration values
|
// configuration values
|
||||||
ALenum format;
|
int _format;
|
||||||
ALsizei size;
|
int _size;
|
||||||
ALsizei freq;
|
int _freq;
|
||||||
|
|
||||||
double pitch;
|
// Buffers hold sound data.
|
||||||
double volume;
|
bool _valid_buffer;
|
||||||
#ifdef USE_SOFTWARE_DOPPLER
|
unsigned int _buffer;
|
||||||
double doppler_pitch_factor;
|
|
||||||
double doppler_volume_factor;
|
|
||||||
#endif
|
|
||||||
double reference_dist;
|
|
||||||
double max_dist;
|
|
||||||
ALboolean loop;
|
|
||||||
|
|
||||||
bool playing;
|
// Sources are points emitting sound.
|
||||||
bool bind_source();
|
bool _valid_source;
|
||||||
bool no_Doppler_effect;
|
unsigned int _source;
|
||||||
|
|
||||||
|
// The orientation of the sound (direction and cut-off angles)
|
||||||
|
float _inner_angle;
|
||||||
|
float _outer_angle;
|
||||||
|
float _outer_gain;
|
||||||
|
|
||||||
|
float _pitch;
|
||||||
|
float _volume;
|
||||||
|
float _master_volume;
|
||||||
|
float _reference_dist;
|
||||||
|
float _max_dist;
|
||||||
|
bool _loop;
|
||||||
|
|
||||||
|
bool _playing;
|
||||||
|
bool _changed;
|
||||||
|
bool _static_changed;
|
||||||
|
bool _is_file;
|
||||||
|
|
||||||
|
void update_absolute_position();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -128,7 +113,7 @@ public:
|
|||||||
should usually be true unless you want to manipulate the data
|
should usually be true unless you want to manipulate the data
|
||||||
later.)
|
later.)
|
||||||
*/
|
*/
|
||||||
SGSoundSample( const char *path, const char *file, bool no_Doppler_effect = true );
|
SGSoundSample( const char *path, const char *file );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
@@ -139,23 +124,50 @@ public:
|
|||||||
should usually be true unless you want to manipulate the data
|
should usually be true unless you want to manipulate the data
|
||||||
later.)
|
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.
|
* Start playing this sample.
|
||||||
*
|
*
|
||||||
* @param _loop Define whether the sound should be played in a loop.
|
* @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.
|
* Stop playing this sample.
|
||||||
*
|
*
|
||||||
* @param sched A pointer to the appropriate scheduler.
|
* @param sched A pointer to the appropriate scheduler.
|
||||||
*/
|
*/
|
||||||
void stop();
|
inline void stop() {
|
||||||
|
_playing = false; _changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Play this sample once.
|
* Play this sample once.
|
||||||
@@ -173,77 +185,226 @@ public:
|
|||||||
* Test if a sample is currently playing.
|
* Test if a sample is currently playing.
|
||||||
* @return true if is is playing, false otherwise.
|
* @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.
|
* 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.
|
* 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.
|
* 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.
|
* 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
|
* Returns the size of the sounds sample
|
||||||
*/
|
*/
|
||||||
inline int get_size() {
|
inline void set_size( int size ) {
|
||||||
return 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
|
* Set position of the sound source (uses same coordinate system as opengl)
|
||||||
* 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
|
* Set the orientation of the sound source, both for direction
|
||||||
* and audio cut-off angles.
|
* and audio cut-off angles.
|
||||||
*/
|
*/
|
||||||
void set_orientation( ALfloat *dir, ALfloat inner_angle=360.0,
|
void set_orientation( SGVec3f dir );
|
||||||
ALfloat outer_angle=360.0,
|
|
||||||
ALfloat outer_gain=0.0);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set velocity of sound source (uses same coordinate system as opengl)
|
* Define the audio cone parameters for directional audio
|
||||||
*/
|
*/
|
||||||
void set_source_vel( ALfloat *vel, ALfloat *listener_vel );
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get velocity of the sound source (uses same coordinate system as opengl)
|
||||||
|
*/
|
||||||
|
inline float *get_velocity() { return _velocity.data(); }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set reference distance of sound (the distance where the gain
|
* Set reference distance of sound (the distance where the gain
|
||||||
* will be half.)
|
* 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
|
* Set maximum distance of sound (the distance where the sound is
|
||||||
* no longer audible.
|
* no longer audible.
|
||||||
*/
|
*/
|
||||||
void set_max_dist( ALfloat dist );
|
void set_max_dist( float dist ) {
|
||||||
|
_max_dist = dist; _static_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load a sound file into a memory buffer only.
|
* Get maximum istance of sound (the distance where the sound is
|
||||||
|
* no longer audible.
|
||||||
*/
|
*/
|
||||||
ALvoid* load_file(const char *path, const char *file);
|
inline float get_max_dist() { return _max_dist; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of this sample
|
||||||
|
*/
|
||||||
|
inline string get_sample_name() { return _sample_name; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+343
-234
@@ -18,8 +18,8 @@
|
|||||||
// General Public License for more details.
|
// General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program; if not, write to the Free Software
|
// along with this program; if not, write to the Free Software Foundation,
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
//
|
//
|
||||||
// $Id$
|
// $Id$
|
||||||
|
|
||||||
@@ -27,173 +27,192 @@
|
|||||||
# include <simgear_config.h>
|
# include <simgear_config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#if defined( __APPLE__ )
|
||||||
|
# include <OpenAL/alut.h>
|
||||||
#if defined(__APPLE__)
|
|
||||||
# include <OpenAL/al.h>
|
|
||||||
# include <OpenAL/alc.h>
|
|
||||||
#else
|
#else
|
||||||
# include <AL/al.h>
|
# include <AL/alut.h>
|
||||||
# include <AL/alc.h>
|
|
||||||
#endif
|
#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
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined (__CYGWIN__)
|
|
||||||
#include <ieeefp.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
|
||||||
#include <simgear/misc/sg_path.hxx>
|
|
||||||
|
|
||||||
#include "soundmgr_openal.hxx"
|
#include "soundmgr_openal.hxx"
|
||||||
|
|
||||||
#if defined(__MINGW32__)
|
#include <simgear/structure/exception.hxx>
|
||||||
#define isnan(x) _isnan(x)
|
#include <simgear/debug/logstream.hxx>
|
||||||
#endif
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
#include <simgear/math/SGMath.hxx>
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_SOURCES 128
|
||||||
|
|
||||||
//
|
//
|
||||||
// Sound Manager
|
// Sound Manager
|
||||||
//
|
//
|
||||||
|
|
||||||
|
int SGSoundMgr::_alut_init = 0;
|
||||||
|
|
||||||
// constructor
|
// constructor
|
||||||
SGSoundMgr::SGSoundMgr() {
|
SGSoundMgr::SGSoundMgr() :
|
||||||
|
_working(false),
|
||||||
SG_LOG( SG_GENERAL, SG_INFO, "Initializing OpenAL sound manager" );
|
_changed(true),
|
||||||
|
_volume(0.5),
|
||||||
// initialize OpenAL
|
_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 defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
|
||||||
if (!alutInit(NULL, NULL))
|
if (_alut_init == 0) {
|
||||||
{
|
if ( !alutInitWithoutContext(NULL, NULL) ) {
|
||||||
ALenum error = alutGetError ();
|
testForALUTError("alut initialization");
|
||||||
SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" );
|
return;
|
||||||
SG_LOG( SG_GENERAL, SG_ALERT, " "+string(alutGetErrorString(error)));
|
}
|
||||||
working = false;
|
_alut_init++;
|
||||||
context = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
working = true;
|
|
||||||
context = alcGetCurrentContext();
|
|
||||||
}
|
|
||||||
#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!" );
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
_alut_init++;
|
||||||
#endif
|
#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!" );
|
|
||||||
}
|
|
||||||
|
|
||||||
// exaggerate the ear candy?
|
|
||||||
alDopplerFactor(1.0);
|
|
||||||
alDopplerVelocity(340.0); // speed of sound in meters per second.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// destructor
|
// destructor
|
||||||
|
|
||||||
SGSoundMgr::~SGSoundMgr() {
|
SGSoundMgr::~SGSoundMgr() {
|
||||||
|
stop();
|
||||||
#if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
|
#if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
|
||||||
alutExit ();
|
_alut_init--;
|
||||||
#else
|
if (_alut_init == 0) {
|
||||||
if (context)
|
alutExit ();
|
||||||
alcDestroyContext( context );
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// initialize the sound manager
|
// initialize the sound manager
|
||||||
void SGSoundMgr::init() {
|
void SGSoundMgr::init() {
|
||||||
//
|
|
||||||
// Remove the samples from the sample manager.
|
SG_LOG( SG_GENERAL, SG_INFO, "Initializing OpenAL sound manager" );
|
||||||
//
|
|
||||||
samples.clear();
|
ALCdevice *device = alcOpenDevice(_devname);
|
||||||
|
if ( testForError(device, "No default audio device available.") ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALCcontext *context = alcCreateContext(device, NULL);
|
||||||
|
if ( testForError(context, "Unable to create a valid context.") ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !alcMakeContextCurrent(context) ) {
|
||||||
|
testForALCError("context initialization");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_context = context;
|
||||||
|
_working = true;
|
||||||
|
|
||||||
|
_listener_ori[0] = 0.0; _listener_ori[1] = 0.0; _listener_ori[2] = -1.0;
|
||||||
|
_listener_ori[3] = 0.0; _listener_ori[4] = 1.0; _listener_ori[5] = 0.0;
|
||||||
|
|
||||||
|
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.3); // speed of sound in meters per second.
|
||||||
|
|
||||||
|
if ( alIsExtensionPresent((const ALchar*)"EXT_exponent_distance") ) {
|
||||||
|
alDistanceModel(AL_EXPONENT_DISTANCE);
|
||||||
|
} else {
|
||||||
|
alDistanceModel(AL_INVERSE_DISTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
testForALError("listener initialization");
|
||||||
|
|
||||||
|
alGetError(); // clear any undetetced error, just to be sure
|
||||||
|
|
||||||
|
// get a free source one at a time
|
||||||
|
// if an error is returned no more (hardware) sources are available
|
||||||
|
for (unsigned int i=0; i<MAX_SOURCES; i++) {
|
||||||
|
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;
|
||||||
|
|
||||||
|
_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 ()
|
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 ()
|
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
|
// run the audio scheduler
|
||||||
void SGSoundMgr::update( double dt ) {
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_changed) {
|
||||||
void
|
alListenerf( AL_GAIN, _volume );
|
||||||
SGSoundMgr::pause ()
|
alListenerfv( AL_VELOCITY, _listener_vel.data() );
|
||||||
{
|
alListenerfv( AL_ORIENTATION, _listener_ori );
|
||||||
if (context) {
|
alListenerfv( AL_POSITION, toVec3f(_listener_pos).data() );
|
||||||
alcSuspendContext( context );
|
// alDopplerVelocity(340.3); // TODO: altitude dependent
|
||||||
if ( alGetError() != AL_NO_ERROR) {
|
testForALError("update");
|
||||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
_changed = false;
|
||||||
"Oops AL error after soundmgr pause()!" );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,151 +221,241 @@ SGSoundMgr::pause ()
|
|||||||
void
|
void
|
||||||
SGSoundMgr::resume ()
|
SGSoundMgr::resume ()
|
||||||
{
|
{
|
||||||
if (context) {
|
if (_working) {
|
||||||
alcProcessContext( context );
|
sample_group_map_iterator sample_grp_current = _sample_groups.begin();
|
||||||
if ( alGetError() != AL_NO_ERROR) {
|
sample_group_map_iterator sample_grp_end = _sample_groups.end();
|
||||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) {
|
||||||
"Oops AL error after soundmgr resume()!" );
|
SGSampleGroup *sgrp = sample_grp_current->second;
|
||||||
|
sgrp->resume();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// add a sound effect, return true if successful
|
// add a sampel group, return true if successful
|
||||||
bool SGSoundMgr::add( SGSoundSample *sound, const string& refname ) {
|
bool SGSoundMgr::add( SGSampleGroup *sgrp, const string& refname )
|
||||||
|
{
|
||||||
sample_map_iterator sample_it = samples.find( refname );
|
sample_group_map_iterator sample_grp_it = _sample_groups.find( refname );
|
||||||
if ( sample_it != samples.end() ) {
|
if ( sample_grp_it != _sample_groups.end() ) {
|
||||||
// sound already exists
|
// sample group already exists
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
samples[refname] = sound;
|
_sample_groups[refname] = sgrp;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// remove a sound effect, return true if successful
|
// remove a sound effect, return true if successful
|
||||||
bool SGSoundMgr::remove( const string &refname ) {
|
bool SGSoundMgr::remove( const string &refname )
|
||||||
|
{
|
||||||
sample_map_iterator sample_it = samples.find( refname );
|
sample_group_map_iterator sample_grp_it = _sample_groups.find( refname );
|
||||||
if ( sample_it != samples.end() ) {
|
if ( sample_grp_it == _sample_groups.end() ) {
|
||||||
// first stop the sound from playing (so we don't bomb the
|
// sample group was not found.
|
||||||
// audio scheduler)
|
|
||||||
samples.erase( sample_it );
|
|
||||||
|
|
||||||
// cout << "sndmgr: removed -> " << refname << endl;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
// cout << "sndmgr: failed remove -> " << refname << endl;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_sample_groups.erase( refname );
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// return true of the specified sound exists in the sound manager system
|
// return true of the specified sound exists in the sound manager system
|
||||||
bool SGSoundMgr::exists( const string &refname ) {
|
bool SGSoundMgr::exists( const string &refname ) {
|
||||||
sample_map_iterator sample_it = samples.find( refname );
|
sample_group_map_iterator sample_grp_it = _sample_groups.find( refname );
|
||||||
if ( sample_it != samples.end() ) {
|
if ( sample_grp_it == _sample_groups.end() ) {
|
||||||
return true;
|
// sample group was not found.
|
||||||
} else {
|
|
||||||
return false;
|
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
|
// in the sound manager system, otherwise return NULL
|
||||||
SGSoundSample *SGSoundMgr::find( const string &refname ) {
|
SGSampleGroup *SGSoundMgr::find( const string &refname, bool create ) {
|
||||||
sample_map_iterator sample_it = samples.find( refname );
|
sample_group_map_iterator sample_grp_it = _sample_groups.find( refname );
|
||||||
if ( sample_it != samples.end() ) {
|
if ( sample_grp_it == _sample_groups.end() ) {
|
||||||
return sample_it->second;
|
// sample group was not found.
|
||||||
} else {
|
if (create) {
|
||||||
return NULL;
|
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
|
void SGSoundMgr::set_volume( float v )
|
||||||
// loop
|
{
|
||||||
bool SGSoundMgr::play_looped( const string &refname ) {
|
_volume = v;
|
||||||
SGSoundSample *sample;
|
if (_volume > 1.0) _volume = 1.0;
|
||||||
|
if (_volume < 0.0) _volume = 0.0;
|
||||||
|
_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
if ( (sample = find( refname )) == NULL ) {
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free up a source id for further use
|
||||||
|
void SGSoundMgr::release_source( unsigned int source )
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i<_sources_in_use.size(); i++) {
|
||||||
|
if ( _sources_in_use[i] == source ) {
|
||||||
|
ALint result;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
#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;
|
return false;
|
||||||
} else {
|
}
|
||||||
sample->play( true );
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
*dbuf = (void *)data;
|
||||||
|
*fmt = (int)format;
|
||||||
|
*sz = (unsigned int)size;
|
||||||
|
*frq = (int)freq;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the orientation of the listener (in opengl coordinates)
|
||||||
|
*
|
||||||
|
* Description: ORIENTATION is a pair of 3-tuples representing the
|
||||||
|
* 'at' direction vector and 'up' direction of the Object in
|
||||||
|
* Cartesian space. AL expects two vectors that are orthogonal to
|
||||||
|
* each other. These vectors are not expected to be normalized. If
|
||||||
|
* one or more vectors have zero length, implementation behavior
|
||||||
|
* is undefined. If the two vectors are linearly dependent,
|
||||||
|
* behavior is undefined.
|
||||||
|
*/
|
||||||
|
void SGSoundMgr::set_orientation( SGQuatd ori )
|
||||||
|
{
|
||||||
|
SGVec3d sgv_up = ori.rotate(SGVec3d::e2());
|
||||||
|
SGVec3d sgv_at = ori.rotate(SGVec3d::e3());
|
||||||
|
for (int i=0; i<3; i++) {
|
||||||
|
_listener_ori[i] = sgv_at[i];
|
||||||
|
_listener_ori[i+3] = sgv_up[i];
|
||||||
|
}
|
||||||
|
_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SGSoundMgr::testForError(void *p, string s)
|
||||||
|
{
|
||||||
|
if (p == NULL) {
|
||||||
|
SG_LOG( SG_GENERAL, SG_ALERT, "Error: " << s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SGSoundMgr::testForALUTError(string s)
|
||||||
// tell the scheduler to play the indexed sample once
|
{
|
||||||
bool SGSoundMgr::play_once( const string& refname ) {
|
ALenum error;
|
||||||
SGSoundSample *sample;
|
error = alutGetError ();
|
||||||
|
if (error != ALUT_ERROR_NO_ERROR) {
|
||||||
if ( (sample = find( refname )) == NULL ) {
|
SG_LOG( SG_GENERAL, SG_ALERT, "ALUT Error (sound manager): "
|
||||||
return false;
|
<< alutGetErrorString(error) << " at "
|
||||||
} else {
|
<< s);
|
||||||
sample->play( false );
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
return false;
|
||||||
|
|
||||||
|
|
||||||
// return true of the specified sound is currently being played
|
|
||||||
bool SGSoundMgr::is_playing( const string& refname ) {
|
|
||||||
SGSoundSample *sample;
|
|
||||||
|
|
||||||
if ( (sample = find( refname )) == NULL ) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return ( sample->is_playing() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// immediate stop playing the sound
|
|
||||||
bool SGSoundMgr::stop( const string& refname ) {
|
|
||||||
SGSoundSample *sample;
|
|
||||||
|
|
||||||
if ( (sample = find( refname )) == NULL ) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
sample->stop();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,113 +37,68 @@
|
|||||||
# error This library requires C++
|
# error This library requires C++
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
#include <map>
|
#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/al.h>
|
||||||
# include <OpenAL/alc.h>
|
# include <OpenAL/alut.h>
|
||||||
#else
|
#else
|
||||||
# include <AL/al.h>
|
# include <AL/al.h>
|
||||||
# include <AL/alc.h>
|
# include <AL/alut.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
#include <simgear/structure/subsystem_mgr.hxx>
|
||||||
|
#include <simgear/math/SGMathFwd.hxx>
|
||||||
|
|
||||||
|
#include "sample_group.hxx"
|
||||||
#include "sample_openal.hxx"
|
#include "sample_openal.hxx"
|
||||||
|
|
||||||
using std::map;
|
using std::map;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
|
typedef map < string, SGSharedPtr<SGSampleGroup> > sample_group_map;
|
||||||
typedef map < string, SGSharedPtr<SGSoundSample> > sample_map;
|
typedef sample_group_map::iterator sample_group_map_iterator;
|
||||||
typedef sample_map::iterator sample_map_iterator;
|
typedef sample_group_map::const_iterator const_sample_group_map_iterator;
|
||||||
typedef sample_map::const_iterator const_sample_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:
|
public:
|
||||||
|
|
||||||
SGSoundMgr();
|
SGSoundMgr();
|
||||||
~SGSoundMgr();
|
~SGSoundMgr();
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* (re) initialize the sound manager.
|
|
||||||
*/
|
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bind properties for the sound manager.
|
|
||||||
*/
|
|
||||||
void bind();
|
void bind();
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unbind properties for the sound manager.
|
|
||||||
*/
|
|
||||||
void unbind();
|
void unbind();
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run the audio scheduler.
|
|
||||||
*/
|
|
||||||
void update(double dt);
|
void update(double dt);
|
||||||
|
|
||||||
|
void suspend();
|
||||||
/**
|
|
||||||
* Pause all sounds.
|
|
||||||
*/
|
|
||||||
void pause();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resume all sounds.
|
|
||||||
*/
|
|
||||||
void resume();
|
void resume();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
inline void reinit() { stop(); init(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* is audio working?
|
* 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(); }
|
bool add( SGSampleGroup *sgrp, const string& refname );
|
||||||
|
|
||||||
/**
|
|
||||||
* add a sound effect, return true if successful
|
|
||||||
*/
|
|
||||||
bool add( SGSoundSample *sound, const string& refname);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* remove a sound effect, return true if successful
|
* remove a sample group, return true if successful
|
||||||
*/
|
*/
|
||||||
bool remove( const string& refname );
|
bool remove( const string& refname );
|
||||||
|
|
||||||
@@ -153,94 +108,91 @@ public:
|
|||||||
bool exists( const string& refname );
|
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
|
* exists in the sound manager system, otherwise return NULL
|
||||||
*/
|
*/
|
||||||
SGSoundSample *find( const string& refname );
|
SGSampleGroup *find( const string& refname, bool create = false );
|
||||||
|
|
||||||
/**
|
|
||||||
* tell the scheduler to play the indexed sample in a continuous
|
|
||||||
* loop
|
|
||||||
*/
|
|
||||||
bool play_looped( const string& refname );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
inline void set_volume( const ALfloat vol ) {
|
|
||||||
if ( vol > 0.0 ) {
|
|
||||||
alListenerf( AL_GAIN, vol );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set the position of the listener (in opengl coordinates)
|
* set the position of the listener (in opengl coordinates)
|
||||||
*/
|
*/
|
||||||
inline void set_listener_pos( ALfloat *pos ) {
|
inline void set_position( SGVec3d pos ) {
|
||||||
listener_pos[0] = pos[0];
|
_listener_pos = pos;
|
||||||
listener_pos[1] = pos[1];
|
_changed = true;
|
||||||
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)
|
* set the velocity of the listener (in opengl coordinates)
|
||||||
*/
|
*/
|
||||||
inline void set_listener_vel( ALfloat *vel ) {
|
inline void set_velocity( SGVec3f vel ) {
|
||||||
listener_vel[0] = vel[0];
|
_listener_vel = vel;
|
||||||
listener_vel[1] = vel[1];
|
_changed = true;
|
||||||
listener_vel[2] = vel[2];
|
|
||||||
#ifdef USE_OPEN_AL_DOPPLER
|
|
||||||
alListenerfv( AL_VELOCITY, listener_vel );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set the orientation of the listener (in opengl coordinates)
|
* 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 ) {
|
void set_orientation( SGQuatd ori );
|
||||||
listener_ori[0] = ori[0];
|
|
||||||
listener_ori[1] = ori[1];
|
enum {
|
||||||
listener_ori[2] = ori[2];
|
NO_SOURCE = (unsigned int)-1,
|
||||||
listener_ori[3] = ori[3];
|
NO_BUFFER = (unsigned int)-1
|
||||||
listener_ori[4] = ori[4];
|
};
|
||||||
listener_ori[5] = ori[5];
|
|
||||||
alListenerfv( AL_ORIENTATION, listener_ori );
|
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 );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+14
-23
@@ -50,14 +50,11 @@ static const struct {
|
|||||||
const char *name;
|
const char *name;
|
||||||
double (*fn)(double);
|
double (*fn)(double);
|
||||||
} __sound_fn[] = {
|
} __sound_fn[] = {
|
||||||
// {"lin", _snd_lin},
|
|
||||||
{"inv", _snd_inv},
|
{"inv", _snd_inv},
|
||||||
{"abs", _snd_abs},
|
{"abs", _snd_abs},
|
||||||
{"sqrt", _snd_sqrt},
|
{"sqrt", _snd_sqrt},
|
||||||
{"log", _snd_log10},
|
{"log", _snd_log10},
|
||||||
{"ln", _snd_log},
|
{"ln", _snd_log},
|
||||||
// {"sqr", _snd_sqr},
|
|
||||||
// {"pow3", _snd_pow3},
|
|
||||||
{"", NULL}
|
{"", NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -84,18 +81,14 @@ SGXmlSound::~SGXmlSound()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SGXmlSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr,
|
SGXmlSound::init(SGPropertyNode *root, SGPropertyNode *node,
|
||||||
const string &path)
|
SGSampleGroup *sgrp, const string &path)
|
||||||
{
|
{
|
||||||
|
|
||||||
//
|
//
|
||||||
// set global sound properties
|
// set global sound properties
|
||||||
//
|
//
|
||||||
|
|
||||||
if (sndmgr->is_working() == false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_name = node->getStringValue("name", "");
|
_name = node->getStringValue("name", "");
|
||||||
SG_LOG(SG_GENERAL, SG_DEBUG, "Loading sound information for: " << _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
|
// Relative position
|
||||||
//
|
//
|
||||||
sgVec3 offset_pos;
|
SGVec3f offset_pos = SGVec3f::zeros();
|
||||||
sgSetVec3( offset_pos, 0.0, 0.0, 0.0 );
|
|
||||||
SGPropertyNode_ptr pos = node->getChild("position");
|
SGPropertyNode_ptr pos = node->getChild("position");
|
||||||
if ( pos != NULL ) {
|
if ( pos != NULL ) {
|
||||||
offset_pos[0] = pos->getDoubleValue("x", 0.0);
|
offset_pos[0] = pos->getDoubleValue("x", 0.0);
|
||||||
@@ -248,9 +240,8 @@ SGXmlSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr,
|
|||||||
//
|
//
|
||||||
// Orientation
|
// Orientation
|
||||||
//
|
//
|
||||||
sgVec3 dir;
|
SGVec3f dir = SGVec3f::zeros();
|
||||||
float inner, outer, outer_gain;
|
float inner, outer, outer_gain;
|
||||||
sgSetVec3( dir, 0.0, 0.0, 0.0 );
|
|
||||||
inner = outer = 360.0;
|
inner = outer = 360.0;
|
||||||
outer_gain = 0.0;
|
outer_gain = 0.0;
|
||||||
pos = node->getChild("orientation");
|
pos = node->getChild("orientation");
|
||||||
@@ -266,8 +257,8 @@ SGXmlSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr,
|
|||||||
//
|
//
|
||||||
// Initialize the sample
|
// Initialize the sample
|
||||||
//
|
//
|
||||||
_mgr = sndmgr;
|
_sgrp = sgrp;
|
||||||
if ( (_sample = _mgr->find(_name)) == NULL ) {
|
if ( (_sample = _sgrp->find(_name)) == NULL ) {
|
||||||
// FIXME: Does it make sense to overwrite a previous entry's
|
// FIXME: Does it make sense to overwrite a previous entry's
|
||||||
// configuration just because a new entry has the same name?
|
// configuration just because a new entry has the same name?
|
||||||
// Note that we can't match on identical "path" because we the
|
// 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
|
// "alSource". The semantics of what is going on here seems
|
||||||
// confused and needs to be thought through more carefully.
|
// confused and needs to be thought through more carefully.
|
||||||
_sample = new SGSoundSample( path.c_str(),
|
_sample = new SGSoundSample( path.c_str(),
|
||||||
node->getStringValue("path", ""),
|
node->getStringValue("path", "") );
|
||||||
false );
|
_sgrp->add( _sample, _name );
|
||||||
|
|
||||||
_mgr->add( _sample, _name );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_sample->set_offset_pos( offset_pos );
|
_sample->set_relative_position( offset_pos );
|
||||||
_sample->set_orientation(dir, inner, outer, outer_gain);
|
_sample->set_orientation( dir );
|
||||||
_sample->set_volume(v);
|
_sample->set_audio_cone(inner, outer, outer_gain);
|
||||||
_sample->set_reference_dist( reference_dist );
|
_sample->set_reference_dist( reference_dist );
|
||||||
_sample->set_max_dist( max_dist );
|
_sample->set_max_dist( max_dist );
|
||||||
|
_sample->set_volume(v);
|
||||||
_sample->set_pitch(p);
|
_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()) {
|
if (_sample->is_playing()) {
|
||||||
SG_LOG(SG_GENERAL, SG_DEBUG, "Stopping audio after " << _dt_play
|
SG_LOG(SG_GENERAL, SG_DEBUG, "Stopping audio after " << _dt_play
|
||||||
<< " sec: " << _name );
|
<< " sec: " << _name );
|
||||||
|
|||||||
@@ -38,8 +38,8 @@
|
|||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
#include <simgear/props/condition.hxx>
|
#include <simgear/props/condition.hxx>
|
||||||
|
|
||||||
|
#include "sample_group.hxx"
|
||||||
#include "sample_openal.hxx"
|
#include "sample_openal.hxx"
|
||||||
#include "soundmgr_openal.hxx"
|
|
||||||
|
|
||||||
static const double MAX_TRANSIT_TIME = 0.1; // 100 ms.
|
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 root The root node of the programs property tree.
|
||||||
* @param child A pointer to the location of the current event as defined
|
* @param child A pointer to the location of the current event as defined
|
||||||
* in the configuration file.
|
* 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.
|
* @param path The path where the audio files remain.
|
||||||
*/
|
*/
|
||||||
virtual void init (SGPropertyNode *, SGPropertyNode *, SGSoundMgr *,
|
virtual void init (SGPropertyNode *, SGPropertyNode *, SGSampleGroup *,
|
||||||
const string &);
|
const string &);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -135,7 +135,7 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
SGSoundMgr * _mgr;
|
SGSampleGroup * _sgrp;
|
||||||
SGSharedPtr<SGSoundSample> _sample;
|
SGSharedPtr<SGSoundSample> _sample;
|
||||||
|
|
||||||
SGSharedPtr<SGCondition> _condition;
|
SGSharedPtr<SGCondition> _condition;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
#include "SGAtomic.hxx"
|
#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.
|
// Usually the apropriate functions are inlined by gcc.
|
||||||
// But if gcc is called with something aequivalent to -march=i386,
|
// But if gcc is called with something aequivalent to -march=i386,
|
||||||
|
|||||||
Reference in New Issue
Block a user