From 5bbcd386fa837885782f128af77ff0162761945c Mon Sep 17 00:00:00 2001 From: curt Date: Sat, 24 Apr 2004 19:02:29 +0000 Subject: [PATCH] Rewrite the entire audio support library on top of OpenAL rather than plib's sound manager. The interface was simplified and cleaned up a bit, and I haven't back ported these changes to the plib sound wrappers ... we could I suppose if someone really had a problem, but I haven't seen anything so far that would indicate the extra effort is worth it. --- configure.ac | 14 + simgear/sound/Makefile.am | 22 +- simgear/sound/jet.wav | Bin 0 -> 35256 bytes simgear/sound/openal_test1.cxx | 125 +++++++ simgear/sound/openal_test2.cxx | 47 +++ simgear/sound/sample_openal.cxx | 181 ++++++++++ simgear/sound/sample_openal.hxx | 170 +++++++++ simgear/sound/soundmgr.cxx | 416 ---------------------- simgear/sound/soundmgr.hxx | 296 --------------- simgear/sound/soundmgr_openal.cxx | 263 ++++++++++++++ simgear/sound/soundmgr_openal.hxx | 177 +++++++++ simgear/sound/{sound.cxx => xmlsound.cxx} | 61 ++-- simgear/sound/{sound.hxx => xmlsound.hxx} | 13 +- 13 files changed, 1036 insertions(+), 749 deletions(-) create mode 100644 simgear/sound/jet.wav create mode 100644 simgear/sound/openal_test1.cxx create mode 100644 simgear/sound/openal_test2.cxx create mode 100644 simgear/sound/sample_openal.cxx create mode 100644 simgear/sound/sample_openal.hxx delete mode 100644 simgear/sound/soundmgr.cxx delete mode 100644 simgear/sound/soundmgr.hxx create mode 100644 simgear/sound/soundmgr_openal.cxx create mode 100644 simgear/sound/soundmgr_openal.hxx rename simgear/sound/{sound.cxx => xmlsound.cxx} (88%) rename simgear/sound/{sound.hxx => xmlsound.hxx} (96%) diff --git a/configure.ac b/configure.ac index 9d448213..fb53c8a3 100644 --- a/configure.ac +++ b/configure.ac @@ -270,7 +270,21 @@ esac opengl_LIBS="$LIBS" LIBS="$base_LIBS" +dnl check for OpenAL libraries +case "${host}" in +*) + dnl default unix style machines + + AC_SEARCH_LIBS(alGenBuffers, openal) + ;; + +esac + +openal_LIBS="$LIBS" +LIBS="$base_LIBS" + AC_SUBST(base_LIBS) +AC_SUBST(openal_LIBS) AC_SUBST(opengl_LIBS) AC_SUBST(thread_LIBS) AC_SUBST(network_LIBS) diff --git a/simgear/sound/Makefile.am b/simgear/sound/Makefile.am index 4aa9f322..da59b224 100644 --- a/simgear/sound/Makefile.am +++ b/simgear/sound/Makefile.am @@ -1,11 +1,29 @@ includedir = @includedir@/sound +EXTRA_DIST = jet.wav + lib_LIBRARIES = libsgsound.a noinst_HEADERS = -include_HEADERS = sound.hxx soundmgr.hxx +include_HEADERS = \ + sample_openal.hxx \ + soundmgr_openal.hxx \ + xmlsound.hxx + +libsgsound_a_SOURCES = \ + sample_openal.cxx \ + soundmgr_openal.cxx \ + xmlsound.cxx + +noinst_PROGRAMS = openal_test1 openal_test2 + +openal_test1_SOURCES = openal_test1.cxx +openal_test2_SOURCES = openal_test2.cxx -libsgsound_a_SOURCES = sound.cxx soundmgr.cxx +openal_test1_LDADD = -lsgdebug -lopenal +openal_test2_LDADD = \ + $(top_builddir)/simgear/sound/libsgsound.a \ + -lsgdebug -lsgmisc -lsgstructure $(openal_LIBS) INCLUDES = -I$(top_srcdir) diff --git a/simgear/sound/jet.wav b/simgear/sound/jet.wav new file mode 100644 index 0000000000000000000000000000000000000000..891c84d0b2064d5e66e594d65e8809b0953c8b07 GIT binary patch literal 35256 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 literal 0 HcmV?d00001 diff --git a/simgear/sound/openal_test1.cxx b/simgear/sound/openal_test1.cxx new file mode 100644 index 00000000..91b8c849 --- /dev/null +++ b/simgear/sound/openal_test1.cxx @@ -0,0 +1,125 @@ +#include + +#include +#include + +#include + +static void print_openal_error( ALuint error ) { + if ( error == AL_INVALID_NAME ) { + SG_LOG( SG_GENERAL, SG_ALERT, "AL_INVALID_NAME" ); + } else if ( error == AL_ILLEGAL_ENUM ) { + SG_LOG( SG_GENERAL, SG_ALERT, "AL_ILLEGAL_ENUM" ); + } else if ( error == AL_INVALID_VALUE ) { + SG_LOG( SG_GENERAL, SG_ALERT, "AL_INVALID_VALUE" ); + } else if ( error == AL_ILLEGAL_COMMAND ) { + SG_LOG( SG_GENERAL, SG_ALERT, "AL_ILLEGAL_COMMAND" ); + } else if ( error == AL_OUT_OF_MEMORY ) { + SG_LOG( SG_GENERAL, SG_ALERT, "AL_OUT_OF_MEMORY" ); + } else { + SG_LOG( SG_GENERAL, SG_ALERT, "Unhandled error code = " << error ); + } +} + + +int main( int argc, char *argv[] ) { + // initialize OpenAL + alutInit( 0, NULL ); + alGetError(); + if ( alGetError() != AL_NO_ERROR) { + SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" ); + } + + // 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]; + + 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; + + alListenerfv( AL_POSITION, listener_pos ); + alListenerfv( AL_VELOCITY, listener_vel ); + alListenerfv( AL_ORIENTATION, listener_ori ); + + // Buffers hold sound data. + ALuint buffer; + + // Sources are points emitting sound. + ALuint source; + + // Position of the source sound. + ALfloat source_pos[3]; + + // Velocity of the source sound. + ALfloat source_vel[3]; + + // configuration values + ALenum format; + ALsizei size; + ALvoid* data; + ALsizei freq; + ALboolean loop; + + source_pos[0] = 0.0; source_pos[1] = 0.0; source_pos[2] = 0.0; + source_vel[0] = 0.0; source_vel[1] = 0.0; source_vel[2] = 0.0; + + // create an OpenAL buffer handle + alGenBuffers(1, &buffer); + ALuint error = alGetError(); + if ( error != AL_NO_ERROR ) { + print_openal_error( error ); + SG_LOG( SG_GENERAL, SG_ALERT, "Failed to gen OpenAL buffer." ); + } else { + SG_LOG( SG_GENERAL, SG_ALERT, "Buffer created ok!" ); + } + + // Load the sample file + alutLoadWAVFile( (ALbyte *)"jet.wav", &format, &data, &size, &freq, &loop ); + if (alGetError() != AL_NO_ERROR) { + SG_LOG( SG_GENERAL, SG_ALERT, "Failed to load wav file."); + } + + // Copy data to the internal OpenAL buffer + alBufferData( buffer, format, data, size, freq ); + if (alGetError() != AL_NO_ERROR) { + SG_LOG( SG_GENERAL, SG_ALERT, "Failed to buffer data."); + } + + alutUnloadWAV( format, data, size, freq ); + + alGenSources(1, &source); + if (alGetError() != AL_NO_ERROR) { + print_openal_error( error ); + } + + alSourcei( source, AL_BUFFER, buffer ); + alSourcef( source, AL_PITCH, 1.0 ); + alSourcef( source, AL_GAIN, 1.0 ); + alSourcefv( source, AL_POSITION, source_pos ); + alSourcefv( source, AL_VELOCITY, source_vel ); + alSourcei( source, AL_LOOPING, loop ); + + alSourcePlay( source ); + + sleep(10); + + return 0; +} diff --git a/simgear/sound/openal_test2.cxx b/simgear/sound/openal_test2.cxx new file mode 100644 index 00000000..10884c59 --- /dev/null +++ b/simgear/sound/openal_test2.cxx @@ -0,0 +1,47 @@ +#include + +#include "sample_openal.hxx" +#include "soundmgr_openal.hxx" + + +int main( int argc, char *argv[] ) { + SGSoundMgr sm; + + SGSoundSample sample1( ".", "jet.wav" ); + sample1.set_volume(0.5); + sample1.set_volume(0.2); + sample1.play_looped(); + sleep(1); + + SGSoundSample sample2( ".", "jet.wav" ); + sample2.set_volume(0.5); + sample2.set_pitch(0.4); + sample2.play_looped(); + sleep(1); + + SGSoundSample sample3( ".", "jet.wav" ); + sample3.set_volume(0.5); + sample3.set_pitch(0.8); + sample3.play_looped(); + sleep(1); + + SGSoundSample sample4( ".", "jet.wav" ); + sample4.set_volume(0.5); + sample4.set_pitch(1.2); + sample4.play_looped(); + sleep(1); + + SGSoundSample sample5( ".", "jet.wav" ); + sample5.set_volume(0.5); + sample5.set_pitch(1.6); + sample5.play_looped(); + sleep(1); + + SGSoundSample sample6( ".", "jet.wav" ); + sample6.set_volume(0.5); + sample6.set_pitch(2.0); + sample6.play_looped(); + sleep(1); + + sleep(10); +} diff --git a/simgear/sound/sample_openal.cxx b/simgear/sound/sample_openal.cxx new file mode 100644 index 00000000..a4459788 --- /dev/null +++ b/simgear/sound/sample_openal.cxx @@ -0,0 +1,181 @@ +// sample.cxx -- Sound sample encapsulation class +// +// Written by Curtis Olson, started April 2004. +// +// Copyright (C) 2004 Curtis L. Olson - curt@flightgear.org +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + + +#include +#include + +#include +#include +#include + +#include "sample_openal.hxx" + + +// +// SGSoundSample +// + + +static void print_openal_error( ALuint error ) { + if ( error == AL_INVALID_NAME ) { + SG_LOG( SG_GENERAL, SG_ALERT, "AL_INVALID_NAME" ); + } else if ( error == AL_ILLEGAL_ENUM ) { + SG_LOG( SG_GENERAL, SG_ALERT, "AL_ILLEGAL_ENUM" ); + } else if ( error == AL_INVALID_VALUE ) { + SG_LOG( SG_GENERAL, SG_ALERT, "AL_INVALID_VALUE" ); + } else if ( error == AL_ILLEGAL_COMMAND ) { + SG_LOG( SG_GENERAL, SG_ALERT, "AL_ILLEGAL_COMMAND" ); + } else if ( error == AL_OUT_OF_MEMORY ) { + SG_LOG( SG_GENERAL, SG_ALERT, "AL_OUT_OF_MEMORY" ); + } else { + SG_LOG( SG_GENERAL, SG_ALERT, "Unhandled error code = " << error ); + } +} + + +// constructor +SGSoundSample::SGSoundSample( const char *path, const char *file ) : + pitch(1.0), + volume(1.0), + loop(AL_FALSE) +{ + SGPath samplepath( path ); + if ( strlen(file) ) { + samplepath.append( file ); + } + + SG_LOG( SG_GENERAL, SG_ALERT, "From file sounds sample = " + << samplepath.str() ); + + ALuint error; + + source_pos[0] = 0.0; source_pos[1] = 0.0; source_pos[2] = 0.0; + source_vel[0] = 0.0; source_vel[1] = 0.0; source_vel[2] = 0.0; + + // clear errors from elsewhere? + alGetError(); + + // create an OpenAL buffer handle + alGenBuffers(1, &buffer); + error = alGetError(); + if ( error != AL_NO_ERROR ) { + print_openal_error( error ); + throw sg_exception("Failed to gen OpenAL buffer."); + } else { + SG_LOG( SG_GENERAL, SG_ALERT, "Buffer created ok!" ); + } + + // Load the sample file + alutLoadWAVFile( (ALbyte *)samplepath.c_str(), + &format, &data, &size, &freq, &loop ); + if (alGetError() != AL_NO_ERROR) { + throw sg_exception("Failed to load wav file."); + } + + // Copy data to the internal OpenAL buffer + alBufferData( buffer, format, data, size, freq ); + if (alGetError() != AL_NO_ERROR) { + throw sg_exception("Failed to buffer data."); + } + + alutUnloadWAV( format, data, size, freq ); + + // Bind buffer with a source. + alGenSources(1, &source); + if (alGetError() != AL_NO_ERROR) { + throw sg_exception("Failed to gen source."); + } + + alSourcei( source, AL_BUFFER, buffer ); + alSourcef( source, AL_PITCH, pitch ); + alSourcef( source, AL_GAIN, volume ); + alSourcefv( source, AL_POSITION, source_pos ); + alSourcefv( source, AL_VELOCITY, source_vel ); + alSourcei( source, AL_LOOPING, loop ); +} + + +// constructor +SGSoundSample::SGSoundSample( unsigned char *_data, int len, int _freq ) : + pitch(1.0), + volume(1.0), + loop(AL_FALSE) +{ + SG_LOG( SG_GENERAL, SG_ALERT, "In memory sounds sample" ); + + source_pos[0] = 0.0; source_pos[1] = 0.0; source_pos[2] = 0.0; + source_vel[0] = 0.0; source_vel[1] = 0.0; source_vel[2] = 0.0; + + // Load wav data into a buffer. + alGenBuffers(1, &buffer); + if (alGetError() != AL_NO_ERROR) { + SG_LOG( SG_GENERAL, SG_ALERT, "Error in alGenBuffers()" ); + return; + } + + format = AL_FORMAT_MONO8; + size = len; + data = _data; + freq = _freq; + + alBufferData( buffer, format, data, size, freq ); + + // Bind buffer with a source. + alGenSources(1, &source); + if (alGetError() != AL_NO_ERROR) { + throw sg_exception("Failed to gen source."); + } + + alSourcei( source, AL_BUFFER, buffer ); + alSourcef( source, AL_PITCH, pitch ); + alSourcef( source, AL_GAIN, volume ); + alSourcefv( source, AL_POSITION, source_pos ); + alSourcefv( source, AL_VELOCITY, source_vel ); + alSourcei( source, AL_LOOPING, loop ); +} + + +// destructor +SGSoundSample::~SGSoundSample() { + SG_LOG( SG_GENERAL, SG_ALERT, "Deleting a sample" ); + alDeleteSources(1, &source); + alDeleteBuffers(1, &buffer); +} + + +// play the sample +void SGSoundSample::play( bool _loop ) { + loop = _loop; + + // make sure sound isn't already playing + alSourceStop( source ); + + alSourcei( source, AL_LOOPING, loop ); + alSourcePlay( source ); +} + + +// stop playing the sample +void SGSoundSample::stop() { + alSourceStop( source ); +} diff --git a/simgear/sound/sample_openal.hxx b/simgear/sound/sample_openal.hxx new file mode 100644 index 00000000..fe79cb68 --- /dev/null +++ b/simgear/sound/sample_openal.hxx @@ -0,0 +1,170 @@ +// sample.hxx -- Sound sample encapsulation class +// +// Written by Curtis Olson, started April 2004. +// +// Copyright (C) 2004 Curtis L. Olson - curt@flightgear.org +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +/** + * \file sample.hxx + * Provides a sound sample encapsulation + */ + +#ifndef _SG_SAMPLE_HXX +#define _SG_SAMPLE_HXX 1 + +#ifndef __cplusplus +# error This library requires C++ +#endif + +#include + +#include + +#include + + +/** + * manages everything we need to know for an individual sound sample + */ + +class SGSoundSample { + +private: + + // Buffers hold sound data. + ALuint buffer; + + // Sources are points emitting sound. + ALuint source; + + // Position of the source sound. + ALfloat source_pos[3]; + + // Velocity of the source sound. + ALfloat source_vel[3]; + + // configuration values + ALenum format; + ALsizei size; + ALvoid* data; + ALsizei freq; + + double pitch; + double volume; + ALboolean loop; + +public: + + SGSoundSample( const char *path, const char *file ); + SGSoundSample( unsigned char *_data, int len, int _freq ); + ~SGSoundSample(); + + /** + * Start playing this sample. + * + * @param looped Define wether the sound should be played in a loop. + */ + void play( bool _loop ); + + /** + * Stop playing this sample. + * + * @param sched A pointer to the appropriate scheduler. + */ + void stop(); + + /** + * Play this sample once. + * @see #play + */ + inline void play_once() { play(false); } + + /** + * Play this sample looped. + * @see #play + */ + inline void play_looped() { play(true); } + + /** + * Test if a sample is curretnly playing. + * @return true if is is playing, false otherwise. + */ + inline 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()!" ); + } + return (result == AL_PLAYING) ; + } + + /** + * Get the current pitch setting of this sample. + */ + inline double get_pitch() const { return pitch; } + + /** + * Set the pitch of this sample. + */ + inline void set_pitch( double p ) { + 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 ); + } + } + + /** + * Get the current volume setting of this sample. + */ + inline double get_volume() const { return volume; } + + /** + * Set the volume of this sample. + */ + inline 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()!" ); + } + } + + /** + * Returns the size of the sounds sample + */ + inline int get_size() { + return size; + } + + /** + * Return a pointer to the raw data + */ + inline char *get_data() { + return (char *)data; + } +}; + + +#endif // _SG_SAMPLE_HXX + + diff --git a/simgear/sound/soundmgr.cxx b/simgear/sound/soundmgr.cxx deleted file mode 100644 index 31065656..00000000 --- a/simgear/sound/soundmgr.cxx +++ /dev/null @@ -1,416 +0,0 @@ -// soundmgr.cxx -- Sound effect management class -// -// Sound manager initially written by David Findlay -// 2001 -// -// C++-ified by Curtis Olson, started March 2001. -// -// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org -// -// 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., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// $Id$ - -#include - -#include -#include - -#include "soundmgr.hxx" - -#define SOUND_SAFETY_MULT 3 -#define MAX_SOUND_SAFETY ( 1.0 / SOUND_SAFETY_MULT ) - -// -// SGSimpleSound -// - -// constructor -SGSimpleSound::SGSimpleSound( const char *path, const char *file ) - : sample(NULL), - pitch_envelope(NULL), - volume_envelope(NULL), - pitch(1.0), - volume(1.0) -{ - SGPath slfile( path ); - if ( file ) - slfile.append( file ); - - sample = new slSample ( slfile.c_str() ); - pitch_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT ); - volume_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT ); - pitch_envelope->setStep ( 0, 0.01, 1.0 ); - volume_envelope->setStep ( 0, 0.01, 1.0 ); -} - -SGSimpleSound::SGSimpleSound( unsigned char *buffer, int len ) - : pitch(1.0), - volume(1.0) -{ - sample = new slSample ( buffer, len ); - pitch_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT ); - volume_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT ); - pitch_envelope->setStep ( 0, 0.01, 1.0 ); - volume_envelope->setStep ( 0, 0.01, 1.0 ); -} - -// destructor -SGSimpleSound::~SGSimpleSound() { - delete pitch_envelope; - delete volume_envelope; - delete sample; -} - -void SGSimpleSound::play( slScheduler *sched, bool looped ) { - - // make sure sound isn't already playing - if ( sample->getPlayCount() > 0 ) { - sched->stopSample(sample); - // return; - } - - if ( looped ) { - sched->loopSample(sample); - } else { - sched->playSample(sample); - } - - sched->addSampleEnvelope(sample, 0, 0, pitch_envelope, SL_PITCH_ENVELOPE); - sched->addSampleEnvelope(sample, 0, 1, volume_envelope, SL_VOLUME_ENVELOPE); -} - -void SGSimpleSound::stop( slScheduler *sched ) { - - sched->stopSample( sample ); -} - -// -// Sound Manager -// - -// constructor -SGSoundMgr::SGSoundMgr() { - audio_sched = new slScheduler( 8000 ); - if ( audio_sched->notWorking() ) { - SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" ); - } else { - audio_sched -> setMaxConcurrent ( SL_MAX_MIXERINPUTS ); - - audio_mixer = new smMixer; - - SG_LOG( SG_GENERAL, SG_INFO, - "Rate = " << audio_sched->getRate() - << " Bps = " << audio_sched->getBps() - << " Stereo = " << audio_sched->getStereo() ); - } -} - -// destructor - -SGSoundMgr::~SGSoundMgr() { - - // - // Remove the samples from the sample manager. - // - sample_map_iterator sample_current = samples.begin(); - sample_map_iterator sample_end = samples.end(); - for ( ; sample_current != sample_end; ++sample_current ) { - sample_ref *sr = sample_current->second; - - audio_sched->stopSample(sr->sample); - delete sr->sample; - delete sr; - } - - // - // Remove the sounds from the sound manager. - // - sound_map_iterator sound_current = sounds.begin(); - sound_map_iterator sound_end = sounds.end(); - for ( ; sound_current != sound_end; ++sound_current ) { - SGSimpleSound *s = sound_current->second; - - audio_sched->stopSample(s->get_sample()); - delete s->get_sample(); - delete s; - } - - delete audio_sched; - delete audio_mixer; -} - - -// initialize the sound manager -void SGSoundMgr::init() { - safety = MAX_SOUND_SAFETY; - - // audio_mixer -> setMasterVolume ( 80 ) ; /* 80% of max volume. */ - audio_sched -> setSafetyMargin ( SOUND_SAFETY_MULT * safety ) ; - - - // - // Remove the samples from the sample manager. - // - sample_map_iterator sample_current = samples.begin(); - sample_map_iterator sample_end = samples.end(); - for ( ; sample_current != sample_end; ++sample_current ) { - sample_ref *sr = sample_current->second; - - audio_sched->stopSample(sr->sample); - delete sr->sample; - delete sr; - } - samples.clear(); - - // - // Remove the sounds from the sound manager. - // - sound_map_iterator sound_current = sounds.begin(); - sound_map_iterator sound_end = sounds.end(); - for ( ; sound_current != sound_end; ++sound_current ) { - SGSimpleSound *s = sound_current->second; - - audio_sched->stopSample(s->get_sample()); - delete s->get_sample(); - delete s; - } - sounds.clear(); - -} - - -void SGSoundMgr::bind () -{ - // no properties yet -} - - -void SGSoundMgr::unbind () -{ - // no properties yet -} - - -// run the audio scheduler -void SGSoundMgr::update( double dt ) { - if ( dt > safety ) { - safety = dt; - } else { - safety = safety * 0.99 + dt * 0.01; - } - if ( safety > MAX_SOUND_SAFETY ) { - safety = MAX_SOUND_SAFETY; - } - // cout << "safety = " << safety << endl; - audio_sched -> setSafetyMargin ( SOUND_SAFETY_MULT * safety ) ; - - if ( !audio_sched->not_working() ) - audio_sched -> update(); -} - - -void -SGSoundMgr::pause () -{ - audio_sched->pauseSample(0, 0); -} - - -void -SGSoundMgr::resume () -{ - audio_sched->resumeSample(0, 0); -} - - -// add a sound effect, return true if successful -bool SGSoundMgr::add( SGSimpleSound *sound, const string& refname ) { - - sound_map_iterator sound_it = sounds.find( refname ); - if ( sound_it != sounds.end() ) { - // sound already exists - return false; - } - - sample_map_iterator sample_it = samples.find( refname ); - if ( sample_it != samples.end() ) { - // this sound has existed in the past and it's sample is still - // here, delete the sample so we can replace it. - samples.erase( sample_it ); - } - - sample_ref *sr = new sample_ref; - - sr->n=1; - sr->sample = sound->get_sample(); - samples[refname] = sr; - - sounds[refname] = sound; - - return true; -} - - -// add a sound from a file, return the sample if successful, else return NULL -SGSimpleSound *SGSoundMgr::add( const string &refname, - const char *path, const char *file ) { - SGSimpleSound *sound; - - SGPath slfile( path ); - if ( file ) - slfile.append( file ); - - if ( slfile.str().empty() ) - return NULL; - - sample_map_iterator it = samples.find(slfile.str()); - if (it == samples.end()) { - - sound = new SGSimpleSound(slfile.c_str()); - sounds[refname] = sound; - - sample_ref *sr = new sample_ref; - - sr->n=1; - sr->sample = sound->get_sample(); - samples[slfile.str()] = sr; - - } else { - sample_ref *sr = it->second; - - sr->n++; - sound = - new SGSimpleSound(sr->sample->getBuffer(), sr->sample->getLength()); - sounds[refname] = sound; - - } - - return sound; -} - - -// remove a sound effect, return true if successful -bool SGSoundMgr::remove( const string &refname ) { - - sound_map_iterator it = sounds.find( refname ); - if ( it != sounds.end() ) { - // first stop the sound from playing (so we don't bomb the - // audio scheduler) - SGSimpleSound *sample = it->second; - - // cout << "Playing " << sample->get_sample()->getPlayCount() - // << " instances!" << endl; - - audio_sched->stopSample( sample->get_sample() ); - audio_sched->addSampleEnvelope( sample->get_sample(), 0, 0, - NULL, - SL_PITCH_ENVELOPE ); - audio_sched->addSampleEnvelope( sample->get_sample(), 0, 1, - NULL, - SL_VOLUME_ENVELOPE ); - - // must call audio_sched->update() after stopping the sound - // but before deleting it. - audio_sched -> update(); - // cout << "Still playing " << sample->get_sample()->getPlayCount() - // << " instances!" << endl; - - // - // FIXME: - // Due to the change in the sound manager, samples live - // until the sound manager gets removed. - // - // delete sample; - sounds.erase( it ); - - // cout << "sndmgr: removed -> " << refname << endl; - return true; - } else { - // cout << "sndmgr: failed remove -> " << refname << endl; - return false; - } -} - - -// return true of the specified sound exists in the sound manager system -bool SGSoundMgr::exists( const string &refname ) { - sound_map_iterator it = sounds.find( refname ); - if ( it != sounds.end() ) { - return true; - } else { - return false; - } -} - - -// return a pointer to the SGSimpleSound if the specified sound exists -// in the sound manager system, otherwise return NULL -SGSimpleSound *SGSoundMgr::find( const string &refname ) { - sound_map_iterator it = sounds.find( refname ); - if ( it != sounds.end() ) { - return it->second; - } else { - return NULL; - } -} - - -// tell the scheduler to play the indexed sample in a continuous -// loop -bool SGSoundMgr::play_looped( const string &refname ) { - SGSimpleSound *sample; - - if ((sample = find( refname )) == NULL) - return false; - - sample->play(audio_sched, true); - return true; -} - - -// tell the scheduler to play the indexed sample once -bool SGSoundMgr::play_once( const string& refname ) { - SGSimpleSound *sample; - - if ((sample = find( refname )) == NULL) - return false; - - sample->play(audio_sched, false); - return true; -} - - -// return true of the specified sound is currently being played -bool SGSoundMgr::is_playing( const string& refname ) { - SGSimpleSound *sample; - - if ((sample = find( refname )) == NULL) - return false; - - return (sample->get_sample()->getPlayCount() > 0 ); -} - - -// immediate stop playing the sound -bool SGSoundMgr::stop( const string& refname ) { - SGSimpleSound *sample; - - if ((sample = find( refname )) == NULL) - return false; - - audio_sched->stopSample( sample->get_sample() ); - return true; -} diff --git a/simgear/sound/soundmgr.hxx b/simgear/sound/soundmgr.hxx deleted file mode 100644 index 852fdc02..00000000 --- a/simgear/sound/soundmgr.hxx +++ /dev/null @@ -1,296 +0,0 @@ -// soundmgr.hxx -- Sound effect management class -// -// Sound manager initially written by David Findlay -// 2001 -// -// C++-ified by Curtis Olson, started March 2001. -// -// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org -// -// 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., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// $Id$ - -/** - * \file soundmgr.hxx - * Provides a sound manager class to keep track of - * multiple sounds and manage playing them with different effects and - * timings. - */ - -#ifndef _SG_SOUNDMGR_HXX -#define _SG_SOUNDMGR_HXX 1 - -#ifndef __cplusplus -# error This library requires C++ -#endif - -#include -#include - -#include STL_STRING -#include - -#include -#include - -SG_USING_STD(map); -SG_USING_STD(string); - - -/** - * manages everything we need to know for an individual sound sample - */ -class SGSimpleSound { - -private: - - slSample *sample; - slEnvelope *pitch_envelope; - slEnvelope *volume_envelope; - double pitch; - double volume; - -public: - - SGSimpleSound( const char *path, const char *file = NULL ); - SGSimpleSound( unsigned char *buffer, int len ); - ~SGSimpleSound(); - - /** - * Start playing this sample. - * - * @param sched A pointer to the appropriate scheduler. - * @param looped Define wether the sound should be played in a loop. - */ - void play( slScheduler *sched, bool looped ); - - /** - * Stop playing this sample. - * - * @param sched A pointer to the appropriate scheduler. - */ - void stop( slScheduler *sched ); - - /** - * Play this sample once. - * @see #play - */ - inline void play_once( slScheduler *sched ) { play( sched, false); } - - /** - * Play this sample looped. - * @see #play - */ - inline void play_looped( slScheduler *sched ) { play( sched, true); } - - /** - * Test if a sample is curretnly playing. - * @return true if is is playing, false otherwise. - */ - inline bool is_playing( ) { - return ( sample->getPlayCount() > 0 ); - } - - /** - * Get the current pitch setting of this sample. - */ - inline double get_pitch() const { return pitch; } - - /** - * Set the pitch of this sample. - */ - inline void set_pitch( double p ) { - pitch = p; - pitch_envelope->setStep( 0, 0.01, pitch ); - } - - /** - * Get the current volume setting of this sample. - */ - inline double get_volume() const { return volume; } - - /** - * Set the volume of this sample. - */ - inline void set_volume( double v ) { - volume = v; - volume_envelope->setStep( 0, 0.01, volume ); - } - - /** - * Get a refference to the raw sample. - */ - inline slSample *get_sample() { return sample; } - - /** - * Get the pitch envelope setting of this sample. - */ - inline slEnvelope *get_pitch_envelope() { return pitch_envelope; } - - /** - * Get the volume envelope setting of this sample. - */ - inline slEnvelope *get_volume_envelope() { return volume_envelope; } -}; - - -typedef struct { - int n; - slSample *sample; -} sample_ref; - -typedef map < string, sample_ref * > sample_map; -typedef sample_map::iterator sample_map_iterator; -typedef sample_map::const_iterator const_sample_map_iterator; - -typedef map < string, SGSimpleSound * > sound_map; -typedef sound_map::iterator sound_map_iterator; -typedef sound_map::const_iterator const_sound_map_iterator; - - -/** - * Manage a collection of SGSimpleSound instances - */ -class SGSoundMgr -{ - - slScheduler *audio_sched; - smMixer *audio_mixer; - - sound_map sounds; - sample_map samples; - - double safety; - -public: - - SGSoundMgr(); - ~SGSoundMgr(); - - - /** - * (re) initialize the sound manager. - */ - void init(); - - - /** - * Bind properties for the sound manager. - */ - void bind (); - - - /** - * Unbind properties for the sound manager. - */ - void unbind (); - - - /** - * Run the audio scheduler. - */ - void update(double dt); - - - /** - * Pause all sounds. - */ - void pause (); - - - /** - * Resume all sounds. - */ - void resume (); - - - /** - * is audio working? - */ - inline bool is_working() const { return !audio_sched->notWorking(); } - - /** - * reinitialize the sound manager - */ - inline void reinit() { init(); } - - /** - * add a sound effect, return true if successful - */ - bool add( SGSimpleSound *sound, const string& refname); - - /** - * Add a sound file to the sound manager. - * - * The advantage of using this function over the previous one is that - * it doesn't load a sample if it already is in memory, but instead it - * uses the already loaded sample data. - * - * @param refname A refference name to make a distincion between samples. - * @param path The path or full filename of the sample to load. - * @param file An optional filename which will be appended to the path. - * @return An instance of the sound for further manipulation. - */ - SGSimpleSound *add( const string& refname, - const char *path, const char *file = NULL ); - - /** - * 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 SGSimpleSound if the specified sound - * exists in the sound manager system, otherwise return NULL - */ - SGSimpleSound *find( const string& refname ); - - /** - * 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 ); - - /** - * return the audio scheduler - */ - inline slScheduler *get_scheduler( ) { return audio_sched; }; -}; - - -#endif // _SG_SOUNDMGR_HXX - - diff --git a/simgear/sound/soundmgr_openal.cxx b/simgear/sound/soundmgr_openal.cxx new file mode 100644 index 00000000..2578f1cc --- /dev/null +++ b/simgear/sound/soundmgr_openal.cxx @@ -0,0 +1,263 @@ +// soundmgr.cxx -- Sound effect management class +// +// Sound manager initially written by David Findlay +// 2001 +// +// C++-ified by Curtis Olson, started March 2001. +// +// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#include + +#include +#include +#include + +#include +#include + +#include "soundmgr_openal.hxx" + + +// +// Sound Manager +// + +// constructor +SGSoundMgr::SGSoundMgr() { + + SG_LOG( SG_GENERAL, SG_ALERT, "Initializing OpenAL sound manager" ); + + // initialize OpenAL + alutInit( 0, NULL ); + alGetError(); + if ( alGetError() == AL_NO_ERROR) { + working = true; + } else { + working = false; + SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" ); + } + + 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; + + 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!" ); + } +} + +// destructor + +SGSoundMgr::~SGSoundMgr() { + + // + // Remove the samples from the sample manager. + // + 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; + delete sample; + } + + alutExit(); +} + + +// initialize the sound manager +void SGSoundMgr::init() { + // + // Remove the samples from the sample manager. + // + 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; + delete sample; + } + samples.clear(); +} + + +void SGSoundMgr::bind () +{ + // no properties +} + + +void SGSoundMgr::unbind () +{ + // no properties +} + + +// run the audio scheduler +void SGSoundMgr::update( double dt ) { +} + + +void +SGSoundMgr::pause () +{ + ALCcontext *pCurContext = alcGetCurrentContext(); + alcSuspendContext( pCurContext ); + if ( alGetError() != AL_NO_ERROR) { + SG_LOG( SG_GENERAL, SG_ALERT, + "Oops AL error after soundmgr pause()!" ); + } +} + + +void +SGSoundMgr::resume () +{ + ALCcontext *pCurContext = alcGetCurrentContext(); + alcProcessContext( pCurContext ); + if ( alGetError() != AL_NO_ERROR) { + SG_LOG( SG_GENERAL, SG_ALERT, + "Oops AL error after soundmgr resume()!" ); + } +} + + +// add a sound effect, return true if successful +bool SGSoundMgr::add( SGSoundSample *sound, const string& refname ) { + + sample_map_iterator sample_it = samples.find( refname ); + if ( sample_it != samples.end() ) { + // sound already exists + return false; + } + + samples[refname] = sound; + + return true; +} + + +// remove a sound effect, return true if successful +bool SGSoundMgr::remove( const string &refname ) { + + sample_map_iterator sample_it = samples.find( refname ); + if ( sample_it != samples.end() ) { + // first stop the sound from playing (so we don't bomb the + // audio scheduler) + SGSoundSample *sample = sample_it->second; + delete sample; + samples.erase( sample_it ); + + // cout << "sndmgr: removed -> " << refname << endl; + return true; + } else { + // cout << "sndmgr: failed remove -> " << refname << endl; + return false; + } +} + + +// return true of the specified sound exists in the sound manager system +bool SGSoundMgr::exists( const string &refname ) { + sample_map_iterator sample_it = samples.find( refname ); + if ( sample_it != samples.end() ) { + return true; + } else { + return false; + } +} + + +// return a pointer to the SGSoundSample if the specified sound exists +// in the sound manager system, otherwise return NULL +SGSoundSample *SGSoundMgr::find( const string &refname ) { + sample_map_iterator sample_it = samples.find( refname ); + if ( sample_it != samples.end() ) { + return sample_it->second; + } else { + return NULL; + } +} + + +// tell the scheduler to play the indexed sample in a continuous +// loop +bool SGSoundMgr::play_looped( const string &refname ) { + SGSoundSample *sample; + + if ( (sample = find( refname )) == NULL ) { + return false; + } else { + sample->play( true ); + return true; + } +} + + +// tell the scheduler to play the indexed sample once +bool SGSoundMgr::play_once( const string& refname ) { + SGSoundSample *sample; + + if ( (sample = find( refname )) == NULL ) { + return false; + } else { + sample->play( false ); + return true; + } +} + + +// 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; + } +} diff --git a/simgear/sound/soundmgr_openal.hxx b/simgear/sound/soundmgr_openal.hxx new file mode 100644 index 00000000..02b732d8 --- /dev/null +++ b/simgear/sound/soundmgr_openal.hxx @@ -0,0 +1,177 @@ +// soundmgr.hxx -- Sound effect management class +// +// Sound manager initially written by David Findlay +// 2001 +// +// C++-ified by Curtis Olson, started March 2001. +// +// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +/** + * \file soundmgr.hxx + * Provides a sound manager class to keep track of + * multiple sounds and manage playing them with different effects and + * timings. + */ + +#ifndef _SG_SOUNDMGR_OPENAL_HXX +#define _SG_SOUNDMGR_OPENAL_HXX 1 + +#ifndef __cplusplus +# error This library requires C++ +#endif + +#include + +#include STL_STRING +#include + +#include + +#include "sample_openal.hxx" + +SG_USING_STD(map); +SG_USING_STD(string); + + +typedef map < string, SGSoundSample * > sample_map; +typedef sample_map::iterator sample_map_iterator; +typedef sample_map::const_iterator const_sample_map_iterator; + + +/** + * Manage a collection of SGSoundSample instances + */ +class SGSoundMgr +{ + + // Position of the listener. + ALfloat listener_pos[3]; + + // Velocity of the listener. + ALfloat listener_vel[3]; + + // Orientation of the listener. (first 3 elements are "at", second + // 3 are "up") + ALfloat listener_ori[6]; + + sample_map samples; + + bool working; + double safety; + +public: + + SGSoundMgr(); + ~SGSoundMgr(); + + + /** + * (re) initialize the sound manager. + */ + void init(); + + + /** + * Bind properties for the sound manager. + */ + void bind(); + + + /** + * Unbind properties for the sound manager. + */ + void unbind(); + + + /** + * Run the audio scheduler. + */ + void update(double dt); + + + /** + * Pause all sounds. + */ + void pause(); + + + /** + * Resume all sounds. + */ + void resume(); + + + /** + * is audio working? + */ + inline bool is_working() const { return working; } + + /** + * reinitialize the sound manager + */ + inline void reinit() { init(); } + + /** + * 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 ); + + /** + * 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 ); +}; + + +#endif // _SG_SOUNDMGR_OPENAL_HXX + + diff --git a/simgear/sound/sound.cxx b/simgear/sound/xmlsound.cxx similarity index 88% rename from simgear/sound/sound.cxx rename to simgear/sound/xmlsound.cxx index 8ceaf182..f9d6e3e5 100644 --- a/simgear/sound/sound.cxx +++ b/simgear/sound/xmlsound.cxx @@ -35,7 +35,7 @@ #include -#include "sound.hxx" +#include "xmlsound.hxx" // static double _snd_lin(double v) { return v; } @@ -62,13 +62,13 @@ static const struct { {"", NULL} }; -SGSound::SGSound() +SGXmlSound::SGXmlSound() : _sample(NULL), _condition(NULL), _property(NULL), _active(false), _name(""), - _mode(SGSound::ONCE), + _mode(SGXmlSound::ONCE), _prev_value(0), _dt_play(0.0), _dt_stop(0.0), @@ -76,24 +76,24 @@ SGSound::SGSound() { } -SGSound::~SGSound() +SGXmlSound::~SGXmlSound() { - _mgr->get_scheduler()->stopSample(_sample->get_sample()); + _sample->stop(); - if (_property) - delete _property; + if (_property) + delete _property; - if (_condition) - delete _condition; + if (_condition) + delete _condition; - _volume.clear(); - _pitch.clear(); - delete _sample; + _volume.clear(); + _pitch.clear(); + delete _sample; } void -SGSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr, - const string &path) +SGXmlSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr, + const string &path) { // @@ -105,13 +105,13 @@ SGSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr, const char *mode_str = node->getStringValue("mode", ""); if ( !strcmp(mode_str, "looped") ) { - _mode = SGSound::LOOPED; + _mode = SGXmlSound::LOOPED; } else if ( !strcmp(mode_str, "in-transit") ) { - _mode = SGSound::IN_TRANSIT; + _mode = SGXmlSound::IN_TRANSIT; } else { - _mode = SGSound::ONCE; + _mode = SGXmlSound::ONCE; if ( strcmp(mode_str, "") ) SG_LOG(SG_GENERAL,SG_INFO, " Unknown sound mode, default to 'once'"); @@ -132,7 +132,7 @@ SGSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr, unsigned int i; float v = 0.0; vector kids = node->getChildren("volume"); - for (i = 0; (i < kids.size()) && (i < SGSound::MAXPROP); i++) { + for (i = 0; (i < kids.size()) && (i < SGXmlSound::MAXPROP); i++) { _snd_prop volume = {NULL, NULL, NULL, 1.0, 0.0, 0.0, 0.0, false}; if (strcmp(kids[i]->getStringValue("property"), "")) @@ -186,7 +186,7 @@ SGSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr, // float p = 0.0; kids = node->getChildren("pitch"); - for (i = 0; (i < kids.size()) && (i < SGSound::MAXPROP); i++) { + for (i = 0; (i < kids.size()) && (i < SGXmlSound::MAXPROP); i++) { _snd_prop pitch = {NULL, NULL, NULL, 1.0, 1.0, 0.0, 0.0, false}; if (strcmp(kids[i]->getStringValue("property", ""), "")) @@ -237,15 +237,18 @@ SGSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr, // Initialize the sample // _mgr = sndmgr; - if ((_sample = _mgr->find(_name)) == NULL) - _sample = _mgr->add(_name, path.c_str(), node->getStringValue("path", "")); + if ( (_sample = _mgr->find(_name)) == NULL ) { + _sample = new SGSoundSample( path.c_str(), + node->getStringValue("path", "") ); + _mgr->add( _sample, _name ); + } _sample->set_volume(v); _sample->set_pitch(p); } void -SGSound::update (double dt) +SGXmlSound::update (double dt) { double curr_value = 0.0; @@ -260,17 +263,17 @@ SGSound::update (double dt) (!_condition && _property && ( !curr_value || - ( (_mode == SGSound::IN_TRANSIT) && (curr_value == _prev_value) ) + ( (_mode == SGXmlSound::IN_TRANSIT) && (curr_value == _prev_value) ) ) ) ) { - if ((_mode != SGSound::IN_TRANSIT) || (_stopping > MAX_TRANSIT_TIME)) { + if ((_mode != SGXmlSound::IN_TRANSIT) || (_stopping > MAX_TRANSIT_TIME)) { if (_sample->is_playing()) { SG_LOG(SG_GENERAL, SG_INFO, "Stopping audio after " << _dt_play << " sec: " << _name ); - _sample->stop( _mgr->get_scheduler() ); + _sample->stop(); } _active = false; @@ -287,7 +290,7 @@ SGSound::update (double dt) // If the mode is ONCE and the sound is still playing, // we have nothing to do anymore. // - if (_active && (_mode == SGSound::ONCE)) { + if (_active && (_mode == SGXmlSound::ONCE)) { if (!_sample->is_playing()) { _dt_stop += dt; @@ -392,11 +395,11 @@ SGSound::update (double dt) // if (!_active) { - if (_mode == SGSound::ONCE) - _sample->play(_mgr->get_scheduler(), false); + if (_mode == SGXmlSound::ONCE) + _sample->play(false); else - _sample->play(_mgr->get_scheduler(), true); + _sample->play(true); SG_LOG(SG_GENERAL, SG_INFO, "Playing audio after " << _dt_stop << " sec: " << _name); diff --git a/simgear/sound/sound.hxx b/simgear/sound/xmlsound.hxx similarity index 96% rename from simgear/sound/sound.hxx rename to simgear/sound/xmlsound.hxx index 48888b0a..e290b393 100644 --- a/simgear/sound/sound.hxx +++ b/simgear/sound/xmlsound.hxx @@ -36,7 +36,8 @@ #include #include -#include "soundmgr.hxx" +#include "sample_openal.hxx" +#include "soundmgr_openal.hxx" static const double MAX_TRANSIT_TIME = 0.1; // 100 ms. @@ -49,13 +50,13 @@ static const double MAX_TRANSIT_TIME = 0.1; // 100 ms. * settings, setting up its internal states, and managing sound * playback whenever such an event happens. */ -class SGSound +class SGXmlSound { public: - SGSound(); - virtual ~SGSound(); + SGXmlSound(); + virtual ~SGXmlSound(); /** * Initialize the sound event. @@ -117,7 +118,7 @@ protected: enum { ONCE=0, LOOPED, IN_TRANSIT }; enum { LEVEL=0, INVERTED, FLIPFLOP }; - // SGSound properties + // SGXmlSound properties typedef struct { SGPropertyNode * prop; double (*fn)(double); @@ -132,7 +133,7 @@ protected: private: SGSoundMgr * _mgr; - SGSimpleSound * _sample; + SGSoundSample * _sample; SGCondition * _condition; SGPropertyNode * _property; -- 2.39.5