Erik Hofman

1. Remove the dependency on alut  which (on certein platforms) might pose
   some restrictuons on commercial use.

2. Create a sound source just prior to playing the sound and destroy it
   again when the sound has stopped. This should greatly reduce the
   error reports from Windows users.
This commit is contained in:
ehofman
2005-01-24 15:51:37 +00:00
parent 1e87dd7903
commit f6314d3124
4 changed files with 211 additions and 146 deletions
+186 -62
View File
@@ -43,20 +43,24 @@
// //
static void print_openal_error( ALuint error ) { static bool print_openal_error(const string &s = "unknown") {
if ( error == AL_INVALID_NAME ) { ALuint error = alGetError();
SG_LOG( SG_GENERAL, SG_ALERT, "AL_INVALID_NAME" ); 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 ) { } else if ( error == AL_ILLEGAL_ENUM ) {
SG_LOG( SG_GENERAL, SG_ALERT, "AL_ILLEGAL_ENUM" ); SG_LOG( SG_GENERAL, SG_ALERT, "OpenAL error (AL_ILLEGAL_ENUM): " << s );
} else if ( error == AL_INVALID_VALUE ) { } else if ( error == AL_INVALID_VALUE ) {
SG_LOG( SG_GENERAL, SG_ALERT, "AL_INVALID_VALUE" ); SG_LOG( SG_GENERAL, SG_ALERT, "OpenAL error (AL_INVALID_VALUE): " << s );
} else if ( error == AL_ILLEGAL_COMMAND ) { } else if ( error == AL_ILLEGAL_COMMAND ) {
SG_LOG( SG_GENERAL, SG_ALERT, "AL_ILLEGAL_COMMAND" ); SG_LOG( SG_GENERAL, SG_ALERT, "OpenAL error (AL_ILLEGAL_COMMAND): " << s );
} else if ( error == AL_OUT_OF_MEMORY ) { } else if ( error == AL_OUT_OF_MEMORY ) {
SG_LOG( SG_GENERAL, SG_ALERT, "AL_OUT_OF_MEMORY" ); SG_LOG( SG_GENERAL, SG_ALERT, "OpenAL error (AL_OUT_OF_MEMORY): " << s );
} else { } else {
SG_LOG( SG_GENERAL, SG_ALERT, "Unhandled error code = " << error ); SG_LOG( SG_GENERAL, SG_ALERT, "Unhandled error code = " << error );
} }
return error;
} }
@@ -64,11 +68,14 @@ static void print_openal_error( ALuint error ) {
SGSoundSample::SGSoundSample( const char *path, const char *file, SGSoundSample::SGSoundSample( const char *path, const char *file,
bool cleanup ) : bool cleanup ) :
data(NULL), data(NULL),
buffer(0),
source(0),
pitch(1.0), pitch(1.0),
volume(1.0), volume(1.0),
reference_dist(500.0), reference_dist(500.0),
max_dist(3000.), max_dist(3000.),
loop(AL_FALSE) loop(AL_FALSE),
playing(false)
{ {
SGPath samplepath( path ); SGPath samplepath( path );
if ( strlen(file) ) { if ( strlen(file) ) {
@@ -91,9 +98,7 @@ SGSoundSample::SGSoundSample( const char *path, const char *file,
// create an OpenAL buffer handle // create an OpenAL buffer handle
alGenBuffers(1, &buffer); alGenBuffers(1, &buffer);
ALuint error = alGetError(); if ( print_openal_error("constructor (alGenBuffers)") ) {
if ( error != AL_NO_ERROR ) {
print_openal_error( error );
throw sg_exception("Failed to gen OpenAL buffer."); throw sg_exception("Failed to gen OpenAL buffer.");
} }
@@ -105,13 +110,13 @@ SGSoundSample::SGSoundSample( const char *path, const char *file,
alutLoadWAVFile( (ALbyte *)samplepath.c_str(), alutLoadWAVFile( (ALbyte *)samplepath.c_str(),
&format, &data, &size, &freq, &loop ); &format, &data, &size, &freq, &loop );
#endif #endif
if (alGetError() != AL_NO_ERROR) { if ( print_openal_error("constructor (alutLoadWAVFile)") ) {
throw sg_exception("Failed to load wav file."); throw sg_exception("Failed to load wav file.");
} }
// Copy data to the internal OpenAL buffer // Copy data to the internal OpenAL buffer
alBufferData( buffer, format, data, size, freq ); alBufferData( buffer, format, data, size, freq );
if (alGetError() != AL_NO_ERROR) { if ( print_openal_error("constructor (alBufferData)") ) {
throw sg_exception("Failed to buffer data."); throw sg_exception("Failed to buffer data.");
} }
@@ -120,26 +125,7 @@ SGSoundSample::SGSoundSample( const char *path, const char *file,
data = NULL; data = NULL;
} }
// Bind buffer with a source. print_openal_error("constructor return");
alGenSources(1, &source);
if (alGetError() != AL_NO_ERROR) {
throw sg_exception("Failed to gen source.\nPlease update your sound driver and try again.");
}
alSourcei( source, AL_BUFFER, buffer );
alSourcef( source, AL_PITCH, pitch );
alSourcef( source, AL_GAIN, volume );
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);
alSourcefv( source, AL_VELOCITY, source_vel );
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 );
} }
@@ -147,11 +133,14 @@ SGSoundSample::SGSoundSample( const char *path, const char *file,
SGSoundSample::SGSoundSample( unsigned char *_data, int len, int _freq, SGSoundSample::SGSoundSample( unsigned char *_data, int len, int _freq,
bool cleanup) : bool cleanup) :
data(NULL), data(NULL),
buffer(0),
source(0),
pitch(1.0), pitch(1.0),
volume(1.0), volume(1.0),
reference_dist(500.0), reference_dist(500.0),
max_dist(3000.), max_dist(3000.),
loop(AL_FALSE) loop(AL_FALSE),
playing(false)
{ {
SG_LOG( SG_GENERAL, SG_DEBUG, "In memory sounds sample" ); SG_LOG( SG_GENERAL, SG_DEBUG, "In memory sounds sample" );
@@ -168,11 +157,8 @@ SGSoundSample::SGSoundSample( unsigned char *_data, int len, int _freq,
// Load wav data into a buffer. // Load wav data into a buffer.
alGenBuffers(1, &buffer); alGenBuffers(1, &buffer);
ALuint error = alGetError(); if ( print_openal_error("constructor (alGenBuffers)") ) {
if ( error != AL_NO_ERROR ) {
print_openal_error( error );
throw sg_exception("Failed to gen buffer." ); throw sg_exception("Failed to gen buffer." );
return;
} }
format = AL_FORMAT_MONO8; format = AL_FORMAT_MONO8;
@@ -181,7 +167,7 @@ SGSoundSample::SGSoundSample( unsigned char *_data, int len, int _freq,
freq = _freq; freq = _freq;
alBufferData( buffer, format, data, size, freq ); alBufferData( buffer, format, data, size, freq );
if (alGetError() != AL_NO_ERROR) { if ( print_openal_error("constructor (alBufferData)") ) {
throw sg_exception("Failed to buffer data."); throw sg_exception("Failed to buffer data.");
} }
@@ -190,10 +176,63 @@ SGSoundSample::SGSoundSample( unsigned char *_data, int len, int _freq,
data = NULL; data = NULL;
} }
print_openal_error("constructor return");
}
// destructor
SGSoundSample::~SGSoundSample() {
SG_LOG( SG_GENERAL, SG_INFO, "Deleting a sample" );
alDeleteBuffers(1, &buffer);
}
// play the sample
void SGSoundSample::play( bool _loop ) {
if ( source ) {
alSourceStop( source );
}
playing = bind_source();
if ( playing ) {
loop = _loop;
alSourcei( source, AL_LOOPING, loop );
alSourcePlay( source );
print_openal_error("play (alSourcePlay)");
}
}
// 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;
}
// Bind buffer with a source. // Bind buffer with a source.
alGetError();
alGenSources(1, &source); alGenSources(1, &source);
if (alGetError() != AL_NO_ERROR) { if ( print_openal_error("bind_source (alGenSources)") ) {
throw sg_exception("Failed to gen source.\nPlease update your sound driver and try again."); // 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 ); alSourcei( source, AL_BUFFER, buffer );
@@ -203,37 +242,122 @@ SGSoundSample::SGSoundSample( unsigned char *_data, int len, int _freq,
alSourcefv( source, AL_DIRECTION, direction ); alSourcefv( source, AL_DIRECTION, direction );
alSourcef( source, AL_CONE_INNER_ANGLE, inner ); alSourcef( source, AL_CONE_INNER_ANGLE, inner );
alSourcef( source, AL_CONE_OUTER_ANGLE, outer ); alSourcef( source, AL_CONE_OUTER_ANGLE, outer );
alSourcef( source, AL_CONE_OUTER_GAIN, outergain ); alSourcef( source, AL_CONE_OUTER_GAIN, outergain);
alSourcefv( source, AL_VELOCITY, source_vel ); alSourcefv( source, AL_VELOCITY, source_vel );
alSourcei( source, AL_LOOPING, loop ); alSourcei( source, AL_LOOPING, loop );
alSourcei( source, AL_SOURCE_RELATIVE, AL_TRUE ); alSourcei( source, AL_SOURCE_RELATIVE, AL_TRUE );
alSourcef( source, AL_REFERENCE_DISTANCE, reference_dist ); alSourcef( source, AL_REFERENCE_DISTANCE, reference_dist );
alSourcef( source, AL_MAX_DISTANCE, max_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) {
alSourcef( source, AL_PITCH, pitch );
print_openal_error("set_pitch");
}
}
void
SGSoundSample::set_volume( double v ) {
volume = v;
if (playing) {
alSourcef( source, AL_GAIN, volume );
print_openal_error("set_volume");
}
} }
// destructor bool
SGSoundSample::~SGSoundSample() { SGSoundSample::is_playing( ) {
SG_LOG( SG_GENERAL, SG_INFO, "Deleting a sample" ); if (playing) {
alDeleteSources(1, &source); ALint result;
alDeleteBuffers(1, &buffer); 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 );
}
}
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 );
}
}
void
SGSoundSample::set_orientation( ALfloat *dir, ALfloat inner_angle,
ALfloat outer_angle,
ALfloat outer_gain)
{
inner = inner_angle;
outer = outer_angle;
outergain = outer_gain;
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 ) {
source_vel[0] = vel[0];
source_vel[1] = vel[1];
source_vel[2] = vel[2];
if (playing) {
alSourcefv( source, AL_VELOCITY, source_vel );
}
}
void
SGSoundSample::set_reference_dist( ALfloat dist ) {
reference_dist = dist;
if (playing) {
alSourcef( source, AL_REFERENCE_DISTANCE, reference_dist );
}
} }
// play the sample void
void SGSoundSample::play( bool _loop ) { SGSoundSample::set_max_dist( ALfloat dist ) {
loop = _loop; max_dist = dist;
if (playing) {
// make sure sound isn't already playing alSourcef( source, AL_MAX_DISTANCE, max_dist );
alSourceStop( source ); }
alSourcei( source, AL_LOOPING, loop );
alSourcePlay( source );
}
// stop playing the sample
void SGSoundSample::stop() {
alSourceStop( source );
} }
+12 -75
View File
@@ -93,6 +93,8 @@ private:
double max_dist; double max_dist;
ALboolean loop; ALboolean loop;
bool playing;
bool bind_source();
public: public:
@@ -149,15 +151,7 @@ public:
* Test if a sample is curretnly playing. * Test if a sample is curretnly playing.
* @return true if is is playing, false otherwise. * @return true if is is playing, false otherwise.
*/ */
inline bool is_playing( ) { bool is_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) ;
}
/** /**
* Get the current pitch setting of this sample. * Get the current pitch setting of this sample.
@@ -167,18 +161,7 @@ public:
/** /**
* Set the pitch of this sample. * Set the pitch of this sample.
*/ */
inline void set_pitch( double p ) { void 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;
alSourcef( source, AL_PITCH, pitch );
if ( alGetError() != AL_NO_ERROR) {
SG_LOG( SG_GENERAL, SG_ALERT,
"Oops AL error in sample set_pitch()! " << p
<< " for " << sample_name );
}
}
/** /**
* Get the current volume setting of this sample. * Get the current volume setting of this sample.
@@ -188,15 +171,7 @@ public:
/** /**
* Set the volume of this sample. * Set the volume of this sample.
*/ */
inline void set_volume( double v ) { void set_volume( double v );
volume = v;
alSourcef( source, AL_GAIN, volume );
if ( alGetError() != AL_NO_ERROR) {
SG_LOG( SG_GENERAL, SG_ALERT,
"Oops AL error in sample set_volume()! " << v
<< " for " << sample_name );
}
}
/** /**
* Returns the size of the sounds sample * Returns the size of the sounds sample
@@ -215,78 +190,40 @@ public:
/** /**
* Set position of sound source (uses same coordinate system as opengl) * Set position of sound source (uses same coordinate system as opengl)
*/ */
inline void set_source_pos( ALfloat *pos ) { void set_source_pos( ALfloat *pos );
source_pos[0] = pos[0];
source_pos[1] = pos[1];
source_pos[2] = pos[2];
sgVec3 final_pos;
sgAddVec3( final_pos, source_pos, offset_pos );
alSourcefv( source, AL_POSITION, final_pos );
}
/** /**
* Set "constant" offset position of sound source (uses same * Set "constant" offset position of sound source (uses same
* coordinate system as opengl) * coordinate system as opengl)
*/ */
inline void set_offset_pos( ALfloat *pos ) { void set_offset_pos( ALfloat *pos );
offset_pos[0] = pos[0];
offset_pos[1] = pos[1];
offset_pos[2] = pos[2];
sgVec3 final_pos;
sgAddVec3( final_pos, source_pos, offset_pos );
alSourcefv( source, AL_POSITION, final_pos );
}
/** /**
* 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.
*/ */
inline void set_orientation( ALfloat *dir, ALfloat inner_angle=360.0, void set_orientation( ALfloat *dir, ALfloat inner_angle=360.0,
ALfloat outer_angle=360.0, ALfloat outer_angle=360.0,
ALfloat outer_gain=0.0) ALfloat outer_gain=0.0);
{
inner = inner_angle;
outer = outer_angle;
outergain = outer_gain;
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 );
}
/** /**
* Set velocity of sound source (uses same coordinate system as opengl) * Set velocity of sound source (uses same coordinate system as opengl)
*/ */
inline void set_source_vel( ALfloat *vel ) { void set_source_vel( ALfloat *vel );
source_vel[0] = vel[0];
source_vel[1] = vel[1];
source_vel[2] = vel[2];
alSourcefv( source, AL_VELOCITY, source_vel );
}
/** /**
* 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.)
*/ */
inline void set_reference_dist( ALfloat dist ) { void set_reference_dist( ALfloat dist );
reference_dist = dist;
alSourcef( source, AL_REFERENCE_DISTANCE, reference_dist );
}
/** /**
* Set maximume distance of sound (the distance where the sound is * Set maximume distance of sound (the distance where the sound is
* no longer audible. * no longer audible.
*/ */
inline void set_max_dist( ALfloat dist ) { void set_max_dist( ALfloat dist );
max_dist = dist;
alSourcef( source, AL_MAX_DISTANCE, max_dist );
}
}; };
+8 -9
View File
@@ -27,11 +27,9 @@
#if defined(__APPLE__) #if defined(__APPLE__)
# include <OpenAL/al.h> # include <OpenAL/al.h>
# include <OpenAL/alut.h>
# include <OpenAL/alc.h> # include <OpenAL/alc.h>
#else #else
# include <AL/al.h> # include <AL/al.h>
# include <AL/alut.h>
# include <AL/alc.h> # include <AL/alc.h>
#endif #endif
@@ -71,11 +69,13 @@ SGSoundMgr::SGSoundMgr() {
SG_LOG( SG_GENERAL, SG_INFO, "Initializing OpenAL sound manager" ); SG_LOG( SG_GENERAL, SG_INFO, "Initializing OpenAL sound manager" );
// initialize OpenAL // initialize OpenAL
alutInit( 0, NULL ); if ( (dev = alcOpenDevice( NULL )) != NULL) {
atexit(alutExit); context = alcCreateContext( dev, NULL );
}
if ( alGetError() == AL_NO_ERROR) { if ( (dev != NULL) && (context != NULL) ) {
working = true; working = true;
alcMakeContextCurrent( context );
} else { } else {
working = false; working = false;
SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" ); SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" );
@@ -115,6 +115,7 @@ SGSoundMgr::SGSoundMgr() {
SGSoundMgr::~SGSoundMgr() { SGSoundMgr::~SGSoundMgr() {
alcDestroyContext( context );
// //
// Remove the samples from the sample manager. // Remove the samples from the sample manager.
// //
@@ -162,8 +163,7 @@ void SGSoundMgr::update( double dt ) {
void void
SGSoundMgr::pause () SGSoundMgr::pause ()
{ {
ALCcontext *pCurContext = alcGetCurrentContext(); alcSuspendContext( context );
alcSuspendContext( pCurContext );
if ( alGetError() != AL_NO_ERROR) { if ( alGetError() != AL_NO_ERROR) {
SG_LOG( SG_GENERAL, SG_ALERT, SG_LOG( SG_GENERAL, SG_ALERT,
"Oops AL error after soundmgr pause()!" ); "Oops AL error after soundmgr pause()!" );
@@ -174,8 +174,7 @@ SGSoundMgr::pause ()
void void
SGSoundMgr::resume () SGSoundMgr::resume ()
{ {
ALCcontext *pCurContext = alcGetCurrentContext(); alcProcessContext( context );
alcProcessContext( pCurContext );
if ( alGetError() != AL_NO_ERROR) { if ( alGetError() != AL_NO_ERROR) {
SG_LOG( SG_GENERAL, SG_ALERT, SG_LOG( SG_GENERAL, SG_ALERT,
"Oops AL error after soundmgr resume()!" ); "Oops AL error after soundmgr resume()!" );
+5
View File
@@ -44,8 +44,10 @@
#if defined( __APPLE__ ) #if defined( __APPLE__ )
# include <OpenAL/al.h> # include <OpenAL/al.h>
# include <OpenAL/alc.h>
#else #else
# include <AL/al.h> # include <AL/al.h>
# include <AL/alc.h>
#endif #endif
#include "sample_openal.hxx" #include "sample_openal.hxx"
@@ -65,6 +67,9 @@ typedef sample_map::const_iterator const_sample_map_iterator;
class SGSoundMgr class SGSoundMgr
{ {
ALCdevice *dev;
ALCcontext *context;
// Position of the listener. // Position of the listener.
ALfloat listener_pos[3]; ALfloat listener_pos[3];