Panda3D
|
00001 // Filename: openalAudioManager.cxx 00002 // Created by: Ben Buchwald <bb2@alumni.cmu.edu> 00003 // 00004 // 00005 //////////////////////////////////////////////////////////////////// 00006 // 00007 // PANDA 3D SOFTWARE 00008 // Copyright (c) Carnegie Mellon University. All rights reserved. 00009 // 00010 // All use of this software is subject to the terms of the revised BSD 00011 // license. You should have received a copy of this license along 00012 // with this source code in a file named "LICENSE." 00013 // 00014 //////////////////////////////////////////////////////////////////// 00015 00016 #include "pandabase.h" 00017 00018 #ifdef HAVE_OPENAL //[ 00019 00020 //Panda headers. 00021 #include "config_audio.h" 00022 #include "config_util.h" 00023 #include "config_express.h" 00024 #include "openalAudioManager.h" 00025 #include "openalAudioSound.h" 00026 #include "virtualFileSystem.h" 00027 #include "movieAudio.h" 00028 00029 #include <algorithm> 00030 00031 TypeHandle OpenALAudioManager::_type_handle; 00032 00033 int OpenALAudioManager::_active_managers = 0; 00034 bool OpenALAudioManager::_openal_active = false; 00035 ALCdevice* OpenALAudioManager::_device = NULL; 00036 ALCcontext* OpenALAudioManager::_context = NULL; 00037 00038 // This is the list of all OpenALAudioManager objects in the world. It 00039 // must be a pointer rather than a concrete object, so it won't be 00040 // destructed at exit time before we're done removing things from it. 00041 OpenALAudioManager::Managers *OpenALAudioManager::_managers = NULL; 00042 00043 OpenALAudioManager::SourceCache *OpenALAudioManager::_al_sources = NULL; 00044 00045 00046 //////////////////////////////////////////////////////////////////// 00047 // Central dispatcher for audio errors. 00048 //////////////////////////////////////////////////////////////////// 00049 void al_audio_errcheck(const char *context) { 00050 ALenum result = alGetError(); 00051 if (result != AL_NO_ERROR) { 00052 audio_error(context << ": " << alGetString(result) ); 00053 } 00054 } 00055 00056 void alc_audio_errcheck(const char *context,ALCdevice* device) { 00057 ALCenum result = alcGetError(device); 00058 if (result != ALC_NO_ERROR) { 00059 audio_error(context << ": " << alcGetString(device,result) ); 00060 } 00061 } 00062 00063 //////////////////////////////////////////////////////////////////// 00064 // Function: Create_OpenALAudioManager 00065 // Access: Private 00066 // Description: Factory Function 00067 //////////////////////////////////////////////////////////////////// 00068 AudioManager *Create_OpenALAudioManager() { 00069 audio_debug("Create_OpenALAudioManager()"); 00070 return new OpenALAudioManager; 00071 } 00072 00073 00074 //////////////////////////////////////////////////////////////////// 00075 // Function: OpenALAudioManager::Constructor 00076 // Access: Public 00077 // Description: 00078 //////////////////////////////////////////////////////////////////// 00079 OpenALAudioManager:: 00080 OpenALAudioManager() { 00081 if (_managers == (Managers *)NULL) { 00082 _managers = new Managers; 00083 _al_sources = new SourceCache; 00084 } 00085 00086 _managers->insert(this); 00087 00088 _cleanup_required = true; 00089 _active = audio_active; 00090 _volume = audio_volume; 00091 _play_rate = 1.0f; 00092 00093 _cache_limit = audio_cache_limit; 00094 00095 _concurrent_sound_limit = 0; 00096 _is_valid = true; 00097 00098 //Init 3D attributes 00099 _distance_factor = 3.28; 00100 _drop_off_factor = 1; 00101 00102 _position[0] = 0; 00103 _position[1] = 0; 00104 _position[2] = 0; 00105 00106 _velocity[0] = 0; 00107 _velocity[1] = 0; 00108 _velocity[2] = 0; 00109 00110 _forward_up[0] = 0; 00111 _forward_up[1] = 0; 00112 _forward_up[2] = 0; 00113 _forward_up[3] = 0; 00114 _forward_up[4] = 0; 00115 _forward_up[5] = 0; 00116 00117 // Initialization 00118 if (_active_managers==0 || !_openal_active) { 00119 _device = alcOpenDevice(NULL); // select the "preferred device" 00120 if (!_device) { 00121 // this is a unique kind of error 00122 audio_error("OpenALAudioManager: alcOpenDevice(NULL): ALC couldn't open device"); 00123 } else { 00124 alcGetError(_device); // clear errors 00125 _context=alcCreateContext(_device,NULL); 00126 alc_audio_errcheck("alcCreateContext(_device,NULL)",_device); 00127 if (_context!=NULL) { 00128 _openal_active = true; 00129 } 00130 } 00131 } 00132 // We increment _active_managers regardless of possible errors above. 00133 // The shutdown call will do the right thing when it's called, 00134 // either way. 00135 ++_active_managers; 00136 nassertv(_active_managers>0); 00137 00138 if (!_device || !_context) { 00139 audio_error("OpenALAudioManager: No open device or context"); 00140 _is_valid = false; 00141 } else { 00142 alcGetError(_device); // clear errors 00143 alcMakeContextCurrent(_context); 00144 alc_audio_errcheck("alcMakeContextCurrent(_context)",_device); 00145 00146 00147 // set 3D sound characteristics as they are given in the configrc 00148 audio_3d_set_doppler_factor(audio_doppler_factor); 00149 audio_3d_set_distance_factor(audio_distance_factor); 00150 audio_3d_set_drop_off_factor(audio_drop_off_factor); 00151 } 00152 00153 audio_cat->debug() << "ALC_DEVICE_SPECIFIER:" << alcGetString(_device, ALC_DEVICE_SPECIFIER) << endl; 00154 audio_cat->debug() << "AL_RENDERER:" << alGetString(AL_RENDERER) << endl; 00155 audio_cat->debug() << "AL_VENDOR:" << alGetString(AL_VENDOR) << endl; 00156 audio_cat->debug() << "AL_VERSION:" << alGetString(AL_VERSION) << endl; 00157 00158 } 00159 00160 //////////////////////////////////////////////////////////////////// 00161 // Function: OpenALAudioManager::Destructor 00162 // Access: Public 00163 // Description: 00164 //////////////////////////////////////////////////////////////////// 00165 OpenALAudioManager:: 00166 ~OpenALAudioManager() { 00167 nassertv(_managers != (Managers *)NULL); 00168 Managers::iterator mi = _managers->find(this); 00169 nassertv(mi != _managers->end()); 00170 _managers->erase(mi); 00171 cleanup(); 00172 } 00173 00174 //////////////////////////////////////////////////////////////////// 00175 // Function: OpenALAudioManager::shutdown 00176 // Access: Published, Virtual 00177 // Description: Call this at exit time to shut down the audio system. 00178 // This will invalidate all currently-active 00179 // AudioManagers and AudioSounds in the system. If you 00180 // change your mind and want to play sounds again, you 00181 // will have to recreate all of these objects. 00182 //////////////////////////////////////////////////////////////////// 00183 void OpenALAudioManager:: 00184 shutdown() { 00185 if (_managers != (Managers *)NULL) { 00186 Managers::iterator mi; 00187 for (mi = _managers->begin(); mi != _managers->end(); ++mi) { 00188 (*mi)->cleanup(); 00189 } 00190 } 00191 00192 nassertv(_active_managers == 0); 00193 } 00194 00195 00196 //////////////////////////////////////////////////////////////////// 00197 // Function: OpenALAudioManager::is_valid 00198 // Access: 00199 // Description: This is mostly for debugging, but it it could be 00200 // used to detect errors in a release build if you 00201 // don't mind the cpu cost. 00202 //////////////////////////////////////////////////////////////////// 00203 bool OpenALAudioManager:: 00204 is_valid() { 00205 return _is_valid; 00206 } 00207 00208 //////////////////////////////////////////////////////////////////// 00209 // Function: OpenALAudioManager::make_current 00210 // Access: Private 00211 // Description: This makes this manager's OpenAL context the 00212 // current context. Needed before any parameter sets. 00213 //////////////////////////////////////////////////////////////////// 00214 void OpenALAudioManager:: 00215 make_current() const { 00216 // Since we only use one context, this is now a no-op. 00217 } 00218 00219 //////////////////////////////////////////////////////////////////// 00220 // Function: OpenALAudioManager::can_use_audio 00221 // Access: Private 00222 // Description: Returns true if the specified MovieAudioCursor 00223 // can be used by this AudioManager. Mostly, this 00224 // involves checking whether or not the format is 00225 // implemented/supported. 00226 //////////////////////////////////////////////////////////////////// 00227 bool OpenALAudioManager:: 00228 can_use_audio(MovieAudioCursor *source) { 00229 int channels = source->audio_channels(); 00230 if ((channels != 1)&&(channels != 2)) { 00231 audio_error("Currently, only mono and stereo are supported."); 00232 return false; 00233 } 00234 return true; 00235 } 00236 00237 //////////////////////////////////////////////////////////////////// 00238 // Function: OpenALAudioManager::should_load_audio 00239 // Access: Private 00240 // Description: Returns true if the specified MovieAudio should be 00241 // cached into RAM. A lot of conditions have to be met 00242 // in order to allow caching - if any are not met, 00243 // the file will be streamed. 00244 //////////////////////////////////////////////////////////////////// 00245 bool OpenALAudioManager:: 00246 should_load_audio(MovieAudioCursor *source, int mode) { 00247 if (mode == SM_stream) { 00248 // If the user asked for streaming, give him streaming. 00249 return false; 00250 } 00251 if (source->get_source()->get_filename().empty()) { 00252 // Non-files cannot be preloaded. 00253 return false; 00254 } 00255 if (source->ready() != 0x40000000) { 00256 // Streaming sources cannot be preloaded. 00257 return false; 00258 } 00259 if (source->length() > 3600.0) { 00260 // Anything longer than an hour cannot be preloaded. 00261 return false; 00262 } 00263 int channels = source->audio_channels(); 00264 int samples = (int)(source->length() * source->audio_rate()); 00265 int bytes = samples * channels * 2; 00266 if ((mode == SM_heuristic)&&(bytes > audio_preload_threshold)) { 00267 // In heuristic mode, if file is long, stream it. 00268 return false; 00269 } 00270 return true; 00271 } 00272 00273 //////////////////////////////////////////////////////////////////// 00274 // Function: OpenALAudioManager::get_sound_data 00275 // Access: Private 00276 // Description: Obtains a SoundData for the specified sound. 00277 // 00278 // When you are done with the SoundData, you need 00279 // to decrement the client count. 00280 //////////////////////////////////////////////////////////////////// 00281 OpenALAudioManager::SoundData *OpenALAudioManager:: 00282 get_sound_data(MovieAudio *movie, int mode) { 00283 const Filename &path = movie->get_filename(); 00284 00285 // Search for an already-cached sample or an already-opened stream. 00286 if (!path.empty()) { 00287 00288 if (mode != SM_stream) { 00289 SampleCache::iterator lsmi=_sample_cache.find(path); 00290 if (lsmi != _sample_cache.end()) { 00291 SoundData *sd = (*lsmi).second; 00292 increment_client_count(sd); 00293 return sd; 00294 } 00295 } 00296 00297 if (mode != SM_sample) { 00298 ExpirationQueue::iterator exqi; 00299 for (exqi=_expiring_streams.begin(); exqi!=_expiring_streams.end(); exqi++) { 00300 SoundData *sd = (SoundData*)(*exqi); 00301 if (sd->_movie->get_filename() == path) { 00302 increment_client_count(sd); 00303 return sd; 00304 } 00305 } 00306 } 00307 } 00308 00309 PT(MovieAudioCursor) stream = movie->open(); 00310 if (stream == 0) { 00311 audio_error("Cannot open file: "<<path); 00312 return NULL; 00313 } 00314 00315 if (!can_use_audio(stream)) { 00316 audio_error("File is not in usable format: "<<path); 00317 return NULL; 00318 } 00319 00320 SoundData *sd = new SoundData(); 00321 sd->_client_count = 1; 00322 sd->_manager = this; 00323 sd->_movie = movie; 00324 sd->_rate = stream->audio_rate(); 00325 sd->_channels = stream->audio_channels(); 00326 sd->_length = stream->length(); 00327 audio_debug("Creating: " << sd->_movie->get_filename().get_basename()); 00328 audio_debug(" - Rate: " << sd->_rate); 00329 audio_debug(" - Channels: " << sd->_channels); 00330 audio_debug(" - Length: " << sd->_length); 00331 00332 if (should_load_audio(stream, mode)) { 00333 audio_debug(path.get_basename() << ": loading as sample"); 00334 make_current(); 00335 alGetError(); // clear errors 00336 sd->_sample = 0; 00337 alGenBuffers(1, &sd->_sample); 00338 al_audio_errcheck("alGenBuffers"); 00339 if (sd->_sample == 0) { 00340 audio_error("Could not create an OpenAL buffer object"); 00341 delete sd; 00342 return NULL; 00343 } 00344 int channels = stream->audio_channels(); 00345 int samples = (int)(stream->length() * stream->audio_rate()); 00346 PN_int16 *data = new PN_int16[samples * channels]; 00347 stream->read_samples(samples, data); 00348 alBufferData(sd->_sample, 00349 (channels>1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16, 00350 data, samples * channels * 2, stream->audio_rate()); 00351 int err = alGetError(); 00352 if (err != AL_NO_ERROR) { 00353 audio_error("could not fill OpenAL buffer object with data"); 00354 delete sd; 00355 return NULL; 00356 } 00357 _sample_cache.insert(SampleCache::value_type(path, sd)); 00358 } else { 00359 audio_debug(path.get_basename() << ": loading as stream"); 00360 sd->_stream = stream; 00361 } 00362 00363 return sd; 00364 } 00365 00366 //////////////////////////////////////////////////////////////////// 00367 // Function: OpenALAudioManager::get_sound 00368 // Access: Public 00369 // Description: This is what creates a sound instance. 00370 //////////////////////////////////////////////////////////////////// 00371 PT(AudioSound) OpenALAudioManager:: 00372 get_sound(MovieAudio *sound, bool positional, int mode) { 00373 if(!is_valid()) { 00374 return get_null_sound(); 00375 } 00376 PT(OpenALAudioSound) oas = 00377 new OpenALAudioSound(this, sound, positional, mode); 00378 00379 _all_sounds.insert(oas); 00380 PT(AudioSound) res = (AudioSound*)(OpenALAudioSound*)oas; 00381 return res; 00382 } 00383 00384 //////////////////////////////////////////////////////////////////// 00385 // Function: OpenALAudioManager::get_sound 00386 // Access: Public 00387 // Description: This is what creates a sound instance. 00388 //////////////////////////////////////////////////////////////////// 00389 PT(AudioSound) OpenALAudioManager:: 00390 get_sound(const string &file_name, bool positional, int mode) { 00391 if(!is_valid()) { 00392 return get_null_sound(); 00393 } 00394 00395 Filename path = file_name; 00396 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); 00397 vfs->resolve_filename(path, get_model_path()); 00398 00399 if (path.empty()) { 00400 audio_error("get_sound - invalid filename"); 00401 return NULL; 00402 } 00403 00404 PT(MovieAudio) mva = MovieAudio::get(path); 00405 00406 PT(OpenALAudioSound) oas = 00407 new OpenALAudioSound(this, mva, positional, mode); 00408 00409 _all_sounds.insert(oas); 00410 PT(AudioSound) res = (AudioSound*)(OpenALAudioSound*)oas; 00411 return res; 00412 } 00413 00414 //////////////////////////////////////////////////////////////////// 00415 // Function: OpenALAudioManager::uncache_sound 00416 // Access: Public 00417 // Description: Deletes a sample from the expiration queues. 00418 // If the sound is actively in use, then the sound 00419 // cannot be deleted, and this function has no effect. 00420 //////////////////////////////////////////////////////////////////// 00421 void OpenALAudioManager:: 00422 uncache_sound(const string& file_name) { 00423 assert(is_valid()); 00424 Filename path = file_name; 00425 00426 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); 00427 vfs->resolve_filename(path, get_model_path()); 00428 00429 SampleCache::iterator sci = _sample_cache.find(path); 00430 if (sci != _sample_cache.end()) { 00431 SoundData *sd = (*sci).second; 00432 if (sd->_client_count == 0) { 00433 _expiring_samples.erase(sd->_expire); 00434 _sample_cache.erase(sci); 00435 delete sd; 00436 } 00437 } 00438 } 00439 00440 //////////////////////////////////////////////////////////////////// 00441 // Function: OpenALAudioManager::clear_cache 00442 // Access: Public 00443 // Description: Clear out the sound cache. 00444 //////////////////////////////////////////////////////////////////// 00445 void OpenALAudioManager:: 00446 clear_cache() { 00447 discard_excess_cache(0); 00448 } 00449 00450 //////////////////////////////////////////////////////////////////// 00451 // Function: OpenALAudioManager::set_cache_limit 00452 // Access: Public 00453 // Description: Set the number of sounds that the cache can hold. 00454 //////////////////////////////////////////////////////////////////// 00455 void OpenALAudioManager:: 00456 set_cache_limit(unsigned int count) { 00457 _cache_limit=count; 00458 discard_excess_cache(count); 00459 } 00460 00461 //////////////////////////////////////////////////////////////////// 00462 // Function: OpenALAudioManager::get_cache_limit 00463 // Access: Public 00464 // Description: 00465 //////////////////////////////////////////////////////////////////// 00466 unsigned int OpenALAudioManager:: 00467 get_cache_limit() const { 00468 return _cache_limit; 00469 } 00470 00471 //////////////////////////////////////////////////////////////////// 00472 // Function: OpenALAudioManager::release_sound 00473 // Access: Public 00474 // Description: 00475 //////////////////////////////////////////////////////////////////// 00476 void OpenALAudioManager:: 00477 release_sound(OpenALAudioSound* audioSound) { 00478 AllSounds::iterator ai = _all_sounds.find(audioSound); 00479 if (ai != _all_sounds.end()) { 00480 _all_sounds.erase(ai); 00481 } 00482 } 00483 00484 //////////////////////////////////////////////////////////////////// 00485 // Function: OpenALAudioManager::set_volume(float volume) 00486 // Access: Public 00487 // Description: 00488 // Sets listener gain 00489 //////////////////////////////////////////////////////////////////// 00490 void OpenALAudioManager::set_volume(float volume) { 00491 if (_volume!=volume) { 00492 _volume = volume; 00493 00494 // Tell our AudioSounds to adjust: 00495 AllSounds::iterator i=_all_sounds.begin(); 00496 for (; i!=_all_sounds.end(); ++i) { 00497 (**i).set_volume((**i).get_volume()); 00498 } 00499 00500 /* 00501 // this was neat alternative to the above look 00502 // when we had a seperate context for each manager 00503 make_current(); 00504 00505 alGetError(); // clear errors 00506 alListenerf(AL_GAIN,(ALfloat)_volume); 00507 al_audio_errcheck("alListerf(AL_GAIN)");*/ 00508 } 00509 } 00510 00511 //////////////////////////////////////////////////////////////////// 00512 // Function: OpenALAudioManager::get_volume() 00513 // Access: Public 00514 // Description: 00515 // Gets listener gain 00516 //////////////////////////////////////////////////////////////////// 00517 float OpenALAudioManager:: 00518 get_volume() const { 00519 return _volume; 00520 } 00521 00522 //////////////////////////////////////////////////////////////////// 00523 // Function: OpenALAudioManager::set_play_rate 00524 // Access: Public 00525 // Description: set the overall play rate 00526 //////////////////////////////////////////////////////////////////// 00527 void OpenALAudioManager:: 00528 set_play_rate(float play_rate) { 00529 if (_play_rate!=play_rate) { 00530 _play_rate = play_rate; 00531 // Tell our AudioSounds to adjust: 00532 AllSounds::iterator i=_all_sounds.begin(); 00533 for (; i!=_all_sounds.end(); ++i) { 00534 (**i).set_play_rate((**i).get_play_rate()); 00535 } 00536 } 00537 } 00538 00539 //////////////////////////////////////////////////////////////////// 00540 // Function: OpenALAudioManager::get_play_rate 00541 // Access: Public 00542 // Description: get the overall speed/pitch/play rate 00543 //////////////////////////////////////////////////////////////////// 00544 float OpenALAudioManager:: 00545 get_play_rate() const { 00546 return _play_rate; 00547 } 00548 00549 //////////////////////////////////////////////////////////////////// 00550 // Function: OpenALAudioManager::set_active(bool active) 00551 // Access: Public 00552 // Description: Turn on/off 00553 // Warning: not implemented. 00554 //////////////////////////////////////////////////////////////////// 00555 void OpenALAudioManager:: 00556 set_active(bool active) { 00557 if (_active!=active) { 00558 _active=active; 00559 // Tell our AudioSounds to adjust: 00560 AllSounds::iterator i=_all_sounds.begin(); 00561 for (; i!=_all_sounds.end(); ++i) { 00562 (**i).set_active(_active); 00563 } 00564 } 00565 } 00566 00567 //////////////////////////////////////////////////////////////////// 00568 // Function: OpenALAudioManager::get_active() 00569 // Access: Public 00570 // Description: 00571 //////////////////////////////////////////////////////////////////// 00572 bool OpenALAudioManager:: 00573 get_active() const { 00574 return _active; 00575 } 00576 00577 //////////////////////////////////////////////////////////////////// 00578 // Function: OpenALAudioManager::audio_3d_set_listener_attributes 00579 // Access: Public 00580 // Description: Set position of the "ear" that picks up 3d sounds 00581 // NOW LISTEN UP!!! THIS IS IMPORTANT! 00582 // Both Panda3D and OpenAL use a right handed coordinate system. 00583 // But there is a major difference! 00584 // In Panda3D the Y-Axis is going into the Screen and the Z-Axis is going up. 00585 // In OpenAL the Y-Axis is going up and the Z-Axis is coming out of the screen. 00586 // The solution is simple, we just flip the Y and Z axis and negate the Z, as we move coordinates 00587 // from Panda to OpenAL and back. 00588 // What does did mean to average Panda user? Nothing, they shouldn't notice anyway. 00589 // But if you decide to do any 3D audio work in here you have to keep it in mind. 00590 // I told you, so you can't say I didn't. 00591 //////////////////////////////////////////////////////////////////// 00592 void OpenALAudioManager:: 00593 audio_3d_set_listener_attributes(float px, float py, float pz, float vx, float vy, float vz, float fx, float fy, float fz, float ux, float uy, float uz) { 00594 _position[0] = px; 00595 _position[1] = pz; 00596 _position[2] = -py; 00597 00598 _velocity[0] = vx; 00599 _velocity[1] = vz; 00600 _velocity[2] = -vy; 00601 00602 _forward_up[0] = fx; 00603 _forward_up[1] = fz; 00604 _forward_up[2] = -fy; 00605 00606 _forward_up[3] = ux; 00607 _forward_up[4] = uz; 00608 _forward_up[5] = -uy; 00609 00610 00611 make_current(); 00612 00613 alGetError(); // clear errors 00614 alListenerfv(AL_POSITION,_position); 00615 al_audio_errcheck("alListerfv(AL_POSITION)"); 00616 alListenerfv(AL_VELOCITY,_velocity); 00617 al_audio_errcheck("alListerfv(AL_VELOCITY)"); 00618 alListenerfv(AL_ORIENTATION,_forward_up); 00619 al_audio_errcheck("alListerfv(AL_ORIENTATION)"); 00620 } 00621 00622 //////////////////////////////////////////////////////////////////// 00623 // Function: OpenALAudioManager::audio_3d_get_listener_attributes 00624 // Access: Public 00625 // Description: Get position of the "ear" that picks up 3d sounds 00626 //////////////////////////////////////////////////////////////////// 00627 void OpenALAudioManager:: 00628 audio_3d_get_listener_attributes(float *px, float *py, float *pz, float *vx, float *vy, float *vz, float *fx, float *fy, float *fz, float *ux, float *uy, float *uz) { 00629 *px = _position[0]; 00630 *py = -_position[2]; 00631 *pz = _position[1]; 00632 00633 *vx = _velocity[0]; 00634 *vy = -_velocity[2]; 00635 *vz = _velocity[1]; 00636 00637 *fx = _forward_up[0]; 00638 *fy = -_forward_up[2]; 00639 *fz = _forward_up[1]; 00640 00641 *ux = _forward_up[3]; 00642 *uy = -_forward_up[5]; 00643 *uz = _forward_up[4]; 00644 } 00645 00646 00647 //////////////////////////////////////////////////////////////////// 00648 // Function: OpenALAudioManager::audio_3d_set_distance_factor 00649 // Access: Public 00650 // Description: Set units per foot 00651 // WARNING: OpenAL has no distance factor but we use this as a scale 00652 // on the min/max distances of sounds to preserve FMOD compatibility. 00653 // Also, adjusts the speed of sound to compensate for unit difference. 00654 // OpenAL's default speed of sound is 343.3 m/s == 1126.3 ft/s 00655 //////////////////////////////////////////////////////////////////// 00656 void OpenALAudioManager:: 00657 audio_3d_set_distance_factor(float factor) { 00658 _distance_factor = factor; 00659 00660 make_current(); 00661 00662 alGetError(); // clear errors 00663 00664 if (_distance_factor>0) { 00665 alSpeedOfSound(1126.3*_distance_factor); 00666 al_audio_errcheck("alSpeedOfSound()"); 00667 // resets the doppler factor to the correct setting in case it was set to 0.0 by a distance_factor<=0.0 00668 alDopplerFactor(_doppler_factor); 00669 al_audio_errcheck("alDopplerFactor()"); 00670 } else { 00671 audio_debug("can't set speed of sound if distance_factor <=0.0, setting doppler factor to 0.0 instead"); 00672 alDopplerFactor(0.0); 00673 al_audio_errcheck("alDopplerFactor()"); 00674 } 00675 00676 AllSounds::iterator i=_all_sounds.begin(); 00677 for (; i!=_all_sounds.end(); ++i) { 00678 (**i).set_3d_min_distance((**i).get_3d_min_distance()); 00679 (**i).set_3d_max_distance((**i).get_3d_max_distance()); 00680 } 00681 } 00682 00683 //////////////////////////////////////////////////////////////////// 00684 // Function: OpenALAudioManager::audio_3d_get_distance_factor 00685 // Access: Public 00686 // Description: Sets units per foot 00687 //////////////////////////////////////////////////////////////////// 00688 float OpenALAudioManager:: 00689 audio_3d_get_distance_factor() const { 00690 return _distance_factor; 00691 } 00692 00693 //////////////////////////////////////////////////////////////////// 00694 // Function: OpenALAudioManager::audio_3d_set_doppler_factor 00695 // Access: Public 00696 // Description: Exaggerates or diminishes the Doppler effect. 00697 // Defaults to 1.0 00698 //////////////////////////////////////////////////////////////////// 00699 void OpenALAudioManager:: 00700 audio_3d_set_doppler_factor(float factor) { 00701 _doppler_factor = factor; 00702 00703 make_current(); 00704 00705 alGetError(); // clear errors 00706 alDopplerFactor(_doppler_factor); 00707 al_audio_errcheck("alDopplerFactor()"); 00708 } 00709 00710 //////////////////////////////////////////////////////////////////// 00711 // Function: OpenALAudioManager::audio_3d_get_doppler_factor 00712 // Access: Public 00713 // Description: 00714 //////////////////////////////////////////////////////////////////// 00715 float OpenALAudioManager:: 00716 audio_3d_get_doppler_factor() const { 00717 return _doppler_factor; 00718 } 00719 00720 //////////////////////////////////////////////////////////////////// 00721 // Function: OpenALAudioManager::audio_3d_set_drop_off_factor 00722 // Access: Public 00723 // Description: Control the effect distance has on audability. 00724 // Defaults to 1.0 00725 //////////////////////////////////////////////////////////////////// 00726 void OpenALAudioManager:: 00727 audio_3d_set_drop_off_factor(float factor) { 00728 _drop_off_factor = factor; 00729 00730 AllSounds::iterator i=_all_sounds.begin(); 00731 for (; i!=_all_sounds.end(); ++i) { 00732 (**i).set_3d_drop_off_factor((**i).get_3d_drop_off_factor()); 00733 } 00734 } 00735 00736 //////////////////////////////////////////////////////////////////// 00737 // Function: OpenALAudioManager::audio_3d_get_drop_off_factor 00738 // Access: Public 00739 // Description: 00740 //////////////////////////////////////////////////////////////////// 00741 float OpenALAudioManager:: 00742 audio_3d_get_drop_off_factor() const { 00743 return _drop_off_factor; 00744 } 00745 00746 //////////////////////////////////////////////////////////////////// 00747 // Function: OpenALAudioManager::starting_sound 00748 // Access: 00749 // Description: Inform the manager that a sound is about to play. 00750 // The manager will add this sound to the table of 00751 // sounds that are playing, and will allocate a source 00752 // to this sound. 00753 //////////////////////////////////////////////////////////////////// 00754 void OpenALAudioManager:: 00755 starting_sound(OpenALAudioSound* audio) { 00756 ALuint source=0; 00757 00758 // If the sound already has a source, we don't need to do anything. 00759 if (audio->_source) { 00760 return; 00761 } 00762 00763 // first give all sounds that have finished a chance to stop, so that these get stopped first 00764 update(); 00765 00766 if (_concurrent_sound_limit) { 00767 reduce_sounds_playing_to(_concurrent_sound_limit-1); // because we're about to add one 00768 } 00769 00770 // get a source from the source pool or create a new source 00771 if (_al_sources->empty()) { 00772 make_current(); 00773 alGetError(); // clear errors 00774 alGenSources(1,&source); 00775 ALenum result = alGetError(); 00776 if (result!=AL_NO_ERROR) { 00777 audio_error("alGenSources(): " << alGetString(result) ); 00778 // if we can't create any more sources, set stop a sound to free a source 00779 reduce_sounds_playing_to(_sounds_playing.size()-1); 00780 source = 0; 00781 } 00782 } 00783 // get a source from the source bool if we didn't just allocate one 00784 if (!source && !_al_sources->empty()) { 00785 source = *(_al_sources->begin()); 00786 _al_sources->erase(source); 00787 } 00788 00789 audio->_source = source; 00790 00791 if (source) 00792 _sounds_playing.insert(audio); 00793 } 00794 00795 //////////////////////////////////////////////////////////////////// 00796 // Function: OpenALAudioManager::stopping_sound 00797 // Access: 00798 // Description: Inform the manager that a sound is finished or 00799 // someone called stop on the sound (this should not 00800 // be called if a sound is only paused). 00801 //////////////////////////////////////////////////////////////////// 00802 void OpenALAudioManager:: 00803 stopping_sound(OpenALAudioSound* audio) { 00804 if (audio->_source) { 00805 _al_sources->insert(audio->_source); 00806 audio->_source = 0; 00807 } 00808 _sounds_playing.erase(audio); // This could cause the sound to destruct. 00809 } 00810 00811 //////////////////////////////////////////////////////////////////// 00812 // Function: OpenALAudioManager::set_concurrent_sound_limit 00813 // Access: Public 00814 // Description: 00815 //////////////////////////////////////////////////////////////////// 00816 void OpenALAudioManager:: 00817 set_concurrent_sound_limit(unsigned int limit) { 00818 _concurrent_sound_limit = limit; 00819 reduce_sounds_playing_to(_concurrent_sound_limit); 00820 } 00821 00822 //////////////////////////////////////////////////////////////////// 00823 // Function: OpenALAudioManager::get_concurrent_sound_limit 00824 // Access: Public 00825 // Description: 00826 //////////////////////////////////////////////////////////////////// 00827 unsigned int OpenALAudioManager:: 00828 get_concurrent_sound_limit() const { 00829 return _concurrent_sound_limit; 00830 } 00831 00832 //////////////////////////////////////////////////////////////////// 00833 // Function: OpenALAudioManager::reduce_sounds_playing_to 00834 // Access: Private 00835 // Description: 00836 //////////////////////////////////////////////////////////////////// 00837 void OpenALAudioManager:: 00838 reduce_sounds_playing_to(unsigned int count) { 00839 // first give all sounds that have finished a chance to stop, so that these get stopped first 00840 update(); 00841 00842 int limit = _sounds_playing.size() - count; 00843 while (limit-- > 0) { 00844 SoundsPlaying::iterator sound = _sounds_playing.begin(); 00845 assert(sound != _sounds_playing.end()); 00846 // When the user stops a sound, there is still a PT in the 00847 // user's hand. When we stop a sound here, however, 00848 // this can remove the last PT. This can cause an ugly 00849 // recursion where stop calls the destructor, and the 00850 // destructor calls stop. To avoid this, we create 00851 // a temporary PT, stop the sound, and then release the PT. 00852 PT(OpenALAudioSound) s = (*sound); 00853 s->stop(); 00854 } 00855 } 00856 00857 //////////////////////////////////////////////////////////////////// 00858 // Function: OpenALAudioManager::stop_all_sounds() 00859 // Access: Public 00860 // Description: Stop playback on all sounds managed by this manager. 00861 //////////////////////////////////////////////////////////////////// 00862 void OpenALAudioManager:: 00863 stop_all_sounds() { 00864 reduce_sounds_playing_to(0); 00865 } 00866 00867 //////////////////////////////////////////////////////////////////// 00868 // Function: OpenALAudioManager::update 00869 // Access: Public 00870 // Description: Perform all per-frame update functions. 00871 //////////////////////////////////////////////////////////////////// 00872 void OpenALAudioManager:: 00873 update() { 00874 00875 // See if any of our playing sounds have ended 00876 // we must first collect a seperate list of finished sounds and then 00877 // iterated over those again calling their finished method. We 00878 // can't call finished() within a loop iterating over _sounds_playing 00879 // since finished() modifies _sounds_playing 00880 SoundsPlaying sounds_finished; 00881 00882 double rtc = TrueClock::get_global_ptr()->get_short_time(); 00883 SoundsPlaying::iterator i=_sounds_playing.begin(); 00884 for (; i!=_sounds_playing.end(); ++i) { 00885 OpenALAudioSound *sound = (*i); 00886 sound->pull_used_buffers(); 00887 sound->push_fresh_buffers(); 00888 sound->restart_stalled_audio(); 00889 sound->cache_time(rtc); 00890 if ((sound->_source == 0)|| 00891 ((sound->_stream_queued.size() == 0)&& 00892 (sound->_loops_completed >= sound->_playing_loops))) { 00893 sounds_finished.insert(*i); 00894 } 00895 } 00896 00897 i=sounds_finished.begin(); 00898 for (; i!=sounds_finished.end(); ++i) { 00899 (**i).finished(); 00900 } 00901 } 00902 00903 00904 //////////////////////////////////////////////////////////////////// 00905 // Function: OpenALAudioManager::cleanup 00906 // Access: Private 00907 // Description: Shuts down the audio manager and releases any 00908 // resources associated with it. Also cleans up all 00909 // AudioSounds created via the manager. 00910 //////////////////////////////////////////////////////////////////// 00911 void OpenALAudioManager:: 00912 cleanup() { 00913 if (!_cleanup_required) { 00914 return; 00915 } 00916 00917 stop_all_sounds(); 00918 00919 AllSounds sounds(_all_sounds); 00920 AllSounds::iterator ai; 00921 for (ai = sounds.begin(); ai != sounds.end(); ++ai) { 00922 (*ai)->cleanup(); 00923 } 00924 00925 clear_cache(); 00926 00927 nassertv(_active_managers > 0); 00928 --_active_managers; 00929 00930 if (_active_managers == 0) { 00931 if (_openal_active) { 00932 // empty the source cache 00933 int i=0; 00934 ALuint *sources; 00935 sources = new ALuint[_al_sources->size()]; 00936 for (SourceCache::iterator si = _al_sources->begin(); si!=_al_sources->end(); ++si) { 00937 sources[i++]=*si; 00938 } 00939 make_current(); 00940 alGetError(); // clear errors 00941 alDeleteSources(_al_sources->size(),sources); 00942 al_audio_errcheck("alDeleteSources()"); 00943 delete [] sources; 00944 _al_sources->clear(); 00945 00946 // make sure that the context is not current when it is destroyed 00947 alcGetError(_device); // clear errors 00948 alcMakeContextCurrent(NULL); 00949 alc_audio_errcheck("alcMakeContextCurrent(NULL)",_device); 00950 00951 alcDestroyContext(_context); 00952 alc_audio_errcheck("alcDestroyContext(_context)",_device); 00953 _context = NULL; 00954 00955 if (_device) { 00956 audio_debug("Going to try to close openAL"); 00957 alcCloseDevice(_device); 00958 //alc_audio_errcheck("alcCloseDevice(_device)",_device); 00959 _device = NULL; 00960 audio_debug("openAL Closed"); 00961 } 00962 00963 _openal_active = false; 00964 } 00965 } 00966 _cleanup_required = false; 00967 } 00968 00969 //////////////////////////////////////////////////////////////////// 00970 // Function: OpenALAudioManager::SoundData::Constructor 00971 // Access: Public 00972 // Description: 00973 //////////////////////////////////////////////////////////////////// 00974 OpenALAudioManager::SoundData:: 00975 SoundData() : 00976 _manager(0), 00977 _movie(0), 00978 _sample(0), 00979 _stream(NULL), 00980 _length(0.0), 00981 _rate(0), 00982 _channels(0), 00983 _client_count(0) 00984 { 00985 } 00986 00987 //////////////////////////////////////////////////////////////////// 00988 // Function: OpenALAudioManager::SoundData::Destructor 00989 // Access: Public 00990 // Description: 00991 //////////////////////////////////////////////////////////////////// 00992 OpenALAudioManager::SoundData:: 00993 ~SoundData() { 00994 if (_sample != 0) { 00995 if (_manager->_is_valid) { 00996 _manager->make_current(); 00997 alDeleteBuffers(1,&_sample); 00998 } 00999 _sample = 0; 01000 } 01001 } 01002 01003 //////////////////////////////////////////////////////////////////// 01004 // Function: OpenALAudioManager::increment_client_count 01005 // Access: Public 01006 // Description: Increments the SoundData's client count. Any 01007 // SoundData that is actively in use (ie, has a client) 01008 // is removed entirely from the expiration queue. 01009 //////////////////////////////////////////////////////////////////// 01010 void OpenALAudioManager:: 01011 increment_client_count(SoundData *sd) { 01012 sd->_client_count += 1; 01013 audio_debug("Incrementing: " << sd->_movie->get_filename().get_basename() << " " << sd->_client_count); 01014 if (sd->_client_count == 1) { 01015 if (sd->_sample) { 01016 _expiring_samples.erase(sd->_expire); 01017 } else { 01018 _expiring_streams.erase(sd->_expire); 01019 } 01020 } 01021 } 01022 01023 //////////////////////////////////////////////////////////////////// 01024 // Function: OpenALAudioManager::decrement_client_count 01025 // Access: Public 01026 // Description: Decrements the SoundData's client count. Sounds 01027 // that are no longer in use (ie, have no clients) 01028 // go into the expiration queue. When the expiration 01029 // queue reaches the cache limit, the first item on 01030 // the queue is freed. 01031 //////////////////////////////////////////////////////////////////// 01032 void OpenALAudioManager:: 01033 decrement_client_count(SoundData *sd) { 01034 sd->_client_count -= 1; 01035 audio_debug("Decrementing: " << sd->_movie->get_filename().get_basename() << " " << sd->_client_count); 01036 if (sd->_client_count == 0) { 01037 if (sd->_sample) { 01038 _expiring_samples.push_back(sd); 01039 sd->_expire = _expiring_samples.end(); 01040 sd->_expire--; 01041 } else { 01042 _expiring_streams.push_back(sd); 01043 sd->_expire = _expiring_streams.end(); 01044 sd->_expire--; 01045 } 01046 discard_excess_cache(_cache_limit); 01047 } 01048 } 01049 01050 //////////////////////////////////////////////////////////////////// 01051 // Function: OpenALAudioManager::discard_excess_cache 01052 // Access: Public 01053 // Description: Discards sounds from the sound cache until the 01054 // number of sounds remaining is under the limit. 01055 //////////////////////////////////////////////////////////////////// 01056 void OpenALAudioManager:: 01057 discard_excess_cache(int sample_limit) { 01058 int stream_limit = 5; 01059 01060 while (((int)_expiring_samples.size()) > sample_limit) { 01061 SoundData *sd = (SoundData*)(_expiring_samples.front()); 01062 assert(sd->_client_count == 0); 01063 assert(sd->_expire == _expiring_samples.begin()); 01064 _expiring_samples.pop_front(); 01065 _sample_cache.erase(_sample_cache.find(sd->_movie->get_filename())); 01066 audio_debug("Expiring: " << sd->_movie->get_filename().get_basename()); 01067 delete sd; 01068 } 01069 01070 while (((int)_expiring_streams.size()) > stream_limit) { 01071 SoundData *sd = (SoundData*)(_expiring_streams.front()); 01072 assert(sd->_client_count == 0); 01073 assert(sd->_expire == _expiring_streams.begin()); 01074 _expiring_streams.pop_front(); 01075 audio_debug("Expiring: " << sd->_movie->get_filename().get_basename()); 01076 delete sd; 01077 } 01078 } 01079 01080 #endif //]