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 - curt@flightgear.org
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., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <simgear/compiler.h>
28 #if defined(__APPLE__)
29 # include <OpenAL/al.h>
30 # include <OpenAL/alut.h>
31 # include <OpenAL/alc.h>
38 #if defined (__APPLE__)
39 // any C++ header file undefines isinf and isnan
40 // so this should be included before <iostream>
41 inline int (isinf)(double r) { return isinf(r); }
42 inline int (isnan)(double r) { return isnan(r); }
45 #if defined(__MINGW32__)
46 #define isnan(x) _isnan(x)
51 #include <simgear/debug/logstream.hxx>
52 #include <simgear/misc/sg_path.hxx>
54 #include "soundmgr_openal.hxx"
62 SGSoundMgr::SGSoundMgr() {
64 SG_LOG( SG_GENERAL, SG_ALERT, "Initializing OpenAL sound manager" );
69 if ( alGetError() == AL_NO_ERROR) {
73 SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" );
76 listener_pos[0] = 0.0;
77 listener_pos[1] = 0.0;
78 listener_pos[2] = 0.0;
80 listener_vel[0] = 0.0;
81 listener_vel[1] = 0.0;
82 listener_vel[2] = 0.0;
84 listener_ori[0] = 0.0;
85 listener_ori[1] = 0.0;
86 listener_ori[2] = -1.0;
87 listener_ori[3] = 0.0;
88 listener_ori[4] = 1.0;
89 listener_ori[5] = 0.0;
91 alListenerfv( AL_POSITION, listener_pos );
92 alListenerfv( AL_VELOCITY, listener_vel );
93 alListenerfv( AL_ORIENTATION, listener_ori );
95 if ( alGetError() != AL_NO_ERROR) {
96 SG_LOG( SG_GENERAL, SG_ALERT,
97 "Oops AL error after audio initialization!" );
100 // exaggerate the ear candy?
101 alDopplerFactor(1.0);
102 alDopplerVelocity(340.0); // speed of sound in meters per second.
107 SGSoundMgr::~SGSoundMgr() {
110 // Remove the samples from the sample manager.
112 sample_map_iterator sample_current = samples.begin();
113 sample_map_iterator sample_end = samples.end();
114 for ( ; sample_current != sample_end; ++sample_current ) {
115 SGSoundSample *sample = sample_current->second;
123 // initialize the sound manager
124 void SGSoundMgr::init() {
126 // Remove the samples from the sample manager.
128 sample_map_iterator sample_current = samples.begin();
129 sample_map_iterator sample_end = samples.end();
130 for ( ; sample_current != sample_end; ++sample_current ) {
131 SGSoundSample *sample = sample_current->second;
138 void SGSoundMgr::bind ()
144 void SGSoundMgr::unbind ()
150 // run the audio scheduler
151 void SGSoundMgr::update( double dt ) {
158 ALCcontext *pCurContext = alcGetCurrentContext();
159 alcSuspendContext( pCurContext );
160 if ( alGetError() != AL_NO_ERROR) {
161 SG_LOG( SG_GENERAL, SG_ALERT,
162 "Oops AL error after soundmgr pause()!" );
168 SGSoundMgr::resume ()
170 ALCcontext *pCurContext = alcGetCurrentContext();
171 alcProcessContext( pCurContext );
172 if ( alGetError() != AL_NO_ERROR) {
173 SG_LOG( SG_GENERAL, SG_ALERT,
174 "Oops AL error after soundmgr resume()!" );
179 // add a sound effect, return true if successful
180 bool SGSoundMgr::add( SGSoundSample *sound, const string& refname ) {
182 sample_map_iterator sample_it = samples.find( refname );
183 if ( sample_it != samples.end() ) {
184 // sound already exists
188 samples[refname] = sound;
194 // remove a sound effect, return true if successful
195 bool SGSoundMgr::remove( const string &refname ) {
197 sample_map_iterator sample_it = samples.find( refname );
198 if ( sample_it != samples.end() ) {
199 // first stop the sound from playing (so we don't bomb the
201 SGSoundSample *sample = sample_it->second;
203 samples.erase( sample_it );
205 // cout << "sndmgr: removed -> " << refname << endl;
208 // cout << "sndmgr: failed remove -> " << refname << endl;
214 // return true of the specified sound exists in the sound manager system
215 bool SGSoundMgr::exists( const string &refname ) {
216 sample_map_iterator sample_it = samples.find( refname );
217 if ( sample_it != samples.end() ) {
225 // return a pointer to the SGSoundSample if the specified sound exists
226 // in the sound manager system, otherwise return NULL
227 SGSoundSample *SGSoundMgr::find( const string &refname ) {
228 sample_map_iterator sample_it = samples.find( refname );
229 if ( sample_it != samples.end() ) {
230 return sample_it->second;
237 // tell the scheduler to play the indexed sample in a continuous
239 bool SGSoundMgr::play_looped( const string &refname ) {
240 SGSoundSample *sample;
242 if ( (sample = find( refname )) == NULL ) {
245 sample->play( true );
251 // tell the scheduler to play the indexed sample once
252 bool SGSoundMgr::play_once( const string& refname ) {
253 SGSoundSample *sample;
255 if ( (sample = find( refname )) == NULL ) {
258 sample->play( false );
264 // return true of the specified sound is currently being played
265 bool SGSoundMgr::is_playing( const string& refname ) {
266 SGSoundSample *sample;
268 if ( (sample = find( refname )) == NULL ) {
271 return ( sample->is_playing() );
276 // immediate stop playing the sound
277 bool SGSoundMgr::stop( const string& refname ) {
278 SGSoundSample *sample;
280 if ( (sample = find( refname )) == NULL ) {
289 // set source position of all managed sounds
290 void SGSoundMgr::set_source_pos_all( ALfloat *pos ) {
291 if ( isnan(pos[0]) || isnan(pos[1]) || isnan(pos[2]) ) {
292 // bail if a bad position is passed in
296 sample_map_iterator sample_current = samples.begin();
297 sample_map_iterator sample_end = samples.end();
298 for ( ; sample_current != sample_end; ++sample_current ) {
299 SGSoundSample *sample = sample_current->second;
300 sample->set_source_pos( pos );
305 // set source velocity of all managed sounds
306 void SGSoundMgr::set_source_vel_all( ALfloat *vel ) {
307 if ( isnan(vel[0]) || isnan(vel[1]) || isnan(vel[2]) ) {
308 // bail if a bad velocity is passed in
312 sample_map_iterator sample_current = samples.begin();
313 sample_map_iterator sample_end = samples.end();
314 for ( ; sample_current != sample_end; ++sample_current ) {
315 SGSoundSample *sample = sample_current->second;
316 sample->set_source_vel( vel );