Browse Source

fix fmod for OSX; fix reference count leaks; use model-path as well as sound-path

David Rose 19 years ago
parent
commit
694873dc37

+ 8 - 0
panda/src/audio/config_audio.cxx

@@ -41,6 +41,14 @@ ConfigVariableString audio_library_name
 ConfigVariableDouble audio_volume 
 ("audio-volume", 1.0f);
 
+ConfigVariableFilename audio_dls_file 
+("audio-dls-file", Filename(),
+ PRC_DESC("Specifies a DLS file that defines an instrument set to load "
+          "for MIDI file playback.  If this is not specified, the sound "
+          "interface will try to use the system default DLS file, if "
+          "one is available; the likely success of this depends on the "
+          "operating system."));
+
 // Config variables for Fmod:
 
 //I should note this somewhere.  The actual number of sound one could

+ 1 - 0
panda/src/audio/config_audio.h

@@ -36,6 +36,7 @@ NotifyCategoryDecl(audio, EXPCL_PANDA, EXPTP_PANDA);
 extern EXPCL_PANDA ConfigVariableBool audio_active;
 extern EXPCL_PANDA ConfigVariableInt audio_cache_limit;
 extern EXPCL_PANDA ConfigVariableDouble audio_volume;
+extern EXPCL_PANDA ConfigVariableFilename audio_dls_file;
 
 //We Need This one.
 extern EXPCL_PANDA ConfigVariableString audio_library_name;

+ 1 - 1
panda/src/audiotraits/Sources.pp

@@ -26,7 +26,7 @@
 #begin lib_target
   #define TARGET fmod_audio
   #define BUILD_TARGET $[HAVE_FMODEX]
-  #define USE_PACKAGES fmod
+  #define USE_PACKAGES fmodex
   #define BUILDING_DLL BUILDING_FMOD_AUDIO
   #define LOCAL_LIBS audio event
   #define WIN_SYS_LIBS $[WIN_SYS_LIBS] user32.lib advapi32.lib winmm.lib

+ 15 - 15
panda/src/audiotraits/fmodAudioDSP.cxx

@@ -51,7 +51,7 @@ FmodAudioDSP(AudioManager *manager, AudioManager::DSP_category cat) {
   FMOD_DSP_TYPE dsptype = (FMOD_DSP_TYPE)cat;
 
   result = _manager->_system->createDSPByType( dsptype, &_dsp);
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_system->createDSPByType()", result);
 
   set_in_chain(false);
 
@@ -74,10 +74,10 @@ FmodAudioDSP::
   FMOD_RESULT result;
 
   result = _dsp->remove();
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_dsp->remove()", result);
 
   result = _dsp->release();
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_dsp->release()", result);
 
   audio_debug("DSP GONE");
 }
@@ -98,7 +98,7 @@ reset() {
   FMOD_RESULT result;
 
   result = _dsp->reset();
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_dsp->reset()", result);
 
   audio_debug("DSP Reset.");
 }
@@ -118,7 +118,7 @@ remove() {
   FMOD_RESULT result;
 
   result = _dsp->remove();
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_dsp->remove()", result);
 
   audio_debug("DSP Removed from relative effects chain.");
 }
@@ -138,7 +138,7 @@ set_bypass(bool bypass) {
   FMOD_RESULT result;
 
   result = _dsp->setBypass(bypass);
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_dsp->setBypass()", result);
 
   audio_debug("DSP Bypass set to:" << bypass );
 }
@@ -159,7 +159,7 @@ get_bypass() {
   bool bypass;
 
   result = _dsp->getBypass(&bypass);
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_dsp->getBypass()", result);
 
   return bypass;
 }
@@ -183,7 +183,7 @@ set_parameter(const string &name, float value) {
   FMOD_RESULT result;
 
   result = _dsp->setParameter(parameterIndex, value);
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_dsp->setParameter()", result);
 }
 
 
@@ -203,7 +203,7 @@ get_num_parameters() {
   int numOfParameters;
 
   result = _dsp->getNumParameters(&numOfParameters);
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_dsp->getNumParameters()", result);
 
   return numOfParameters;
 }
