Browse Source

Cort Stratton's FMOD implementation

David Rose 23 years ago
parent
commit
92fca841bd

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

@@ -210,6 +210,8 @@ class ShowBase(DirectObject.DirectObject):
         del self.win
         del self.win
         del self.winList
         del self.winList
         del self.pipe
         del self.pipe
+        del self.musicManager
+        del self.sfxManagerList
 
 
         try:
         try:
             direct.panel.destroy()
             direct.panel.destroy()

+ 7 - 0
dtool/Config.pp

@@ -365,6 +365,13 @@
 #define RAD_MSS_LIBS Mss32
 #define RAD_MSS_LIBS Mss32
 #defer HAVE_RAD_MSS $[libtest $[RAD_MSS_LPATH],$[RAD_MSS_LIBS]]
 #defer HAVE_RAD_MSS $[libtest $[RAD_MSS_LPATH],$[RAD_MSS_LIBS]]
 
 
+// Info for the Fmod audio engine
+// note this may be overwritten in wintools Config.pp
+#define FMOD_IPATH
+#define FMOD_LPATH
+#define FMOD_LIBS fmod
+#defer HAVE_FMOD $[libtest $[FMOD_LPATH],$[FMOD_LIBS]]
+
 // Info for http://www.sourceforge.net/projects/chromium
 // Info for http://www.sourceforge.net/projects/chromium
 // note this may be overwritten in wintools Config.pp
 // note this may be overwritten in wintools Config.pp
 #define CHROMIUM_IPATH /usr/include/chromium/include
 #define CHROMIUM_IPATH /usr/include/chromium/include

+ 3 - 0
dtool/LocalSetup.pp

@@ -19,6 +19,9 @@ $[cdefine HAVE_PYTHON]
 /* Define if we have RAD game tools, Miles Sound System installed.  */
 /* Define if we have RAD game tools, Miles Sound System installed.  */
 $[cdefine HAVE_RAD_MSS]
 $[cdefine HAVE_RAD_MSS]
 
 
+/* Define if we have FMOD installed. */
+$[cdefine HAVE_FMOD]
+
 /* Define if we have Freetype 2.0 or better available. */
 /* Define if we have Freetype 2.0 or better available. */
 $[cdefine HAVE_FREETYPE]
 $[cdefine HAVE_FREETYPE]
 
 

+ 5 - 0
dtool/Package.pp

@@ -184,6 +184,11 @@
 #set RAD_MSS_LIBS $[RAD_MSS_LIBS]
 #set RAD_MSS_LIBS $[RAD_MSS_LIBS]
 #set HAVE_RAD_MSS $[HAVE_RAD_MSS]
 #set HAVE_RAD_MSS $[HAVE_RAD_MSS]
 
 
+#set FMOD_IPATH $[unixfilename $[FMOD_IPATH]]
+#set FMOD_LPATH $[unixfilename $[FMOD_LPATH]]
+#set FMOD_LIBS $[FMOD_LIBS]
+#set HAVE_FMOD $[HAVE_FMOD]
+
 #set CHROMIUM_IPATH $[unixfilename $[CHROMIUM_IPATH]]
 #set CHROMIUM_IPATH $[unixfilename $[CHROMIUM_IPATH]]
 #set CHROMIUM_LPATH $[unixfilename $[CHROMIUM_LPATH]]
 #set CHROMIUM_LPATH $[unixfilename $[CHROMIUM_LPATH]]
 #set CHROMIUM_LIBS $[CHROMIUM_LIBS]
 #set CHROMIUM_LIBS $[CHROMIUM_LIBS]

+ 6 - 0
dtool/pptempl/Global.pp

@@ -236,6 +236,12 @@
   #define rad_mss_libs $[RAD_MSS_LIBS]
   #define rad_mss_libs $[RAD_MSS_LIBS]
 #endif
 #endif
 
 
+#if $[HAVE_FMOD]
+  #define fmod_ipath $[wildcard $[FMOD_IPATH]]
+  #define fmod_lpath $[wildcard $[FMOD_LPATH]]
+  #define fmod_libs $[FMOD_LIBS]
+#endif
+
 #if $[HAVE_CHROMIUM]
 #if $[HAVE_CHROMIUM]
   #define chromium_ipath $[wildcard $[CHROMIUM_IPATH]]
   #define chromium_ipath $[wildcard $[CHROMIUM_IPATH]]
   #define chromium_lpath $[wildcard $[CHROMIUM_LPATH]]
   #define chromium_lpath $[wildcard $[CHROMIUM_LPATH]]

