Przeglądaj źródła

changed the sound code: added reduce sounds to and set finished event

Dave Schuyler 22 lat temu
rodzic
commit
24b2117dbc

+ 2 - 1
direct/src/showbase/ShowBase.py

@@ -716,7 +716,8 @@ class ShowBase(DirectObject.DirectObject):
         self.musicManagerIsValid=self.musicManager!=None \
                 and self.musicManager.isValid()
         if self.musicManagerIsValid:
-            self.musicManager.setMutuallyExclusive(1)  # ensure only 1 midi song is playing at a time
+            # ensure only 1 midi song is playing at a time:
+            self.musicManager.setConcurrentSoundLimit(1)
             self.musicManager.setActive(self.musicActive)
 
     # enableMusic/enableSoundEffects are meant to be called in response to a user request

+ 0 - 5
panda/src/audio/audioManager.cxx

@@ -79,7 +79,6 @@ create_AudioManager() {
   if (!am->is_valid()) {
     am = create_NullAudioManger();
   }
-  am->_bExclusive = false;
   return am;
 }
 
@@ -99,7 +98,3 @@ get_null_sound() {
   return _null_sound;
 }
 
-void AudioManager::
-set_mutually_exclusive(bool bExclusive) {
-  _bExclusive = bExclusive;
-}

+ 41 - 9
panda/src/audio/audioManager.h

@@ -38,6 +38,14 @@ PUBLISHED:
 
   static PT(AudioManager) create_AudioManager();
   virtual ~AudioManager() {}
+  
+  // If you're interested in knowing whether this audio manager
+  // is valid, here's the call to do it.  It is not necessary
+  // to check whether the audio manager is valid before making other
+  // calls.  You are free to use an invalid sound manager, you
+  // may get silent sounds from it though.  The sound manager and
+  // the sounds it creates should not crash the application even
+  // when the objects are not valid.
   virtual bool is_valid() = 0;
   
   // Get a sound:
@@ -51,12 +59,8 @@ PUBLISHED:
   // in its pool/cache.
   virtual void uncache_sound(const string& file_name) = 0;
   virtual void clear_cache() = 0;
-  virtual void set_cache_limit(int count) = 0;
-  virtual int get_cache_limit() = 0;
-
-  // if set, turn off any currently-playing sounds before playing
-  // a new one (useful for midi songs)
-  void set_mutually_exclusive(bool bExclusive);
+  virtual void set_cache_limit(unsigned int count) = 0;
+  virtual unsigned int get_cache_limit() const = 0;
 
   // Control volume:
   // FYI:
@@ -65,7 +69,7 @@ PUBLISHED:
   // 0 = minimum; 1.0 = maximum.
   // inits to 1.0.
   virtual void set_volume(float volume) = 0;
-  virtual float get_volume() = 0;
+  virtual float get_volume() const = 0;
   
   // Turn the manager on or off.
   // If you play a sound while the manager is inactive, it won't start.
@@ -76,14 +80,42 @@ PUBLISHED:
   // they will start playing from the begining of their loop.
   // inits to true.
   virtual void set_active(bool flag) = 0;
-  virtual bool get_active() = 0;
+  virtual bool get_active() const = 0;
+  
+  // This controls the number of sounds that you allow at once.  This
+  // is more of a user choice -- it avoids talk over and the creation
+  // of a cacophony.
+  // It can also be used to help performance.
+  // 0 == unlimited.
+  // 1 == mutually exclusive (one sound at a time).  Which is an example of:
+  // n == allow n sounds to be playing at the same time.
+  virtual void set_concurrent_sound_limit(unsigned int limit = 0) = 0;
+  virtual unsigned int get_concurrent_sound_limit() const = 0;
+  
+  // This is likely to be a utility function for the concurrent_sound_limit
+  // options.  It is exposed as an API, because it's reasonable that it
+  // may be useful to be here.  It reduces the number of concurrently
+  // playing sounds to count by some implementation specific means.
+  // If the number of sounds currently playing is at or below count then
+  // there is no effect.
+  virtual void reduce_sounds_playing_to(unsigned int count) = 0;
+
+  // Stop playback on all sounds managed by this manager.
+  // This is effectively the same as reduce_sounds_playing_to(0), but
+  // this call may be for efficient on some implementations.
+  virtual void stop_all_sounds() = 0;
 
 public:
   static void register_AudioManager_creator(Create_AudioManager_proc* proc);
 
 protected:
+  friend class AudioSound;
+  
+  // Avoid adding data members (instance variables) to this mostly abstract
+  // base class.  This allows implementors of various sound systems the
+  // best flexibility.
+  
   static Create_AudioManager_proc* _create_AudioManager;
