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