+ 20 - 0
panda/src/audiotraits/Sources.pp

@@ -21,6 +21,26 @@
 
 
 #end lib_target
 #end lib_target
 
 
+#begin lib_target
+  #define TARGET fmod_audio
+  #define BUILD_TARGET $[HAVE_FMOD]
+  #define USE_PACKAGES fmod
+  #define BUILDING_DLL BUILDING_FMOD_AUDIO
+  #define LOCAL_LIBS audio
+  #define WIN_SYS_LIBS $[WIN_SYS_LIBS] user32.lib advapi32.lib winmm.lib
+
+  #define COMBINED_SOURCES $[TARGET]_composite1.cxx
+
+  #define SOURCES \
+      config_fmodAudio.h \
+      fmodAudioManager.h \
+      fmodAudioSound.I fmodAudioSound.h
+
+  #define INCLUDED_SOURCES \
+      config_fmodAudio.cxx fmodAudioManager.cxx fmodAudioSound.cxx
+
+#end lib_target
+
 //#begin lib_target
 //#begin lib_target
 //  #define TARGET audio_linux
 //  #define TARGET audio_linux
 //  #define BUILDING_DLL BUILDING_MISC
 //  #define BUILDING_DLL BUILDING_MISC

+ 54 - 0
panda/src/audiotraits/config_fmodAudio.cxx

