]> git.mxchange.org Git - simgear.git/blob - simgear/sound/soundmgr_openal.cxx
Pigeons remaining fix for the soundmanager crashes.
[simgear.git] / simgear / sound / soundmgr_openal.cxx
1 // soundmgr.cxx -- Sound effect management class
2 //
3 // Sound manager initially written by David Findlay
4 // <david_j_findlay@yahoo.com.au> 2001
5 //
6 // C++-ified by Curtis Olson, started March 2001.
7 //
8 // Copyright (C) 2001  Curtis L. Olson - http://www.flightgear.org/~curt
9 //
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.
14 //
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.
19 //
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.
23 //
24 // $Id$
25
26 #ifdef HAVE_CONFIG_H
27 #  include <simgear_config.h>
28 #endif
29
30 #include <simgear/compiler.h>
31
32 #if defined(__APPLE__)
33 # include <OpenAL/al.h>
34 # include <OpenAL/alc.h>
35 #else
36 # include <AL/al.h>
37 # include <AL/alc.h>
38 #endif
39
40 #if defined (__APPLE__)
41 #  ifdef __GNUC__
42 #    if ( __GNUC__ >= 3 ) && ( __GNUC_MINOR__ >= 3 )
43 //  #        include <math.h>
44 inline int (isnan)(double r) { return !(r <= 0 || r >= 0); }
45 #    else
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);
51 #    endif
52 #  else
53 //    inline int (isinf)(double r) { return isinf(r); }
54 //    inline int (isnan)(double r) { return isnan(r); }
55 #  endif
56 #endif
57
58 #if defined (__FreeBSD__)
59 #  if __FreeBSD_version < 500000
60      extern "C" {
61        inline int isnan(double r) { return !(r <= 0 || r >= 0); }
62      }
63 #  endif
64 #endif
65
66 #include STL_IOSTREAM
67
68 #include <simgear/debug/logstream.hxx>
69 #include <simgear/misc/sg_path.hxx>
70
71 #include "soundmgr_openal.hxx"
72
73 #if defined(__MINGW32__)
74 #define isnan(x) _isnan(x)
75 #endif
76
77 //
78 // Sound Manager
79 //
80
81 // constructor
82 SGSoundMgr::SGSoundMgr() {
83
84     SG_LOG( SG_GENERAL, SG_INFO, "Initializing OpenAL sound manager" );
85
86     // initialize OpenAL
87 #if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
88     if (!alutInit(NULL, NULL))
89     {
90         ALenum error = alutGetError ();
91         SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" );
92         SG_LOG( SG_GENERAL, SG_ALERT, "   "+string(alutGetErrorString(error)));
93         working = false;
94         context = 0;
95     }
96     else
97     {
98         working = true;
99         context = alcGetCurrentContext();
100     }
101 #else
102     if ( (dev = alcOpenDevice( NULL )) != NULL
103             && ( context = alcCreateContext( dev, NULL )) != NULL ) {
104         working = true;
105         alcMakeContextCurrent( context );
106     } else {
107         working = false;
108         context = 0;
109         SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" );
110     }
111 #endif
112
113     listener_pos[0] = 0.0;
114     listener_pos[1] = 0.0;
115     listener_pos[2] = 0.0;
116
117     listener_vel[0] = 0.0;
118     listener_vel[1] = 0.0;
119     listener_vel[2] = 0.0;
120     
121     listener_ori[0] = 0.0;
122     listener_ori[1] = 0.0;
123     listener_ori[2] = -1.0;
124     listener_ori[3] = 0.0;
125     listener_ori[4] = 1.0;
126     listener_ori[5] = 0.0;
127
128     alListenerf( AL_GAIN, 0.0f );
129     alListenerfv( AL_POSITION, listener_pos );
130     alListenerfv( AL_VELOCITY, listener_vel );
131     alListenerfv( AL_ORIENTATION, listener_ori );
132     alGetError();
133     if ( alGetError() != AL_NO_ERROR) {
134         SG_LOG( SG_GENERAL, SG_ALERT,
135                 "Oops AL error after audio initialization!" );
136     }
137
138     // exaggerate the ear candy?
139     alDopplerFactor(1.0);
140     alDopplerVelocity(340.0);   // speed of sound in meters per second.
141 }
142
143 // destructor
144
145 SGSoundMgr::~SGSoundMgr() {
146
147 #if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
148     alutExit ();
149 #else
150     if (context)
151         alcDestroyContext( context );
152 #endif
153 }
154
155
156 // initialize the sound manager
157 void SGSoundMgr::init() {
158     //
159     // Remove the samples from the sample manager.
160     //
161     samples.clear();
162 }
163
164
165 void SGSoundMgr::bind ()
166 {
167     // no properties
168 }
169
170
171 void SGSoundMgr::unbind ()
172 {
173     // no properties
174 }
175
176
177 // run the audio scheduler
178 void SGSoundMgr::update( double dt ) {
179 }
180
181
182 void
183 SGSoundMgr::pause ()
184 {
185     if (context) {
186         alcSuspendContext( context );
187         if ( alGetError() != AL_NO_ERROR) {
188             SG_LOG( SG_GENERAL, SG_ALERT,
189                     "Oops AL error after soundmgr pause()!" );
190         }
191     }
192 }
193
194
195 void
196 SGSoundMgr::resume ()
197 {
198     if (context) {
199         alcProcessContext( context );
200         if ( alGetError() != AL_NO_ERROR) {
201             SG_LOG( SG_GENERAL, SG_ALERT,
202                     "Oops AL error after soundmgr resume()!" );
203         }
204     }
205 }
206
207
208 // add a sound effect, return true if successful
209 bool SGSoundMgr::add( SGSoundSample *sound, const string& refname ) {
210
211     sample_map_iterator sample_it = samples.find( refname );
212     if ( sample_it != samples.end() ) {
213         // sound already exists
214         return false;
215     }
216
217     samples[refname] = sound;
218
219     return true;
220 }
221
222
223 // remove a sound effect, return true if successful
224 bool SGSoundMgr::remove( const string &refname ) {
225
226     sample_map_iterator sample_it = samples.find( refname );
227     if ( sample_it != samples.end() ) {
228         // first stop the sound from playing (so we don't bomb the
229         // audio scheduler)
230         samples.erase( sample_it );
231
232         // cout << "sndmgr: removed -> " << refname << endl;
233         return true;
234     } else {
235         // cout << "sndmgr: failed remove -> " << refname << endl;
236         return false;
237     }
238 }
239
240
241 // return true of the specified sound exists in the sound manager system
242 bool SGSoundMgr::exists( const string &refname ) {
243     sample_map_iterator sample_it = samples.find( refname );
244     if ( sample_it != samples.end() ) {
245         return true;
246     } else {
247         return false;
248     }
249 }
250
251
252 // return a pointer to the SGSoundSample if the specified sound exists
253 // in the sound manager system, otherwise return NULL
254 SGSoundSample *SGSoundMgr::find( const string &refname ) {
255     sample_map_iterator sample_it = samples.find( refname );
256     if ( sample_it != samples.end() ) {
257         return sample_it->second;
258     } else {
259         return NULL;
260     }
261 }
262
263
264 // tell the scheduler to play the indexed sample in a continuous
265 // loop
266 bool SGSoundMgr::play_looped( const string &refname ) {
267     SGSoundSample *sample;
268
269     if ( (sample = find( refname )) == NULL ) {
270         return false;
271     } else {
272         sample->play( true );
273         return true;
274     }
275 }
276
277
278 // tell the scheduler to play the indexed sample once
279 bool SGSoundMgr::play_once( const string& refname ) {
280     SGSoundSample *sample;
281
282     if ( (sample = find( refname )) == NULL ) {
283         return false;
284     } else {
285         sample->play( false );
286         return true;
287     }
288 }
289
290
291 // return true of the specified sound is currently being played
292 bool SGSoundMgr::is_playing( const string& refname ) {
293     SGSoundSample *sample;
294
295     if ( (sample = find( refname )) == NULL ) {
296         return false;
297     } else {
298         return ( sample->is_playing() );
299     }
300 }
301
302
303 // immediate stop playing the sound
304 bool SGSoundMgr::stop( const string& refname ) {
305     SGSoundSample *sample;
306
307     if ( (sample = find( refname )) == NULL ) {
308         return false;
309     } else {
310         sample->stop();
311         return true;
312     }
313 }
314
315
316 // set source position of all managed sounds
317 void SGSoundMgr::set_source_pos_all( ALfloat *pos ) {
318     if ( isnan(pos[0]) || isnan(pos[1]) || isnan(pos[2]) ) {
319         // bail if a bad position is passed in
320         return;
321     }
322
323     sample_map_iterator sample_current = samples.begin();
324     sample_map_iterator sample_end = samples.end();
325     for ( ; sample_current != sample_end; ++sample_current ) {
326         SGSoundSample *sample = sample_current->second;
327         sample->set_source_pos( pos );
328     }
329 }
330
331
332 // set source velocity of all managed sounds
333 void SGSoundMgr::set_source_vel_all( ALfloat *vel ) {
334     if ( isnan(vel[0]) || isnan(vel[1]) || isnan(vel[2]) ) {
335         // bail if a bad velocity is passed in
336         return;
337     }
338
339     sample_map_iterator sample_current = samples.begin();
340     sample_map_iterator sample_end = samples.end();
341     for ( ; sample_current != sample_end; ++sample_current ) {
342         SGSoundSample *sample = sample_current->second;
343         sample->set_source_vel( vel );
344     }
345 }