@@ -231,7 +231,7 @@ get_parameter_name(int parameterIndex) {
   float parameterMax;
 
   result = _dsp->getParameterInfo(parameterIndex, parameterName, parameterLabel, parameterDescription, parameterDescriptionLength, &parameterMin, &parameterMax);
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_dsp->getParameterInfo()", result);
 
   string returnInfo = (parameterName);
 
@@ -275,7 +275,7 @@ get_parameter_description(int parameterIndex) {
   float parameterMax;
 
   result = _dsp->getParameterInfo(parameterIndex, parameterName, parameterLabel, parameterDescription, parameterDescriptionLength, &parameterMin, &parameterMax);
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_dsp->getParameterInfo()", result);
 
   return parameterLabel;
 
@@ -304,7 +304,7 @@ get_parameter_min(int parameterIndex) {
   float parameterMax;
 
   result = _dsp->getParameterInfo(parameterIndex, parameterName, parameterLabel, parameterDescription, parameterDescriptionLength, &parameterMin, &parameterMax);
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_dsp->getParameterInfo()", result);
 
   return parameterMin;
 }
@@ -332,7 +332,7 @@ get_parameter_max(int parameterIndex) {
   float parameterMax;
 
   result = _dsp->getParameterInfo(parameterIndex, parameterName, parameterLabel, parameterDescription, parameterDescriptionLength, &parameterMin, &parameterMax);
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_dsp->getParameterInfo()", result);
 
   return parameterMax;
 }
@@ -361,7 +361,7 @@ get_parameter_value(const string &name) {
 
 
   result = _dsp->getParameter(parameterIndex, &parameterValue, valuestr, valuestrlen);
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_dsp->getParameter()", result);
 
   return parameterValue;
 }
@@ -404,7 +404,7 @@ get_dsp_name() {
   int   configheight;
 
   result = _dsp->getInfo(name, &version, &channels, &configwidth, &configheight);
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_dsp->getInfo()", result);
 
   string returnInfo = (name);
   //returnInfo.append(" Version: ");

+ 185 - 48
panda/src/audiotraits/fmodAudioManager.cxx

@@ -43,15 +43,31 @@
 
 TypeHandle FmodAudioManager::_type_handle;
 
+FMOD::System *FmodAudioManager::_system; 
 pset<FmodAudioManager *> FmodAudioManager::_all_managers;
 
+bool FmodAudioManager::_system_is_valid = false;
+
+
+//  This sets the distance factor for 3D audio to use feet. 
+//  FMOD uses meters by default.
+//  Since Panda use feet we need to compensate for that with a factor of 3.28
+//
+//  This can be overwritten.  You just need to call
+//  audio_3d_set_distance_factor(float factor) and set your new factor.
+
+float FmodAudioManager::_doppler_factor = 1;
+float FmodAudioManager::_distance_factor = 3.28;
+float FmodAudioManager::_drop_off_factor = 1;
+
+
 ////////////////////////////////////////////////////////////////////
 // Central dispatcher for audio errors.
 ////////////////////////////////////////////////////////////////////
 
-void fmod_audio_errcheck(FMOD_RESULT result) {
+void fmod_audio_errcheck(const char *context, FMOD_RESULT result) {
   if (result != 0) {
-    audio_error("FMOD Error: "<< FMOD_ErrorString(result) );
+    audio_error(context << ": " << FMOD_ErrorString(result) );
   }
 }
 
@@ -95,48 +111,60 @@ FmodAudioManager() {
   _up.x = 0;
   _up.y = 0;
   _up.z = 0;
-    
-  result = FMOD::System_Create(&_system);
-  fmod_audio_errcheck(result);
 
-  //  Let check the Version of FMOD to make sure the Headers and Libraries are correct.
-  result = _system->getVersion(&version);
-  fmod_audio_errcheck(result);
+  if (_system == (FMOD::System *)NULL) {
+    // Create the global FMOD System object.  This one object must be
+    // shared by all FmodAudioManagers (this is particularly true on
+    // OSX, but the FMOD documentation is unclear as to whether this
+    // is the intended design on all systems).
+
+    result = FMOD::System_Create(&_system);
+    fmod_audio_errcheck("FMOD::System_Create()", result);
+
+    //  Let check the Version of FMOD to make sure the Headers and Libraries are correct.
+    result = _system->getVersion(&version);
+    fmod_audio_errcheck("_system->getVersion()", result);
   
-  if (version < FMOD_VERSION){
-    audio_error("You are using an old version of FMOD.  This program requires:" << FMOD_VERSION);
-  }
+    if (version < FMOD_VERSION){
+      audio_error("You are using an old version of FMOD.  This program requires:" << FMOD_VERSION);
+    }
 
-  //Stick Surround Sound 5.1 thing Here.
-  if (fmod_use_surround_sound) {
-    audio_debug("Setting FMOD to use 5.1 Surround Sound.");
-    result = _system->setSpeakerMode( FMOD_SPEAKERMODE_5POINT1 );
-    fmod_audio_errcheck(result);
-  }
+    //Stick Surround Sound 5.1 thing Here.
+    if (fmod_use_surround_sound) {
+      audio_debug("Setting FMOD to use 5.1 Surround Sound.");
+      result = _system->setSpeakerMode( FMOD_SPEAKERMODE_5POINT1 );
+      fmod_audio_errcheck("_system->setSpeakerMode()", result);
+    }
 
-  //Now we Initialize the System.
-  result = _system->init(fmod_number_of_sound_channels, FMOD_INIT_NORMAL, 0);
-  fmod_audio_errcheck(result);
+    //Now we Initialize the System.
+    result = _system->init(fmod_number_of_sound_channels, FMOD_INIT_NORMAL, 0);
+    fmod_audio_errcheck("_system->init()", result);
 
-  if (result == FMOD_OK){
-    _is_valid = true;
-  } else {
-    _is_valid = false;
+    _system_is_valid = (result == FMOD_OK);
+
+    if (_system_is_valid) {
+      result = _system->set3DSettings( _doppler_factor, _distance_factor, _drop_off_factor);
+      fmod_audio_errcheck("_system->set3DSettings()", result);
+
+      result = _system->setFileSystem(open_callback, close_callback, read_callback, seek_callback, -1);
+      fmod_audio_errcheck("_system->setFileSystem()", result);
+    }
   }
 
-  //  This sets the distance factor for 3D audio to use feet. 
-  //  FMOD uses meters by default.
-  //  Since Panda use feet we need to compensate for that with a factor of 3.28
-  //
-  //  This can be over written.  You just need to call
-  //  audio_3d_set_distance_factor(float factor) and set you new factor.
-  
-  _doppler_factor = 1;
-  _distance_factor = 3.28;
-  _drop_off_factor = 1;
+  _is_valid = _system_is_valid;
 
-  result = _system->set3DSettings( _doppler_factor, _distance_factor, _drop_off_factor);
-  fmod_audio_errcheck( result );
+  memset(&_midi_info, 0, sizeof(_midi_info));
+  _midi_info.cbsize = sizeof(_midi_info);
+
+  Filename dls_filename = audio_dls_file;
+  if (!dls_filename.empty()) {
+    VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+    vfs->resolve_filename(dls_filename, get_sound_path()) ||
+      vfs->resolve_filename(dls_filename, get_model_path());
+    
+    _dlsname = dls_filename.to_os_specific();
+    _midi_info.dlsname = _dlsname.c_str();
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -158,8 +186,12 @@ FmodAudioManager::
   // Remove me from the managers list.
   _all_managers.erase(this);
 
+  if (_all_managers.empty()) {
     result = _system->release();
-  fmod_audio_errcheck(result);
+    fmod_audio_errcheck("_system->release()", result);
+    _system = NULL;
+    _system_is_valid = false;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -186,7 +218,8 @@ get_sound(const string &file_name, bool positional) {
   Filename path = file_name;
 
   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
-  vfs->resolve_filename(path, get_sound_path());
+  vfs->resolve_filename(path, get_sound_path()) ||
+    vfs->resolve_filename(path, get_model_path());
 
   // Build a new AudioSound from the audio data.
   PT(AudioSound) audioSound = 0;
@@ -233,7 +266,7 @@ add_dsp( PT(AudioDSP) x) {
     return false;
   } else {
     result = _system->addDSP( fdsp->_dsp );
-    fmod_audio_errcheck( result );
+    fmod_audio_errcheck("_system->addDSP()", result);
     _system_dsp.insert(fdsp);
     fdsp->set_in_chain(true);
     return true;
@@ -256,7 +289,7 @@ remove_dsp(PT(AudioDSP) x) {
 
   if ( fdsp->get_in_chain() ) {
     result = fdsp->_dsp->remove();
-    fmod_audio_errcheck( result );
+    fmod_audio_errcheck("_dsp->remove()", result);
 
     _system_dsp.erase(fdsp);
 
@@ -281,7 +314,7 @@ getSpeakerSetup() {
   int returnMode;
 
   result = _system->getSpeakerMode( &speakerMode );
-  fmod_audio_errcheck( result );
+  fmod_audio_errcheck("_system->getSpeakerMode()", result);
 
   switch (speakerMode) {
     case  FMOD_SPEAKERMODE_RAW:
@@ -343,7 +376,7 @@ setSpeakerSetup(AudioManager::SpeakerModeCategory cat) {
   FMOD_RESULT result;
   FMOD_SPEAKERMODE speakerModeType = (FMOD_SPEAKERMODE)cat;
   result = _system->setSpeakerMode( speakerModeType);
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_system->setSpeakerMode()", result);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -378,7 +411,16 @@ get_volume() const {
 ////////////////////////////////////////////////////////////////////
 void FmodAudioManager::
 set_active(bool active) {
-  _active = active;
+  if (_active != active) {
+    _active = active;
+
+    // Tell our AudioSounds to adjust:
+    for (SoundSet::iterator i = _all_sounds.begin(); 
+         i != _all_sounds.end(); 
+         ++i) {
+      (*i)->set_active(_active);
+    }
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -398,8 +440,17 @@ get_active() const {
 ////////////////////////////////////////////////////////////////////
 void FmodAudioManager::
 stop_all_sounds() {
-  for (SoundSet::iterator i = _all_sounds.begin(); i != _all_sounds.end(); ++i) {
+  // We have to walk through this list with some care, since stopping
+  // a sound may also remove it from the set (if there are no other
+  // references to the sound).
+  SoundSet::iterator i;
+  i = _all_sounds.begin();
+  while (i != _all_sounds.end()) {
+    SoundSet::iterator next = i;
+    ++next;
+
     (*i)->stop();
+    i = next;
   }
 }
 
@@ -451,7 +502,7 @@ audio_3d_set_listener_attributes(float px, float py, float pz, float vx, float v
   _up.z = uy;
     
   result = _system->set3DListenerAttributes( 0, &_position, &_velocity, &_forward, &_up);
-  fmod_audio_errcheck( result );
+  fmod_audio_errcheck("_system->set3DListenerAttributes()", result);
 
 }
 
@@ -482,7 +533,7 @@ audio_3d_set_distance_factor(float factor) {
   _distance_factor = factor;
 
   result = _system->set3DSettings( _doppler_factor, _distance_factor, _drop_off_factor);
-  fmod_audio_errcheck( result );
+  fmod_audio_errcheck("_system->set3DSettings()", result);
 
 
 }
@@ -515,7 +566,7 @@ audio_3d_set_doppler_factor(float factor) {
   _doppler_factor = factor;
 
   result = _system->set3DSettings( _doppler_factor, _distance_factor, _drop_off_factor);
-  fmod_audio_errcheck( result );
+  fmod_audio_errcheck("_system->set3DSettings()", result);
 
 }
 
@@ -546,7 +597,7 @@ audio_3d_set_drop_off_factor(float factor) {
   _drop_off_factor = factor;
 
   result = _system->set3DSettings( _doppler_factor, _distance_factor, _drop_off_factor);
-  fmod_audio_errcheck( result );
+  fmod_audio_errcheck("_system->set3DSettings()", result);
 
 }
 
@@ -646,6 +697,92 @@ get_cache_limit() const {
   return 0;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::open_callback
+//       Access: Private, Static
+//  Description: A hook into Panda's virtual file system.
+////////////////////////////////////////////////////////////////////
+FMOD_RESULT F_CALLBACK FmodAudioManager::
+open_callback(const char *name, int, unsigned int *file_size,
+              void **handle, void **user_data) {
+  if (name == (const char *)NULL || name[0] == '\0') {
+    // An invalid attempt to open an unnamed file.
+    return FMOD_ERR_FILE_NOTFOUND;
+  }
+    
+  VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+
+  PT(VirtualFile) file = vfs->get_file(Filename(name));
+  if (file == (VirtualFile *)NULL) {
+    return FMOD_ERR_FILE_NOTFOUND;
+  }
+  istream *str = file->open_read_file(true);
+
+  (*file_size) = file->get_file_size(str);
+  (*handle) = (void *)str;
+  (*user_data) = NULL;
+
+  return FMOD_OK;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::close_callback
+//       Access: Private, Static
+//  Description: A hook into Panda's virtual file system.
+////////////////////////////////////////////////////////////////////
+FMOD_RESULT F_CALLBACK FmodAudioManager::
+close_callback(void *handle, void *user_data) {
+  VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+
+  istream *str = (istream *)handle;
+  vfs->close_read_file(str);
+
+  return FMOD_OK;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::read_callback
+//       Access: Private, Static
+//  Description: A hook into Panda's virtual file system.
+////////////////////////////////////////////////////////////////////
+FMOD_RESULT F_CALLBACK FmodAudioManager::
+read_callback(void *handle, void *buffer, unsigned int size_bytes,
+              unsigned int *bytes_read, void *user_data) {
+  istream *str = (istream *)handle;
+  str->read((char *)buffer, size_bytes);
+  (*bytes_read) = str->gcount();
+
+  if (str->eof()) {
+    if ((*bytes_read) == 0) {
+      return FMOD_ERR_FILE_EOF;
+    } else {
+      // Report the EOF next time.
+      return FMOD_OK;
+    }
+  } if (str->fail()) {
+    return FMOD_ERR_FILE_BAD;
+  } else {
+    return FMOD_OK;
+  }
+}
+  
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::seek_callback
+//       Access: Private, Static
+//  Description: A hook into Panda's virtual file system.
+////////////////////////////////////////////////////////////////////
+FMOD_RESULT F_CALLBACK FmodAudioManager::
+seek_callback(void *handle, unsigned int pos, void *user_data) {
+  istream *str = (istream *)handle;
+  str->clear();
+  str->seekg(pos);
+
+  if (str->fail() && !str->eof()) {
+    return FMOD_ERR_FILE_COULDNOTSEEK;
+  } else {
+    return FMOD_OK;
+  }
+}
 
 
 #endif //]

+ 66 - 39
panda/src/audiotraits/fmodAudioManager.h

@@ -23,43 +23,52 @@
 
 ////////////////////////////////////////////////////////////////////
 //
-//Hello, all future Panda audio code people! This is my errata documentation to
-//help any future programmer maintain FMOD and PANDA.
+//Hello, all future Panda audio code people! This is my errata
+//documentation to help any future programmer maintain FMOD and PANDA.
 //
-//This documentation more then that is needed, but I wanted to go all out, with
-//the documentation. Because I was a totally newbie at programming [especially
-//with C/C++] this semester I want to make sure future code maintainers have that
-//insight I did not when starting on the PANDA project here at the ETC/CMU.
+//This documentation more then that is needed, but I wanted to go all
+//out, with the documentation. Because I was a totally newbie at
+//programming [especially with C/C++] this semester I want to make
+//sure future code maintainers have that insight I did not when
+//starting on the PANDA project here at the ETC/CMU.
 //
-//As of Spring 2006, Panda's FMOD audio support has been pretty much completely
-//rewritten. This has been done so PANDA can use FMOD-EX [or AKA FMOD 4] and some
-//of its new features.
+//As of Spring 2006, Panda's FMOD audio support has been pretty much
+//completely rewritten. This has been done so PANDA can use FMOD-EX
+//[or AKA FMOD 4] and some of its new features.
 //
-//First, the FMOD-EX API itself has been completely rewritten compared to previous
-//versions. FMOD now handles any type of audio files, wave audio [WAV, AIF, MP3,
-//OGG, etc...] or musical file [MID, TRACKERS] as the same type of an object. The
-//API has also been structured more like a sound studio, with 'sounds' and
-//'channels'. This will be covered more in the FmodAudioSound.h/.cxx sources.
+//First, the FMOD-EX API itself has been completely rewritten compared
+//to previous versions. FMOD now handles any type of audio files, wave
+//audio [WAV, AIF, MP3, OGG, etc...] or musical file [MID, TRACKERS]
+//as the same type of an object. The API has also been structured more
+//like a sound studio, with 'sounds' and 'channels'. This will be
+//covered more in the FmodAudioSound.h/.cxx sources.
 //
-//Second, FMOD now offers virtually unlimited sounds to be played at once via
-//their virtual channels system. Actually the theoretical limit is around 4000,
-//but that is still a lot. What you need to know about this, is that even thought
-//you might only hear 32 sound being played at once, FMOD will keep playing any
-//additional sounds, and swap those on virtual channels in and out with those on real channels
-//depending on priority, or distance [if you are dealing with 3D audio].
+//Second, FMOD now offers virtually unlimited sounds to be played at
+//once via their virtual channels system. Actually the theoretical
+//limit is around 4000, but that is still a lot. What you need to know
+//about this, is that even thought you might only hear 32 sound being
+//played at once, FMOD will keep playing any additional sounds, and
+//swap those on virtual channels in and out with those on real
+//channels depending on priority, or distance [if you are dealing with
+//3D audio].
 //
-//Third, FMOD's DSP support has been added. So you can now add GLOBAL or SOUND
-//specific DSP effects. Right not you can only use FMOD's built in DSP effects.
-//But adding support for FMOD's support of VST effects shouldn't be that hard.
+//Third, FMOD's DSP support has been added. So you can now add GLOBAL
+//or SOUND specific DSP effects. Right not you can only use FMOD's
+//built in DSP effects.  But adding support for FMOD's support of VST
+//effects shouldn't be that hard.
 //
-//As for the FmodManager itself, it is pretty straight forward, I hope. As a
-//manager class, it will create the FMOD system with the ‘_system’ variable which
-//is an instance of FMOD::SYSTEM. This class is also the one responsible for
-//creation of Sounds, DSP, and maintaining the GLOBAL DSP chains [The GLOBAL DSP
-//chain is the DSP Chain which affects ALL the sounds].
+//As for the FmodManager itself, it is pretty straight forward, I
+//hope. As a manager class, it will create the FMOD system with the
+//"_system" variable which is an instance of FMOD::SYSTEM. (Actually,
+//we create only one global _system variable now, and share it with
+//all outstanding FmodManager objects--this appears to be the way FMOD
+//wants to work.)  The FmodManager class is also the one responsible
+//for creation of Sounds, DSP, and maintaining the GLOBAL DSP chains
+//[The GLOBAL DSP chain is the DSP Chain which affects ALL the
+//sounds].
 //
-//Any way that is it for an intro, lets move on to looking at the rest of the
-//code.
+//Any way that is it for an intro, lets move on to looking at the rest
+//of the code.
 //
 ////////////////////////////////////////////////////////////////////
 
@@ -82,7 +91,7 @@
 class FmodAudioSound;
 class FmodAudioDSP;
 
-extern void fmod_audio_errcheck(FMOD_RESULT n);
+extern void fmod_audio_errcheck(const char *context, FMOD_RESULT n);
 
 class EXPCL_FMOD_AUDIO FmodAudioManager : public AudioManager {
   friend class FmodAudioSound;
@@ -163,24 +172,44 @@ class EXPCL_FMOD_AUDIO FmodAudioManager : public AudioManager {
   virtual unsigned int get_cache_limit() const;
   ////////////////////////////////////////////////////////////////////
 
- private:
+private:
+  static FMOD_RESULT F_CALLBACK 
+  open_callback(const char *name, int unicode, unsigned int *file_size,
+                void **handle, void **user_data);
+
+  static FMOD_RESULT F_CALLBACK 
+  close_callback(void *handle, void *user_data);
 
-  FMOD::System *_system; 
+  static FMOD_RESULT F_CALLBACK 
+  read_callback(void *handle, void *buffer, unsigned int size_bytes,
+                unsigned int *bytes_read, void *user_data);
   
+  static FMOD_RESULT F_CALLBACK 
+  seek_callback(void *handle, unsigned int pos, void *user_data);
+
+ private:
+
+  static FMOD::System *_system; 
   static pset<FmodAudioManager *> _all_managers;
 
+  static bool _system_is_valid;
+
+  static float _distance_factor;
+  static float _doppler_factor;
+  static float _drop_off_factor;
+
   FMOD_VECTOR _position;
   FMOD_VECTOR _velocity;
   FMOD_VECTOR _forward;
   FMOD_VECTOR _up;
 
+  // DLS info for MIDI files
+  string _dlsname;
+  FMOD_CREATESOUNDEXINFO _midi_info;
+
   bool _is_valid;
   bool _active;
 
-  float _distance_factor;
-  float _doppler_factor;
-  float _drop_off_factor;
-
   // The set of all sounds.  Needed only to implement stop_all_sounds.
   typedef pset<FmodAudioSound *> SoundSet;
   SoundSet _all_sounds;
@@ -189,8 +218,6 @@ class EXPCL_FMOD_AUDIO FmodAudioManager : public AudioManager {
   typedef pset<PT (FmodAudioDSP) > DSPSet;
   DSPSet _system_dsp;
 
-  friend class FmodAudioSound;
-
   ////////////////////////////////////////////////////////////
   //These are needed for Panda's Pointer System. DO NOT ERASE!
   ////////////////////////////////////////////////////////////

+ 75 - 62
panda/src/audiotraits/fmodAudioSound.cxx

@@ -45,6 +45,8 @@ FmodAudioSound::
 FmodAudioSound(AudioManager *manager, Filename file_name, bool positional) { 
   audio_debug("FmodAudioSound::FmodAudioSound() Creating new sound, filename: " << file_name  );
 
+  _active = manager->get_active();
+
   //Local Variables that are needed.
   FMOD_RESULT result;
 
@@ -73,9 +75,11 @@ FmodAudioSound(AudioManager *manager, Filename file_name, bool positional) {
   _channel = 0;
   _file_name = file_name;
 
+  FMOD_CREATESOUNDEXINFO *sound_info = NULL;
+
   //Get the Speaker Mode [Important for later on.]
   result = _manager->_system->getSpeakerMode( &_speakermode );
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_system->getSpeakerMode()", result);
 
   // Calculate the approximate uncompressed size of the sound.
   int size =  file_name.get_file_size();
@@ -84,12 +88,20 @@ FmodAudioSound(AudioManager *manager, Filename file_name, bool positional) {
   
   int flag = positional ? FMOD_3D : FMOD_2D;
   int streamflag = (size > 250000) ? FMOD_CREATESTREAM : FMOD_CREATESAMPLE;
-  
-  result = _manager->_system->createSound( file_name.to_os_specific().c_str(), FMOD_SOFTWARE | streamflag | flag , 0, &_sound);
+  if (ext == "mid") {
+    streamflag = FMOD_CREATESTREAM;
+    sound_info = &_manager->_midi_info;
+  }
+
+  result = _manager->_system->createSound( file_name.c_str(), FMOD_SOFTWARE | streamflag | flag , 
+                                           sound_info, &_sound);
   if (result != FMOD_OK) {
+    audio_error("createSound(" << file_name << "): " << FMOD_ErrorString(result));
+
+    // We couldn't load the sound file.  Create a blank sound record
+    // instead.
     char blank_data[100];
     FMOD_CREATESOUNDEXINFO exinfo;
-    audio_error("CreateSound " << file_name << ": " << FMOD_ErrorString(result));
     memset(&exinfo, 0, sizeof(exinfo));
     memset(blank_data, 0, sizeof(blank_data));
     exinfo.cbsize = sizeof(exinfo);
@@ -98,7 +110,7 @@ FmodAudioSound(AudioManager *manager, Filename file_name, bool positional) {
     exinfo.defaultfrequency = 8000;
     exinfo.format = FMOD_SOUND_FORMAT_PCM16;
     result = _manager->_system->createSound( blank_data, FMOD_SOFTWARE | flag | FMOD_OPENMEMORY | FMOD_OPENRAW, &exinfo, &_sound);
-    fmod_audio_errcheck(result);
+    fmod_audio_errcheck("createSound (blank)", result);
   }
   
   //This is just to collect the defaults of the sound, so we don't
@@ -107,7 +119,7 @@ FmodAudioSound(AudioManager *manager, Filename file_name, bool positional) {
   //'set_play_rate()' and 'get_play_rate()' methods later;
   
   result = _sound->getDefaults( &_sampleFrequency, &_volume , &_balance, &_priority);
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_sound->getDefaults()", result);
 }
 
 
@@ -128,7 +140,7 @@ FmodAudioSound::
 
   //The Release Sound
   result = _sound->release();
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_sound->release()", result);
 }
 
 
@@ -154,7 +166,7 @@ FMOD_RESULT F_CALLBACK sound_end_callback(FMOD_CHANNEL *  channel,
 					  unsigned int  commanddata1, 
 					  unsigned int  commanddata2) {
   FmodAudioSound *fsound = (FmodAudioSound*)command;
-  fsound->unref();
+  fsound->_self_ref = fsound;
   return FMOD_OK;
 }
 
@@ -170,9 +182,9 @@ stop() {
   if (_channel != 0) {
     result =_channel->stop();
     if (result == FMOD_OK) {
-      unref();
+      _self_ref.clear();
     }
-    fmod_audio_errcheck(result);
+    fmod_audio_errcheck("_channel->stop()", result);
   }
 }
 
@@ -187,11 +199,10 @@ set_loop(bool loop) {
   FMOD_RESULT result;
   if ( loop ) {
     result = _sound->setMode(FMOD_LOOP_NORMAL);
-    fmod_audio_errcheck(result);
   } else {
     result = _sound->setMode(FMOD_LOOP_OFF);  
-    fmod_audio_errcheck(result);
   }
+  fmod_audio_errcheck("_sound->setMode()", result);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -210,7 +221,7 @@ get_loop() const {
   bool loopState;
 
   result = _sound->getMode( &loopMode );
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_sound->getMode()", result);
 
   if ( (loopMode & FMOD_LOOP_NORMAL) != 0 ) {
     loopState = true;
@@ -244,11 +255,10 @@ set_loop_count(unsigned long loop_count) {
 
   if (numberOfLoops == 0) {
     result = _sound->setLoopCount( -1 );
-    fmod_audio_errcheck(result);
   } else {
     result = _sound->setLoopCount( numberOfLoops );
-    fmod_audio_errcheck(result);
   }
+  fmod_audio_errcheck("_sound->setLoopCount()", result);
 
   audio_debug("FmodAudioSound::set_loop_count()   Sound's loop count should be set to: " << loop_count);
 }
@@ -268,7 +278,7 @@ get_loop_count() const {
   unsigned long returnedNumber;
 
   result = _sound->getLoopCount( &loop_count );
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_sound->getLoopCount()", result);
 
   audio_debug("FmodAudioSound::get_loop_count() returning "<< loop_count);
 
@@ -285,34 +295,36 @@ get_loop_count() const {
 void FmodAudioSound::
 set_time(float start_time) {
   FMOD_RESULT result;
-  bool playing;
 
   int startTime = (int)(start_time * 1000);
 
   if (_channel != 0) {
     // try backing up current sound.
     result = _channel->setPosition( startTime , FMOD_TIMEUNIT_MS );
-    if (result == FMOD_ERR_INVALID_HANDLE) {
-      _channel = 0;
-    } else {
-      fmod_audio_errcheck(result);
-    }
-    result = _channel->isPlaying(&playing);
-    if ((result == FMOD_ERR_INVALID_HANDLE) || (playing == false)) {
+    if (result == FMOD_ERR_INVALID_HANDLE ||
+        result == FMOD_ERR_CHANNEL_STOLEN) {
       _channel = 0;
+
     } else {
-      fmod_audio_errcheck(result);
+      fmod_audio_errcheck("_channel->setPosition()", result);
+
+      bool playing;
+      result = _channel->isPlaying(&playing);
+      fmod_audio_errcheck("_channel->isPlaying()", result);
+      if (result != FMOD_OK || !playing) {
+        _channel = 0;
+      }
     }
   }
   
   if (_channel == 0) {
 
     result = _manager->_system->playSound(FMOD_CHANNEL_FREE, _sound, true, &_channel);
-    fmod_audio_errcheck(result);
+    fmod_audio_errcheck("_system->playSound()", result);
     result = _channel->setCallback(FMOD_CHANNEL_CALLBACKTYPE_END, sound_end_callback, (int)this);
-    fmod_audio_errcheck(result);
+    fmod_audio_errcheck("_channel->setCallback()", result);
     result = _channel->setPosition( startTime , FMOD_TIMEUNIT_MS );
-    fmod_audio_errcheck(result);
+    fmod_audio_errcheck("_channel->setPosition()", result);
 
     set_volume_on_channel();
     set_play_rate_on_channel();
@@ -320,13 +332,13 @@ set_time(float start_time) {
     add_dsp_on_channel();
     set_3d_attributes_on_channel();
 
-    result = _channel->setPaused(false);
-    fmod_audio_errcheck(result);
+    if (_active) {
+      result = _channel->setPaused(false);
+      fmod_audio_errcheck("_channel->setPaused()", result);
+    }
     
-    this->ref();
+    _self_ref = this;
   }
-
-  fmod_audio_errcheck(result);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -347,7 +359,7 @@ get_time() const {
   if (result == FMOD_ERR_INVALID_HANDLE) {
     return 0.0f;
   }
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_channel->getPosition()", result);
 
   current_time = current_time / 1000;
 
@@ -390,7 +402,7 @@ set_volume_on_channel() {
     if (result == FMOD_ERR_INVALID_HANDLE) {
       _channel = 0;
     } else {
-      fmod_audio_errcheck(result);
+      fmod_audio_errcheck("_channel->setVolume()", result);
     }
   }
 }
@@ -459,7 +471,7 @@ set_play_rate_on_channel() {
     if (result == FMOD_ERR_INVALID_HANDLE) {
       _channel = 0;
     } else {
-      fmod_audio_errcheck(result);
+      fmod_audio_errcheck("_channel->setFrequency()", result);
     }
   }
 }
@@ -486,7 +498,7 @@ length() const {
   unsigned int length;
 
   result = _sound->getLength( &length, FMOD_TIMEUNIT_MS );
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_sound->getLength()", result);
 
   length = length / 1000;
 
@@ -532,14 +544,14 @@ set_3d_attributes_on_channel() {
   FMOD_MODE soundMode;
 
   result = _sound->getMode(&soundMode);
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_sound->getMode()", result);
   
   if ((_channel != 0) && (soundMode & FMOD_3D)) {
     result = _channel->set3DAttributes( &_location, &_velocity );
     if (result == FMOD_ERR_INVALID_HANDLE) {
       _channel = 0;
     } else {
-      fmod_audio_errcheck(result);
+      fmod_audio_errcheck("_channel->set3DAttributes()", result);
     }
   }
 }
@@ -568,7 +580,7 @@ set_3d_min_distance(float dist) {
   _min_dist = dist;
 
   result = _sound->set3DMinMaxDistance( dist, _max_dist );
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_sound->set3DMinMaxDistance()", result);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -593,7 +605,7 @@ set_3d_max_distance(float dist) {
   _max_dist = dist;
 
   result = _sound->set3DMinMaxDistance( _min_dist, dist );
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_sound->set3DMinMaxDistance()", result);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -636,10 +648,10 @@ add_dsp( PT(AudioDSP) x) {
     
     if ( _channel != 0 ) {
       result = _channel->isPlaying( &playingState );
-      fmod_audio_errcheck(result);
+      fmod_audio_errcheck("_channel->isPlaying()", result);
       if ( playingState ) {
         result = _channel->addDSP( fdsp->_dsp );
-        fmod_audio_errcheck( result );
+        fmod_audio_errcheck("_channel->addDSP()", result);
       }
     }
     
@@ -665,7 +677,7 @@ add_dsp_on_channel() {
       if (result == FMOD_ERR_INVALID_HANDLE) {
         _channel = 0;
       } else {
-        fmod_audio_errcheck( result );
+        fmod_audio_errcheck("_channel->addDSP()", result);
       }
     }
   }
@@ -689,7 +701,7 @@ remove_dsp(PT(AudioDSP) x) {
   if ( fdsp->get_in_chain() ) {
 
     result = fdsp->_dsp->remove();
-    fmod_audio_errcheck( result );
+    fmod_audio_errcheck("_dsp->remove()", result);
 
     _sound_dsp.erase(fdsp);
 
@@ -736,7 +748,7 @@ get_speaker_mix(AudioManager::SpeakerId speaker) {
   float sideright;
 
   result = _channel->getSpeakerMix( &frontleft, &frontright, &center, &sub, &backleft, &backright, &sideleft, &sideright );
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_channel->getSpeakerMix()", result);
 
   switch(speaker) {
   case AudioManager::SPK_frontleft:  return frontleft;
@@ -798,7 +810,7 @@ set_speaker_mix_or_balance_on_channel() {
   FMOD_MODE soundMode;
 
   result = _sound->getMode(&soundMode);
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_sound->getMode()", result);
 
   if ((_channel != 0) && (( soundMode & FMOD_3D ) == 0)) {
     if ( _speakermode == FMOD_SPEAKERMODE_STEREO ) {
@@ -817,7 +829,7 @@ set_speaker_mix_or_balance_on_channel() {
     if (result == FMOD_ERR_INVALID_HANDLE) {
       _channel = 0;
     } else {
-      fmod_audio_errcheck(result);
+      fmod_audio_errcheck("_channel->setSpeakerMix()/setPan()", result);
     }
   }
 }
@@ -852,7 +864,7 @@ set_priority(int priority) {
   _priority = priority;
 
   result = _sound->setDefaults( _sampleFrequency, _volume , _balance, _priority);
-  fmod_audio_errcheck(result);
+  fmod_audio_errcheck("_sound->setDefaults()", result);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -880,31 +892,32 @@ status() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioSound::set_active
 //       Access: public
-//  Description: NOT USED ANYMORE!!!
-//
-//        
+//  Description: Sets whether the sound is marked "active".  By
+//               default, the active flag true for all sounds.  If the
+//               active flag is set to false for any particular sound,
+//               the sound will not be heard.
 ////////////////////////////////////////////////////////////////////
 void FmodAudioSound::
 set_active(bool active) {
-  audio_debug("NOT USED ANYMORE in FMOD-EX version of PANDA.");
+  _active = active;
+
+  if (status() == PLAYING) {
+    // If the sound is (or should be) playing, then pause or unpause
+    // it in the system.
+    FMOD_RESULT result = _channel->setPaused(!_active);
+    fmod_audio_errcheck("_channel->setPaused()", result);
+  }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioSound::get_active 
 //       Access: public
-//  Description: NOT 'REALLY' USED ANYMORE!!!
-//        This is actually an layover from the old version of the FMOD code.
-//        The old version used a weird cache system to keep track of the sounds' states.
-//        I just converted this method, to return if a sound is 'Playing' or not.
-//        This is not exactly how the orignal use of this function btu I figured I might
-//        as well get some use out of it.
+//  Description: Returns whether the sound has been marked "active".
 ////////////////////////////////////////////////////////////////////
 bool FmodAudioSound::
 get_active() const {
-  audio_debug("FmodAudioSound::get_active()  Going to get a sound's activity.");
-  audio_debug("NOT USED ANYMORE in FMOD-EX version of PANDA.");
-  return false;
+  return _active;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 50 - 34
panda/src/audiotraits/fmodAudioSound.h

@@ -23,44 +23,50 @@
 //
 ////////////////////////////////////////////////////////////////////
 //
-//[FIRST READ FmodAudioManager for an Introduction if you haven't already].
+//[FIRST READ FmodAudioManager for an Introduction if you haven't
+//already].
 //
-//Hello, all future Panda audio code people! This is my errata documentation to
-//Help any future programmer maintain FMOD and PANDA.
+//Hello, all future Panda audio code people! This is my errata
+//documentation to Help any future programmer maintain FMOD and PANDA.
 //
-//Well, if you reading this you probably want to know how PANDA deals with sounds
-//directly using FMOD-EX. Well I am going to tell you.
+//Well, if you reading this you probably want to know how PANDA deals
+//with sounds directly using FMOD-EX. Well I am going to tell you.
 //
-//The first thing, you as the programmer have to understand, especially if you
-//never have done sound programming before, is how the FMOD-EX API works.
+//The first thing, you as the programmer have to understand,
+//especially if you never have done sound programming before, is how
+//the FMOD-EX API works.
 //
-//With FMOD-EX the guys at Firelight, adopted a model of managing sounds with FMOD
-//similar to how a Sound Designer creates sound in a sound studio using SOUNDS
-//and CHANNELS. Although this may seem strange at first, if you are not familiar
-//with sound programming, there is a very good metaphor you are probably already
-//familiar with to explain how FMOD-EX works.
+//With FMOD-EX the guys at Firelight, adopted a model of managing
+//sounds with FMOD similar to how a Sound Designer creates sound in a
+//sound studio using SOUNDS and CHANNELS. Although this may seem
+//strange at first, if you are not familiar with sound programming,
+//there is a very good metaphor you are probably already familiar with
+//to explain how FMOD-EX works.
 //
-//Think of you standard GUI API. Usually a GUI API is made up of two things:
-//Windows and Widgets. These correspond to CHANNELS and SOUNDS, where a
-//Channel is a Window and a Sound is Widget. Sounds are played within channels,
-//and channels don’t exist unless they have something to display.
+//Think of you standard GUI API. Usually a GUI API is made up of two
+//things: Windows and Widgets. These correspond to CHANNELS and
+//SOUNDS, where a Channel is a Window and a Sound is Widget. Sounds
+//are played within channels, and channels don't exist unless they
+//have something to display.
 //
-//Now why am I explaining all of this? When PANDA was created they set up the
-//basic audio classes to handle only the idea of a SOUND. The idea of a
-//Channel really wasn't prevalent as in more modern Audio APIs. With this rewrite
-//of PANDA to use the FMOD-EX API, the PANDA FmodAudioSound Class, now has to
-//handle two different parts of the FMOD-EX API in order to play a sound.
+//Now why am I explaining all of this? When PANDA was created they set
+//up the basic audio classes to handle only the idea of a SOUND. The
+//idea of a Channel really wasn't prevalent as in more modern Audio
+//APIs. With this rewrite of PANDA to use the FMOD-EX API, the PANDA
+//FmodAudioSound Class, now has to handle two different parts of the
+//FMOD-EX API in order to play a sound.
 //
-//SOUND: The object the handles the audio data in form of WAV, AIF, OGG, MID, IT,
-//MP3, etc... And CHANNEL: The object that actually plays the sound and
-//manipulates it in real time.
+//SOUND: The object the handles the audio data in form of WAV, AIF,
+//OGG, MID, IT, MP3, etc... And CHANNEL: The object that actually
+//plays the sound and manipulates it in real time.
 //
-//Ultimately this isn’t a problem expect for a couple situations when you go to
-//play a sound, which I will explain in more detail in that part of the code. All
-//that you have to know right now is that Channels in FMOD  do not exist
-//unless they are playing a sound. And in the PANDA FmodAudioSound API class there
-//is only ONE dedicated channel per sound.
-//Otherwise there is really nothing to worry about.
+//Ultimately this isn't a problem expect for a couple situations when
+//you go to play a sound, which I will explain in more detail in that
+//part of the code. All that you have to know right now is that
+//Channels in FMOD do not exist unless they are playing a sound. And
+//in the PANDA FmodAudioSound API class there is only ONE dedicated
+//channel per sound.  Otherwise there is really nothing to worry
+//about.
 //
 ////////////////////////////////////////////////////////////////////
 
@@ -126,7 +132,7 @@ class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound {
   void set_play_rate(float play_rate=1.0f);
   float get_play_rate() const;
 
-  const string& get_name() const;
+  const string &get_name() const;
             
   // return: playing time in seconds.
   float length() const;
@@ -151,13 +157,13 @@ class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound {
   virtual float get_speaker_mix(AudioManager::SpeakerId speaker);
   virtual void set_speaker_mix(float frontleft, float frontright, float center, float sub, float backleft, float backright, float sideleft, float  sideright);
 
+  void set_active(bool active=true);
+  bool get_active() const;
+
   //THESE ARE NOT USED ANYMORE.
   //THEY ARE ONLY HERE BECAUSE THEY are still needed by Miles.
   //THESE are stubs in FMOD-EX version
   ////////////////////////////////////////////////////////////////////
-  void set_active(bool active=true);
-  bool get_active() const;
-
   void finished();
   void set_finished_event(const string& event);
   const string& get_finished_event() const;
@@ -204,6 +210,16 @@ class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound {
   typedef pset<PT (FmodAudioDSP) > DSPSet;
   DSPSet _sound_dsp;
 
+  bool _active;
+
+  // This reference-counting pointer is set to this while the sound is
+  // playing, and cleared when we get an indication that the sound has
+  // stopped.  This prevents a sound from destructing while it is
+  // playing.  We use a PT instead of managing the reference counts by
+  // hand to help guard against accidental reference count leaks or
+  // other mismanagement.
+  PT(FmodAudioSound) _self_ref;
+
   //THESE AREN'T USED ANYMORE.
   //THEY ARE ONLY HERE BECAUSE THEY are still need by Miles.
   //THESE are stubs in FMOD-EX version

+ 10 - 2
panda/src/audiotraits/milesAudioManager.cxx

@@ -333,7 +333,8 @@ get_sound(const string& file_name, bool) {
   Filename path = file_name;
 
   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
-  vfs->resolve_filename(path, get_sound_path());
+  vfs->resolve_filename(path, get_sound_path()) ||
+    vfs->resolve_filename(path, get_model_path());
   audio_debug("  resolved file_name is '"<<path<<"'");
 
   PT(SoundData) sd;
@@ -402,7 +403,8 @@ uncache_sound(const string& file_name) {
   Filename path = file_name;
 
   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
-  vfs->resolve_filename(path, get_sound_path());
+  vfs->resolve_filename(path, get_sound_path()) ||
+    vfs->resolve_filename(path, get_model_path());
 
   audio_debug("  path=\""<<path<<"\"");
   SoundMap::iterator i=_sounds.find(path);
@@ -737,6 +739,12 @@ get_registry_entry(HKEY base, const char* subKeyName,
 ////////////////////////////////////////////////////////////////////
 void MilesAudioManager::
 get_gm_file_path(string& result) {
+  Filename dls_filename = audio_dls_file;
+  if (!dls_filename.empty()) {
+    result = dls_filename.to_os_specific();
+    return;
+  }
+
 #ifdef WIN32
   if(!get_registry_entry(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\DirectMusic", "GMFilePath", result)) {
           char sysdir[MAX_PATH+1];