]> git.mxchange.org Git - simgear.git/blob - simgear/sound/sample_group.cxx
c85e386f44e213223bedfdb257f94db950a4cf05
[simgear.git] / simgear / sound / sample_group.cxx
1 #ifdef HAVE_CONFIG_H
2 #  include <simgear_config.h>
3 #endif
4
5 #include <simgear/compiler.h>
6
7 #if defined (__APPLE__)
8 #  ifdef __GNUC__
9 #    if ( __GNUC__ >= 3 ) && ( __GNUC_MINOR__ >= 3 )
10 //  #        include <math.h>
11 inline int (isnan)(double r) { return !(r <= 0 || r >= 0); }
12 #    else
13     // any C++ header file undefines isinf and isnan
14     // so this should be included before <iostream>
15     // the functions are STILL in libm (libSystem on mac os x)
16 extern "C" int isnan (double);
17 extern "C" int isinf (double);
18 #    endif
19 #  else
20 //    inline int (isinf)(double r) { return isinf(r); }
21 //    inline int (isnan)(double r) { return isnan(r); }
22 #  endif
23 #endif
24
25 #if defined (__FreeBSD__)
26 #  if __FreeBSD_version < 500000
27      extern "C" {
28        inline int isnan(double r) { return !(r <= 0 || r >= 0); }
29      }
30 #  endif
31 #endif
32
33 #if defined (__CYGWIN__)
34 #  include <ieeefp.h>
35 #endif
36
37 #if defined(__MINGW32__)
38 #  define isnan(x) _isnan(x)
39 #endif
40
41 #include "soundmgr_openal.hxx"
42 #include "sample_group.hxx"
43
44 SGSampleGroup::SGSampleGroup () :
45     _smgr(NULL),
46     _refname(""),
47     _active(false),
48     _tied_to_listener(false),
49     _velocity(SGVec3d::zeros()),
50     _position(SGGeod()),
51     _orientation(SGQuatd::zeros())
52 {
53     _samples.clear();
54 }
55
56 SGSampleGroup::SGSampleGroup ( SGSoundMgr *smgr, const string &refname ) :
57     _smgr(smgr),
58     _refname(refname),
59     _active(false), 
60     _tied_to_listener(false),
61     _velocity(SGVec3d::zeros()),
62     _position(SGGeod()),
63     _orientation(SGQuatd::zeros())
64 {
65     _smgr->add(this, refname);
66     _active = _smgr->is_working();
67     _samples.clear();
68 }
69
70 SGSampleGroup::~SGSampleGroup ()
71 {
72     _active = false;
73
74     sample_map_iterator sample_current = _samples.begin();
75     sample_map_iterator sample_end = _samples.end();
76     for ( ; sample_current != sample_end; ++sample_current ) {
77         SGSoundSample *sample = sample_current->second;
78
79         if ( sample->is_valid_source() && sample->is_playing() ) {
80             sample->no_valid_source();
81             _smgr->release_source( sample->get_source() );
82             _smgr->release_buffer( sample );
83         }
84     }
85
86     _smgr = 0;
87 }
88
89 void SGSampleGroup::update( double dt ) {
90
91     if ( !_active ) return;
92
93     // testForALError("start of update!!\n");
94
95     sample_map_iterator sample_current = _samples.begin();
96     sample_map_iterator sample_end = _samples.end();
97     for ( ; sample_current != sample_end; ++sample_current ) {
98         SGSoundSample *sample = sample_current->second;
99
100         if ( !sample->is_valid_source() && sample->is_playing() ) {
101             //
102             // a request to start playing a sound has been filed.
103             //
104             if ( _smgr->request_buffer(sample) == SGSoundMgr::NO_BUFFER )
105                 continue;
106
107             // start playing the sample
108             ALboolean looping = sample->get_looping() ? AL_TRUE : AL_FALSE;
109             ALuint buffer = sample->get_buffer();
110             ALuint source = _smgr->request_source();
111             if (alIsSource(source) == AL_TRUE && alIsBuffer(buffer) == AL_TRUE)
112             {
113                 sample->set_source( source );
114                 
115                 alSourcei( source, AL_BUFFER, buffer );
116                 testForALError("assign buffer to source");
117
118                 sample->set_source( source );
119                 update_sample_config( sample );
120
121                 alSourcei( source, AL_SOURCE_RELATIVE, AL_FALSE );
122                 alSourcei( source, AL_LOOPING, looping );
123                 alSourcef( source, AL_ROLLOFF_FACTOR, 1.2 );
124                 alSourcePlay( source );
125                 testForALError("sample play");
126             } else {
127                 if (alIsBuffer(buffer) == AL_FALSE) 
128                    SG_LOG( SG_GENERAL, SG_ALERT, "No such buffer!\n");
129                 // sample->no_valid_source();
130                 // sadly, no free source available at this time
131             }
132
133         } else if ( sample->is_valid_source() && sample->has_changed() ) {
134             if ( !sample->is_playing() ) {
135                 // a request to stop playing the sound has been filed.
136
137                 sample->no_valid_source();
138                 sample->stop();
139                 _smgr->release_source( sample->get_source() );
140             } else  {
141                 update_sample_config( sample );
142             }
143
144         } else if ( sample->is_valid_source() ) {
145             // check if the sound has stopped by itself
146
147             unsigned int source = sample->get_source();
148             int result;
149
150             alGetSourcei( source, AL_SOURCE_STATE, &result );
151             if ( result == AL_STOPPED ) {
152                 // sample is stoped because it wasn't looping
153                 sample->no_valid_source();
154                 sample->stop();
155                 _smgr->release_source( source );
156             }
157         }
158         testForALError("update");
159     }
160 }
161
162 // add a sound effect, return true if successful
163 bool SGSampleGroup::add( SGSoundSample *sound, const string& refname ) {
164
165     sample_map_iterator sample_it = _samples.find( refname );
166     if ( sample_it != _samples.end() ) {
167         // sample name already exists
168         return false;
169     }
170
171     _samples[refname] = sound;
172     return true;
173 }
174
175
176 // remove a sound effect, return true if successful
177 bool SGSampleGroup::remove( const string &refname ) {
178
179     sample_map_iterator sample_it = _samples.find( refname );
180     if ( sample_it == _samples.end() ) {
181         // sample was not found
182         return false;
183     }
184
185     // remove the sources buffer
186     _smgr->release_buffer( sample_it->second );
187     _samples.erase( refname );
188
189     return true;
190 }
191
192
193 // return true of the specified sound exists in the sound manager system
194 bool SGSampleGroup::exists( const string &refname ) {
195     sample_map_iterator sample_it = _samples.find( refname );
196     if ( sample_it == _samples.end() ) {
197         // sample was not found
198         return false;
199     }
200
201     return true;
202 }
203
204
205 // return a pointer to the SGSoundSample if the specified sound exists
206 // in the sound manager system, otherwise return NULL
207 SGSoundSample *SGSampleGroup::find( const string &refname ) {
208     sample_map_iterator sample_it = _samples.find( refname );
209     if ( sample_it == _samples.end() ) {
210         // sample was not found
211         return NULL;
212     }
213
214     return sample_it->second;
215 }
216
217
218 // stop playing all associated samples
219 void
220 SGSampleGroup::suspend ()
221 {
222     _active = false;
223     sample_map_iterator sample_current = _samples.begin();
224     sample_map_iterator sample_end = _samples.end();
225     for ( ; sample_current != sample_end; ++sample_current ) {
226         SGSoundSample *sample = sample_current->second;
227
228         if ( sample->is_valid_source() && sample->is_playing() ) {
229             unsigned int source = sample->get_source();
230             alSourcePause( source );
231         }
232     }
233     testForALError("suspend");
234 }
235
236 // resume playing all associated samples
237 void
238 SGSampleGroup::resume ()
239 {
240     sample_map_iterator sample_current = _samples.begin();
241     sample_map_iterator sample_end = _samples.end();
242     for ( ; sample_current != sample_end; ++sample_current ) {
243         SGSoundSample *sample = sample_current->second;
244
245         if ( sample->is_valid_source() && sample->is_playing() ) {
246             unsigned int source = sample->get_source();
247             alSourcePlay( source );
248         }
249     }
250     testForALError("resume");
251     _active = true;
252 }
253
254
255 // tell the scheduler to play the indexed sample in a continuous loop
256 bool SGSampleGroup::play( const string &refname, bool looping = false ) {
257     SGSoundSample *sample = find( refname );
258
259     if ( sample == NULL ) {
260         return false;
261     }
262
263     sample->play( looping );
264     return true;
265 }
266
267
268 // return true of the specified sound is currently being played
269 bool SGSampleGroup::is_playing( const string& refname ) {
270     SGSoundSample *sample = find( refname );
271
272     if ( sample == NULL ) {
273         return false;
274     }
275
276     return ( sample->is_playing() ) ? true : false;
277 }
278
279 // immediate stop playing the sound
280 bool SGSampleGroup::stop( const string& refname ) {
281     SGSoundSample *sample  = find( refname );
282
283     if ( sample == NULL ) {
284         return false;
285     }
286
287     sample->stop();
288     return true;
289 }
290
291 // set source velocity of all managed sounds
292 void SGSampleGroup::set_velocity( SGVec3d &vel ) {
293     if ( isnan(vel[0]) || isnan(vel[1]) || isnan(vel[2]) )
294     {
295         SG_LOG( SG_GENERAL, SG_ALERT, "NAN's found in SampleGroup velocity");
296         return;
297     }
298
299     if (_velocity != vel) {
300         sample_map_iterator sample_current = _samples.begin();
301         sample_map_iterator sample_end = _samples.end();
302         for ( ; sample_current != sample_end; ++sample_current ) {
303             SGSoundSample *sample = sample_current->second;
304             sample->set_velocity( vel );
305         }
306         _velocity = vel;
307     }
308 }
309
310 // ste the source orientation of all managed sounds
311 void SGSampleGroup::set_position( SGGeod pos ) {
312
313     sample_map_iterator sample_current = _samples.begin();
314     sample_map_iterator sample_end = _samples.end();
315     for ( ; sample_current != sample_end; ++sample_current ) {
316         SGSoundSample *sample = sample_current->second;
317         sample->set_position( pos );
318     }
319     _position = pos;
320 }
321
322
323 // ste the source orientation of all managed sounds
324 void SGSampleGroup::set_orientation( SGQuatd ori ) {
325
326     if (_orientation != ori) {
327         sample_map_iterator sample_current = _samples.begin();
328         sample_map_iterator sample_end = _samples.end();
329         for ( ; sample_current != sample_end; ++sample_current ) {
330             SGSoundSample *sample = sample_current->second;
331             sample->set_orientation( ori );
332         }
333         _orientation = ori;
334     }
335 }
336
337 void SGSampleGroup::set_volume( float vol )
338 {
339     _volume = vol;
340     if (_volume < 0.0) _volume = 0.0;
341     if (_volume > 1.0) _volume = 1.0;
342
343     sample_map_iterator sample_current = _samples.begin();
344     sample_map_iterator sample_end = _samples.end();
345     for ( ; sample_current != sample_end; ++sample_current ) {
346         SGSoundSample *sample = sample_current->second;
347         sample->set_master_volume( _volume );
348     }
349 }
350
351 void SGSampleGroup::update_sample_config( SGSoundSample *sample ) {
352     if ( sample->is_valid_source() ) {
353         unsigned int source = sample->get_source();
354
355         if ( _tied_to_listener && _smgr->has_changed() ) {
356             alSourcefv( source, AL_POSITION, _smgr->get_position().data() );
357             alSourcefv( source, AL_DIRECTION, _smgr->get_direction().data() );
358             alSourcefv( source, AL_VELOCITY, _smgr->get_velocity().data() );
359         } else {
360             alSourcefv( source, AL_POSITION, sample->get_position());
361             alSourcefv( source, AL_DIRECTION, sample->get_orientation() );
362             alSourcefv( source, AL_VELOCITY, sample->get_velocity() );
363         }
364         testForALError("position and orientation");
365
366         alSourcef( source, AL_PITCH, sample->get_pitch() );
367         alSourcef( source, AL_GAIN, sample->get_volume() );
368         testForALError("pitch and gain");
369
370         if ( sample->has_static_data_changed() ) {
371             alSourcef( source, AL_CONE_INNER_ANGLE, sample->get_innerangle() );
372             alSourcef( source, AL_CONE_OUTER_ANGLE, sample->get_outerangle() );
373             alSourcef( source, AL_CONE_OUTER_GAIN, sample->get_outergain() );
374             testForALError("audio cone");
375
376             alSourcef( source, AL_MAX_DISTANCE, sample->get_max_dist() );
377             alSourcef( source, AL_REFERENCE_DISTANCE,
378                                sample->get_reference_dist() );
379             testForALError("distance rolloff");
380         }
381     }
382 }
383
384 bool SGSampleGroup::testForError(void *p, string s)
385 {
386    if (p == NULL) {
387       SG_LOG( SG_GENERAL, SG_ALERT, "Error (sample group): " << s);
388       return true;
389    }
390    return false;
391 }
392
393 bool SGSampleGroup::testForALError(string s)
394 {
395     ALenum error = alGetError();
396     if (error != AL_NO_ERROR)  {
397        SG_LOG( SG_GENERAL, SG_ALERT, "AL Error (" << _refname << "): "
398                                       << alGetString(error) << " at " << s);
399        return true;
400     }
401     return false;
402 }
403