Panda3D

fmodAudioManager.cxx

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 //]
 All Classes Functions Variables Enumerations