Browse Source

Cort Stratton's latest updates adding cache limit support

David Rose 23 years ago
parent
commit
12de6f6b58
2 changed files with 135 additions and 19 deletions
  1. 123 19
      panda/src/audiotraits/fmodAudioManager.cxx
  2. 12 0
      panda/src/audiotraits/fmodAudioManager.h

+ 123 - 19
panda/src/audiotraits/fmodAudioManager.cxx

@@ -53,8 +53,10 @@ FmodAudioManager() {
   audio_debug("  audio_volume="<<audio_volume);
   audio_debug("  audio_volume="<<audio_volume);
 
 
   _active = audio_active;
   _active = audio_active;
+  _cache_limit = audio_cache_limit;
 
 
   // Initialize FMOD, if this is the first manager created.
   // Initialize FMOD, if this is the first manager created.
+  _is_valid = true;
   if (_active_managers == 0) {
   if (_active_managers == 0) {
     do {
     do {
       audio_debug("Initializing FMOD for real.");
       audio_debug("Initializing FMOD for real.");
@@ -65,14 +67,15 @@ FmodAudioManager() {
 	_is_valid = false;
 	_is_valid = false;
 	break;
 	break;
       }
       }
+      
       if (FSOUND_Init(44100, 32, 0) == 0) {
       if (FSOUND_Init(44100, 32, 0) == 0) {
 	audio_error("Fmod initialization failure.");
 	audio_error("Fmod initialization failure.");
 	_is_valid = false;
 	_is_valid = false;
 	break;
 	break;
       }
       }
+
     }
     }
     while(0);
     while(0);
-    _is_valid = true;
   }
   }
 
 
   // increment regardless of whether an error has occured -- the
   // increment regardless of whether an error has occured -- the
