1 // soundmgr.cxx -- Sound effect management class
3 // Sound manager initially written by David Findlay
4 // <david_j_findlay@yahoo.com.au> 2001
6 // C++-ified by Curtis Olson, started March 2001.
8 // Copyright (C) 2001 Curtis L. Olson - http://www.flightgear.org/~curt
10 // This program is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU General Public License as
12 // published by the Free Software Foundation; either version 2 of the
13 // License, or (at your option) any later version.
15 // This program is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // General Public License for more details.
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 # include <simgear_config.h>
30 #include <simgear/compiler.h>
32 #if defined(__APPLE__)
33 # include <OpenAL/al.h>
34 # include <OpenAL/alc.h>
40 #if defined (__APPLE__)
42 # if ( __GNUC__ >= 3 ) && ( __GNUC_MINOR__ >= 3 )
44 inline int (isnan)(double r) { return !(r <= 0 || r >= 0); }
46 // any C++ header file undefines isinf and isnan
47 // so this should be included before <iostream>
48 // the functions are STILL in libm (libSystem on mac os x)
49 extern "C" int isnan (double);
50 extern "C" int isinf (double);
53 // inline int (isinf)(double r) { return isinf(r); }
54 // inline int (isnan)(double r) { return isnan(r); }
58 #if defined (__FreeBSD__)
59 # if __FreeBSD_version < 500000
61 inline int isnan(double r) { return !(r <= 0 || r >= 0); }
66 #if defined (__CYGWIN__)
73 #include <simgear/debug/logstream.hxx>
74 #include <simgear/misc/sg_path.hxx>
76 #include "soundmgr_openal.hxx"
78 #if defined(__MINGW32__)
79 #define isnan(x) _isnan(x)
87 SGSoundMgr::SGSoundMgr() {
89 SG_LOG( SG_GENERAL, SG_INFO, "Initializing OpenAL sound manager" );
92 #if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
93 if (!alutInit(NULL, NULL))
95 ALenum error = alutGetError ();
96 SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" );
97 SG_LOG( SG_GENERAL, SG_ALERT, " "+string(alutGetErrorString(error)));
104 context = alcGetCurrentContext();
107 if ( (dev = alcOpenDevice( NULL )) != NULL
108 && ( context = alcCreateContext( dev, NULL )) != NULL ) {
110 alcMakeContextCurrent( context );
114 SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" );
118 listener_pos[0] = 0.0;
119 listener_pos[1] = 0.0;
120 listener_pos[2] = 0.0;
122 listener_vel[0] = 0.0;
123 listener_vel[1] = 0.0;
124 listener_vel[2] = 0.0;
126 listener_ori[0] = 0.0;
127 listener_ori[1] = 0.0;
128 listener_ori[2] = -1.0;
129 listener_ori[3] = 0.0;
130 listener_ori[4] = 1.0;
131 listener_ori[5] = 0.0;
133 alListenerf( AL_GAIN, 0.0f );
134 alListenerfv( AL_POSITION, listener_pos );
135 alListenerfv( AL_VELOCITY, listener_vel );
136 alListenerfv( AL_ORIENTATION, listener_ori );
138 if ( alGetError() != AL_NO_ERROR) {
139 SG_LOG( SG_GENERAL, SG_ALERT,
140 "Oops AL error after audio initialization!" );
143 // exaggerate the ear candy?
144 alDopplerFactor(1.0);
145 alDopplerVelocity(340.0); // speed of sound in meters per second.
150 SGSoundMgr::~SGSoundMgr() {
152 #if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
156 alcDestroyContext( context );
161 // initialize the sound manager
162 void SGSoundMgr::init() {
164 // Remove the samples from the sample manager.
170 void SGSoundMgr::bind ()
176 void SGSoundMgr::unbind ()
182 // run the audio scheduler
183 void SGSoundMgr::update( double dt ) {
191 alcSuspendContext( context );
192 if ( alGetError() != AL_NO_ERROR) {
193 SG_LOG( SG_GENERAL, SG_ALERT,
194 "Oops AL error after soundmgr pause()!" );
201 SGSoundMgr::resume ()
204 alcProcessContext( context );
205 if ( alGetError() != AL_NO_ERROR) {
206 SG_LOG( SG_GENERAL, SG_ALERT,
207 "Oops AL error after soundmgr resume()!" );
213 // add a sound effect, return true if successful
214 bool SGSoundMgr::add( SGSoundSample *sound, const string& refname ) {
216 sample_map_iterator sample_it = samples.find( refname );
217 if ( sample_it != samples.end() ) {
218 // sound already exists
222 samples[refname] = sound;
228 // remove a sound effect, return true if successful
229 bool SGSoundMgr::remove( const string &refname ) {
231 sample_map_iterator sample_it = samples.find( refname );
232 if ( sample_it != samples.end() ) {
233 // first stop the sound from playing (so we don't bomb the
235 samples.erase( sample_it );
237 // cout << "sndmgr: removed -> " << refname << endl;
240 // cout << "sndmgr: failed remove -> " << refname << endl;
246 // return true of the specified sound exists in the sound manager system
247 bool SGSoundMgr::exists( const string &refname ) {
248 sample_map_iterator sample_it = samples.find( refname );
249 if ( sample_it != samples.end() ) {
257 // return a pointer to the SGSoundSample if the specified sound exists
258 // in the sound manager system, otherwise return NULL
259 SGSoundSample *SGSoundMgr::find( const string &refname ) {
260 sample_map_iterator sample_it = samples.find( refname );
261 if ( sample_it != samples.end() ) {
262 return sample_it->second;
269 // tell the scheduler to play the indexed sample in a continuous
271 bool SGSoundMgr::play_looped( const string &refname ) {
272 SGSoundSample *sample;
274 if ( (sample = find( refname )) == NULL ) {
277 sample->play( true );
283 // tell the scheduler to play the indexed sample once
284 bool SGSoundMgr::play_once( const string& refname ) {
285 SGSoundSample *sample;
287 if ( (sample = find( refname )) == NULL ) {
290 sample->play( false );
296 // return true of the specified sound is currently being played
297 bool SGSoundMgr::is_playing( const string& refname ) {
298 SGSoundSample *sample;
300 if ( (sample = find( refname )) == NULL ) {
303 return ( sample->is_playing() );
308 // immediate stop playing the sound
309 bool SGSoundMgr::stop( const string& refname ) {
310 SGSoundSample *sample;
312 if ( (sample = find( refname )) == NULL ) {
321 // set source position of all managed sounds
322 void SGSoundMgr::set_source_pos_all( ALfloat *pos ) {
323 if ( isnan(pos[0]) || isnan(pos[1]) || isnan(pos[2]) ) {
324 // bail if a bad position is passed in
328 sample_map_iterator sample_current = samples.begin();
329 sample_map_iterator sample_end = samples.end();
330 for ( ; sample_current != sample_end; ++sample_current ) {
331 SGSoundSample *sample = sample_current->second;
332 sample->set_source_pos( pos );
337 // set source velocity of all managed sounds
338 void SGSoundMgr::set_source_vel_all( ALfloat *vel ) {
339 if ( isnan(vel[0]) || isnan(vel[1]) || isnan(vel[2]) ) {
340 // bail if a bad velocity is passed in
344 sample_map_iterator sample_current = samples.begin();
345 sample_map_iterator sample_end = samples.end();
346 for ( ; sample_current != sample_end; ++sample_current ) {
347 SGSoundSample *sample = sample_current->second;
348 sample->set_source_vel( vel, listener_vel );