00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 # include <simgear_config.h>
00025 #endif
00026
00027 #include <simgear/compiler.h>
00028
00029 #include "soundmgr_openal.hxx"
00030 #include "sample_group.hxx"
00031
00032 bool isNaN(float *v) {
00033 return (isnan(v[0]) || isnan(v[1]) || isnan(v[2]));
00034 }
00035
00036 SGSampleGroup::SGSampleGroup () :
00037 _smgr(NULL),
00038 _refname(""),
00039 _active(false),
00040 _changed(false),
00041 _pause(false),
00042 _volume(1.0),
00043 _tied_to_listener(false),
00044 _velocity(SGVec3d::zeros()),
00045 _orientation(SGQuatd::zeros())
00046 {
00047 _samples.clear();
00048 }
00049
00050 SGSampleGroup::SGSampleGroup ( SGSoundMgr *smgr, const string &refname ) :
00051 _smgr(smgr),
00052 _refname(refname),
00053 _active(false),
00054 _changed(false),
00055 _pause(false),
00056 _volume(1.0),
00057 _tied_to_listener(false),
00058 _velocity(SGVec3d::zeros()),
00059 _orientation(SGQuatd::zeros())
00060 {
00061 _smgr->add(this, refname);
00062 _samples.clear();
00063 }
00064
00065 SGSampleGroup::~SGSampleGroup ()
00066 {
00067 _active = false;
00068
00069 sample_map_iterator sample_current = _samples.begin();
00070 sample_map_iterator sample_end = _samples.end();
00071 for ( ; sample_current != sample_end; ++sample_current ) {
00072 SGSoundSample *sample = sample_current->second;
00073
00074 if ( sample->is_valid_source() && sample->is_playing() ) {
00075 sample->no_valid_source();
00076 _smgr->release_source( sample->get_source() );
00077 _smgr->release_buffer( sample );
00078 }
00079 }
00080
00081 _smgr = 0;
00082 }
00083
00084 void SGSampleGroup::update( double dt ) {
00085
00086 if ( !_active || _pause ) return;
00087
00088 testForALError("start of update!!\n");
00089
00090
00091 unsigned int size = _removed_samples.size();
00092 for (unsigned int i=0; i<size; ) {
00093 SGSoundSample *sample = _removed_samples[i];
00094 ALint result = AL_STOPPED;
00095
00096 if ( sample->is_valid_source() ) {
00097 if ( sample->is_looping() ) {
00098 sample->no_valid_source();
00099 _smgr->release_source( sample->get_source() );
00100 }
00101 else
00102 alGetSourcei( sample->get_source(), AL_SOURCE_STATE, &result );
00103 }
00104
00105 if ( result == AL_STOPPED ) {
00106 ALuint buffer = sample->get_buffer();
00107 alDeleteBuffers( 1, &buffer );
00108 testForALError("buffer remove");
00109 _removed_samples.erase( _removed_samples.begin()+i );
00110 size--;
00111 continue;
00112 }
00113 i++;
00114 }
00115
00116
00117 if ( _changed || _smgr->has_changed() ) {
00118 update_pos_and_orientation();
00119 _changed = false;
00120 }
00121
00122 sample_map_iterator sample_current = _samples.begin();
00123 sample_map_iterator sample_end = _samples.end();
00124 for ( ; sample_current != sample_end; ++sample_current ) {
00125 SGSoundSample *sample = sample_current->second;
00126
00127 if ( !sample->is_valid_source() && sample->is_playing() ) {
00128
00129
00130
00131 if ( _smgr->request_buffer(sample) == SGSoundMgr::NO_BUFFER )
00132 continue;
00133
00134
00135 ALuint buffer = sample->get_buffer();
00136 ALuint source = _smgr->request_source();
00137 if (alIsSource(source) == AL_TRUE && alIsBuffer(buffer) == AL_TRUE)
00138 {
00139 sample->set_source( source );
00140
00141 alSourcei( source, AL_BUFFER, buffer );
00142 testForALError("assign buffer to source");
00143
00144 sample->set_source( source );
00145 update_sample_config( sample );
00146
00147 ALboolean looping = sample->is_looping() ? AL_TRUE : AL_FALSE;
00148 alSourcei( source, AL_LOOPING, looping );
00149 alSourcef( source, AL_ROLLOFF_FACTOR, 0.3 );
00150 alSourcei( source, AL_SOURCE_RELATIVE, AL_FALSE );
00151 alSourcePlay( source );
00152 testForALError("sample play");
00153 } else {
00154 if (alIsBuffer(buffer) == AL_FALSE)
00155 SG_LOG( SG_GENERAL, SG_ALERT, "No such buffer!\n");
00156
00157
00158 }
00159
00160 } else if ( sample->is_valid_source() && sample->has_changed() ) {
00161 if ( !sample->is_playing() ) {
00162
00163
00164 sample->stop();
00165 sample->no_valid_source();
00166 _smgr->release_source( sample->get_source() );
00167 } else if ( _smgr->has_changed() ) {
00168 update_sample_config( sample );
00169 }
00170
00171 } else if ( sample->is_valid_source() ) {
00172
00173
00174 unsigned int source = sample->get_source();
00175 int result;
00176
00177 alGetSourcei( source, AL_SOURCE_STATE, &result );
00178 if ( result == AL_STOPPED ) {
00179
00180 sample->stop();
00181 sample->no_valid_source();
00182 _smgr->release_source( source );
00183 _smgr->release_buffer( sample );
00184 remove( sample->get_sample_name() );
00185 }
00186 }
00187 testForALError("update");
00188 }
00189 }
00190
00191
00192 bool SGSampleGroup::add( SGSharedPtr<SGSoundSample> sound, const string& refname ) {
00193
00194 sample_map_iterator sample_it = _samples.find( refname );
00195 if ( sample_it != _samples.end() ) {
00196
00197 return false;
00198 }
00199
00200 _samples[refname] = sound;
00201 return true;
00202 }
00203
00204
00205
00206 bool SGSampleGroup::remove( const string &refname ) {
00207
00208 sample_map_iterator sample_it = _samples.find( refname );
00209 if ( sample_it == _samples.end() ) {
00210
00211 return false;
00212 }
00213
00214 if ( sample_it->second->is_valid_buffer() )
00215 _removed_samples.push_back( sample_it->second );
00216 _samples.erase( sample_it );
00217
00218 return true;
00219 }
00220
00221
00222
00223 bool SGSampleGroup::exists( const string &refname ) {
00224 sample_map_iterator sample_it = _samples.find( refname );
00225 if ( sample_it == _samples.end() ) {
00226
00227 return false;
00228 }
00229
00230 return true;
00231 }
00232
00233
00234
00235
00236 SGSoundSample *SGSampleGroup::find( const string &refname ) {
00237 sample_map_iterator sample_it = _samples.find( refname );
00238 if ( sample_it == _samples.end() ) {
00239
00240 return NULL;
00241 }
00242
00243 return sample_it->second;
00244 }
00245
00246
00247 void
00248 SGSampleGroup::stop ()
00249 {
00250 _pause = true;
00251 sample_map_iterator sample_current = _samples.begin();
00252 sample_map_iterator sample_end = _samples.end();
00253 for ( ; sample_current != sample_end; ++sample_current ) {
00254 SGSoundSample *sample = sample_current->second;
00255
00256 if ( sample->is_valid_source() ) {
00257 ALint source = sample->get_source();
00258 if ( sample->is_playing() ) {
00259 alSourceStop( source );
00260 alSourcei( source, AL_BUFFER, 0 );
00261 }
00262 _smgr->release_source( source );
00263 sample->no_valid_source();
00264 }
00265
00266 if (sample->is_valid_buffer() ) {
00267 _smgr->release_buffer( sample );
00268 sample->no_valid_buffer();
00269 }
00270 }
00271 testForALError("stop");
00272 }
00273
00274
00275 void
00276 SGSampleGroup::suspend ()
00277 {
00278 if (_active && _pause == false) {
00279 _pause = true;
00280 sample_map_iterator sample_current = _samples.begin();
00281 sample_map_iterator sample_end = _samples.end();
00282 for ( ; sample_current != sample_end; ++sample_current ) {
00283 SGSoundSample *sample = sample_current->second;
00284
00285 if ( sample->is_valid_source() && sample->is_playing() ) {
00286 alSourcePause( sample->get_source() );
00287 }
00288 }
00289 testForALError("suspend");
00290 }
00291 }
00292
00293
00294 void
00295 SGSampleGroup::resume ()
00296 {
00297 if (_active && _pause == true) {
00298 sample_map_iterator sample_current = _samples.begin();
00299 sample_map_iterator sample_end = _samples.end();
00300 for ( ; sample_current != sample_end; ++sample_current ) {
00301 SGSoundSample *sample = sample_current->second;
00302
00303 if ( sample->is_valid_source() && sample->is_playing() ) {
00304 alSourcePlay( sample->get_source() );
00305 }
00306 }
00307 testForALError("resume");
00308 _pause = false;
00309 }
00310 }
00311
00312
00313
00314 bool SGSampleGroup::play( const string &refname, bool looping = false ) {
00315 SGSoundSample *sample = find( refname );
00316
00317 if ( sample == NULL ) {
00318 return false;
00319 }
00320
00321 sample->play( looping );
00322 return true;
00323 }
00324
00325
00326
00327 bool SGSampleGroup::is_playing( const string& refname ) {
00328 SGSoundSample *sample = find( refname );
00329
00330 if ( sample == NULL ) {
00331 return false;
00332 }
00333
00334 return ( sample->is_playing() ) ? true : false;
00335 }
00336
00337
00338 bool SGSampleGroup::stop( const string& refname ) {
00339 SGSoundSample *sample = find( refname );
00340
00341 if ( sample == NULL ) {
00342 return false;
00343 }
00344
00345 sample->stop();
00346 return true;
00347 }
00348
00349 void SGSampleGroup::set_volume( float vol )
00350 {
00351 if (vol > _volume*1.01 || vol < _volume*0.99) {
00352 _volume = vol;
00353 if (_volume < 0.0) _volume = 0.0;
00354 if (_volume > 1.0) _volume = 1.0;
00355 _changed = true;
00356 }
00357 }
00358
00359
00360 void SGSampleGroup::update_pos_and_orientation() {
00361
00362 SGVec3d position = SGVec3d::fromGeod(_base_pos) - _smgr->get_position();
00363 SGQuatd hlOr = SGQuatd::fromLonLat(_base_pos);
00364 SGQuatd ec2body = hlOr*_orientation;
00365
00366 SGVec3f velocity = SGVec3f::zeros();
00367 if ( _velocity[0] || _velocity[1] || _velocity[2] ) {
00368 velocity = toVec3f( hlOr.backTransform(_velocity*SG_FEET_TO_METER) );
00369 }
00370
00371 sample_map_iterator sample_current = _samples.begin();
00372 sample_map_iterator sample_end = _samples.end();
00373 for ( ; sample_current != sample_end; ++sample_current ) {
00374 SGSoundSample *sample = sample_current->second;
00375 sample->set_master_volume( _volume );
00376 sample->set_orientation( _orientation );
00377 sample->set_rotation( ec2body );
00378 sample->set_position( position );
00379 sample->set_velocity( velocity );
00380 }
00381 }
00382
00383 void SGSampleGroup::update_sample_config( SGSoundSample *sample ) {
00384 SGVec3f orientation, velocity;
00385 SGVec3d position;
00386
00387 if ( _tied_to_listener ) {
00388 orientation = _smgr->get_direction();
00389 position = SGVec3d::zeros();
00390 velocity = _smgr->get_velocity();
00391 } else {
00392 sample->update_pos_and_orientation();
00393 orientation = sample->get_orientation();
00394 position = sample->get_position();
00395 velocity = sample->get_velocity();
00396 }
00397
00398 if (_smgr->bad_doppler_effect()) {
00399 velocity *= 100.0f;
00400 }
00401
00402 #if 0
00403 if (length(position) > 20000)
00404 printf("%s source and listener distance greater than 20km!\n",
00405 _refname.c_str());
00406 if (isNaN(toVec3f(position).data())) printf("NaN in source position\n");
00407 if (isNaN(orientation.data())) printf("NaN in source orientation\n");
00408 if (isNaN(velocity.data())) printf("NaN in source velocity\n");
00409 #endif
00410
00411 unsigned int source = sample->get_source();
00412 alSourcefv( source, AL_POSITION, toVec3f(position).data() );
00413 alSourcefv( source, AL_VELOCITY, velocity.data() );
00414 alSourcefv( source, AL_DIRECTION, orientation.data() );
00415 testForALError("position and orientation");
00416
00417 alSourcef( source, AL_PITCH, sample->get_pitch() );
00418 alSourcef( source, AL_GAIN, sample->get_volume() );
00419 testForALError("pitch and gain");
00420
00421 if ( sample->has_static_data_changed() ) {
00422 alSourcef( source, AL_CONE_INNER_ANGLE, sample->get_innerangle() );
00423 alSourcef( source, AL_CONE_OUTER_ANGLE, sample->get_outerangle() );
00424 alSourcef( source, AL_CONE_OUTER_GAIN, sample->get_outergain() );
00425 testForALError("audio cone");
00426
00427 alSourcef( source, AL_MAX_DISTANCE, sample->get_max_dist() );
00428 alSourcef( source, AL_REFERENCE_DISTANCE,
00429 sample->get_reference_dist() );
00430 testForALError("distance rolloff");
00431 }
00432 }
00433
00434 bool SGSampleGroup::testForError(void *p, string s)
00435 {
00436 if (p == NULL) {
00437 SG_LOG( SG_GENERAL, SG_ALERT, "Error (sample group): " << s);
00438 return true;
00439 }
00440 return false;
00441 }
00442
00443 bool SGSampleGroup::testForALError(string s)
00444 {
00445 ALenum error = alGetError();
00446 if (error != AL_NO_ERROR) {
00447 SG_LOG( SG_GENERAL, SG_ALERT, "AL Error (" << _refname << "): "
00448 << alGetString(error) << " at " << s);
00449 return true;
00450 }
00451 return false;
00452 }
00453