@@ -110,8 +113,22 @@ FmodAudioManager::
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool FmodAudioManager::
 bool FmodAudioManager::
 is_valid() {
 is_valid() {
-  // verify the cache and LRU list here.
-  return true;
+  bool check=true;
+  if (_sounds.size() != _lru.size()) {
+    audio_debug("--sizes--");
+    check=false;
+  } else {
+    LRU::const_iterator i=_lru.begin();
+    for (; i != _lru.end(); ++i) {
+      SoundMap::const_iterator smi=_sounds.find(*i);
+      if (smi == _sounds.end()) {
+        audio_debug("--"<<*i<<"--");
+        check=false;
+        break;
+      }
+    }
+  }
+  return _is_valid && check;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -159,6 +176,10 @@ get_sound(const string &file_name) {
     new_entry.stale = true;
     new_entry.stale = true;
 
 
     // Add to the cache
     // Add to the cache
+    while (_sounds.size() >= (unsigned int)_cache_limit) {
+      uncache_a_sound();
+    }
+
     si = _sounds.insert(SoundMap::value_type(path, new_entry)).first;
     si = _sounds.insert(SoundMap::value_type(path, new_entry)).first;
 
 
     // It's important that we assign entry to the address of the entry
     // It's important that we assign entry to the address of the entry
@@ -193,6 +214,7 @@ get_sound(const string &file_name) {
     return 0;
     return 0;
   }
   }
   inc_refcount(path);
   inc_refcount(path);
+  most_recently_used(path);
 
 
   // determine length of sound
   // determine length of sound
   float length = (float)FSOUND_Stream_GetLengthMs(stream) * 0.001f;
   float length = (float)FSOUND_Stream_GetLengthMs(stream) * 0.001f;
@@ -218,8 +240,16 @@ get_sound(const string &file_name) {
 void FmodAudioManager::
 void FmodAudioManager::
 uncache_sound(const string& file_name) {
 uncache_sound(const string& file_name) {
   audio_debug("FmodAudioManager::uncache_sound(\""<<file_name<<"\")");
   audio_debug("FmodAudioManager::uncache_sound(\""<<file_name<<"\")");
-  Filename path = file_name;
   assert(is_valid());
   assert(is_valid());
+  Filename path = file_name;
+
+  if (use_vfs) {
+    VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+    vfs->resolve_filename(path, get_sound_path());
+  } else {
+    path.resolve_filename(get_sound_path());
+  }
+  audio_debug("  path=\""<<path<<"\"");
   SoundMap::iterator itor = _sounds.find(path);
   SoundMap::iterator itor = _sounds.find(path);
   if (itor == _sounds.end()) {
   if (itor == _sounds.end()) {
     audio_error("FmodAudioManager::uncache_sound: no such entry "<<file_name);
     audio_error("FmodAudioManager::uncache_sound: no such entry "<<file_name);
@@ -227,13 +257,20 @@ uncache_sound(const string& file_name) {
   }
   }
 
 
   // Mark the entry as stale -- when its refcount reaches zero, it will
   // Mark the entry as stale -- when its refcount reaches zero, it will
-  // be removed from the cache.  If the refcount is already zero, it can be
-  // purged right now!
+  // be removed from the cache.
   SoundCacheEntry *entry = &(*itor).second;
   SoundCacheEntry *entry = &(*itor).second;
   if (entry->refcount == 0) {
   if (entry->refcount == 0) {
+    // If the refcount is already zero, it can be
+    // purged right now!
     audio_debug("FmodAudioManager::uncache_sound: purging "<<path
     audio_debug("FmodAudioManager::uncache_sound: purging "<<path
 		<< " from the cache.");
 		<< " from the cache.");
     delete [] entry->data;
     delete [] entry->data;
+
+    // Erase the sound from the LRU list as well.
+    assert(_lru.size()>0);
+    LRU::iterator lru_i=find(_lru.begin(), _lru.end(), itor->first);
+    assert(lru_i != _lru.end());
+    _lru.erase(lru_i);
     _sounds.erase(itor);
     _sounds.erase(itor);
   } else {
   } else {
     entry->stale = true;
     entry->stale = true;
@@ -242,6 +279,48 @@ uncache_sound(const string& file_name) {
   assert(is_valid());
   assert(is_valid());
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::uncache_a_sound
+//       Access: Public
+//  Description: Uncaches the least recently used sound.
+////////////////////////////////////////////////////////////////////
+void FmodAudioManager::
+uncache_a_sound() {
+  audio_debug("FmodAudioManager::uncache_a_sound()");
+  assert(is_valid());
+  // uncache least recently used:
+  assert(_lru.size()>0);
+  LRU::reference path=_lru.front();
+  SoundMap::iterator i = _sounds.find(path);
+  assert(i != _sounds.end());
+  _lru.pop_front();
+
+  if (i != _sounds.end()) {
+    audio_debug("  uncaching \""<<i->first<<"\"");
+    uncache_sound(path);
+  }
+  assert(is_valid());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::most_recently_used
+//       Access: Public
+//  Description: Indicates that the given sound was the most recently used.
+////////////////////////////////////////////////////////////////////
+void FmodAudioManager::
+most_recently_used(const string& path) {
+  audio_debug("FmodAudioManager::most_recently_used(path=\""
+      <<path<<"\")");
+  LRU::iterator i=find(_lru.begin(), _lru.end(), path);
+  if (i != _lru.end()) {
+    _lru.erase(i);
+  }
+  // At this point, path should not exist in the _lru:
+  assert(find(_lru.begin(), _lru.end(), path) == _lru.end());
+  _lru.push_back(path);
+  assert(is_valid());
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioManager::clear_cache
 //     Function: FmodAudioManager::clear_cache
 //       Access: Public
 //       Access: Public
@@ -249,6 +328,7 @@ uncache_sound(const string& file_name) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void FmodAudioManager::
 void FmodAudioManager::
 clear_cache() {
 clear_cache() {
+  audio_debug("FmodAudioManager::clear_cache()");
   // Mark all cache entries as stale.  Delete those which already have 
   // Mark all cache entries as stale.  Delete those which already have 
   // refcounts of zero.
   // refcounts of zero.
 
 
@@ -262,7 +342,14 @@ clear_cache() {
       audio_debug("FmodAudioManager::clear_cache: purging "<< (*itor).first
       audio_debug("FmodAudioManager::clear_cache: purging "<< (*itor).first
 		  << " from the cache.");
 		  << " from the cache.");
       delete [] entry->data;
       delete [] entry->data;
+
+      // Erase the sound from the LRU list as well.
+      assert(_lru.size()>0);
+      LRU::iterator lru_i=find(_lru.begin(), _lru.end(), itor->first);
+      assert(lru_i != _lru.end());
+      _lru.erase(lru_i);
       _sounds.erase(itor);
       _sounds.erase(itor);
+
       itor = _sounds.begin();
       itor = _sounds.begin();
     } else {
     } else {
       entry->stale = true;
       entry->stale = true;
@@ -277,8 +364,17 @@ clear_cache() {
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void FmodAudioManager::
 void FmodAudioManager::
-set_cache_limit(int) {
-  // intentionally blank.
+set_cache_limit(int count) {
+  audio_debug("FmodAudioManager::set_cache_limit(count="
+      <<count<<")");
+  assert(is_valid());
+  
+  while (_lru.size() > (unsigned int) count) {
+    uncache_a_sound();
+  }
+
+  _cache_limit = count;
+  assert(is_valid());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -288,8 +384,9 @@ set_cache_limit(int) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int FmodAudioManager::
 int FmodAudioManager::
 get_cache_limit() {
 get_cache_limit() {
-  // intentionally blank.
-  return 0;
+  audio_debug("FmodAudioManager::get_cache_limit() returning "
+	      <<_cache_limit);
+  return _cache_limit;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -377,16 +474,17 @@ stop_all_sounds(void) {
 void FmodAudioManager::
 void FmodAudioManager::
 inc_refcount(const string& file_name) {
 inc_refcount(const string& file_name) {
   Filename path = file_name;
   Filename path = file_name;
-  SoundMap::iterator itor = _sounds.find(path.to_os_specific());
-  if (itor != _sounds.end()) {
-    SoundCacheEntry *entry = &(*itor).second;
-    entry->refcount++;
-    entry->stale = false; // definitely not stale!
-    audio_debug("FmodAudioManager: "<<path<<" has a refcount of "
-		<< entry->refcount);
-  } else {
+  SoundMap::iterator itor = _sounds.find(path);
+  if (itor == _sounds.end()) {
     audio_debug("FmodAudioManager::inc_refcount: no such file "<<path);
     audio_debug("FmodAudioManager::inc_refcount: no such file "<<path);
+    return;
   }
   }
+
+  SoundCacheEntry *entry = &(*itor).second;
+  entry->refcount++;
+  entry->stale = false; // definitely not stale!
+  audio_debug("FmodAudioManager: "<<path<<" has a refcount of "
+	      << entry->refcount);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -399,7 +497,7 @@ inc_refcount(const string& file_name) {
 void FmodAudioManager::
 void FmodAudioManager::
 dec_refcount(const string& file_name) {
 dec_refcount(const string& file_name) {
   Filename path = file_name;
   Filename path = file_name;
-  SoundMap::iterator itor = _sounds.find(path.to_os_specific());
+  SoundMap::iterator itor = _sounds.find(path);
   if (itor != _sounds.end()) {
   if (itor != _sounds.end()) {
     SoundCacheEntry *entry = &(*itor).second;
     SoundCacheEntry *entry = &(*itor).second;
     entry->refcount--;
     entry->refcount--;
@@ -408,6 +506,12 @@ dec_refcount(const string& file_name) {
     if (entry->refcount == 0 && entry->stale) {
     if (entry->refcount == 0 && entry->stale) {
       audio_debug("FmodAudioManager::dec_refcount: purging "<<path<< " from the cache.");
       audio_debug("FmodAudioManager::dec_refcount: purging "<<path<< " from the cache.");
       delete [] entry->data;
       delete [] entry->data;
+
+      // Erase the sound from the LRU list as well.
+      assert(_lru.size()>0);
+      LRU::iterator lru_i=find(_lru.begin(), _lru.end(), itor->first);
+      assert(lru_i != _lru.end());
+      _lru.erase(lru_i);
       _sounds.erase(itor);
       _sounds.erase(itor);
     }
     }
   } else {
   } else {

+ 12 - 0
panda/src/audiotraits/fmodAudioManager.h

@@ -26,6 +26,7 @@
 #include "audioManager.h"
 #include "audioManager.h"
 class FmodAudioSound;
 class FmodAudioSound;
 #include "filename.h"
 #include "filename.h"
+#include "pdeque.h"
 #include "pmap.h"
 #include "pmap.h"
 #include "pset.h"
 #include "pset.h"
 
 
@@ -48,6 +49,12 @@ public:
   virtual void set_cache_limit(int);
   virtual void set_cache_limit(int);
   virtual int get_cache_limit();
   virtual int get_cache_limit();
 
 
+  // Indicates that the given sound was the most recently used.
+  void most_recently_used(const string& path);
+
+  // Uncaches the least recently used sound.
+  void uncache_a_sound();
+
   virtual void set_volume(float);
   virtual void set_volume(float);
   virtual float get_volume();
   virtual float get_volume();
   
   
@@ -74,8 +81,13 @@ private:
   // The offspring of this manager:
   // The offspring of this manager:
   AudioSet _soundsOnLoan;
   AudioSet _soundsOnLoan;
 
 
+  // The Least Recently Used mechanism:
+  typedef pdeque<string> LRU;
+  LRU _lru;
+
   void release_sound(FmodAudioSound *audioSound);
   void release_sound(FmodAudioSound *audioSound);
 
 
+  int _cache_limit;
   static int _active_managers;
   static int _active_managers;
   bool _is_valid;
   bool _is_valid;
   bool _active;
   bool _active;