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