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