@@ -0,0 +1,54 @@
+// Filename: config_fmodAudio.cxx
+// Created by:  cort
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pandabase.h"
+#ifdef HAVE_FMOD //[
+
+#include "config_fmodAudio.h"
+#include "fmodAudioManager.h"
+#include "fmodAudioSound.h"
+#include "dconfig.h"
+
+ConfigureDef(config_fmodAudio);
+NotifyCategoryDef(fmodAudio, "");
+
+ConfigureFn(config_fmodAudio) {
+  init_libFmodAudio();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: init_libFmodAudio
+//  Description: Initializes the library.  This must be called at
+//               least once before any of the functions or classes in
+//               this library can be used.  Normally it will be
+//               called by the static initializers and need not be
+//               called explicitly, but special cases exist.
+////////////////////////////////////////////////////////////////////
+void
+init_libFmodAudio() {
+  static bool initialized = false;
+  if (initialized) {
+    return;
+  }
+  
+  initialized = true;
+
+  AudioManager::register_AudioManager_creator(Create_AudioManager);
+}
+
+#endif //]

+ 35 - 0
panda/src/audiotraits/config_fmodAudio.h

@@ -0,0 +1,35 @@
+// Filename: config_fmodAudio.h
+// Created by:  cort
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CONFIG_FMODAUDIO_H
+#define CONFIG_FMODAUDIO_H
+
+#include "pandabase.h"
+
+#ifdef HAVE_FMOD //[
+#include "notifyCategoryProxy.h"
+#include "dconfig.h"
+
+ConfigureDecl(config_fmodAudio, EXPCL_FMOD_AUDIO, EXPTP_FMOD_AUDIO);
+NotifyCategoryDecl(fmodAudio, EXPCL_FMOD_AUDIO, EXPTP_FMOD_AUDIO);
+
+extern EXPCL_FMOD_AUDIO void init_libFmodAudio();
+
+#endif //]
+
+#endif // CONFIG_FMODAUDIO_H

+ 482 - 0
panda/src/audiotraits/fmodAudioManager.cxx

@@ -0,0 +1,482 @@
+// Filename: fmodAudioManager.cxx
+// Created by:  cort (January 22, 2003)
+// Prior system by: cary
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pandabase.h"
+#ifdef HAVE_FMOD //[
+
+#include "config_audio.h"
+#include "config_util.h"
+#include "config_express.h"
+#include "filename.h"
+#include "fmodAudioManager.h"
+#include "fmodAudioSound.h"
+#include "nullAudioSound.h"
+
+#include <algorithm>
+#include <cctype>
+#include <fmod.h>
+#include <iostream>
+using std::cerr;
+
+PT(AudioManager) Create_AudioManager() {
+  audio_debug("Create_AudioManager() Fmod.");
+  return new FmodAudioManager;
+}
+
+int FmodAudioManager::_active_managers = 0;
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::FmodAudioManager
+//       Access: 
+//  Description: 
+////////////////////////////////////////////////////////////////////
+FmodAudioManager::
+FmodAudioManager() {
+  audio_debug("FmodAudioManager::FmodAudioManager()");
+  audio_debug("  audio_active="<<audio_active);
+  audio_debug("  audio_volume="<<audio_volume);
+
+  _active = audio_active;
+
+  // Initialize FMOD, if this is the first manager created.
+  if (_active_managers == 0) {
+    do {
+      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;
+      }
+      if (FSOUND_Init(44100, 32, 0) == 0) {
+	audio_error("Fmod initialization failure.");
+	_is_valid = false;
+	break;
+      }
+    }
+    while(0);
+    _is_valid = true;
+  }
+
+  // increment regardless of whether an error has occured -- the
+  // destructor will do the right thing.
+  ++_active_managers;
+  audio_debug("  _active_managers="<<_active_managers);
+
+  if (_is_valid)  {
+    assert(is_valid());    
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::~FmodAudioManager
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+FmodAudioManager::
+~FmodAudioManager() {
+  // Be sure to delete associated sounds before deleting the manager!
+  nassertv(_soundsOnLoan.empty());
+  clear_cache();
+  --_active_managers;
+  audio_debug("~FmodAudioManager(): "<<_active_managers<<" still active");
+  if (_active_managers == 0) {
+    audio_debug("Shutting down FMOD");
+    FSOUND_Close();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::is_valid
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+bool FmodAudioManager::
+is_valid() {
+  // verify the cache and LRU list here.
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::get_sound
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PT(AudioSound) FmodAudioManager::
+get_sound(const string &file_name) {
+  audio_debug("FmodAudioManager::get_sound(file_name=\""<<file_name<<"\")");
+
+  if(!is_valid()) {
+     audio_debug("invalid FmodAudioManager returning NullSound");
+     return new NullAudioSound();
+  }
+
+  assert(is_valid());
+  Filename path = file_name;
+
+  audio_debug("  resolved file_name is '"<<path<<"'");
+
+  // Get the sound, either from the cache or from disk.
+  SoundMap::iterator si = _sounds.find(path);
+  SoundCacheEntry *entry = NULL;
+  if (si != _sounds.end()) {
+    // The sound was found in the cache.
+    entry = &(*si).second;
+    audio_debug("Sound file '"<<path<<"' found in cache.");
+  } else {
+    // The sound was not found in the cache.  Load it from disk.
+    SoundCacheEntry new_entry;
+    new_entry.size = get_file_size(path);
+    if (new_entry.size == 0) {
+      audio_error("FmodAudioManager::get_file_size failed.");
+      return 0;
+    }
+    new_entry.data = load(path, new_entry.size);
+    if (!new_entry.data) {
+      audio_error("FmodAudioManager::load failed.");
+      return 0;
+    }
+    new_entry.refcount = 0;
+    new_entry.stale = true;
+
+    // Add to the cache
+    entry = &new_entry;
+    _sounds[path] = new_entry;
+  }
+  assert(entry != NULL);
+  
+  // Create an FMOD object from the memory-mapped file.  Here remains
+  // one last vestige of special-case MIDI code: apparently, FMOD
+  // doesn't like creating streams from memory-mapped MIDI files.
+  // They must therefore be streamed from disk every time.  This
+  // causes strange things to happen when the same MIDI file is loaded
+  // twice, and played simultaneously...so, *don't do that then*.  all
+  // I can say is that MIDI support will be significantly improved in
+  // FMOD v4.0!
+  FSOUND_STREAM *stream = NULL;
+  int flags = FSOUND_LOADMEMORY | FSOUND_MPEGACCURATE;
+  string os_path = path.to_os_specific();
+  string suffix = path.get_extension();
+  std::transform(suffix.begin(), suffix.end(), suffix.begin(), tolower);
+  if (suffix == "mid" || suffix == "rmi" || suffix == "midi") {
+    stream = FSOUND_Stream_OpenFile(os_path.c_str(), 0, 0);
+  } else {
+    stream = FSOUND_Stream_OpenFile((const char*)(entry->data),
+				    flags, entry->size);
+  }
+  if (stream == NULL) {
+    audio_error("FmodAudioManager::get_sound failed.");
+    return 0;
+  }
+  inc_refcount(path);
+
+  // determine length of sound
+  float length = (float)FSOUND_Stream_GetLengthMs(stream) * 0.001f;
+
+  // Build a new AudioSound from the audio data.
+  PT(AudioSound) audioSound = 0;
+  PT(FmodAudioSound) fmodAudioSound = new FmodAudioSound(this, stream, path,
+							 length);
+  fmodAudioSound->set_active(_active);
+  _soundsOnLoan.insert(fmodAudioSound);
+  audioSound = fmodAudioSound;
+  
+  audio_debug("  returning 0x" << (void*)audioSound);
+  assert(is_valid());
+  return audioSound;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::uncache_sound
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void FmodAudioManager::
+uncache_sound(const string& file_name) {
+  audio_debug("FmodAudioManager::uncache_sound(\""<<file_name<<"\")");
+  Filename path = file_name;
+  assert(is_valid());
+  SoundMap::iterator itor = _sounds.find(path);
+  if (itor == _sounds.end()) {
+    audio_error("FmodAudioManager::uncache_sound: no such entry "<<file_name);
+    return;
+  }
+
+  // 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!
+  SoundCacheEntry *entry = &(*itor).second;
+  if (entry->refcount == 0) {
+    audio_debug("FmodAudioManager::dec_refcount: purging "<<path
+		<< " from the cache.");
+    delete [] entry->data;
+    _sounds.erase(itor);
+  } else {
+    entry->stale = true;
+  }
+
+  assert(is_valid());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::clear_cache
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void FmodAudioManager::
+clear_cache() {
+  // Mark all cache entries as stale.  Delete those which already have 
+  // refcounts of zero.
+  SoundMap::iterator itor = _sounds.begin();
+  for( ; itor != _sounds.end(); ++itor) {
+    SoundCacheEntry *entry = &(*itor).second;
+    if (entry->refcount == 0) {
+      audio_debug("FmodAudioManager: purging "<< (*itor).first
+		  << " from the cache.");
+      delete [] entry->data;
+      _sounds.erase(itor);
+      itor = _sounds.begin();
+    } else {
+      entry->stale = true;
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::set_cache_limit
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void FmodAudioManager::
+set_cache_limit(int) {
+  // intentionally blank.
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::get_cache_limit
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+int FmodAudioManager::
+get_cache_limit() {
+  // intentionally blank.
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::release_sound
+//       Access: Private
+//  Description:
+////////////////////////////////////////////////////////////////////
+void FmodAudioManager::
+release_sound(FmodAudioSound* audioSound) {
+  audio_debug("FmodAudioManager::release_sound(audioSound=\""
+      <<audioSound->get_name()<<"\")");
+  dec_refcount(audioSound->get_name());
+  _soundsOnLoan.erase(audioSound);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::set_volume
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void FmodAudioManager::
+set_volume(float) {
+  // intentionally blank.
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::get_volume
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float FmodAudioManager::
+get_volume() {
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::set_active
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void FmodAudioManager::
+set_active(bool active) {
+  audio_debug("FmodAudioManager::set_active(flag="<<active<<")");
+  if (_active!=active) {
+    _active=active;
+    // Tell our AudioSounds to adjust:
+    AudioSet::iterator i=_soundsOnLoan.begin();
+    for (; i!=_soundsOnLoan.end(); ++i) {
+      (**i).set_active(_active);
+    }
+  }
+  _active = active;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::get_active
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+bool FmodAudioManager::
+get_active() {
+  return _active;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::stop_all_sounds
+//       Access: Public
+//  Description: Stop playback on all sounds managed by this manager.
+////////////////////////////////////////////////////////////////////
+void FmodAudioManager::
+stop_all_sounds(void) {
+  audio_debug("FmodAudioManager::stop_all_sounds()");
+  AudioSet::iterator i=_soundsOnLoan.begin();
+  for (; i!=_soundsOnLoan.end(); ++i) {
+    if((**i).status()==AudioSound::PLAYING)
+      (**i).stop();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::inc_refcount
+//       Access: Protected
+//  Description: Increments the refcount of a file's cache entry.
+////////////////////////////////////////////////////////////////////
+void FmodAudioManager::
+inc_refcount(const string& 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 {
+    audio_debug("FmodAudioManager::inc_refcount: no such file "<<path);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::dec_refcount
+//       Access: Protected
+//  Description: Decrements the refcount of a file's cache entry. If
+//               the refcount reaches zero and the entry is stale, it
+//               will be removed from the cache.
+////////////////////////////////////////////////////////////////////
+void FmodAudioManager::
+dec_refcount(const string& 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--;
+    audio_debug("FmodAudioManager: "<<path<<" has a refcount of "
+		<< entry->refcount);
+    if (entry->refcount == 0 && entry->stale) {
+      audio_debug("FmodAudioManager: purging "<<path<< " from the cache.");
+      delete [] entry->data;
+      _sounds.erase(itor);
+    }
+  } else {
+    audio_debug("FmodAudioManager::dec_refcount: no such file "<<path);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::load
+//       Access: Private
+//  Description: Loads the specified file into memory.
+//               Returns NULL if an error occurs.
+////////////////////////////////////////////////////////////////////
+void* FmodAudioManager::
+load(const Filename& filename, const size_t size) const {
+  // Check file type (based on filename suffix
+  string suffix = filename.get_extension();
+  std::transform(suffix.begin(), suffix.end(), suffix.begin(), tolower);
+  bool bSupported = false;
+  if (suffix == "wav" || suffix == "mp3" || suffix == "mid"
+      || suffix == "rmi" || suffix == "midi") {
+    bSupported = true;
+  }
+  if (!bSupported) {
+    audio_error("FmodAudioManager::load: "<<filename
+		<<" is not a supported file format.");
+    audio_error("Supported formats are: WAV, MP3, MIDI");
+    return NULL;
+  }
+
+  // open the file.
+  string os_filename = filename.to_os_specific();
+  FILE *audioFile = fopen(os_filename.c_str(), "rb");
+  if (!audioFile) {
+    audio_error("File "<<filename<<" does not exist.");
+    return NULL;
+  }
+  
+  // Read the entire file into memory.
+  char *buffer = new char[size];
+  if (buffer == NULL) {
+    audio_error("out-of-memory error while loading "<<filename);
+    fclose(audioFile);
+    return NULL;
+  }
+  long bytes_read = fread(buffer, size, 1, audioFile);
+  if (bytes_read != 1) {
+    audio_error("Read error while loading "<<filename);
+    fclose(audioFile);
+    delete [] buffer;
+    return NULL;
+  }
+
+  fclose(audioFile);
+  return buffer;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::get_file_size
+//       Access: Private
+//  Description: Calculates the size of the given file, in bytes.
+////////////////////////////////////////////////////////////////////
+size_t FmodAudioManager::
+get_file_size(const Filename& filename) const {
+  // open the file.
+  string os_filename = filename.to_os_specific();
+  FILE *audioFile = fopen(os_filename.c_str(), "rb");
+  if (!audioFile) {
+    audio_error("File "<<filename<<" does not exist.");
+    return 0;
+  }
+  
+  // Read the entire file into memory.
+  if (fseek(audioFile, 0, SEEK_END) != 0) {
+    audio_error("Seek error while loading "<<filename);
+    fclose(audioFile);
+    return 0;
+  }
+  size_t file_size = ftell(audioFile);
+  fclose(audioFile);
+  return file_size;
+}
+
+#endif //]

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

@@ -0,0 +1,93 @@
+// Filename: fmodAudioManager.h
+// Created by:  cort (January 22, 2003)
+// Prior system by: cary
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef __FMOD_AUDIO_MANAGER_H__
+#define __FMOD_AUDIO_MANAGER_H__
+
+#include <pandabase.h>
+#ifdef HAVE_FMOD //[
+
+#include "audioManager.h"
+class FmodAudioSound;
+#include "filename.h"
+#include "pmap.h"
+#include "pset.h"
+
+#include <fmod.h>
+
+class EXPCL_FMOD_AUDIO FmodAudioManager : public AudioManager {
+  // All of these methods are stubbed out to some degree.
+  // If you're looking for a starting place for a new AudioManager,
+  // please consider looking at the milesAudioManager.
+  
+public:
+  FmodAudioManager();
+  virtual ~FmodAudioManager();
+  
+  virtual bool is_valid();
+  
+  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_volume(float);
+  virtual float get_volume();
+  
+  virtual void set_active(bool);
+  virtual bool get_active();
+  void stop_all_sounds();
+
+protected:
+  // increment or decrement the refcount of the given file's cache entry.
+  // sounds can only be uncached when their refcounts are zero.
+  void inc_refcount(const string& file_name);
+  void dec_refcount(const string& file_name);
+private:
+  typedef struct {
+    size_t size; // size of the data field, in bytes
+    unsigned int refcount; // how many AudioSound objects are referencing me?
+    bool stale; // can this entry be  purged from the cache?
+    void *data; // the memory-mapped audio file.
+  } SoundCacheEntry;
+  typedef pmap<string, SoundCacheEntry > SoundMap;
+  SoundMap _sounds;
+
+  typedef pset<FmodAudioSound* > AudioSet;
+  // The offspring of this manager:
+  AudioSet _soundsOnLoan;
+
+  void release_sound(FmodAudioSound *audioSound);
+
+  static int _active_managers;
+  bool _is_valid;
+  bool _active;
+  
+  void* load(const Filename& filename, const size_t size) const;
+  size_t get_file_size(const Filename& filename) const;
+
+  friend FmodAudioSound;
+};
+
+EXPCL_FMOD_AUDIO PT(AudioManager) Create_AudioManager();
+
+#endif //]
+
+#endif /* __FMOD_AUDIO_MANAGER_H__ */

+ 24 - 0
panda/src/audiotraits/fmodAudioSound.I

@@ -0,0 +1,24 @@
+// Filename: fmodAudioSound.I
+// Created by:  cort (January 22, 2003)
+// Prior system by: cary
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+
+
+
+

+ 239 - 0
panda/src/audiotraits/fmodAudioSound.cxx

@@ -0,0 +1,239 @@
+// Filename: fmodAudioSound.cxx
+// Created by:  cort (January 22, 2003)
+// Prior system by: cary
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include <pandabase.h>
+#ifdef HAVE_FMOD //[
+
+#include "fmodAudioSound.h"
+#include "fmodAudioManager.h"
+
+#include <cmath>
+
+#ifndef NDEBUG //[
+  #define fmod_audio_debug(x) \
+      audio_debug("FmodAudioSound "<<" \""<<get_name()<<"\" "<< x )
+#else //][
+  #define fmod_audio_debug(x) ((void)0)
+#endif //]
+
+FmodAudioSound::
+FmodAudioSound(FmodAudioManager* manager, FSOUND_STREAM *audio_data,
+	       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<<")");
+}
+
+FmodAudioSound::
+~FmodAudioSound() {
+  fmod_audio_debug("~FmodAudioSound()");
+  this->stop();
+  _manager->release_sound(this);
+}
+  
+void FmodAudioSound::
+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();
+  }
+
+  // Play the stream, but start it paused so we can set the volume and
+  // panning first.
+  bool bStatusOK = false;
+  assert(_audio != NULL);
+  _channel = FSOUND_Stream_PlayEx(FSOUND_FREE, _audio, NULL, 1);
+  if (_channel == -1) {
+    fmod_audio_debug("play() failed");
+    return;
+  }
+  
+  // Set volume.
+  unsigned char new_volume = (unsigned char)(_volume*255.0f);
+  FSOUND_SetVolume(_channel, new_volume);
+  
+  // Set panning.
+  unsigned char new_balance = (unsigned char)( (_balance+1.0f)*0.5f*255.0f);
+  FSOUND_SetPan(_channel, new_balance);
+  
+  // Set looping -- unimplemented
+  
+  // Unpause and set status to playing
+  FSOUND_SetPaused(_channel, 0);
+
+  // 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));
+}
+
+void FmodAudioSound::stop() {
+  FSOUND_Stream_Stop(_audio);
+  _channel = -1;
+}
+
+void FmodAudioSound::set_loop(bool loop) {
+  audio_error("FmodAudioSound::set_loop() -- not yet implemented");
+  fmod_audio_debug("set_loop() set to "<<loop);
+  _loop_count = loop ? 0 : 1;
+}
+
+bool FmodAudioSound::get_loop() const {
+  fmod_audio_debug("get_loop() returning "<<(_loop_count==0));
+  return (_loop_count == 0);
+}
+  
+void FmodAudioSound::set_loop_count(unsigned long loop_count) {
+  audio_error("FmodAudioSound::set_loop_count() -- not yet implemented");
+  fmod_audio_debug("set_loop_count() set to "<<loop_count);
+  _loop_count = loop_count;
+}
+
+unsigned long FmodAudioSound::get_loop_count() const {
+  fmod_audio_debug("get_loop_count() returning "<<_loop_count);
+  return _loop_count;
+}
+  
+void FmodAudioSound::set_time(float start_time) {
+  if (start_time < 0.0f) {
+    fmod_audio_debug("set_time(): param "<<start_time<<" out of range.");
+    fmod_audio_debug("set_time(): clamping to zero.");
+    start_time = 0.0f;
+  } else if (start_time > _length) {
+    fmod_audio_debug("set_time(): param "<<start_time<<" out of range.");
+    fmod_audio_debug("set_time(): clamping to length ("<<_length<<".");
+    start_time = _length - 0.01;
+  }
+  // FMOD measures time in milliseconds, so scale up by 1000.
+  FSOUND_Stream_SetTime(_audio, start_time * 1000.0f);
+}
+
+float FmodAudioSound::get_time() const {
+  // A bug in stream WAV files causes FSOUND_Stream_GetTime() to
+  // divide-by-zero somewhere if the stream isn't currently playing.
+  // In this case, we should just return zero.
+  if (!FSOUND_IsPlaying(_channel)) {
+    return 0.0f;
+  }
+
+  // FMOD measures time in milliseconds, so scale down by 1000.
+  float current_time = FSOUND_Stream_GetTime(_audio) * 0.001f;
+  //fmod_audio_debug("get_time() returning "<<current_time);
+  return current_time;
+}
+
+void FmodAudioSound::set_volume(float vol) {
+  if (vol < 0.0f) {
+    fmod_audio_debug("set_volume(): param "<<vol<<" out of range.");
+    fmod_audio_debug("set_volume(): clamping to zero.");
+    vol = 0.0f;
+  } else if (vol > 1.0f) {
+    fmod_audio_debug("set_volume(): param "<<vol<<" out of range.");
+    fmod_audio_debug("set_volume(): clamping to 1.0");
+    vol = 1.0f;
+  }
+  _volume = vol;
+  unsigned char new_volume = (unsigned char)(_volume*255.0f);
+  FSOUND_SetVolume(_channel, new_volume);
+}
+
+float FmodAudioSound::get_volume() const {
+  fmod_audio_debug("get_volume() returning "<<_volume);
+  return _volume;
+}
+
+void FmodAudioSound::set_balance(float bal) {
+  if (bal < -1.0f) {
+    fmod_audio_debug("set_balance(): param "<<bal<<" out of range.");
+    fmod_audio_debug("set_balance(): clamping to -1.0.");
+    bal = -1.0f;
+  } else if (bal > 1.0f) {
+    fmod_audio_debug("set_balance(): param "<<bal<<" out of range.");
+    fmod_audio_debug("set_balance(): clamping to 1.0");
+    bal = 1.0f;
+  }
+  _balance = bal;
+  unsigned char new_balance = (unsigned char)( (_balance+1.0f)*0.5f*255.0f);
+  FSOUND_SetPan(_channel, new_balance);
+}
+
+float FmodAudioSound::get_balance() const {
+  fmod_audio_debug("get_balance() returning "<<_balance);
+  return _balance;
+}
+
+void FmodAudioSound::set_active(bool active) {
+  fmod_audio_debug("set_active(active="<<active<<")");
+  if (!active) {
+    // Once looping works, a looping sound should be paused, not
+    // stopped.  When the sound is activated again, it is unpaused.
+    this->stop();
+  }
+  _active = active;
+}
+
+bool FmodAudioSound::get_active() const {
+  fmod_audio_debug("get_active() returning "<<_active);
+  return _active;
+}
+
+const string& FmodAudioSound::get_name() const {
+  //fmod_audio_debug("get_name() returning "<<_file_name);
+  return _file_name;
+}
+
+float FmodAudioSound::length() const {
+  return _length;
+}
+
+AudioSound::SoundStatus FmodAudioSound::status() const {
+  // If the stream's channel isn't playing anything, then the stream
+  // definitely isn't playing.
+  if (!FSOUND_IsPlaying(_channel)) {
+    return AudioSound::READY;
+  }
+  
+  // If the channel is playing, see whether the current time is at the
+  // end of the file.  If not, the stream is playing.
+  float current_time = this->get_time();
+  if (current_time >= _length - 0.01f) {
+    // FMOD MIDI files don't stop automatically when they hit the end of the
+    // file.  Their channel isn't released unless the stream is stopped
+    // explicitly.
+    FSOUND_Stream_Stop(_audio);
+    return AudioSound::READY;
+  } else {
+    return AudioSound::PLAYING;
+  }
+}
+
+#endif //]

+ 108 - 0
panda/src/audiotraits/fmodAudioSound.h

@@ -0,0 +1,108 @@
+// Filename: fmodAudioSound.h
+// Created by:  cort (January 22, 2003)
+// Prior system by: cary
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef __FMOD_AUDIO_SOUND_H__
+#define __FMOD_AUDIO_SOUND_H__
+
+#include <pandabase.h>
+#ifdef HAVE_FMOD //[
+
+#include "audioSound.h"
+class FmodAudioManager;
+#include <fmod.h>
+
+
+class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound {
+public:
+  ~FmodAudioSound();
+  
+  // For best compatability, set the loop_count, start_time,
+  // volume, and balance, prior to calling play().  You may
+  // set them while they're playing, but it's implementation
+  // specific whether you get the results.
+  void play();
+  void stop();
+  
+  // loop: false = play once; true = play forever.
+  // inits to false.
+  void set_loop(bool loop=true);
+  bool get_loop() const;
+  
+  // loop_count: 0 = forever; 1 = play once; n = play n times.
+  // inits to 1.
+  void set_loop_count(unsigned long loop_count=1);
+  unsigned long get_loop_count() const;
+  
+  // 0 = begining; length() = end.
+  // inits to 0.0.
+  void set_time(float start_time=0.0);
+  float get_time() const;
+  
+  // 0 = minimum; 1.0 = maximum.
+  // inits to 1.0.
+  void set_volume(float volume=1.0);
+  float get_volume() const;
+  
+  // -1.0 is hard left
+  // 0.0 is centered
+  // 1.0 is hard right
+  // inits to 0.0.
+  void set_balance(float balance_right=0.0);
+  float get_balance() const;
+
+  // inits to manager's state.
+  void set_active(bool active=true);
+  bool get_active() const;
+  
+  const string& get_name() const;
+  
+  // return: playing time in seconds.
+  float length() const;
+
+  AudioSound::SoundStatus status() const;
+
+protected:
+
+private:
+  FSOUND_STREAM *_audio;
+  PT(FmodAudioManager) _manager;
+  float _volume; // 0..1.0
+  float _balance; // -1..1
+  mutable float _length; // in seconds.
+  unsigned long _loop_count;
+  string _file_name;
+  bool _active;
+  bool _paused;
+  int _channel;
+
+  FmodAudioSound(FmodAudioManager* manager, FSOUND_STREAM *audio_data,
+		 string file_name, float length=0.0f);
+
+  // forbidden functions!
+  FmodAudioSound(const FmodAudioSound& rhs) {}
+  const FmodAudioSound& operator=(const FmodAudioSound& rhs) { return *this; }
+
+  friend class FmodAudioManager;
+};
+
+#include "fmodAudioSound.I"
+
+#endif //]
+
+#endif /* __FMOD_AUDIO_SOUND_H__ */

+ 5 - 0
panda/src/audiotraits/fmod_audio_composite.cxx

@@ -0,0 +1,5 @@
+/* Generated automatically by ppremake 1.11 from Sources.pp. */
+/* ################################# DO NOT EDIT ########################### */
+
+#include "fmod_audio_composite1.cxx"
+

+ 5 - 0
panda/src/audiotraits/fmod_audio_composite1.cxx

@@ -0,0 +1,5 @@
+
+#include "config_fmodAudio.cxx"
+#include "fmodAudioManager.cxx"
+#include "fmodAudioSound.cxx"
+      

+ 8 - 0
panda/src/pandabase/pandasymbols.h

@@ -52,6 +52,14 @@
   #define EXPTP_MILES_AUDIO extern
   #define EXPTP_MILES_AUDIO extern
 #endif
 #endif
 
 
+#ifdef BUILDING_FMOD_AUDIO
+  #define EXPCL_FMOD_AUDIO __declspec(dllexport)
+  #define EXPTP_FMOD_AUDIO
+#else
+  #define EXPCL_FMOD_AUDIO __declspec(dllimport)
+  #define EXPTP_FMOD_AUDIO extern
+#endif
+
 #ifdef BUILDING_PANDA
 #ifdef BUILDING_PANDA
   #define EXPCL_PANDA __declspec(dllexport)
   #define EXPCL_PANDA __declspec(dllexport)
   #define EXPTP_PANDA
   #define EXPTP_PANDA