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