-  bool _bExclusive;
   PT(AudioSound) _null_sound;
 
   AudioManager() {

+ 5 - 0
panda/src/audio/audioSound.h

@@ -84,6 +84,11 @@ PUBLISHED:
   // inits to manager's state.
   virtual void set_active(bool flag=true) = 0;
   virtual bool get_active() const = 0;
+
+  // Set (or clear) the event that will be thrown when the sound
+  // finishes playing.  To clear the event, pass an empty string.
+  virtual void set_finished_event(const string& event) = 0;
+  virtual const string& get_finished_event() const = 0;
   
   // There is no set_name(), this is intentional.
   virtual const string& get_name() const = 0;

+ 45 - 5
panda/src/audio/nullAudioManager.cxx

@@ -86,7 +86,7 @@ clear_cache() {
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 void NullAudioManager::
-set_cache_limit(int) {
+set_cache_limit(unsigned int) {
   // intentionally blank.
 }
 
@@ -95,8 +95,8 @@ set_cache_limit(int) {
 //       Access: Public
 //  Description: 
 ////////////////////////////////////////////////////////////////////
-int NullAudioManager::
-get_cache_limit() {
+unsigned int NullAudioManager::
+get_cache_limit() const {
   // intentionally blank.
   return 0;
 }
@@ -117,7 +117,7 @@ set_volume(float) {
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 float NullAudioManager::
-get_volume() {
+get_volume() const {
   return 0;
 }
 
@@ -137,6 +137,46 @@ set_active(bool) {
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 bool NullAudioManager::
-get_active() {
+get_active() const {
   return 0;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: NullAudioManager::set_concurrent_sound_limit
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void NullAudioManager::
+set_concurrent_sound_limit(unsigned int) {
+  // intentionally blank.
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NullAudioManager::get_concurrent_sound_limit
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+unsigned int NullAudioManager::
+get_concurrent_sound_limit() const {
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NullAudioManager::reduce_sounds_playing_to
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void NullAudioManager::
+reduce_sounds_playing_to(unsigned int) {
+  // intentionally blank.
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NullAudioManager::stop_all_sounds
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void NullAudioManager::
+stop_all_sounds() {
+  // intentionally blank.
+}

+ 11 - 4
panda/src/audio/nullAudioManager.h

@@ -37,14 +37,21 @@ public:
   virtual PT(AudioSound) get_sound(const string&);
   virtual void uncache_sound(const string&);
   virtual void clear_cache();
-  virtual void set_cache_limit(int);
-  virtual int get_cache_limit();
+  virtual void set_cache_limit(unsigned int);
+  virtual unsigned int get_cache_limit() const;
 
   virtual void set_volume(float);
-  virtual float get_volume();
+  virtual float get_volume() const;
   
   virtual void set_active(bool);
-  virtual bool get_active();
+  virtual bool get_active() const;
+
+  virtual void set_concurrent_sound_limit(unsigned int limit);
+  virtual unsigned int get_concurrent_sound_limit() const;
+
+  virtual void reduce_sounds_playing_to(unsigned int count);
+
+  virtual void stop_all_sounds();
 };
 
 #endif /* __NULL_AUDIO_MANAGER_H__ */

+ 12 - 1
panda/src/audio/nullAudioSound.cxx

@@ -20,6 +20,10 @@
 #include "nullAudioSound.h"
 
 
+namespace {
+  static const string blank="";
+}
+
 NullAudioSound::NullAudioSound() {
   // Intentionally blank.
 }
@@ -84,8 +88,15 @@ bool NullAudioSound::get_active() const {
   return false; 
 }
 
+void NullAudioSound::set_finished_event(const string& event) {
+  // Intentionally blank.
+}
+
+const string& NullAudioSound::get_finished_event() const {
+  return blank;
+}
+
 const string& NullAudioSound::get_name() const {
-  static const string blank="";
   return blank;
 }
 

+ 3 - 0
panda/src/audio/nullAudioSound.h

@@ -54,6 +54,9 @@ public:
 
   void set_active(bool);
   bool get_active() const;
+
+  void set_finished_event(const string& event);
+  const string& get_finished_event() const;
   
   const string& get_name() const;
   

+ 61 - 26
panda/src/audiotraits/fmodAudioManager.cxx

@@ -54,6 +54,7 @@ FmodAudioManager() {
 
   _active = audio_active;
   _cache_limit = audio_cache_limit;
+  _concurrent_sound_limit = 0;
 
   // Initialize FMOD, if this is the first manager created.
   _is_valid = true;
@@ -62,20 +63,19 @@ FmodAudioManager() {
       audio_debug("Initializing FMOD for real.");
       float fmod_dll_version = FSOUND_GetVersion();
       if (fmod_dll_version < FMOD_VERSION) {
-	audio_error("Wrong FMOD DLL version.  You have "<<fmod_dll_version
-		    <<".  You need "<<FMOD_VERSION);
-	_is_valid = false;
-	break;
+        audio_error("Wrong FMOD DLL version.  You have "<<fmod_dll_version
+            <<".  You need "<<FMOD_VERSION);
+        _is_valid = false;
+        break;
       }
       
       if (FSOUND_Init(44100, 32, 0) == 0) {
-	audio_error("Fmod initialization failure.");
-	_is_valid = false;
-	break;
+        audio_error("Fmod initialization failure.");
+        _is_valid = false;
+        break;
       }
-
     }
-    while(0);
+    while(0); // curious -- why is there a non-loop here?
   }
 
   // increment regardless of whether an error has occured -- the
@@ -222,7 +222,7 @@ get_sound(const string &file_name) {
   // Build a new AudioSound from the audio data.
   PT(AudioSound) audioSound = 0;
   PT(FmodAudioSound) fmodAudioSound = new FmodAudioSound(this, stream, path,
-							 length);
+               length);
   fmodAudioSound->set_active(_active);
   _soundsOnLoan.insert(fmodAudioSound);
   audioSound = fmodAudioSound;
@@ -263,7 +263,7 @@ uncache_sound(const string& file_name) {
     // If the refcount is already zero, it can be
     // purged right now!
     audio_debug("FmodAudioManager::uncache_sound: purging "<<path
-		<< " from the cache.");
+    << " from the cache.");
     delete [] entry->data;
 
     // Erase the sound from the LRU list as well.
@@ -324,7 +324,7 @@ most_recently_used(const string& path) {
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioManager::clear_cache
 //       Access: Public
-//  Description: 
+//  Description: Clear out the sound cache.
 ////////////////////////////////////////////////////////////////////
 void FmodAudioManager::
 clear_cache() {
@@ -340,7 +340,7 @@ clear_cache() {
     SoundCacheEntry *entry = &(*itor).second;
     if (entry->refcount == 0) {
       audio_debug("FmodAudioManager::clear_cache: purging "<< (*itor).first
-		  << " from the cache.");
+      << " from the cache.");
       delete [] entry->data;
 
       // Erase the sound from the LRU list as well.
@@ -361,18 +361,15 @@ clear_cache() {
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioManager::set_cache_limit
 //       Access: Public
-//  Description: 
+//  Description: Set the number of sounds that the cache can hold.
 ////////////////////////////////////////////////////////////////////
 void FmodAudioManager::
-set_cache_limit(int count) {
-  audio_debug("FmodAudioManager::set_cache_limit(count="
-      <<count<<")");
+set_cache_limit(unsigned int count) {
+  audio_debug("FmodAudioManager::set_cache_limit(count="<<count<<")");
   assert(is_valid());
-  
-  while (_lru.size() > (unsigned int) count) {
+  while (_lru.size() > count) {
     uncache_a_sound();
   }
-
   _cache_limit = count;
   assert(is_valid());
 }
@@ -385,7 +382,7 @@ set_cache_limit(int count) {
 int FmodAudioManager::
 get_cache_limit() {
   audio_debug("FmodAudioManager::get_cache_limit() returning "
-	      <<_cache_limit);
+        <<_cache_limit);
   return _cache_limit;
 }
 
@@ -451,18 +448,56 @@ get_active() {
   return _active;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::set_concurrent_sound_limit
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void FmodAudioManager::
+set_concurrent_sound_limit(unsigned int limit) {
+  _concurrent_sound_limit = limit;
+  reduce_sounds_playing_to(_concurrent_sound_limit);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::get_concurrent_sound_limit
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+unsigned int FmodAudioManager::
+get_concurrent_sound_limit() const {
+  return _concurrent_sound_limit;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::reduce_sounds_playing_to
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void FmodAudioManager::
+reduce_sounds_playing_to(unsigned int count) {
+  // This is an example from Miles audio, this should be done for fmod:
+  //int limit = _sounds_playing.size() - count;
+  //while (limit-- > 0) {
+  //  SoundsPlaying::iterator sound = _sounds_playing.begin();
+  //  assert(sound != _sounds_playing.end());
+  //  (**sound).stop();
+  //}
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioManager::stop_all_sounds
 //       Access: Public
 //  Description: Stop playback on all sounds managed by this manager.
 ////////////////////////////////////////////////////////////////////
 void FmodAudioManager::
-stop_all_sounds(void) {
+stop_all_sounds() {
   audio_debug("FmodAudioManager::stop_all_sounds()");
   AudioSet::iterator i=_soundsOnLoan.begin();
   for (; i!=_soundsOnLoan.end(); ++i) {
-    if((**i).status()==AudioSound::PLAYING)
+    if ((**i).status()==AudioSound::PLAYING) {
       (**i).stop();
+    }
   }
 }
 
@@ -484,7 +519,7 @@ inc_refcount(const string& file_name) {
   entry->refcount++;
   entry->stale = false; // definitely not stale!
   audio_debug("FmodAudioManager: "<<path<<" has a refcount of "
-	      << entry->refcount);
+        << entry->refcount);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -502,7 +537,7 @@ dec_refcount(const string& file_name) {
     SoundCacheEntry *entry = &(*itor).second;
     entry->refcount--;
     audio_debug("FmodAudioManager: "<<path<<" has a refcount of "
-		<< entry->refcount);
+    << entry->refcount);
     if (entry->refcount == 0 && entry->stale) {
       audio_debug("FmodAudioManager::dec_refcount: purging "<<path<< " from the cache.");
       delete [] entry->data;
@@ -537,7 +572,7 @@ load(const Filename& filename, size_t &size) const {
   }
   if (!bSupported) {
     audio_error("FmodAudioManager::load: "<<filename
-		<<" is not a supported file format.");
+    <<" is not a supported file format.");
     audio_error("Supported formats are: WAV, MP3, MIDI");
     return NULL;
   }

+ 11 - 4
panda/src/audiotraits/fmodAudioManager.h

@@ -20,7 +20,7 @@
 #ifndef __FMOD_AUDIO_MANAGER_H__
 #define __FMOD_AUDIO_MANAGER_H__
 
-#include <pandabase.h>
+#include "pandabase.h"
 #ifdef HAVE_FMOD //[
 
 #include "audioManager.h"
@@ -30,7 +30,7 @@ class FmodAudioSound;
 #include "pmap.h"
 #include "pset.h"
 
-#include <fmod.h>
+#include <fmod.h> // Is fmod.h really a system file?  I think maybe this should be "fmod.h".
 
 class EXPCL_FMOD_AUDIO FmodAudioManager : public AudioManager {
   // All of these methods are stubbed out to some degree.
@@ -46,7 +46,7 @@ public:
   virtual PT(AudioSound) get_sound(const string&);
   virtual void uncache_sound(const string&);
   virtual void clear_cache();
-  virtual void set_cache_limit(int);
+  virtual void set_cache_limit(unsigned int count);
   virtual int get_cache_limit();
 
   // Indicates that the given sound was the most recently used.
@@ -60,7 +60,13 @@ public:
   
   virtual void set_active(bool);
   virtual bool get_active();
-  void stop_all_sounds();
+
+  virtual void set_concurrent_sound_limit(unsigned int limit = 0);
+  virtual unsigned int get_concurrent_sound_limit() const;
+
+  virtual void reduce_sounds_playing_to(unsigned int count);
+
+  virtual void stop_all_sounds();
 
 protected:
   // increment or decrement the refcount of the given file's cache entry.
@@ -80,6 +86,7 @@ private:
   typedef pset<FmodAudioSound* > AudioSet;
   // The offspring of this manager:
   AudioSet _soundsOnLoan;
+  unsigned int _concurrent_sound_limit;
 
   // The Least Recently Used mechanism:
   typedef pdeque<string> LRU;

+ 9 - 9
panda/src/audiotraits/fmodAudioSound.cxx

@@ -34,14 +34,14 @@
 
 FmodAudioSound::
 FmodAudioSound(FmodAudioManager* manager, FSOUND_STREAM *audio_data,
-	       string file_name, float length)
+         string file_name, float length)
   : _manager(manager), _audio(audio_data), _file_name(file_name),
     _volume(1.0f), _balance(0), _loop_count(1), _length(length),
     _active(true), _paused(false), _channel(-1) {
   nassertv(!file_name.empty());
   nassertv(audio_data != NULL);
   audio_debug("FmodAudioSound(manager=0x"<<(void*)&manager
-	      <<", file_name="<<file_name<<")");
+        <<", file_name="<<file_name<<")");
 }
 
 FmodAudioSound::
@@ -56,16 +56,14 @@ play() {
   if (!_active) {
     return;
   }
-
-  if(_manager->_bExclusive) {
-    // stop any other sound that parent mgr is playing
-    _manager->stop_all_sounds();
-  }
-
   // If the sound is already playing, stop it.
   if (this->status() == AudioSound::PLAYING) {
     this->stop();
   }
+  if (_manager->stop_a_sound()) {
+    // stop another sound that parent mgr is playing
+    _manager->stop_all_sounds();
+  }
 
   // Play the stream, but start it paused so we can set the volume and
   // panning first.
@@ -92,7 +90,9 @@ play() {
   // Delay until the channel is actually playing.  This shouldn't
   // result in a noticeable delay, and allows you to immediately test
   // the status of the sound after initiating playback.
-  while (!FSOUND_IsPlaying(_channel));
+  while (!FSOUND_IsPlaying(_channel)) {
+    // intentinaly empty loop.
+  }
 }
 
 void FmodAudioSound::stop() {

+ 4 - 1
panda/src/audiotraits/fmodAudioSound.h

@@ -69,6 +69,9 @@ public:
   // inits to manager's state.
   void set_active(bool active=true);
   bool get_active() const;
+
+  void set_finished_event(const string& event);
+  const string& get_finished_event() const;
   
   const string& get_name() const;
   
@@ -92,7 +95,7 @@ private:
   int _channel;
 
   FmodAudioSound(FmodAudioManager* manager, FSOUND_STREAM *audio_data,
-		 string file_name, float length=0.0f);
+     string file_name, float length=0.0f);
 
   // forbidden functions!
   FmodAudioSound(const FmodAudioSound& rhs) {}

+ 153 - 94
panda/src/audiotraits/milesAudioManager.cxx

@@ -32,54 +32,49 @@
 int MilesAudioManager::_active_managers = 0;
 HDLSFILEID MilesAudioManager::_dls_field = NULL;
 bool bMilesShutdownCalled = false;
-bool bMilesShutdownAtExitRegistered = false;
 
 PT(AudioManager) Create_AudioManager() {
   audio_debug("Create_AudioManager() Miles.");
   return new MilesAudioManager();
 }
 
-void fMilesShutdown(void) {
-    if(bMilesShutdownCalled)
-      return;
-
-    bMilesShutdownCalled = true;
-
-    if (MilesAudioManager::_dls_field!=NULL) {
-      HDLSDEVICE dls= NULL;
-      AIL_quick_handles(0, 0, &dls);
-      if(dls!=NULL) {
-          AIL_DLS_unload(dls,MilesAudioManager::_dls_field);
-      }
+void CustomMilesShutdown() {
+  if (bMilesShutdownCalled) {
+    return;
+  }
+  bMilesShutdownCalled = true;
 
-      #ifndef NDEBUG //[
-        // Clear _dls_field in debug version (for assert in ctor):
-        MilesAudioManager::_dls_field = NULL;  
-      #endif //]
+  if (MilesAudioManager::_dls_field!=NULL) {
+    HDLSDEVICE dls= NULL;
+    AIL_quick_handles(0, 0, &dls);
+    if (dls!=NULL) {
+      AIL_DLS_unload(dls,MilesAudioManager::_dls_field);
     }
+    #ifndef NDEBUG //[
+      // Clear _dls_field in debug version (for assert in ctor):
+      MilesAudioManager::_dls_field = NULL;  
+    #endif //]
+  }
 
-
-   #define SHUTDOWN_HACK
-   
-   // if python crashes, the midi notes are left on,
-   // so we need to turn them off.  Unfortunately
-   // in Miles 6.5, AIL_quick_shutdown() crashes
-   // when it's called from atexit after a python crash, probably
-   // because mss32.dll has already been unloaded
-   // workaround: use these internal values in the miles struct
-   //             to reset the win32 midi ourselves
-   
-   #ifdef SHUTDOWN_HACK
-    HMDIDRIVER hMid=NULL;
-    AIL_quick_handles(0, &hMid, 0);
-    if ((hMid!=NULL) && (hMid->deviceid != MIDI_NULL_DRIVER) && (hMid->hMidiOut != NULL)) {
-      midiOutReset(hMid->hMidiOut);
-      midiOutClose(hMid->hMidiOut);
-    }
-   #else
-    audio_debug("  AIL_quick_shutdown()");
-    AIL_quick_shutdown();
-   #endif
+  #define SHUTDOWN_HACK
+  // if python crashes, the midi notes are left on,
+  // so we need to turn them off.  Unfortunately
+  // in Miles 6.5, AIL_quick_shutdown() crashes
+  // when it's called from atexit after a python crash, probably
+  // because mss32.dll has already been unloaded
+  // workaround: use these internal values in the miles struct
+  //             to reset the win32 midi ourselves
+  #ifdef SHUTDOWN_HACK
+  HMDIDRIVER hMid=NULL;
+  AIL_quick_handles(0, &hMid, 0);
+  if ((hMid!=NULL) && (hMid->deviceid != MIDI_NULL_DRIVER) && (hMid->hMidiOut != NULL)) {
+    midiOutReset(hMid->hMidiOut);
+    midiOutClose(hMid->hMidiOut);
+  }
+  #else
+  audio_debug("  AIL_quick_shutdown()");
+  AIL_quick_shutdown();
+  #endif
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -95,8 +90,9 @@ MilesAudioManager() {
   _active = audio_active;
   _volume = audio_volume;
   _cache_limit = audio_cache_limit;
+  _concurrent_sound_limit = 0;
   _is_valid = true;
-  _bHasMidiSounds = false;
+  _hasMidiSounds = false;
   if (_active_managers==0) {
     S32 use_digital=(audio_play_wave || audio_play_mp3)?1:0;
     S32 use_MIDI=(audio_play_midi)?1:0;
@@ -146,7 +142,7 @@ MilesAudioManager() {
           audio_info("  using Miles software midi");
         }
       } else {
-          audio_info("  using Miles hardware midi");
+        audio_info("  using Miles hardware midi");
       }
 
       if (use_vfs) {
@@ -169,9 +165,10 @@ MilesAudioManager() {
   if (_is_valid)  {
     assert(is_valid());
 
-    if(!bMilesShutdownAtExitRegistered) {
-       bMilesShutdownAtExitRegistered = true;
-       atexit(fMilesShutdown);
+    static bool atexit_registered = false;
+    if(!atexit_registered) {
+       atexit_registered = true;
+       atexit(CustomMilesShutdown);
     }
   }
 }
@@ -185,7 +182,7 @@ MilesAudioManager::
 ~MilesAudioManager() {
   audio_debug("MilesAudioManager::~MilesAudioManager()");
   // Be sure to delete associated sounds before deleting the manager:
-  nassertv(_soundsOnLoan.empty());
+  nassertv(_sounds_on_loan.empty());
   clear_cache();
   --_active_managers;
   audio_debug("  _active_managers="<<_active_managers);
@@ -238,10 +235,8 @@ is_valid() {
 HAUDIO MilesAudioManager::
 load(Filename file_name) {
   HAUDIO audio;
-
   if (use_vfs) {
     audio = AIL_quick_load(file_name.c_str());
-
   } else {
     string stmp = file_name.to_os_specific();
     audio_debug("  \"" << stmp << "\"");
@@ -318,11 +313,11 @@ get_sound(const string& file_name) {
         =new MilesAudioSound(this, audio, (*si).first);
     nassertr(milesAudioSound, 0);
     milesAudioSound->set_active(_active);
-    _soundsOnLoan.insert(milesAudioSound);
+    _sounds_on_loan.insert(milesAudioSound);
     audioSound=milesAudioSound;
   }
 
-  _bHasMidiSounds |= (file_name.find(".mid")!=string::npos);
+  _hasMidiSounds |= (file_name.find(".mid")!=string::npos);
   audio_debug("  returning 0x" << (void*)audioSound);
   assert(is_valid());
   return audioSound;
@@ -406,7 +401,7 @@ most_recently_used(const string& path) {
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioManager::clear_cache
 //       Access: Public
-//  Description:
+//  Description: Clear out the sound cache.
 ////////////////////////////////////////////////////////////////////
 void MilesAudioManager::
 clear_cache() {
@@ -424,14 +419,13 @@ clear_cache() {
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioManager::set_cache_limit
 //       Access: Public
-//  Description:
+//  Description: Set the number of sounds that the cache can hold.
 ////////////////////////////////////////////////////////////////////
 void MilesAudioManager::
-set_cache_limit(int count) {
-  audio_debug("MilesAudioManager::set_cache_limit(count="
-      <<count<<")");
+set_cache_limit(unsigned int count) {
+  audio_debug("MilesAudioManager::set_cache_limit(count="<<count<<")");
   assert(is_valid());
-  while (_lru.size() > (unsigned int) count) {
+  while (_lru.size() > count) {
     uncache_a_sound();
   }
   _cache_limit=count;
@@ -443,8 +437,8 @@ set_cache_limit(int count) {
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-int MilesAudioManager::
-get_cache_limit() {
+unsigned int MilesAudioManager::
+get_cache_limit() const {
   audio_debug("MilesAudioManager::get_cache_limit() returning "
       <<_cache_limit);
   return _cache_limit;
@@ -459,7 +453,7 @@ void MilesAudioManager::
 release_sound(MilesAudioSound* audioSound) {
   audio_debug("MilesAudioManager::release_sound(audioSound=\""
       <<audioSound->get_name()<<"\")");
-  _soundsOnLoan.erase(audioSound);
+  _sounds_on_loan.erase(audioSound);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -473,53 +467,43 @@ set_volume(float volume) {
   if (_volume!=volume) {
     _volume = volume;
     // Tell our AudioSounds to adjust:
-    AudioSet::iterator i=_soundsOnLoan.begin();
-    for (; i!=_soundsOnLoan.end(); ++i) {
+    AudioSet::iterator i=_sounds_on_loan.begin();
+    for (; i!=_sounds_on_loan.end(); ++i) {
       (**i).set_volume((**i).get_volume());
     }
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioManager::force_midi_reset
+//       Access: Public
+//  Description: ?????.
+////////////////////////////////////////////////////////////////////
 void MilesAudioManager::
-stop_all_sounds(void) {
-  audio_debug("MilesAudioManager::stop_all_sounds()");
-  AudioSet::iterator i=_soundsOnLoan.begin();
-  for (; i!=_soundsOnLoan.end(); ++i) {
-      if((**i).status()==AudioSound::PLAYING)
-          (**i).stop();
+force_midi_reset() {
+  if (!miles_audio_force_midi_reset) {
+    audio_debug("MilesAudioManager::skipping force_midi_reset");  
+    return;
   }
-
-  if(_bHasMidiSounds) {
-      forceMidiReset();
+  audio_debug("MilesAudioManager::force_midi_reset");
+
+  // sometimes Miles seems to leave midi notes hanging, even after stop is called,
+  // so perform an explicit reset using winMM.dll calls, just to ensure silence.
+  HMDIDRIVER hMid=NULL;
+  AIL_quick_handles(0, &hMid, 0);
+  if ((hMid!=NULL) && (hMid->deviceid != MIDI_NULL_DRIVER) && (hMid->hMidiOut != NULL)) {
+    audio_debug("MilesAudioManager::calling midiOutReset");
+    midiOutReset(hMid->hMidiOut);
   }
 }
 
-void MilesAudioManager::
-forceMidiReset(void) {
-    if(!miles_audio_force_midi_reset) {
-        audio_debug("MilesAudioManager::skipping forceMidiReset");  
-        return;
-    }
-
-    audio_debug("MilesAudioManager::ForceMidiReset");
-
-    // sometimes Miles seems to leave midi notes hanging, even after stop is called,
-    // so perform an explicit reset using winMM.dll calls, just to ensure silence.
-    HMDIDRIVER hMid=NULL;
-    AIL_quick_handles(0, &hMid, 0);
-    if ((hMid!=NULL) && (hMid->deviceid != MIDI_NULL_DRIVER) && (hMid->hMidiOut != NULL)) {
-        audio_debug("MilesAudioManager::calling midiOutReset");
-        midiOutReset(hMid->hMidiOut);
-    }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioManager::get_volume
 //       Access: Public
 //  Description: get the overall volume
 ////////////////////////////////////////////////////////////////////
 float MilesAudioManager::
-get_volume() {
+get_volume() const {
   audio_debug("MilesAudioManager::get_volume() returning "<<_volume);
   return _volume;
 }
@@ -535,13 +519,13 @@ set_active(bool active) {
   if (_active!=active) {
     _active=active;
     // Tell our AudioSounds to adjust:
-    AudioSet::iterator i=_soundsOnLoan.begin();
-    for (; i!=_soundsOnLoan.end(); ++i) {
+    AudioSet::iterator i=_sounds_on_loan.begin();
+    for (; i!=_sounds_on_loan.end(); ++i) {
       (**i).set_active(_active);
     }
 
-    if((!_active) && _bHasMidiSounds) {
-        forceMidiReset();
+    if((!_active) && _hasMidiSounds) {
+        force_midi_reset();
     }
   }
 }
@@ -552,11 +536,86 @@ set_active(bool active) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 bool MilesAudioManager::
-get_active() {
+get_active() const {
   audio_debug("MilesAudioManager::get_active() returning "<<_active);
   return _active;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioManager::starting_sound
+//       Access: 
+//  Description: Inform the manager that a sound is about to play.
+////////////////////////////////////////////////////////////////////
+void MilesAudioManager::
+starting_sound(MilesAudioSound* audio) {
+  if (_concurrent_sound_limit) {
+    reduce_sounds_playing_to(_concurrent_sound_limit);
+  }
+  _sounds_playing.insert(audio);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioManager::stoping_sound
+//       Access: 
+//  Description: Inform the manager that a sound is finished or 
+//               someone called stop on the sound (this should not
+//               be called if a sound is only paused).
+////////////////////////////////////////////////////////////////////
+void MilesAudioManager::
+stoping_sound(MilesAudioSound* audio) {
+  _sounds_playing.erase(audio);
+  if (_hasMidiSounds && _sounds_playing.size() == 0) {
+    force_midi_reset();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioManager::set_concurrent_sound_limit
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioManager::
+set_concurrent_sound_limit(unsigned int limit) {
+  _concurrent_sound_limit = limit;
+  reduce_sounds_playing_to(_concurrent_sound_limit);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioManager::get_concurrent_sound_limit
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+unsigned int MilesAudioManager::
+get_concurrent_sound_limit() const {
+  return _concurrent_sound_limit;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioManager::reduce_sounds_playing_to
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioManager::
+reduce_sounds_playing_to(unsigned int count) {
+  int limit = _sounds_playing.size() - count;
+  while (limit-- > 0) {
+    SoundsPlaying::iterator sound = _sounds_playing.begin();
+    assert(sound != _sounds_playing.end());
+    (**sound).stop();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioManager::stop_all_sounds
+//       Access: Public
+//  Description: Stop playback on all sounds managed by this manager.
+////////////////////////////////////////////////////////////////////
+void MilesAudioManager::
+stop_all_sounds() {
+  audio_debug("MilesAudioManager::stop_all_sounds()");
+  reduce_sounds_playing_to(0);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioManager::get_registry_entry
 //       Access: private

+ 24 - 9
panda/src/audiotraits/milesAudioManager.h

@@ -20,7 +20,7 @@
 #ifndef __MILES_AUDIO_MANAGER_H__ //[
 #define __MILES_AUDIO_MANAGER_H__
 
-#include <pandabase.h>
+#include "pandabase.h"
 #ifdef HAVE_RAD_MSS //[
 
 #include "audioManager.h"
@@ -43,16 +43,21 @@ public:
   PT(AudioSound) get_sound(const string& file_name);
   void uncache_sound(const string& file_name);
   void clear_cache();
-  void set_cache_limit(int count);
-  int get_cache_limit();
+  void set_cache_limit(unsigned int count);
+  unsigned int get_cache_limit() const;
 
   void set_volume(float volume);
-  float get_volume();
+  float get_volume() const;
   
   void set_active(bool active);
-  bool get_active();
+  bool get_active() const;
+
+  void set_concurrent_sound_limit(unsigned int limit = 0);
+  unsigned int get_concurrent_sound_limit() const;
+
+  void reduce_sounds_playing_to(unsigned int count);
+
   void stop_all_sounds();
-  void forceMidiReset();
 
   // Optional Downloadable Sound field for software midi:
   // made public so C atexit fn can access it
@@ -65,7 +70,11 @@ private:
 
   typedef pset<MilesAudioSound* > AudioSet;
   // The offspring of this manager:
-  AudioSet _soundsOnLoan;
+  AudioSet _sounds_on_loan;
+
+  typedef pset<MilesAudioSound* > SoundsPlaying;
+  // The sounds from this manager that are currently playing:
+  SoundsPlaying _sounds_playing;
 
   // The Least Recently Used mechanism:
   typedef pdeque<const string* > LRU;
@@ -76,9 +85,10 @@ private:
   int _cache_limit;
   // keep a count for startup and shutdown:
   static int _active_managers;
+  unsigned int _concurrent_sound_limit;
   
   bool _is_valid;
-  bool _bHasMidiSounds;
+  bool _hasMidiSounds;
   
   HAUDIO load(Filename file_name);
   // Tell the manager that the sound dtor was called.
@@ -87,6 +97,9 @@ private:
   void most_recently_used(const string& path);
   void uncache_a_sound();
 
+  void starting_sound(MilesAudioSound* audio);
+  void stoping_sound(MilesAudioSound* audio);
+
   // utility function that should be moved to another class:
   bool get_registry_entry(HKEY base, 
                           const char* subKeyName, 
@@ -95,6 +108,8 @@ private:
   // get the default dls file path:
   void get_gm_file_path(string& result);
 
+  void force_midi_reset();
+
   // These are "callback" functions that implement vfs-style I/O for
   // Miles.
   static U32 AILCALLBACK vfs_open_callback(const char *filename, U32 *file_handle);
@@ -102,7 +117,7 @@ private:
   static S32 AILCALLBACK vfs_seek_callback(U32 file_handle, S32 offset, U32 type);
   static void AILCALLBACK vfs_close_callback(U32 file_handle);
   
-  friend MilesAudioSound;
+  friend class MilesAudioSound;
 };
 
 EXPCL_MILES_AUDIO PT(AudioManager) Create_AudioManager();

+ 134 - 58
panda/src/audiotraits/milesAudioSound.cxx

@@ -16,9 +16,10 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#include <pandabase.h>
+#include "pandabase.h"
 #ifdef HAVE_RAD_MSS //[
 
+#include "throw_event.h"
 #include "milesAudioSound.h"
 #include "milesAudioManager.h"
 
@@ -45,6 +46,72 @@
           return 'x'; // bad.
       }
     }
+
+    AILSEQUENCECB sequence_callback = 0;
+    AILSAMPLECB sample_callback = 0;
+    const user_data_index = 7;
+
+    void AILCALLBACK
+    pandaAudioAilCallback_Sequence(HSEQUENCE S) {
+      assert(S);
+      audio_debug("pandaAudioAilCallback_Sequence(HSEQUENCE="<<((void*)S)<<")");
+      MilesAudioSound* sound = (MilesAudioSound*)AIL_sequence_user_data(
+          S, user_data_index);
+      assert(sound);
+      sound->finished();
+      if (sequence_callback) {
+        sequence_callback(S);
+      }
+    }
+
+    void AILCALLBACK
+    pandaAudioAilCallback_Sample(HSAMPLE S) {
+      assert(S);
+      audio_debug("pandaAudioAilCallback_Sample(HSAMPLE="<<((void*)S)<<")");
+      MilesAudioSound* sound = (MilesAudioSound*)AIL_sample_user_data(
+          S, user_data_index);
+      assert(sound);
+      sound->finished();
+      if (sample_callback) {
+        sample_callback(S);
+      }
+    }
+    
+    void
+    panda_AIL_quick_set_finished_callback(HAUDIO audio, MilesAudioSound* sound) {
+      audio_debug("panda_AIL_quick_set_finished_callback(audio="<<((void*)audio)
+          <<", sound="<<((void*)sound)<<")");
+      if (!audio || !sound) {
+        return;
+      }
+      AIL_lock();
+      if (audio->handle != NULL) {
+        switch (audio->type) {
+        case AIL_QUICK_XMIDI_TYPE:
+          audio_debug("  AIL_register_sequence_callback");
+          AIL_set_sequence_user_data(
+              (HSEQUENCE)audio->handle, user_data_index, (long)sound);
+          sequence_callback=AIL_register_sequence_callback(
+              (HSEQUENCE)audio->handle, pandaAudioAilCallback_Sequence);
+          audio_debug(  "AILCALLBACK "<<((void*)sequence_callback));
+          break;
+        case AIL_QUICK_DIGITAL_TYPE:
+        case AIL_QUICK_MPEG_DIGITAL_TYPE:
+          audio_debug("  AIL_register_EOS_callback");
+          AIL_set_sample_user_data(
+              (HSAMPLE)audio->handle, user_data_index, (long)sound);
+          sample_callback=AIL_register_EOS_callback(
+              (HSAMPLE)audio->handle, pandaAudioAilCallback_Sample);
+          audio_debug("  AILCALLBACK "<<((void*)sample_callback));
+          break;
+        default:
+          audio_debug("  unknown audio type");
+          break;
+        }
+      }
+      AIL_unlock();
+    }
+
   }
 
   #define miles_audio_debug(x) \
@@ -72,6 +139,7 @@ MilesAudioSound(MilesAudioManager* manager,
 MilesAudioSound::
 ~MilesAudioSound() {
   miles_audio_debug("~MilesAudioSound()");
+  stop();
   _manager->release_sound(this);
   AIL_quick_unload(_audio);
 }
@@ -86,12 +154,14 @@ play() {
   
   miles_audio_debug("play()");
   if (_active) {
-    if(_manager->_bExclusive) {
-        // stop any other sound that parent mgr is playing
-        _manager->stop_all_sounds();
+    if (status() == AudioSound::PLAYING) {
+      stop();
     }
+    _manager->starting_sound(this);
     // Start playing:
     if (AIL_quick_play(_audio, _loop_count)) {
+      panda_AIL_quick_set_finished_callback(_audio, this);
+      assert(status()==PLAYING);
       audio_debug("  started sound " << _file_name );
     } else {
       audio_debug("  sound " << _file_name<<" failed to start, err: " <<AIL_last_error());
@@ -105,27 +175,25 @@ play() {
 
 void MilesAudioSound::
 stop() {
-  #if 0
-  if(_file_name.find(".mid")!=string::npos) {
-        miles_audio_debug("stop() midi");
-  } 
-  #endif
-  miles_audio_debug("stopping snd " << _file_name);
-  _paused=false;
+  miles_audio_debug("stop()");
+  _manager->stoping_sound(this);
+  // The _paused flag should not be cleared here.  _paused is not like
+  // the Pause button on a cd/dvd player.  It is used as a flag to say
+  // that it was looping when it was set inactive.  There is no need to
+  // make this symetrical with play().  set_active() is the 'owner' of
+  // _paused.  play() accesses _paused to help in the situation where
+  // someone calls play on an inactive sound().
+  // removing --> _paused=false;
   AIL_quick_halt(_audio);
 }
 
 void MilesAudioSound::
-halt() {
-  #if 0
-  if(_file_name.find(".mid")!=string::npos) {
-        miles_audio_debug("halt() midi");
-        int i=1;
+finished() {
+  miles_audio_debug("finished()");
+  _manager->stoping_sound(this);
+  if (!_finished_event.empty()) {
+    throw_event(_finished_event);
   }
-  #endif
-
-  miles_audio_debug("halt()");
-  AIL_quick_halt(_audio);
 }
 
 void MilesAudioSound::
@@ -154,7 +222,7 @@ set_loop_count(unsigned long loop_count) {
       // need to stop and start the sound, feel free.  Or, maybe I'll spend
       // time on it in the future.  Please set the loop option before starting
       // the sound.
-      halt();
+      stop();
       play();
     }
   }
@@ -234,43 +302,6 @@ get_volume() const {
   return _volume;
 }
 
-void MilesAudioSound::
-set_active(bool active) {
-  miles_audio_debug("set_active(active="<<active<<")");
-  if (_active!=active) {
-    _active=active;
-    if (_active) {
-      // ...activate the sound.
-      if (_paused
-          &&
-          _loop_count==0) {
-        // ...this sound was looping when it was paused.
-        _paused=false;
-        play();
-      }
-    } else {
-      // ...deactivate the sound.
-      if (status()==PLAYING) {
-        if (_loop_count==0) {
-          // ...we're pausing a looping sound.
-          _paused=true;
-        }
-
-        // unlike the user fn stop(), halt() does NOT alter the 'paused' status
-        // this is important, dont want to 'stop' infin looping sounds unless user
-        // explicitly uses "stop()"
-        halt();
-      }
-    }
-  }
-}
-
-bool MilesAudioSound::
-get_active() const {
-  miles_audio_debug("get_active() returning "<<_active);
-  return _active;
-}
-
 void MilesAudioSound::
 set_balance(float balance_right) {
   miles_audio_debug("set_balance(balance_right="<<balance_right<<")");
@@ -327,6 +358,51 @@ length() const {
   return _length;
 }
 
+void MilesAudioSound::
+set_active(bool active) {
+  miles_audio_debug("set_active(active="<<active<<")");
+  if (_active!=active) {
+    _active=active;
+    if (_active) {
+      // ...activate the sound.
+      if (_paused
+          &&
+          _loop_count==0) {
+        // ...this sound was looping when it was paused.
+        _paused=false;
+        play();
+      }
+    } else {
+      // ...deactivate the sound.
+      if (status()==PLAYING) {
+        if (_loop_count==0) {
+          // ...we're pausing a looping sound.
+          _paused=true;
+        }
+        stop();
+      }
+    }
+  }
+}
+
+bool MilesAudioSound::
+get_active() const {
+  miles_audio_debug("get_active() returning "<<_active);
+  return _active;
+}
+
+void MilesAudioSound::
+set_finished_event(const string& event) {
+  miles_audio_debug("set_finished_event(event="<<event<<")");
+  _finished_event = event;
+}
+
+const string& MilesAudioSound::
+get_finished_event() const {
+  miles_audio_debug("get_finished_event() returning "<<_finished_event);
+  return _finished_event;
+}
+
 const string& MilesAudioSound::
 get_name() const {
   //audio_debug("MilesAudioSound::get_name() returning "<<_file_name);

+ 22 - 6
panda/src/audiotraits/milesAudioSound.h

@@ -83,6 +83,12 @@ public:
   // inits to manager's state.
   void set_active(bool active=true);
   bool get_active() const;
+
+  // This is the string that throw_event() will throw
+  // when the sound finishes playing.  It is not triggered
+  // when the sound is stopped with stop().
+  void set_finished_event(const string& event);
+  const string& get_finished_event() const;
   
   const string& get_name() const;
   
@@ -91,11 +97,7 @@ public:
 
   AudioSound::SoundStatus status() const;
 
-protected:
-    // halt is like stop(), except it should not be called by the user.
-    // halt() does not change the "paused" status of a sound, it just stops 
-    // it from playing.  This is useful when the sound needs to be deactivated
-    void halt(void);
+  void finished();
 
 private:
   HAUDIO _audio;
@@ -104,14 +106,28 @@ private:
   float _balance; // -1..1
   mutable float _length; // in seconds.
   unsigned long _loop_count;
+  
+  // This is the string that throw_event() will throw
+  // when the sound finishes playing.  It is not triggered
+  // when the sound is stopped with stop().
+  string _finished_event;
+  
   string _file_name;
+  
+  // _active is for things like a 'turn off sound effects' in
+  // a preferences pannel.
+  // _active is not about whether a sound is currently playing.
+  // Use status() for info on whether the sound is playing.
   bool _active;
+  
+  // _paused is not like the Pause button on a cd/dvd player.
+  // It is used as a flag to say that the sound was looping when
+  // itwas set inactive.
   bool _paused;
 
   MilesAudioSound(MilesAudioManager* manager, 
       HAUDIO audio, string file_name, float length=0.0f);
 
-
   friend class MilesAudioManager;
 };
 

+ 9 - 9
panda/src/chan/chan_headers.h

@@ -16,15 +16,15 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#include <bamReader.h>
-#include <bamWriter.h>
-#include <compose_matrix.h>
-#include <datagram.h>
-#include <datagramIterator.h>
-#include <event.h>
-#include <fftCompressor.h>
-#include <indent.h>
-#include <throw_event.h>
+#include "bamReader.h"
+#include "bamWriter.h"
+#include "compose_matrix.h"
+#include "datagram.h"
+#include "datagramIterator.h"
+#include "event.h"
+#include "fftCompressor.h"
+#include "indent.h"
+#include "throw_event.h"
 
 #include "animBundle.h"
 #include "animBundleNode.h"

+ 1 - 1
panda/src/event/throw_event.h

@@ -19,7 +19,7 @@
 #ifndef THROW_EVENT_H
 #define THROW_EVENT_H
 
-#include <pandabase.h>
+#include "pandabase.h"
 
 #include "eventQueue.h"
 #include "pt_Event.h"

+ 2 - 2
panda/src/lerp/lerp.cxx

@@ -19,8 +19,8 @@
 
 #include "lerp.h"
 
-#include <clockObject.h>
-#include <throw_event.h>
+#include "clockObject.h"
+#include "throw_event.h"
 
 TypeHandle Lerp::_type_handle;
 TypeHandle AutonomousLerp::_type_handle;

+ 6 - 3
panda/src/physics/physicsCollisionHandler.cxx

@@ -73,8 +73,8 @@ apply_linear_force(ColliderDef &def, const LVector3f &force) {
   LVector3f adjustment=force;
   physics_debug("  adjustment set "<<adjustment<<" len "<<adjustment.length());
 
-  NodePath np(def._node);
-  CPT(TransformState) trans = np.get_net_transform();
+  //NodePath np(def._node);
+  //CPT(TransformState) trans = np.get_net_transform();
   //adjustment=adjustment*trans->get_mat();
   physics_debug("  adjustment trn "<<adjustment<<" len "<<adjustment.length());
 
@@ -112,7 +112,10 @@ apply_linear_force(ColliderDef &def, const LVector3f &force) {
       physics_debug("  vel pre  friction "<<vel<<" len "<<vel.length());
       float friction=frictionCoefficient*angle;
       physics_debug("  friction "<<friction);
-      assert(friction>=0.0f && friction<=1.0f);
+      if (friction<0.0f && friction>1.0f) {
+        cerr<<"\n\nfriction error "<<friction<<endl;
+        friction=1.0f;
+      }
       #if 0
       float dt=ClockObject::get_global_clock()->get_dt();
       vel *= (1.0f-friction) * dt * dt;