Panda3D
|
00001 // Filename: fmodAudioManager.cxx 00002 // Created by: cort (January 22, 2003) 00003 // Prior system by: cary 00004 // Rewrite [for new Version of FMOD-EX] by: Stan Rosenbaum "Staque" - Spring 2006 00005 // 00006 // 00007 //////////////////////////////////////////////////////////////////// 00008 // 00009 // PANDA 3D SOFTWARE 00010 // Copyright (c) Carnegie Mellon University. All rights reserved. 00011 // 00012 // All use of this software is subject to the terms of the revised BSD 00013 // license. You should have received a copy of this license along 00014 // with this source code in a file named "LICENSE." 00015 // 00016 //////////////////////////////////////////////////////////////////// 00017 00018 #include "pandabase.h" 00019 #include "config_audio.h" 00020 #include "dcast.h" 00021 00022 #ifdef HAVE_FMODEX //[ 00023 00024 //Panda headers. 00025 #include "config_audio.h" 00026 #include "config_util.h" 00027 #include "fmodAudioManager.h" 00028 #include "fmodAudioSound.h" 00029 //Needed so People use Panda's Generic UNIX Style Paths for Filename. 00030 #include "filename.h" 00031 #include "virtualFileSystem.h" 00032 00033 //FMOD Headers. 00034 #include <fmod.hpp> 00035 #include <fmod_errors.h> 00036 00037 #define USER_DSP_MAGIC ((void*)0x7012AB35) 00038 00039 TypeHandle FmodAudioManager::_type_handle; 00040 00041 FMOD::System *FmodAudioManager::_system; 00042 pset<FmodAudioManager *> FmodAudioManager::_all_managers; 00043 00044 bool FmodAudioManager::_system_is_valid = false; 00045 00046 00047 // This sets the distance factor for 3D audio to use feet. 00048 // FMOD uses meters by default. 00049 // Since Panda use feet we need to compensate for that with a factor of 3.28 00050 // 00051 // This can be overwritten. You just need to call 00052 // audio_3d_set_distance_factor(float factor) and set your new factor. 00053 00054 float FmodAudioManager::_doppler_factor = 1; 00055 float FmodAudioManager::_distance_factor = 3.28; 00056 float FmodAudioManager::_drop_off_factor = 1; 00057 00058 00059 //////////////////////////////////////////////////////////////////// 00060 // Central dispatcher for audio errors. 00061 //////////////////////////////////////////////////////////////////// 00062 00063 void fmod_audio_errcheck(const char *context, FMOD_RESULT result) { 00064 if (result != 0) { 00065 audio_error(context << ": " << FMOD_ErrorString(result) ); 00066 } 00067 } 00068 00069 //////////////////////////////////////////////////////////////////// 00070 // Function: Create_FmodAudioManager 00071 // Access: Private 00072 // Description: Factory Function 00073 //////////////////////////////////////////////////////////////////// 00074 AudioManager *Create_FmodAudioManager() { 00075 audio_debug("Create_FmodAudioManager()"); 00076 return new FmodAudioManager; 00077 } 00078 00079 00080 //////////////////////////////////////////////////////////////////// 00081 // Function: FmodAudioManager::Constructor 00082 // Access: Public 00083 // Description: 00084 //////////////////////////////////////////////////////////////////// 00085 FmodAudioManager:: 00086 FmodAudioManager() { 00087 FMOD_RESULT result; 00088 00089 //We need a varible temporary to check the FMOD Version. 00090 unsigned int version; 00091 00092 _all_managers.insert(this); 00093 00094 //Init 3D attributes 00095 _position.x = 0; 00096 _position.y = 0; 00097 _position.z = 0; 00098 00099 _velocity.x = 0; 00100 _velocity.y = 0; 00101 _velocity.z = 0; 00102 00103 _forward.x = 0; 00104 _forward.y = 0; 00105 _forward.z = 0; 00106 00107 _up.x = 0; 00108 _up.y = 0; 00109 _up.z = 0; 00110 00111 if (_system == (FMOD::System *)NULL) { 00112 // Create the global FMOD System object. This one object must be 00113 // shared by all FmodAudioManagers (this is particularly true on 00114 // OSX, but the FMOD documentation is unclear as to whether this 00115 // is the intended design on all systems). 00116 00117 result = FMOD::System_Create(&_system); 00118 fmod_audio_errcheck("FMOD::System_Create()", result); 00119 00120 // Let check the Version of FMOD to make sure the Headers and Libraries are correct. 00121 result = _system->getVersion(&version); 00122 fmod_audio_errcheck("_system->getVersion()", result); 00123 00124 if (version < FMOD_VERSION){ 00125 audio_error("You are using an old version of FMOD. This program requires:" << FMOD_VERSION); 00126 } 00127 00128 //Stick Surround Sound 5.1 thing Here. 00129 if (fmod_use_surround_sound) { 00130 audio_debug("Setting FMOD to use 5.1 Surround Sound."); 00131 result = _system->setSpeakerMode( FMOD_SPEAKERMODE_5POINT1 ); 00132 fmod_audio_errcheck("_system->setSpeakerMode()", result); 00133 } 00134 00135 //Now we Initialize the System. 00136 int nchan = fmod_number_of_sound_channels; 00137 result = _system->init(nchan, FMOD_INIT_NORMAL, 0); 00138 fmod_audio_errcheck("_system->init()", result); 00139 00140 _system_is_valid = (result == FMOD_OK); 00141 00142 if (_system_is_valid) { 00143 result = _system->set3DSettings( _doppler_factor, _distance_factor, _drop_off_factor); 00144 fmod_audio_errcheck("_system->set3DSettings()", result); 00145 00146 #if (FMOD_VERSION >= 0x00043100) // FMod 4.31.00 changed this API 00147 result = _system->setFileSystem(open_callback, close_callback, read_callback, seek_callback, 0, 0, -1); 00148 #else 00149 result = _system->setFileSystem(open_callback, close_callback, read_callback, seek_callback, -1); 00150 #endif 00151 fmod_audio_errcheck("_system->setFileSystem()", result); 00152 } 00153 } 00154 00155 _is_valid = _system_is_valid; 00156 00157 memset(&_midi_info, 0, sizeof(_midi_info)); 00158 _midi_info.cbsize = sizeof(_midi_info); 00159 00160 Filename dls_pathname = get_dls_pathname(); 00161 00162 #ifdef IS_OSX 00163 // Here's a big kludge. Don't ever let FMOD try to load this 00164 // OSX-provided file; it crashes messily if you do. 00165 if (dls_pathname == "/System/Library/Components/CoreAudio.component/Contents/Resources/gs_instruments.dls") { 00166 dls_pathname = ""; 00167 } 00168 #endif // IS_OSX 00169 00170 if (!dls_pathname.empty()) { 00171 _dlsname = dls_pathname.to_os_specific(); 00172 _midi_info.dlsname = _dlsname.c_str(); 00173 } 00174 00175 result = _system->createChannelGroup("UserGroup", &_channelgroup); 00176 fmod_audio_errcheck("_system->createChannelGroup()", result); 00177 } 00178 00179 //////////////////////////////////////////////////////////////////// 00180 // Function: FmodAudioManager::Destructor 00181 // Access: Public 00182 // Description: 00183 //////////////////////////////////////////////////////////////////// 00184 FmodAudioManager:: 00185 ~FmodAudioManager() { 00186 // Be sure to delete associated sounds before deleting the manager! 00187 FMOD_RESULT result; 00188 00189 //Release Sounds Next 00190 _all_sounds.clear(); 00191 00192 // Remove me from the managers list. 00193 _all_managers.erase(this); 00194 00195 if (_all_managers.empty()) { 00196 result = _system->release(); 00197 fmod_audio_errcheck("_system->release()", result); 00198 _system = NULL; 00199 _system_is_valid = false; 00200 } 00201 } 00202 00203 //////////////////////////////////////////////////////////////////// 00204 // Function: FmodAudioManager::is_valid 00205 // Access: Public 00206 // Description: This just check to make sure the FMOD System is 00207 // up and running correctly. 00208 //////////////////////////////////////////////////////////////////// 00209 bool FmodAudioManager:: 00210 is_valid() { 00211 return _is_valid; 00212 } 00213 00214 //////////////////////////////////////////////////////////////////// 00215 // Function: FmodAudioManager::make_dsp 00216 // Access: Private 00217 // Description: Converts a FilterConfig to an FMOD_DSP 00218 //////////////////////////////////////////////////////////////////// 00219 FMOD::DSP *FmodAudioManager:: 00220 make_dsp(const FilterProperties::FilterConfig &conf) { 00221 FMOD_DSP_TYPE dsptype; 00222 FMOD_RESULT result; 00223 FMOD::DSP *dsp; 00224 switch (conf._type) { 00225 case FilterProperties::FT_lowpass: dsptype = FMOD_DSP_TYPE_LOWPASS; break; 00226 case FilterProperties::FT_highpass: dsptype = FMOD_DSP_TYPE_HIGHPASS; break; 00227 case FilterProperties::FT_echo: dsptype = FMOD_DSP_TYPE_ECHO; break; 00228 case FilterProperties::FT_flange: dsptype = FMOD_DSP_TYPE_FLANGE; break; 00229 case FilterProperties::FT_distort: dsptype = FMOD_DSP_TYPE_DISTORTION; break; 00230 case FilterProperties::FT_normalize: dsptype = FMOD_DSP_TYPE_NORMALIZE; break; 00231 case FilterProperties::FT_parameq: dsptype = FMOD_DSP_TYPE_PARAMEQ; break; 00232 case FilterProperties::FT_pitchshift: dsptype = FMOD_DSP_TYPE_PITCHSHIFT; break; 00233 case FilterProperties::FT_chorus: dsptype = FMOD_DSP_TYPE_CHORUS; break; 00234 case FilterProperties::FT_reverb: dsptype = FMOD_DSP_TYPE_REVERB; break; 00235 case FilterProperties::FT_compress: dsptype = FMOD_DSP_TYPE_COMPRESSOR; break; 00236 default: 00237 audio_error("Garbage in DSP configuration data"); 00238 return NULL; 00239 } 00240 00241 result = _system->createDSPByType( dsptype, &dsp); 00242 if (result != 0) { 00243 audio_error("Could not create DSP object"); 00244 return NULL; 00245 } 00246 00247 FMOD_RESULT res1=FMOD_OK; 00248 FMOD_RESULT res2=FMOD_OK; 00249 FMOD_RESULT res3=FMOD_OK; 00250 FMOD_RESULT res4=FMOD_OK; 00251 FMOD_RESULT res5=FMOD_OK; 00252 FMOD_RESULT res6=FMOD_OK; 00253 FMOD_RESULT res7=FMOD_OK; 00254 FMOD_RESULT res8=FMOD_OK; 00255 00256 switch (conf._type) { 00257 case FilterProperties::FT_lowpass: 00258 res1=dsp->setParameter(FMOD_DSP_LOWPASS_CUTOFF, conf._a); 00259 res2=dsp->setParameter(FMOD_DSP_LOWPASS_RESONANCE, conf._b); 00260 break; 00261 case FilterProperties::FT_highpass: 00262 res1=dsp->setParameter(FMOD_DSP_HIGHPASS_CUTOFF, conf._a); 00263 res2=dsp->setParameter(FMOD_DSP_HIGHPASS_RESONANCE, conf._b); 00264 break; 00265 case FilterProperties::FT_echo: 00266 res1=dsp->setParameter(FMOD_DSP_ECHO_DRYMIX, conf._a); 00267 res2=dsp->setParameter(FMOD_DSP_ECHO_WETMIX, conf._b); 00268 res3=dsp->setParameter(FMOD_DSP_ECHO_DELAY, conf._c); 00269 res4=dsp->setParameter(FMOD_DSP_ECHO_DECAYRATIO, conf._d); 00270 break; 00271 case FilterProperties::FT_flange: 00272 res1=dsp->setParameter(FMOD_DSP_FLANGE_DRYMIX, conf._a); 00273 res2=dsp->setParameter(FMOD_DSP_FLANGE_WETMIX, conf._b); 00274 res3=dsp->setParameter(FMOD_DSP_FLANGE_DEPTH, conf._c); 00275 res4=dsp->setParameter(FMOD_DSP_FLANGE_RATE, conf._d); 00276 break; 00277 case FilterProperties::FT_distort: 00278 res1=dsp->setParameter(FMOD_DSP_DISTORTION_LEVEL, conf._a); 00279 break; 00280 case FilterProperties::FT_normalize: 00281 res1=dsp->setParameter(FMOD_DSP_NORMALIZE_FADETIME, conf._a); 00282 res2=dsp->setParameter(FMOD_DSP_NORMALIZE_THRESHHOLD,conf._b); 00283 res3=dsp->setParameter(FMOD_DSP_NORMALIZE_MAXAMP, conf._c); 00284 break; 00285 case FilterProperties::FT_parameq: 00286 res1=dsp->setParameter(FMOD_DSP_PARAMEQ_CENTER, conf._a); 00287 res2=dsp->setParameter(FMOD_DSP_PARAMEQ_BANDWIDTH, conf._b); 00288 res3=dsp->setParameter(FMOD_DSP_PARAMEQ_GAIN, conf._c); 00289 break; 00290 case FilterProperties::FT_pitchshift: 00291 res1=dsp->setParameter(FMOD_DSP_PITCHSHIFT_PITCH, conf._a); 00292 res2=dsp->setParameter(FMOD_DSP_PITCHSHIFT_FFTSIZE, conf._b); 00293 res3=dsp->setParameter(FMOD_DSP_PITCHSHIFT_OVERLAP, conf._c); 00294 break; 00295 case FilterProperties::FT_chorus: 00296 res1=dsp->setParameter(FMOD_DSP_CHORUS_DRYMIX, conf._a); 00297 res2=dsp->setParameter(FMOD_DSP_CHORUS_WETMIX1, conf._b); 00298 res3=dsp->setParameter(FMOD_DSP_CHORUS_WETMIX2, conf._c); 00299 res4=dsp->setParameter(FMOD_DSP_CHORUS_WETMIX3, conf._d); 00300 res5=dsp->setParameter(FMOD_DSP_CHORUS_DELAY, conf._e); 00301 res6=dsp->setParameter(FMOD_DSP_CHORUS_RATE, conf._f); 00302 res7=dsp->setParameter(FMOD_DSP_CHORUS_DEPTH, conf._g); 00303 res8=dsp->setParameter(FMOD_DSP_CHORUS_FEEDBACK, conf._h); 00304 break; 00305 case FilterProperties::FT_reverb: 00306 res1=dsp->setParameter(FMOD_DSP_REVERB_DRYMIX, conf._a); 00307 res2=dsp->setParameter(FMOD_DSP_REVERB_WETMIX, conf._b); 00308 res3=dsp->setParameter(FMOD_DSP_REVERB_ROOMSIZE, conf._c); 00309 res4=dsp->setParameter(FMOD_DSP_REVERB_DAMP, conf._d); 00310 res5=dsp->setParameter(FMOD_DSP_REVERB_WIDTH, conf._e); 00311 break; 00312 case FilterProperties::FT_compress: 00313 res1=dsp->setParameter(FMOD_DSP_COMPRESSOR_THRESHOLD, conf._a); 00314 res2=dsp->setParameter(FMOD_DSP_COMPRESSOR_ATTACK, conf._b); 00315 res3=dsp->setParameter(FMOD_DSP_COMPRESSOR_RELEASE, conf._c); 00316 res4=dsp->setParameter(FMOD_DSP_COMPRESSOR_GAINMAKEUP,conf._d); 00317 break; 00318 } 00319 00320 if ((res1!=FMOD_OK)||(res2!=FMOD_OK)||(res3!=FMOD_OK)||(res4!=FMOD_OK)|| 00321 (res5!=FMOD_OK)||(res6!=FMOD_OK)||(res7!=FMOD_OK)||(res8!=FMOD_OK)) { 00322 audio_error("Could not configure DSP"); 00323 dsp->release(); 00324 return NULL; 00325 } 00326 00327 dsp->setUserData(USER_DSP_MAGIC); 00328 00329 return dsp; 00330 } 00331 00332 //////////////////////////////////////////////////////////////////// 00333 // Function: FmodAudioManager::update_dsp_chain 00334 // Access: Public 00335 // Description: Alters a DSP chain to make it match the specified 00336 // configuration. 00337 // 00338 // This is an inadequate implementation - it just 00339 // clears the whole DSP chain and rebuilds it from 00340 // scratch. A better implementation would compare 00341 // the existing DSP chain to the desired one, and 00342 // make incremental changes. This would prevent 00343 // a "pop" sound when the changes are made. 00344 //////////////////////////////////////////////////////////////////// 00345 void FmodAudioManager:: 00346 update_dsp_chain(FMOD::DSP *head, FilterProperties *config) { 00347 const FilterProperties::ConfigVector &conf = config->get_config(); 00348 FMOD_RESULT result; 00349 00350 while (1) { 00351 int numinputs; 00352 result = head->getNumInputs(&numinputs); 00353 fmod_audio_errcheck("head->getNumInputs()", result); 00354 if (numinputs != 1) { 00355 break; 00356 } 00357 FMOD::DSP *prev; 00358 result = head->getInput(0, &prev, NULL); 00359 fmod_audio_errcheck("head->getInput()", result); 00360 void *userdata; 00361 result = prev->getUserData(&userdata); 00362 fmod_audio_errcheck("prev->getUserData()", result); 00363 if (userdata != USER_DSP_MAGIC) { 00364 break; 00365 } 00366 result = prev->remove(); 00367 fmod_audio_errcheck("prev->remove()", result); 00368 result = prev->release(); 00369 fmod_audio_errcheck("prev->release()", result); 00370 } 00371 00372 for (int i=0; i<(int)(conf.size()); i++) { 00373 FMOD::DSP *dsp = make_dsp(conf[i]); 00374 result = _channelgroup->addDSP(dsp, NULL); 00375 fmod_audio_errcheck("_channelgroup->addDSP()", result); 00376 } 00377 } 00378 00379 //////////////////////////////////////////////////////////////////// 00380 // Function: FmodAudioManager::configure_filters 00381 // Access: Public 00382 // Description: Configure the global DSP filter chain. 00383 // 00384 // FMOD has a relatively powerful DSP 00385 // implementation. It is likely that most 00386 // configurations will be supported. 00387 //////////////////////////////////////////////////////////////////// 00388 bool FmodAudioManager:: 00389 configure_filters(FilterProperties *config) { 00390 FMOD_RESULT result; 00391 FMOD::DSP *head; 00392 result = _channelgroup->getDSPHead(&head); 00393 if (result != 0) { 00394 audio_error("Getting DSP head: " << FMOD_ErrorString(result) ); 00395 return false; 00396 } 00397 update_dsp_chain(head, config); 00398 return true; 00399 } 00400 00401 //////////////////////////////////////////////////////////////////// 00402 // Function: FmodAudioManager::get_sound 00403 // Access: Public 00404 // Description: This is what creates a sound instance. 00405 //////////////////////////////////////////////////////////////////// 00406 PT(AudioSound) FmodAudioManager:: 00407 get_sound(const string &file_name, bool positional, int) { 00408 //Needed so People use Panda's Generic UNIX Style Paths for Filename. 00409 //path.to_os_specific() converts it back to the proper OS version later on. 00410 00411 Filename path = file_name; 00412 00413 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); 00414 vfs->resolve_filename(path, get_model_path()); 00415 00416 // Build a new AudioSound from the audio data. 00417 PT(AudioSound) audioSound = 0; 00418 PT(FmodAudioSound) fmodAudioSound = new FmodAudioSound(this, path, positional ); 00419 00420 _all_sounds.insert(fmodAudioSound); 00421 00422 audioSound = fmodAudioSound; 00423 00424 return audioSound; 00425 } 00426 00427 //////////////////////////////////////////////////////////////////// 00428 // Function: FmodAudioManager::get_sound 00429 // Access: Public 00430 // Description: This is what creates a sound instance. 00431 //////////////////////////////////////////////////////////////////// 00432 PT(AudioSound) FmodAudioManager:: 00433 get_sound(MovieAudio *source, bool positional, int) { 00434 nassert_raise("FMOD audio manager does not support MovieAudio sources"); 00435 return NULL; 00436 } 00437 00438 //////////////////////////////////////////////////////////////////// 00439 // Function: FmodAudioManager::getSpeakerSetup() 00440 // Access: Published 00441 // Description: This is to query if you are using a MultiChannel Setup. 00442 //////////////////////////////////////////////////////////////////// 00443 int FmodAudioManager:: 00444 getSpeakerSetup() { 00445 FMOD_RESULT result; 00446 FMOD_SPEAKERMODE speakerMode; 00447 int returnMode; 00448 00449 result = _system->getSpeakerMode( &speakerMode ); 00450 fmod_audio_errcheck("_system->getSpeakerMode()", result); 00451 00452 switch (speakerMode) { 00453 case FMOD_SPEAKERMODE_RAW: 00454 returnMode = 0; 00455 break; 00456 case FMOD_SPEAKERMODE_MONO: 00457 returnMode = 1; 00458 break; 00459 case FMOD_SPEAKERMODE_STEREO: 00460 returnMode = 2; 00461 break; 00462 case FMOD_SPEAKERMODE_QUAD: 00463 returnMode = 3; 00464 break; 00465 case FMOD_SPEAKERMODE_SURROUND: 00466 returnMode = 4; 00467 break; 00468 case FMOD_SPEAKERMODE_5POINT1: 00469 returnMode = 5; 00470 break; 00471 case FMOD_SPEAKERMODE_7POINT1: 00472 returnMode = 6; 00473 break; 00474 case FMOD_SPEAKERMODE_PROLOGIC: 00475 returnMode = 7; 00476 break; 00477 case FMOD_SPEAKERMODE_MAX: 00478 returnMode = 8; 00479 break; 00480 default: 00481 returnMode = -1; 00482 } 00483 00484 return returnMode; 00485 } 00486 00487 //////////////////////////////////////////////////////////////////// 00488 // Function: FmodAudioManager::setSpeakerSetup() 00489 // Access: Published 00490 // Description: This is to set up FMOD to use a MultiChannel Setup. 00491 // This method is pretty much useless. 00492 // To set a speaker setup in FMOD for Surround Sound, 00493 // stereo, or whatever you have to set the SpeakerMode 00494 // BEFORE you Initialize FMOD. 00495 // Since Panda Inits the FmodAudioManager right when you 00496 // Start it up, you are never given an oppertunity to call 00497 // this function. 00498 // That is why I stuck a BOOL in the CONFIG.PRC file, whichs 00499 // lets you flag if you want to use a Multichannel or not. 00500 // That will set the speaker setup when an instance of this 00501 // class is constructed. 00502 // Still I put this here as a measure of good faith, since you 00503 // can query the speaker setup after everything in Init. 00504 // Also, maybe someone will completely hack Panda someday, in which 00505 // one can init or re-init the AudioManagers after Panda is running. 00506 //////////////////////////////////////////////////////////////////// 00507 void FmodAudioManager:: 00508 setSpeakerSetup(AudioManager::SpeakerModeCategory cat) { 00509 FMOD_RESULT result; 00510 FMOD_SPEAKERMODE speakerModeType = (FMOD_SPEAKERMODE)cat; 00511 result = _system->setSpeakerMode( speakerModeType); 00512 fmod_audio_errcheck("_system->setSpeakerMode()", result); 00513 } 00514 00515 //////////////////////////////////////////////////////////////////// 00516 // Function: FmodAudioManager::set_volume(float volume) 00517 // Access: Public 00518 // Description: Sets the volume of the AudioManager. 00519 // It is not an override, but a multiplier. 00520 //////////////////////////////////////////////////////////////////// 00521 void FmodAudioManager:: 00522 set_volume(float volume) { 00523 FMOD_RESULT result; 00524 result = _channelgroup->setVolume(volume); 00525 fmod_audio_errcheck("_channelgroup->setVolume()", result); 00526 } 00527 00528 //////////////////////////////////////////////////////////////////// 00529 // Function: FmodAudioManager::get_volume() 00530 // Access: Public 00531 // Description: Returns the AudioManager's volume. 00532 //////////////////////////////////////////////////////////////////// 00533 float FmodAudioManager:: 00534 get_volume() const { 00535 float volume; 00536 FMOD_RESULT result; 00537 result = _channelgroup->getVolume(&volume); 00538 fmod_audio_errcheck("_channelgroup->getVolume()", result); 00539 return volume; 00540 } 00541 00542 //////////////////////////////////////////////////////////////////// 00543 // Function: FmodAudioManager::set_active(bool active) 00544 // Access: Public 00545 // Description: Turn on/off 00546 // Warning: not implemented. 00547 //////////////////////////////////////////////////////////////////// 00548 void FmodAudioManager:: 00549 set_active(bool active) { 00550 if (_active != active) { 00551 _active = active; 00552 00553 // Tell our AudioSounds to adjust: 00554 for (SoundSet::iterator i = _all_sounds.begin(); 00555 i != _all_sounds.end(); 00556 ++i) { 00557 (*i)->set_active(_active); 00558 } 00559 } 00560 } 00561 00562 //////////////////////////////////////////////////////////////////// 00563 // Function: FmodAudioManager::get_active() 00564 // Access: Public 00565 // Description: 00566 //////////////////////////////////////////////////////////////////// 00567 bool FmodAudioManager:: 00568 get_active() const { 00569 return _active; 00570 } 00571 00572 //////////////////////////////////////////////////////////////////// 00573 // Function: FmodAudioManager::stop_all_sounds() 00574 // Access: Public 00575 // Description: Stop playback on all sounds managed by this manager. 00576 //////////////////////////////////////////////////////////////////// 00577 void FmodAudioManager:: 00578 stop_all_sounds() { 00579 // We have to walk through this list with some care, since stopping 00580 // a sound may also remove it from the set (if there are no other 00581 // references to the sound). 00582 SoundSet::iterator i; 00583 i = _all_sounds.begin(); 00584 while (i != _all_sounds.end()) { 00585 SoundSet::iterator next = i; 00586 ++next; 00587 00588 (*i)->stop(); 00589 i = next; 00590 } 00591 } 00592 00593 //////////////////////////////////////////////////////////////////// 00594 // Function: FmodAudioManager::update 00595 // Access: Public 00596 // Description: Perform all per-frame update functions. 00597 //////////////////////////////////////////////////////////////////// 00598 void FmodAudioManager:: 00599 update() { 00600 _system->update(); 00601 } 00602 00603 //////////////////////////////////////////////////////////////////// 00604 // Function: FmodAudioManager::audio_3d_set_listener_attributes 00605 // Access: Public 00606 // Description: Set position of the "ear" that picks up 3d sounds 00607 // NOW LISTEN UP!!! THIS IS IMPORTANT! 00608 // Both Panda3D and FMOD use a left handed coordinate system. 00609 // But there is a major difference! 00610 // In Panda3D the Y-Axis is going into the Screen and the Z-Axis is going up. 00611 // In FMOD the Y-Axis is going up and the Z-Axis is going into the screen. 00612 // The solution is simple, we just flip the Y and Z axis, as we move coordinates 00613 // from Panda to FMOD and back. 00614 // What does did mean to average Panda user? Nothing, they shouldn't notice anyway. 00615 // But if you decide to do any 3D audio work in here you have to keep it in mind. 00616 // I told you, so you can't say I didn't. 00617 //////////////////////////////////////////////////////////////////// 00618 void FmodAudioManager:: 00619 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) { 00620 audio_debug("FmodAudioManager::audio_3d_set_listener_attributes()"); 00621 00622 FMOD_RESULT result; 00623 00624 _position.x = px; 00625 _position.y = pz; 00626 _position.z = py; 00627 00628 _velocity.x = vx; 00629 _velocity.y = vz; 00630 _velocity.z = vy; 00631 00632 _forward.x = fx; 00633 _forward.y = fz; 00634 _forward.z = fy; 00635 00636 _up.x = ux; 00637 _up.y = uz; 00638 _up.z = uy; 00639 00640 result = _system->set3DListenerAttributes( 0, &_position, &_velocity, &_forward, &_up); 00641 fmod_audio_errcheck("_system->set3DListenerAttributes()", result); 00642 00643 } 00644 00645 //////////////////////////////////////////////////////////////////// 00646 // Function: FmodAudioManager::audio_3d_get_listener_attributes 00647 // Access: Public 00648 // Description: Get position of the "ear" that picks up 3d sounds 00649 //////////////////////////////////////////////////////////////////// 00650 void FmodAudioManager:: 00651 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) { 00652 audio_error("audio3dGetListenerAttributes: currently unimplemented. Get the attributes of the attached object"); 00653 00654 } 00655 00656 00657 //////////////////////////////////////////////////////////////////// 00658 // Function: FmodAudioManager::audio_3d_set_distance_factor 00659 // Access: Public 00660 // Description: Set units per meter (Fmod uses meters internally for 00661 // its sound-spacialization calculations) 00662 //////////////////////////////////////////////////////////////////// 00663 void FmodAudioManager:: 00664 audio_3d_set_distance_factor(float factor) { 00665 audio_debug( "FmodAudioManager::audio_3d_set_distance_factor( factor= " << factor << ")" ); 00666 00667 FMOD_RESULT result; 00668 00669 _distance_factor = factor; 00670 00671 result = _system->set3DSettings( _doppler_factor, _distance_factor, _drop_off_factor); 00672 fmod_audio_errcheck("_system->set3DSettings()", result); 00673 00674 00675 } 00676 00677 //////////////////////////////////////////////////////////////////// 00678 // Function: FmodAudioManager::audio_3d_get_distance_factor 00679 // Access: Public 00680 // Description: Gets units per meter (Fmod uses meters internally for 00681 // its sound-spacialization calculations) 00682 //////////////////////////////////////////////////////////////////// 00683 float FmodAudioManager:: 00684 audio_3d_get_distance_factor() const { 00685 audio_debug("FmodAudioManager::audio_3d_get_distance_factor()"); 00686 00687 return _distance_factor; 00688 } 00689 00690 //////////////////////////////////////////////////////////////////// 00691 // Function: FmodAudioManager::audio_3d_set_doppler_factor 00692 // Access: Public 00693 // Description: Exaggerates or diminishes the Doppler effect. 00694 // Defaults to 1.0 00695 //////////////////////////////////////////////////////////////////// 00696 void FmodAudioManager:: 00697 audio_3d_set_doppler_factor(float factor) { 00698 audio_debug("FmodAudioManager::audio_3d_set_doppler_factor(factor="<<factor<<")"); 00699 00700 FMOD_RESULT result; 00701 00702 _doppler_factor = factor; 00703 00704 result = _system->set3DSettings( _doppler_factor, _distance_factor, _drop_off_factor); 00705 fmod_audio_errcheck("_system->set3DSettings()", result); 00706 00707 } 00708 00709 //////////////////////////////////////////////////////////////////// 00710 // Function: FmodAudioManager::audio_3d_get_doppler_factor 00711 // Access: Public 00712 // Description: 00713 //////////////////////////////////////////////////////////////////// 00714 float FmodAudioManager:: 00715 audio_3d_get_doppler_factor() const { 00716 audio_debug("FmodAudioManager::audio_3d_get_doppler_factor()"); 00717 00718 return _doppler_factor; 00719 } 00720 00721 //////////////////////////////////////////////////////////////////// 00722 // Function: FmodAudioManager::audio_3d_set_drop_off_factor 00723 // Access: Public 00724 // Description: Control the effect distance has on audability. 00725 // Defaults to 1.0 00726 //////////////////////////////////////////////////////////////////// 00727 void FmodAudioManager:: 00728 audio_3d_set_drop_off_factor(float factor) { 00729 audio_debug("FmodAudioManager::audio_3d_set_drop_off_factor("<<factor<<")"); 00730 00731 FMOD_RESULT result; 00732 00733 _drop_off_factor = factor; 00734 00735 result = _system->set3DSettings( _doppler_factor, _distance_factor, _drop_off_factor); 00736 fmod_audio_errcheck("_system->set3DSettings()", result); 00737 00738 } 00739 00740 //////////////////////////////////////////////////////////////////// 00741 // Function: FmodAudioManager::audio_3d_get_drop_off_factor 00742 // Access: Public 00743 // Description: 00744 //////////////////////////////////////////////////////////////////// 00745 float FmodAudioManager:: 00746 audio_3d_get_drop_off_factor() const { 00747 audio_debug("FmodAudioManager::audio_3d_get_drop_off_factor()"); 00748 00749 return _drop_off_factor; 00750 00751 } 00752 00753 00754 00755 //////////////////////////////////////////////////////////////////// 00756 // Function: FmodAudioManager::set_concurrent_sound_limit 00757 // Access: Public 00758 // Description: NOT USED FOR FMOD-EX!!! 00759 //////////////////////////////////////////////////////////////////// 00760 void FmodAudioManager:: 00761 set_concurrent_sound_limit(unsigned int limit) { 00762 00763 } 00764 00765 //////////////////////////////////////////////////////////////////// 00766 // Function: FmodAudioManager::get_concurrent_sound_limit 00767 // Access: Public 00768 // Description: NOT USED FOR FMOD-EX!!! 00769 //////////////////////////////////////////////////////////////////// 00770 unsigned int FmodAudioManager:: 00771 get_concurrent_sound_limit() const { 00772 return 1000000; 00773 } 00774 00775 //////////////////////////////////////////////////////////////////// 00776 // Function: FmodAudioManager::reduce_sounds_playing_to 00777 // Access: Private 00778 // Description: NOT USED FOR FMOD-EX!!! 00779 //////////////////////////////////////////////////////////////////// 00780 void FmodAudioManager:: 00781 reduce_sounds_playing_to(unsigned int count) { 00782 00783 } 00784 00785 00786 //////////////////////////////////////////////////////////////////// 00787 // Function: FmodAudioManager::uncache_sound 00788 // Access: Public 00789 // Description: NOT USED FOR FMOD-EX!!! 00790 // Clears a sound out of the sound cache. 00791 //////////////////////////////////////////////////////////////////// 00792 void FmodAudioManager:: 00793 uncache_sound(const string& file_name) { 00794 audio_debug("FmodAudioManager::uncache_sound(\""<<file_name<<"\")"); 00795 00796 } 00797 00798 00799 //////////////////////////////////////////////////////////////////// 00800 // Function: FmodAudioManager::clear_cache 00801 // Access: Public 00802 // Description: NOT USED FOR FMOD-EX!!! 00803 // Clear out the sound cache. 00804 //////////////////////////////////////////////////////////////////// 00805 void FmodAudioManager:: 00806 clear_cache() { 00807 audio_debug("FmodAudioManager::clear_cache()"); 00808 00809 } 00810 00811 //////////////////////////////////////////////////////////////////// 00812 // Function: FmodAudioManager::set_cache_limit 00813 // Access: Public 00814 // Description: NOT USED FOR FMOD-EX!!! 00815 // Set the number of sounds that the cache can hold. 00816 //////////////////////////////////////////////////////////////////// 00817 void FmodAudioManager:: 00818 set_cache_limit(unsigned int count) { 00819 audio_debug("FmodAudioManager::set_cache_limit(count="<<count<<")"); 00820 00821 } 00822 00823 //////////////////////////////////////////////////////////////////// 00824 // Function: FmodAudioManager::get_cache_limit 00825 // Access: Public 00826 // Description: NOT USED FOR FMOD-EX!!! 00827 // Gets the number of sounds that the cache can hold. 00828 //////////////////////////////////////////////////////////////////// 00829 unsigned int FmodAudioManager:: 00830 get_cache_limit() const { 00831 audio_debug("FmodAudioManager::get_cache_limit() returning "); 00832 //return _cache_limit; 00833 return 0; 00834 } 00835 00836 //////////////////////////////////////////////////////////////////// 00837 // Function: FmodAudioManager::open_callback 00838 // Access: Private, Static 00839 // Description: A hook into Panda's virtual file system. 00840 //////////////////////////////////////////////////////////////////// 00841 FMOD_RESULT F_CALLBACK FmodAudioManager:: 00842 open_callback(const char *name, int, unsigned int *file_size, 00843 void **handle, void **user_data) { 00844 if (name == (const char *)NULL || name[0] == '\0') { 00845 // An invalid attempt to open an unnamed file. 00846 return FMOD_ERR_FILE_NOTFOUND; 00847 } 00848 00849 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); 00850 00851 PT(VirtualFile) file = vfs->get_file(Filename(name)); 00852 if (file == (VirtualFile *)NULL) { 00853 return FMOD_ERR_FILE_NOTFOUND; 00854 } 00855 istream *str = file->open_read_file(true); 00856 00857 (*file_size) = file->get_file_size(str); 00858 (*handle) = (void *)str; 00859 (*user_data) = NULL; 00860 00861 return FMOD_OK; 00862 } 00863 00864 //////////////////////////////////////////////////////////////////// 00865 // Function: FmodAudioManager::close_callback 00866 // Access: Private, Static 00867 // Description: A hook into Panda's virtual file system. 00868 //////////////////////////////////////////////////////////////////// 00869 FMOD_RESULT F_CALLBACK FmodAudioManager:: 00870 close_callback(void *handle, void *user_data) { 00871 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); 00872 00873 istream *str = (istream *)handle; 00874 vfs->close_read_file(str); 00875 00876 return FMOD_OK; 00877 } 00878 00879 //////////////////////////////////////////////////////////////////// 00880 // Function: FmodAudioManager::read_callback 00881 // Access: Private, Static 00882 // Description: A hook into Panda's virtual file system. 00883 //////////////////////////////////////////////////////////////////// 00884 FMOD_RESULT F_CALLBACK FmodAudioManager:: 00885 read_callback(void *handle, void *buffer, unsigned int size_bytes, 00886 unsigned int *bytes_read, void *user_data) { 00887 istream *str = (istream *)handle; 00888 str->read((char *)buffer, size_bytes); 00889 (*bytes_read) = str->gcount(); 00890 00891 // We can't yield here, since this callback is made within a 00892 // sub-thread--an OS-level sub-thread spawned by FMod, not a Panda 00893 // thread. 00894 //thread_consider_yield(); 00895 00896 if (str->eof()) { 00897 if ((*bytes_read) == 0) { 00898 return FMOD_ERR_FILE_EOF; 00899 } else { 00900 // Report the EOF next time. 00901 return FMOD_OK; 00902 } 00903 } if (str->fail()) { 00904 return FMOD_ERR_FILE_BAD; 00905 } else { 00906 return FMOD_OK; 00907 } 00908 } 00909 00910 //////////////////////////////////////////////////////////////////// 00911 // Function: FmodAudioManager::seek_callback 00912 // Access: Private, Static 00913 // Description: A hook into Panda's virtual file system. 00914 //////////////////////////////////////////////////////////////////// 00915 FMOD_RESULT F_CALLBACK FmodAudioManager:: 00916 seek_callback(void *handle, unsigned int pos, void *user_data) { 00917 istream *str = (istream *)handle; 00918 str->clear(); 00919 str->seekg(pos); 00920 00921 if (str->fail() && !str->eof()) { 00922 return FMOD_ERR_FILE_COULDNOTSEEK; 00923 } else { 00924 return FMOD_OK; 00925 } 00926 } 00927 00928 00929 #endif //]