Browse Source

new updates from CMU

David Rose 21 years ago
parent
commit
b4eb31344f

+ 4 - 1
direct/src/showbase/pandaSqueezer.py

@@ -41,7 +41,10 @@ def squeezePandaFiles():
     l = getSqueezeableFiles()
     l = getSqueezeableFiles()
     pandaSqueezeTool.squeeze("PandaModules", "PandaModulesUnsqueezed", l)
     pandaSqueezeTool.squeeze("PandaModules", "PandaModulesUnsqueezed", l)
 
 
-    # Clean up the source files now that they've been squeezed.
+    # Clean up the source files now that they've been squeezed.  If
+    # you don't like this behavior (e.g. if you want to inspect the
+    # generated files), use genPyCode -n to avoid squeezing
+    # altogether.
     for i in l:
     for i in l:
         os.unlink(i)
         os.unlink(i)
 
 

+ 7 - 1
dtool/Config.pp

@@ -312,6 +312,12 @@
 #define VRPN_LIBS
 #define VRPN_LIBS
 #defer HAVE_VRPN $[libtest $[VRPN_LPATH],$[VRPN_LIBS]]
 #defer HAVE_VRPN $[libtest $[VRPN_LPATH],$[VRPN_LIBS]]
 
 
+// Is HELIX installed, and where?
+#define HELIX_IPATH
+#define HELIX_LPATH
+#define HELIX_LIBS
+#defer HAVE_HELIX $[libtest $[HELIX_LPATH],$[HELIX_LIBS]]
+
 // Is ZLIB installed, and where?
 // Is ZLIB installed, and where?
 #define ZLIB_IPATH
 #define ZLIB_IPATH
 #define ZLIB_LPATH
 #define ZLIB_LPATH
@@ -664,7 +670,7 @@
 // How to generate a static C or C++ library.  $[target] is the
 // How to generate a static C or C++ library.  $[target] is the
 // name of the library to generate, and $[sources] is the list of .o
 // name of the library to generate, and $[sources] is the list of .o
 // files that will go into the library.
 // files that will go into the library.
-#if $[eq $[PLATFORM], osx]	
+#if $[eq $[PLATFORM], osx]
   #defer STATIC_LIB_C libtool -static -o $[target] $[sources]
   #defer STATIC_LIB_C libtool -static -o $[target] $[sources]
   #defer STATIC_LIB_C++ libtool -static -o $[target] $[sources]
   #defer STATIC_LIB_C++ libtool -static -o $[target] $[sources]
 #else
 #else

+ 3 - 0
dtool/LocalSetup.pp

@@ -123,6 +123,9 @@ $[cdefine HAVE_NURBSPP]
 /* Define if we have VRPN installed.  */
 /* Define if we have VRPN installed.  */
 $[cdefine HAVE_VRPN]
 $[cdefine HAVE_VRPN]
 
 
+/* Define if we have HELIX installed.  */
+$[cdefine HAVE_HELIX]
+
 /* Define if we have CG installed.  */
 /* Define if we have CG installed.  */
 $[cdefine HAVE_CG]
 $[cdefine HAVE_CG]
 
 

+ 5 - 0
dtool/Package.pp

@@ -146,6 +146,11 @@
 #set VRPN_LIBS $[VRPN_LIBS]
 #set VRPN_LIBS $[VRPN_LIBS]
 #set HAVE_VRPN $[HAVE_VRPN]
 #set HAVE_VRPN $[HAVE_VRPN]
 
 
+#set HELIX_IPATH $[unixfilename $[HELIX_IPATH]]
+#set HELIX_LPATH $[unixfilename $[HELIX_LPATH]]
+#set HELIX_LIBS $[HELIX_LIBS]
+#set HAVE_HELIX $[HAVE_HELIX]
+
 #set ZLIB_IPATH $[unixfilename $[ZLIB_IPATH]]
 #set ZLIB_IPATH $[unixfilename $[ZLIB_IPATH]]
 #set ZLIB_LPATH $[unixfilename $[ZLIB_LPATH]]
 #set ZLIB_LPATH $[unixfilename $[ZLIB_LPATH]]
 #set ZLIB_LIBS $[ZLIB_LIBS]
 #set ZLIB_LIBS $[ZLIB_LIBS]

+ 7 - 0
dtool/pptempl/Global.pp

@@ -216,6 +216,13 @@
   #define vrpn_libs $[VRPN_LIBS]
   #define vrpn_libs $[VRPN_LIBS]
 #endif
 #endif
 
 
+#if $[HAVE_HELIX]
+  #define helix_ipath $[wildcard $[HELIX_IPATH]]
+  #define helix_lpath $[wildcard $[HELIX_LPATH]]
+  #define helix_cflags $[HELIX_CFLAGS]
+  #define helix_libs $[HELIX_LIBS]
+#endif
+
 #if $[HAVE_MIKMOD]
 #if $[HAVE_MIKMOD]
   #define mikmod_ipath $[wildcard $[MIKMOD_IPATH]]
   #define mikmod_ipath $[wildcard $[MIKMOD_IPATH]]
   #define mikmod_lpath $[wildcard $[MIKMOD_LPATH]]
   #define mikmod_lpath $[wildcard $[MIKMOD_LPATH]]

+ 4 - 2
dtool/src/parser-inc/Sources.pp

@@ -2,6 +2,8 @@
     algorithm deque ft2build.h iostream list map memory \
     algorithm deque ft2build.h iostream list map memory \
     pair queue set stack stdcompare.h stdtypedefs.h \
     pair queue set stack stdcompare.h stdtypedefs.h \
     string vector windows.h zlib.h md5.h files.h hex.h \
     string vector windows.h zlib.h md5.h files.h hex.h \
-    nurbs.hh stddef.h krb5.h Python.h \
-    Cg/cg.h Cg/cgGL.h
+    nurbs.hh stddef.h krb5.h MainHelix.h dllpath.h hxcom.h \
+    hxcomm.h hxcore.h hxengin.h hxerror.h hxfiles.h hxtbuf.h \
+    hxtbuff.h hxwin.h Python.h Cg/cg.h Cg/cgGL.h
+
 
 

+ 1 - 1
panda/metalibs/panda/Sources.pp

@@ -17,7 +17,7 @@
     parametrics pnm \
     parametrics pnm \
     pnmimagetypes pnmimage sgattrib sgmanip sgraph sgraphutil \
     pnmimagetypes pnmimage sgattrib sgmanip sgraph sgraphutil \
     switchnode pnmtext text tform tiff lerp loader putil \
     switchnode pnmtext text tform tiff lerp loader putil \
-    audio pgui pandabase
+    audio pgui pandabase helix
 
 
 #define LOCAL_LIBS \
 #define LOCAL_LIBS \
   downloader express pandabase
   downloader express pandabase

+ 40 - 1
panda/src/audio/audioManager.h

@@ -49,7 +49,7 @@ PUBLISHED:
   virtual bool is_valid() = 0;
   virtual bool is_valid() = 0;
   
   
   // Get a sound:
   // Get a sound:
-  virtual PT(AudioSound) get_sound(const string& file_name) = 0;
+  virtual PT(AudioSound) get_sound(const string& file_name, bool positional = false) = 0;
   PT(AudioSound) get_null_sound();
   PT(AudioSound) get_null_sound();
 
 
   // Tell the AudioManager there is no need to keep this one cached.
   // Tell the AudioManager there is no need to keep this one cached.
@@ -105,6 +105,45 @@ PUBLISHED:
   // this call may be for efficient on some implementations.
   // this call may be for efficient on some implementations.
   virtual void stop_all_sounds() = 0;
   virtual void stop_all_sounds() = 0;
 
 
+  // Changes to the positions of 3D spacialized sounds and the listener
+  // are all made at once when this method is called. It should be put
+  // in the main program loop.
+  virtual void audio_3d_update() = 0;
+
+  // This controls the "set of ears" that listens to 3D spacialized sound
+  // px, py, pz are position coordinates. Can be NULL to ignore.
+  // vx, vy, vz are a velocity vector in UNITS PER SECOND (default: meters). Can be NULL to ignore.
+  // fx, fy and fz are the respective components of a unit forward-vector
+  // ux, uy and uz are the respective components of a unit up-vector
+  // These changes will NOT be invoked until audio_3d_update() is called.
+  virtual void audio_3d_set_listener_attributes(float px, float py, float pz,
+                                                float vx, float vy, float vz, 
+                                                float fx, float fy, float fz,
+                                                float ux, float uy, float uz) = 0;
+  // Values should all default to NULL, so you can just pass the one you want to get.
+  virtual void audio_3d_get_listener_attributes(float px = NULL, float py = NULL, float pz = NULL,
+                                                float vx = NULL, float vy = NULL, float vz = NULL,
+                                                float fx = NULL, float fy = NULL, float fz = NULL,
+                                                float ux = NULL, float uy = NULL, float uz = NULL) = 0;
+  
+  // Control the "relative distance factor" for 3D spacialized audio. Default is 1.0
+  // Fmod uses meters internally, so give a float in Units-per meter
+  // Don't know what Miles uses.
+  virtual void audio_3d_set_distance_factor(float factor) = 0;
+  virtual float audio_3d_get_distance_factor() const = 0;
+
+  // Control the presence of the Doppler effect. Default is 1.0
+  // Exaggerated Doppler, use >1.0
+  // Diminshed Doppler, use <1.0
+  virtual void audio_3d_set_doppler_factor(float factor) = 0;
+  virtual float audio_3d_get_doppler_factor() const = 0;
+
+  // Exaggerate or diminish the effect of distance on sound. Default is 1.0
+  // Faster drop off, use >1.0
+  // Slower drop off, use <1.0
+  virtual void audio_3d_set_drop_off_factor(float factor) = 0;
+  virtual float audio_3d_get_drop_off_factor() const = 0;
+
 public:
 public:
   static void register_AudioManager_creator(Create_AudioManager_proc* proc);
   static void register_AudioManager_creator(Create_AudioManager_proc* proc);
 
 

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

@@ -95,6 +95,16 @@ PUBLISHED:
   // return: playing time in seconds.
   // return: playing time in seconds.
   virtual float length() const = 0;
   virtual float length() const = 0;
 
 
+  // Controls the position of this sound's emitter.
+  // px, py and pz are the emitter's position.
+  // vx, vy and vz are the emitter's velocity in UNITS PER SECOND (default: meters).
+  // You can pass NULL to either value for either function to ignore that value
+  // if you only want to set/get one of them for some reason.
+  virtual void set_3d_attributes(float px = NULL, float py = NULL, float pz = NULL,
+                                 float vx = NULL, float vy = NULL, float vz = NULL) = 0;
+  virtual void get_3d_attributes(float px = NULL, float py = NULL, float pz = NULL,
+                                 float vx = NULL, float vy = NULL, float vz = NULL) = 0;
+
   enum SoundStatus { BAD, READY, PLAYING };
   enum SoundStatus { BAD, READY, PLAYING };
   virtual SoundStatus status() const = 0;
   virtual SoundStatus status() const = 0;
 
 

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

@@ -35,6 +35,20 @@ int audio_cache_limit
 float audio_volume 
 float audio_volume 
     =config_audio.GetFloat("audio-volume", 1.0f);
     =config_audio.GetFloat("audio-volume", 1.0f);
 
 
+float audio_doppler_factor
+    =config_audio.GetFloat("audio-doppler-factor", 1.0f);
+
+float audio_distance_factor
+    =config_audio.GetFloat("audio-distance-factor", 1.0f);
+
+float audio_drop_off_factor
+    =config_audio.GetFloat("audio-drop-off-factor", 1.0f);
+
+// Guarantee this many channels on local sound card, or just
+// play EVERYTHING in software.
+int audio_min_hw_channels
+    =config_audio.GetInt("audio-min-hw-channels", 15);
+
 bool audio_software_midi 
 bool audio_software_midi 
     =config_audio.GetBool("audio-software-midi", false);
     =config_audio.GetBool("audio-software-midi", false);
 
 

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

@@ -32,6 +32,12 @@ extern EXPCL_PANDA bool audio_active;
 extern EXPCL_PANDA int audio_cache_limit;
 extern EXPCL_PANDA int audio_cache_limit;
 extern EXPCL_PANDA float audio_volume;
 extern EXPCL_PANDA float audio_volume;
 
 
+extern EXPCL_PANDA float audio_doppler_factor;
+extern EXPCL_PANDA float audio_distance_factor;
+extern EXPCL_PANDA float audio_drop_off_factor;
+
+extern EXPCL_PANDA int audio_min_hw_channels;
+
 extern EXPCL_PANDA bool audio_software_midi;
 extern EXPCL_PANDA bool audio_software_midi;
 extern EXPCL_PANDA string* audio_dls_file;
 extern EXPCL_PANDA string* audio_dls_file;
 
 

+ 98 - 1
panda/src/audio/nullAudioManager.cxx

@@ -19,6 +19,10 @@
 
 
 #include "nullAudioManager.h"
 #include "nullAudioManager.h"
 
 
+//namespace {
+    //static const string blank="";
+    //static float no_listener_attributes [] = {0.0f,0.0f,0.0f, 0.0f,0.0f,0.0f, 0.0f,0.0f,0.0f, 0.0f,0.0f,0.0f};
+//}
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NullAudioManager::NullAudioManager
 //     Function: NullAudioManager::NullAudioManager
@@ -56,7 +60,7 @@ is_valid() {
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PT(AudioSound) NullAudioManager::
 PT(AudioSound) NullAudioManager::
-get_sound(const string&) {
+get_sound(const string&, bool positional) {
   return get_null_sound();
   return get_null_sound();
 }
 }
 
 
@@ -180,3 +184,96 @@ void NullAudioManager::
 stop_all_sounds() {
 stop_all_sounds() {
   // intentionally blank.
   // intentionally blank.
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: NullAudioManager::audio_3d_update
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void NullAudioManager::
+audio_3d_update() {
+    // intentionally blank.
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NullAudioManager::audio_3d_set_listener_attributes
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void NullAudioManager::
+audio_3d_set_listener_attributes(float px, float py, float pz, float vx, float vy, float vz, float fx, float fy, float fz, float ux, float uy, float uz) {
+    // intentionally blank.
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NullAudioManager::audio_3d_get_listener_attributes
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void NullAudioManager::
+audio_3d_get_listener_attributes(float px, float py, float pz, float vx, float vy, float vz, float fx, float fy, float fz, float ux, float uy, float uz) {
+    // intentionally blank.
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NullAudioManager::audio_3d_set_distance_factor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void NullAudioManager::
+audio_3d_set_distance_factor(float factor) {
+    // intentionally blank.
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NullAudioManager::audio_3d_get_distance_factor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float NullAudioManager::
+audio_3d_get_distance_factor() const {
+    // intentionally blank.
+    return 0.0f;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NullAudioManager::audio_3d_set_doppler_factor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void NullAudioManager::
+audio_3d_set_doppler_factor(float factor) {
+    // intentionally blank.
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NullAudioManager::audio_3d_get_doppler_factor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float NullAudioManager::
+audio_3d_get_doppler_factor() const {
+    // intentionally blank.
+    return 0.0f;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NullAudioManager::audio_3d_set_drop_off_factor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void NullAudioManager::
+audio_3d_set_drop_off_factor(float factor) {
+    // intentionally blank.
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NullAudioManager::audio_3d_get_drop_off_factor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float NullAudioManager::
+audio_3d_get_drop_off_factor() const {
+    // intentionally blank.
+    return 0.0f;
+}

+ 21 - 1
panda/src/audio/nullAudioManager.h

@@ -34,7 +34,7 @@ public:
   
   
   virtual bool is_valid();
   virtual bool is_valid();
   
   
-  virtual PT(AudioSound) get_sound(const string&);
+  virtual PT(AudioSound) get_sound(const string&, bool positional = false);
   virtual void uncache_sound(const string&);
   virtual void uncache_sound(const string&);
   virtual void clear_cache();
   virtual void clear_cache();
   virtual void set_cache_limit(unsigned int);
   virtual void set_cache_limit(unsigned int);
@@ -52,6 +52,26 @@ public:
   virtual void reduce_sounds_playing_to(unsigned int count);
   virtual void reduce_sounds_playing_to(unsigned int count);
 
 
   virtual void stop_all_sounds();
   virtual void stop_all_sounds();
+
+  virtual void audio_3d_update();
+
+  virtual void audio_3d_set_listener_attributes(float px, float py, float pz,
+                                                float vx, float vy, float vz,
+                                                float fx, float fy, float fz,
+                                                float ux, float uy, float uz);
+  virtual void audio_3d_get_listener_attributes(float px = NULL, float py = NULL, float pz = NULL,
+                                                float vx = NULL, float vy = NULL, float vz = NULL,
+                                                float fx = NULL, float fy = NULL, float fz = NULL,
+                                                float ux = NULL, float uy = NULL, float uz = NULL);
+  
+  virtual void audio_3d_set_distance_factor(float factor);
+  virtual float audio_3d_get_distance_factor() const;
+
+  virtual void audio_3d_set_doppler_factor(float factor);
+  virtual float audio_3d_get_doppler_factor() const;
+
+  virtual void audio_3d_set_drop_off_factor(float factor);
+  virtual float audio_3d_get_drop_off_factor() const;
 };
 };
 
 
 #endif /* __NULL_AUDIO_MANAGER_H__ */
 #endif /* __NULL_AUDIO_MANAGER_H__ */

+ 9 - 0
panda/src/audio/nullAudioSound.cxx

@@ -22,6 +22,7 @@
 
 
 namespace {
 namespace {
   static const string blank="";
   static const string blank="";
+  static float no_attributes [] = {0.0f,0.0f,0.0f, 0.0f,0.0f,0.0f};
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -109,6 +110,14 @@ float NullAudioSound::length() const {
   return 0;
   return 0;
 }
 }
 
 
+void NullAudioSound::set_3d_attributes(float px, float py, float pz, float vx, float vy, float vz) {
+  // Intentionally blank.
+}
+
+void NullAudioSound::get_3d_attributes(float px, float py, float pz, float vx, float vy, float vz) {
+  // Intentionally blank.
+}
+
 AudioSound::SoundStatus NullAudioSound::status() const {
 AudioSound::SoundStatus NullAudioSound::status() const {
   return AudioSound::READY; 
   return AudioSound::READY; 
 }
 }

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

@@ -62,6 +62,9 @@ public:
   
   
   float length() const;
   float length() const;
 
 
+  void set_3d_attributes(float px, float py, float pz, float vx, float vy, float vz);
+  void get_3d_attributes(float px, float py, float pz, float vx, float vy, float vz);
+  
   AudioSound::SoundStatus status() const;
   AudioSound::SoundStatus status() const;
 
 
 // why protect the constructor?!?
 // why protect the constructor?!?

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

@@ -26,7 +26,7 @@
   #define BUILD_TARGET $[HAVE_FMOD]
   #define BUILD_TARGET $[HAVE_FMOD]
   #define USE_PACKAGES fmod
   #define USE_PACKAGES fmod
   #define BUILDING_DLL BUILDING_FMOD_AUDIO
   #define BUILDING_DLL BUILDING_FMOD_AUDIO
-  #define LOCAL_LIBS audio
+  #define LOCAL_LIBS audio event
   #define WIN_SYS_LIBS $[WIN_SYS_LIBS] user32.lib advapi32.lib winmm.lib
   #define WIN_SYS_LIBS $[WIN_SYS_LIBS] user32.lib advapi32.lib winmm.lib
 
 
   #define COMBINED_SOURCES $[TARGET]_composite1.cxx
   #define COMBINED_SOURCES $[TARGET]_composite1.cxx

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

@@ -20,12 +20,6 @@
 #ifdef HAVE_FMOD //[
 #ifdef HAVE_FMOD //[
 
 
 
 
-// Please remove this as part of updating fmod:
-#error The fmod audio needs repair by the fmod implementers
-
-
-
-
 #include "config_fmodAudio.h"
 #include "config_fmodAudio.h"
 #include "fmodAudioManager.h"
 #include "fmodAudioManager.h"
 #include "fmodAudioSound.h"
 #include "fmodAudioSound.h"

+ 244 - 23
panda/src/audiotraits/fmodAudioManager.cxx

@@ -51,8 +51,18 @@ FmodAudioManager() {
   audio_debug("FmodAudioManager::FmodAudioManager()");
   audio_debug("FmodAudioManager::FmodAudioManager()");
   audio_debug("  audio_active="<<audio_active);
   audio_debug("  audio_active="<<audio_active);
   audio_debug("  audio_volume="<<audio_volume);
   audio_debug("  audio_volume="<<audio_volume);
-
   _active = audio_active;
   _active = audio_active;
+  _volume = audio_volume;
+
+  //positional audio data
+  _listener_pos[0]     = 0.0f; _listener_pos[1]     = 0.0f;     _listener_pos[2] = 0.0f;
+  _listener_vel[0]     = 0.0f; _listener_vel[1]     = 0.0f;     _listener_vel[2] = 0.0f;
+  _listener_forward[0] = 0.0f; _listener_forward[1] = 1.0f; _listener_forward[2] = 0.0f;
+  _listener_up[0]      = 0.0f; _listener_up[1]      = 0.0f;      _listener_up[2] = 1.0f;
+  _distance_factor     = audio_distance_factor;
+  _doppler_factor      = audio_doppler_factor;
+  _drop_off_factor     = audio_drop_off_factor;
+
   _cache_limit = audio_cache_limit;
   _cache_limit = audio_cache_limit;
   _concurrent_sound_limit = 0;
   _concurrent_sound_limit = 0;
 
 
@@ -68,8 +78,13 @@ FmodAudioManager() {
         _is_valid = false;
         _is_valid = false;
         break;
         break;
       }
       }
+
+      // If the local system doesn't have enough hardware channels,
+      // Don't even bother trying to use hardware effects. Play EVERYTHING in software.
+      audio_debug("Setting minimum hardware channels(min="<<audio_min_hw_channels<<")");
+      FSOUND_SetMinHardwareChannels(audio_min_hw_channels);
       
       
-      if (FSOUND_Init(44100, 32, 0) == 0) {
+      if (FSOUND_Init(audio_output_rate, audio_cache_limit, 0) == 0) {
         audio_error("Fmod initialization failure.");
         audio_error("Fmod initialization failure.");
         _is_valid = false;
         _is_valid = false;
         break;
         break;
@@ -78,6 +93,10 @@ FmodAudioManager() {
     while(0); // curious -- why is there a non-loop here?
     while(0); // curious -- why is there a non-loop here?
   }
   }
 
 
+  // set 3D sound characteristics as they are given in the configrc
+  audio_3d_set_doppler_factor(audio_doppler_factor);
+  audio_3d_set_distance_factor(audio_distance_factor);
+  audio_3d_set_drop_off_factor(audio_drop_off_factor);
   // increment regardless of whether an error has occured -- the
   // increment regardless of whether an error has occured -- the
   // destructor will do the right thing.
   // destructor will do the right thing.
   ++_active_managers;
   ++_active_managers;
@@ -137,7 +156,7 @@ is_valid() {
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PT(AudioSound) FmodAudioManager::
 PT(AudioSound) FmodAudioManager::
-get_sound(const string &file_name) {
+get_sound(const string &file_name, bool positional) {
   audio_debug("FmodAudioManager::get_sound(file_name=\""<<file_name<<"\")");
   audio_debug("FmodAudioManager::get_sound(file_name=\""<<file_name<<"\")");
 
 
   if(!is_valid()) {
   if(!is_valid()) {
@@ -200,6 +219,21 @@ get_sound(const string &file_name) {
   // FMOD v4.0!
   // FMOD v4.0!
   FSOUND_STREAM *stream = NULL;
   FSOUND_STREAM *stream = NULL;
   int flags = FSOUND_LOADMEMORY | FSOUND_MPEGACCURATE;
   int flags = FSOUND_LOADMEMORY | FSOUND_MPEGACCURATE;
+  // 3D sounds have to be mono. Forcing stereo streams
+  // to be mono will create a speed hit.
+  if (positional) {
+      flags |= FSOUND_HW3D | FSOUND_FORCEMONO;
+  } else {
+      flags |= FSOUND_2D;
+  }
+  if (audio_output_bits == 8) {
+      flags |= FSOUND_8BITS;
+  } else if (audio_output_bits == 16) {
+      flags |= FSOUND_16BITS;
+  }
+  if (audio_output_channels == 1) {
+      flags |= FSOUND_FORCEMONO;
+  }
   string os_path = path.to_os_specific();
   string os_path = path.to_os_specific();
   string suffix = downcase(path.get_extension());
   string suffix = downcase(path.get_extension());
   
   
@@ -223,12 +257,16 @@ get_sound(const string &file_name) {
   PT(AudioSound) audioSound = 0;
   PT(AudioSound) audioSound = 0;
   PT(FmodAudioSound) fmodAudioSound = new FmodAudioSound(this, stream, path,
   PT(FmodAudioSound) fmodAudioSound = new FmodAudioSound(this, stream, path,
                length);
                length);
+  audio_debug("BOO!");
   fmodAudioSound->set_active(_active);
   fmodAudioSound->set_active(_active);
+  audio_debug("GAH!");
   _soundsOnLoan.insert(fmodAudioSound);
   _soundsOnLoan.insert(fmodAudioSound);
+  audio_debug("GIR!");
   audioSound = fmodAudioSound;
   audioSound = fmodAudioSound;
   
   
   audio_debug("  returning 0x" << (void*)audioSound);
   audio_debug("  returning 0x" << (void*)audioSound);
   assert(is_valid());
   assert(is_valid());
+  audio_debug("GOO!");
   return audioSound;
   return audioSound;
 }
 }
 
 
@@ -379,8 +417,8 @@ set_cache_limit(unsigned int count) {
 //       Access: Public
 //       Access: Public
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-int FmodAudioManager::
-get_cache_limit() {
+unsigned int FmodAudioManager::
+get_cache_limit() const {
   audio_debug("FmodAudioManager::get_cache_limit() returning "
   audio_debug("FmodAudioManager::get_cache_limit() returning "
         <<_cache_limit);
         <<_cache_limit);
   return _cache_limit;
   return _cache_limit;
@@ -405,8 +443,16 @@ release_sound(FmodAudioSound* audioSound) {
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void FmodAudioManager::
 void FmodAudioManager::
-set_volume(float) {
-  // intentionally blank.
+set_volume(float volume) {
+  audio_debug("FmodAudioManager::set_volume(volume="<<volume<<")");
+  if (_volume!=volume) {
+    _volume = volume;
+    // Tell our AudioSounds to adjust:
+    AudioSet::iterator i=_soundsOnLoan.begin();
+    for (; i!=_soundsOnLoan.end(); ++i) {
+      (**i).set_volume((**i).get_volume());
+    }
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -415,14 +461,15 @@ set_volume(float) {
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 float FmodAudioManager::
 float FmodAudioManager::
-get_volume() {
-  return 0;
+get_volume() const {
+  audio_debug("FmodAudioManager::get_volume() returning "<<_volume);
+  return _volume;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioManager::set_active
 //     Function: FmodAudioManager::set_active
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description: turn on/off
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void FmodAudioManager::
 void FmodAudioManager::
 set_active(bool active) {
 set_active(bool active) {
@@ -444,7 +491,8 @@ set_active(bool active) {
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool FmodAudioManager::
 bool FmodAudioManager::
-get_active() {
+get_active() const {
+  audio_debug("FmodAudioManager::get_active() returning "<<_active);
   return _active;
   return _active;
 }
 }
 
 
@@ -476,15 +524,28 @@ get_concurrent_sound_limit() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void FmodAudioManager::
 void FmodAudioManager::
 reduce_sounds_playing_to(unsigned int count) {
 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();
-  //}
+  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_a_sound
+//       Access: Public
+//  Description: Stop playback on one sound managed by this manager.
+////////////////////////////////////////////////////////////////////
+//void FmodAudioManager::
+//stop_a_sound() {
+//  audio_debug("FmodAudioManager::stop_a_sound()");
+//  AudioSet::size_type s=_soundsOnLoan.size() - 1;
+//  reduce_sounds_playing_to(s);
+  //if (s == _soundsOnLoan.size()) return true;
+  //return false;
+//}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioManager::stop_all_sounds
 //     Function: FmodAudioManager::stop_all_sounds
 //       Access: Public
 //       Access: Public
@@ -493,12 +554,172 @@ reduce_sounds_playing_to(unsigned int count) {
 void FmodAudioManager::
 void FmodAudioManager::
 stop_all_sounds() {
 stop_all_sounds() {
   audio_debug("FmodAudioManager::stop_all_sounds()");
   audio_debug("FmodAudioManager::stop_all_sounds()");
-  AudioSet::iterator i=_soundsOnLoan.begin();
-  for (; i!=_soundsOnLoan.end(); ++i) {
-    if ((**i).status()==AudioSound::PLAYING) {
-      (**i).stop();
+  reduce_sounds_playing_to(0);
+  //AudioSet::iterator i=_soundsOnLoan.begin();
+  //for (; i!=_soundsOnLoan.end(); ++i) {
+  //  if ((**i).status()==AudioSound::PLAYING) {
+  //    (**i).stop();
+  //  }
+  //}
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::audio_3d_update
+//       Access: Public
+//  Description: Commit position changes to listener and all
+//               positioned sounds. Normally, you'd want to call this
+//               once per iteration of your main loop.
+////////////////////////////////////////////////////////////////////
+void FmodAudioManager::
+audio_3d_update() {
+    audio_debug("FmodAudioManager::audio_3d_update()");
+    //convert panda coordinates to fmod coordinates
+    float fmod_pos [] = {_listener_pos[0], _listener_pos[2], _listener_pos[1]};
+    float fmod_vel [] = {_listener_vel[0], _listener_vel[2], _listener_vel[1]};
+    float fmod_forward [] = {_listener_forward[0], _listener_forward[2], _listener_forward[1]};
+    float fmod_up [] = {_listener_up[0], _listener_up[2], _listener_up[1]};
+
+    FSOUND_3D_Listener_SetAttributes(fmod_pos, fmod_vel,
+                                         fmod_forward[0], fmod_forward[1], fmod_forward[2],
+                                         fmod_up[0], fmod_up[1], fmod_up[2]);
+    FSOUND_Update();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::audio_3d_set_listener_attributes
+//       Access: Public
+//  Description: Set position of the "ear" that picks up 3d sounds
+////////////////////////////////////////////////////////////////////
+void FmodAudioManager::
+audio_3d_set_listener_attributes(float px, float py, float pz, float vx, float vy, float vz, float fx, float fy, float fz, float ux, float uy, float uz) {
+    audio_debug("FmodAudioManager::audio_3d_set_listener_attributes()");
+
+    _listener_pos[0]     = px; _listener_pos[1]     = py; _listener_pos[2]     = pz;
+    _listener_vel[0]     = vx; _listener_vel[1]     = vy; _listener_vel[2]     = vz;
+    _listener_forward[0] = fx; _listener_forward[1] = fy; _listener_forward[2] = fz;
+    _listener_up[0]      = ux; _listener_up[1]      = uy; _listener_up[2]      = uz;
+
+    //FSOUND_3D_Listener_SetAttributes(_listener_pos, _listener_vel, fx, fz, fy, ux, uz, uy);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::audio_3d_get_listener_attributes
+//       Access: Public
+//  Description: Get position of the "ear" that picks up 3d sounds
+////////////////////////////////////////////////////////////////////
+void FmodAudioManager::
+audio_3d_get_listener_attributes(float px, float py, float pz, float vx, float vy, float vz, float fx, float fy, float fz, float ux, float uy, float uz) {
+    audio_error("audio3dGetListenerAttributes: currently unimplemented. Get the attributes of the attached object");
+    //audio_debug("FmodAudioManager::audio_3d_get_listener_attributes()");
+    // NOTE: swap the +y with the +z axis to convert between FMOD
+    //       coordinates and Panda3D coordinates
+    //float temp;
+    //temp = py;
+    //py = pz;
+    //pz = temp;
+
+    //temp = vy;
+    //vy = vz;
+    //vz = temp;
+
+    //float pos [] =   {px, py, pz};
+    //float vel [] =   {vx, vy, vz};
+    //float front [] = {fx, fz, fy};
+    //float up [] =    {ux, uz, uy};
+
+    //FSOUND_3D_Listener_GetAttributes(pos, vel, &front[0], &front[1], &front[2], &up[0], &up[1], &up[2]);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::audio_3d_set_distance_factor
+//       Access: Public
+//  Description: Set units per meter (Fmod uses meters internally for
+//               its sound-spacialization calculations)
+////////////////////////////////////////////////////////////////////
+void FmodAudioManager::
+audio_3d_set_distance_factor(float factor) {
+    audio_debug("FmodAudioManager::audio_3d_set_distance_factor(factor="<<factor<<")");
+    if (factor<0.0) {
+        audio_debug("Recieved value below 0.0. Clamping to 0.0.");
+        factor = 0.0;
     }
     }
-  }
+    if (_distance_factor != factor){
+        _distance_factor = factor;
+        FSOUND_3D_SetDistanceFactor(_distance_factor);
+    }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::audio_3d_get_distance_factor
+//       Access: Public
+//  Description: Gets units per meter (Fmod uses meters internally for
+//               its sound-spacialization calculations)
+////////////////////////////////////////////////////////////////////
+float FmodAudioManager::
+audio_3d_get_distance_factor() const {
+    audio_debug("FmodAudioManager::audio_3d_get_distance_factor()");
+    return _distance_factor;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::audio_3d_set_doppler_factor
+//       Access: Public
+//  Description: Exaggerates or diminishes the Doppler effect. 
+//               Defaults to 1.0
+////////////////////////////////////////////////////////////////////
+void FmodAudioManager::
+audio_3d_set_doppler_factor(float factor) {
+    audio_debug("FmodAudioManager::audio_3d_set_doppler_factor(factor="<<factor<<")");
+    if (factor<0.0) {
+        audio_debug("Recieved value below 0.0. Clamping to 0.0.");
+        factor = 0.0;
+    }
+    if (_doppler_factor != factor) {
+        _doppler_factor = factor;
+        FSOUND_3D_SetDopplerFactor(_doppler_factor);
+    }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::audio_3d_get_doppler_factor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float FmodAudioManager::
+audio_3d_get_doppler_factor() const {
+    audio_debug("FmodAudioManager::audio_3d_get_doppler_factor()");
+    return _doppler_factor;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::audio_3d_set_drop_off_factor
+//       Access: Public
+//  Description: Control the effect distance has on audability.
+//               Defaults to 1.0
+////////////////////////////////////////////////////////////////////
+void FmodAudioManager::
+audio_3d_set_drop_off_factor(float factor) {
+    audio_debug("FmodAudioManager::audio_3d_set_drop_off_factor("<<factor<<")");
+    if (factor<0.0) {
+        audio_debug("Recieved value below 0.0. Clamping to 0.0");
+        factor = 0.0;
+    }
+    if (_drop_off_factor != factor) {
+        _drop_off_factor = factor;
+        FSOUND_3D_SetRolloffFactor(_drop_off_factor);
+    }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioManager::audio_3d_get_drop_off_factor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float FmodAudioManager::
+audio_3d_get_drop_off_factor() const {
+    audio_debug("FmodAudioManager::audio_3d_get_drop_off_factor()");
+    return _drop_off_factor;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

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

@@ -1,5 +1,6 @@
 // Filename: fmodAudioManager.h
 // Filename: fmodAudioManager.h
 // Created by:  cort (January 22, 2003)
 // Created by:  cort (January 22, 2003)
+// Extended by: ben  (October 22, 2003)
 // Prior system by: cary
 // Prior system by: cary
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -43,11 +44,11 @@ public:
   
   
   virtual bool is_valid();
   virtual bool is_valid();
   
   
-  virtual PT(AudioSound) get_sound(const string&);
+  virtual PT(AudioSound) get_sound(const string&, bool positional = false);
   virtual void uncache_sound(const string&);
   virtual void uncache_sound(const string&);
   virtual void clear_cache();
   virtual void clear_cache();
   virtual void set_cache_limit(unsigned int count);
   virtual void set_cache_limit(unsigned int count);
-  virtual int get_cache_limit();
+  virtual unsigned int get_cache_limit() const;
 
 
   // Indicates that the given sound was the most recently used.
   // Indicates that the given sound was the most recently used.
   void most_recently_used(const string& path);
   void most_recently_used(const string& path);
@@ -56,18 +57,58 @@ public:
   void uncache_a_sound();
   void uncache_a_sound();
 
 
   virtual void set_volume(float);
   virtual void set_volume(float);
-  virtual float get_volume();
+  virtual float get_volume() const;
   
   
   virtual void set_active(bool);
   virtual void set_active(bool);
-  virtual bool get_active();
+  virtual bool get_active() const;
 
 
   virtual void set_concurrent_sound_limit(unsigned int limit = 0);
   virtual void set_concurrent_sound_limit(unsigned int limit = 0);
   virtual unsigned int get_concurrent_sound_limit() const;
   virtual unsigned int get_concurrent_sound_limit() const;
 
 
   virtual void reduce_sounds_playing_to(unsigned int count);
   virtual void reduce_sounds_playing_to(unsigned int count);
 
 
+  //virtual void stop_a_sound();
   virtual void stop_all_sounds();
   virtual void stop_all_sounds();
 
 
+  // Changes to the positions of 3D spacialized sounds and the listener
+  // are all made at once when this method is called. It should be put
+  // in the main program loop.
+  virtual void audio_3d_update();
+
+  // This controls the "set of ears" that listens to 3D spacialized sound
+  // px, py, pz are position coordinates. Can be NULL to ignore.
+  // vx, vy, vz are a velocity vector in UNITS PER SECOND (default: meters). Can be NULL to ignore.
+  // fx, fy and fz are the respective components of a unit forward-vector
+  // ux, uy and uz are the respective components of a unit up-vector
+  // These changes will NOT be invoked until audio_3d_update() is called.
+  virtual void audio_3d_set_listener_attributes(float px, float py, float pz,
+                                                float vx, float xy, float xz, 
+                                                float fx, float fy, float fz,
+                                                float ux, float uy, float uz);
+  // Values should all default to NULL, so you can just pass the one you want to get.
+  virtual void audio_3d_get_listener_attributes(float px = NULL, float py = NULL, float pz = NULL,
+                                                float vx = NULL, float vy = NULL, float vz = NULL,
+                                                float fx = NULL, float fy = NULL, float fz = NULL,
+                                                float ux = NULL, float uy = NULL, float uz = NULL);
+  
+  // Control the "relative distance factor" for 3D spacialized audio. Default is 1.0
+  // Fmod uses meters internally, so give a float in Units-per meter
+  // Don't know what Miles uses.
+  virtual void audio_3d_set_distance_factor(float factor);
+  virtual float audio_3d_get_distance_factor() const;
+
+  // Control the presence of the Doppler effect. Default is 1.0
+  // Exaggerated Doppler, use >1.0
+  // Diminshed Doppler, use <1.0
+  virtual void audio_3d_set_doppler_factor(float factor);
+  virtual float audio_3d_get_doppler_factor() const;
+
+  // Exaggerate or diminish the effect of distance on sound. Default is 1.0
+  // Faster drop off, use >1.0
+  // Slower drop off, use <1.0
+  virtual void audio_3d_set_drop_off_factor(float factor);
+  virtual float audio_3d_get_drop_off_factor() const;
+
 protected:
 protected:
   // increment or decrement the refcount of the given file's cache entry.
   // increment or decrement the refcount of the given file's cache entry.
   // sounds can only be uncached when their refcounts are zero.
   // sounds can only be uncached when their refcounts are zero.
@@ -88,6 +129,10 @@ private:
   AudioSet _soundsOnLoan;
   AudioSet _soundsOnLoan;
   unsigned int _concurrent_sound_limit;
   unsigned int _concurrent_sound_limit;
 
 
+  typedef pset<FmodAudioSound* > SoundsPlaying;
+  // The sounds from this manager that are currently playing
+  SoundsPlaying _sounds_playing;
+
   // The Least Recently Used mechanism:
   // The Least Recently Used mechanism:
   typedef pdeque<string> LRU;
   typedef pdeque<string> LRU;
   LRU _lru;
   LRU _lru;
@@ -98,6 +143,14 @@ private:
   static int _active_managers;
   static int _active_managers;
   bool _is_valid;
   bool _is_valid;
   bool _active;
   bool _active;
+  float _volume;
+  float _listener_pos [3];
+  float _listener_vel [3];
+  float _listener_forward [3];
+  float _listener_up [3];
+  float _distance_factor;
+  float _doppler_factor;
+  float _drop_off_factor;
   
   
   char* load(const Filename& filename, size_t &size) const;
   char* load(const Filename& filename, size_t &size) const;
 
 

+ 254 - 13
panda/src/audiotraits/fmodAudioSound.cxx

@@ -1,5 +1,6 @@
 // Filename: fmodAudioSound.cxx
 // Filename: fmodAudioSound.cxx
 // Created by:  cort (January 22, 2003)
 // Created by:  cort (January 22, 2003)
+// Extended by: ben  (October 22, 2003)
 // Prior system by: cary
 // Prior system by: cary
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -20,6 +21,7 @@
 #include "pandabase.h"
 #include "pandabase.h"
 #ifdef HAVE_FMOD //[
 #ifdef HAVE_FMOD //[
 
 
+#include "throw_event.h"
 #include "fmodAudioSound.h"
 #include "fmodAudioSound.h"
 #include "fmodAudioManager.h"
 #include "fmodAudioManager.h"
 
 
@@ -32,25 +34,73 @@
   #define fmod_audio_debug(x) ((void)0)
   #define fmod_audio_debug(x) ((void)0)
 #endif //]
 #endif //]
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: pandaFmodFinishedCallback_Stream
+//       Access: file scope
+//  Description: What happens when a sound ends (not reaches the end
+//               of a loop, but really ends).
+////////////////////////////////////////////////////////////////////
+signed char
+pandaFmodFinishedCallback_Stream( FSOUND_STREAM *audio, void *buff, int len, int p_sound ) {
+    FmodAudioSound* sound = (FmodAudioSound*)p_sound;
+    assert(sound); //sanity test
+    sound->finished();
+    return true; //make signed char happy
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: panda_Fmod_finished_callback
+//       Access: file scope
+//  Description: Sets up a finish callback for a sound. 
+////////////////////////////////////////////////////////////////////
+void 
+panda_Fmod_finished_callback( FSOUND_STREAM *audio, FmodAudioSound* sound ) {
+    if ( !audio || !sound ) {//sanity test
+        return;
+    }
+    audio_debug("panda_Fmod_finished_callback(audio="<<((void*)audio)
+        <<", sound="<<((void*)sound)<<")");
+    FSOUND_STREAMCALLBACK callback = pandaFmodFinishedCallback_Stream;
+                                //actual stream, callback func, pointer to FmodAudioSound
+    FSOUND_Stream_SetEndCallback( audio, callback, (int)sound );
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::FmodAudioSound
+//       Access: 
+//  Description: constructor
+////////////////////////////////////////////////////////////////////
 FmodAudioSound::
 FmodAudioSound::
 FmodAudioSound(FmodAudioManager* manager, FSOUND_STREAM *audio_data,
 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),
   : _manager(manager), _audio(audio_data), _file_name(file_name),
     _volume(1.0f), _balance(0), _loop_count(1), _length(length),
     _volume(1.0f), _balance(0), _loop_count(1), _length(length),
-    _active(true), _paused(false), _channel(-1) {
+    _active(true), _paused(false), _bExclusive(false),_channel(-1) {
+  _pos[0] = 0.0f; _pos[1] = 0.0f; _pos[2] = 0.0f;
+  _vel[0] = 0.0f; _vel[1] = 0.0f; _vel[2] = 0.0f;
   nassertv(!file_name.empty());
   nassertv(!file_name.empty());
   nassertv(audio_data != NULL);
   nassertv(audio_data != NULL);
-  audio_debug("FmodAudioSound(manager=0x"<<(void*)&manager
+  fmod_audio_debug("FmodAudioSound(manager=0x"<<(void*)&manager
         <<", file_name="<<file_name<<")");
         <<", file_name="<<file_name<<")");
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::~FmodAudioSound
+//       Access: public
+//  Description: destructor
+////////////////////////////////////////////////////////////////////
 FmodAudioSound::
 FmodAudioSound::
 ~FmodAudioSound() {
 ~FmodAudioSound() {
   fmod_audio_debug("~FmodAudioSound()");
   fmod_audio_debug("~FmodAudioSound()");
   this->stop();
   this->stop();
   _manager->release_sound(this);
   _manager->release_sound(this);
 }
 }
-  
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound:: play
+//       Access: public
+//  Description: Play a sound
+////////////////////////////////////////////////////////////////////
 void FmodAudioSound::
 void FmodAudioSound::
 play() {
 play() {
   if (!_active) {
   if (!_active) {
@@ -60,11 +110,12 @@ play() {
   if (this->status() == AudioSound::PLAYING) {
   if (this->status() == AudioSound::PLAYING) {
     this->stop();
     this->stop();
   }
   }
-  if (_manager->stop_a_sound()) {
+if (_bExclusive) {
     // stop another sound that parent mgr is playing
     // stop another sound that parent mgr is playing
     _manager->stop_all_sounds();
     _manager->stop_all_sounds();
   }
   }
 
 
+  panda_Fmod_finished_callback( _audio, this );
   // Play the stream, but start it paused so we can set the volume and
   // Play the stream, but start it paused so we can set the volume and
   // panning first.
   // panning first.
   assert(_audio != NULL);
   assert(_audio != NULL);
@@ -81,6 +132,16 @@ play() {
   // Set panning.
   // Set panning.
   unsigned char new_balance = (unsigned char)( (_balance+1.0f)*0.5f*255.0f);
   unsigned char new_balance = (unsigned char)( (_balance+1.0f)*0.5f*255.0f);
   FSOUND_SetPan(_channel, new_balance);
   FSOUND_SetPan(_channel, new_balance);
+
+  // Set 3d attributes, if needed
+  if (FSOUND_Stream_GetMode(_audio) & FSOUND_HW3D) {
+      // Convert from Panda coordinates to Fmod coordinates
+      float fmod_pos [] = {_pos[0], _pos[2], _pos[1]};
+      float fmod_vel [] = {_vel[0], _vel[2], _vel[1]};
+      if(!FSOUND_3D_SetAttributes(_channel, fmod_pos, fmod_vel)) {
+          audio_error("Unable to set 3d attributes for "<<_file_name<<"!");
+      }
+  }
   
   
   // Set looping -- unimplemented
   // Set looping -- unimplemented
   
   
@@ -95,33 +156,103 @@ play() {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::stop
+//       Access: public
+//  Description: Stop a sound
+////////////////////////////////////////////////////////////////////
 void FmodAudioSound::stop() {
 void FmodAudioSound::stop() {
-  FSOUND_Stream_Stop(_audio);
-  _channel = -1;
+    if(!FSOUND_Stream_Stop(_audio)) {
+        audio_error("Stop failed!");
+    }
+    _channel = -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::finished
+//       Access: public
+//  Description: called by finishedCallback function when a sound
+//               terminates (but doesn't loop).
+////////////////////////////////////////////////////////////////////
+void FmodAudioSound::finished() {
+    fmod_audio_debug("finished()");
+    stop();
+    if (!_finished_event.empty()) {
+        throw_event(_finished_event);
+    }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::set_loop
+//       Access: public
+//  Description: Turns looping on and off
+////////////////////////////////////////////////////////////////////
 void FmodAudioSound::set_loop(bool loop) {
 void FmodAudioSound::set_loop(bool loop) {
-  audio_error("FmodAudioSound::set_loop() -- not yet implemented");
   fmod_audio_debug("set_loop() set to "<<loop);
   fmod_audio_debug("set_loop() set to "<<loop);
+  unsigned int mode = FSOUND_Stream_GetMode(_audio);
+  if (loop) {
+      // turn looping on
+      FSOUND_Stream_SetMode(_audio, mode | FSOUND_LOOP_NORMAL);
+  } else {
+      // turn looping off if and only if it is on
+      if (FSOUND_LOOP_NORMAL == (mode & FSOUND_LOOP_NORMAL)) {
+          FSOUND_Stream_SetMode(_audio, mode ^ FSOUND_LOOP_NORMAL);
+      }
+  }
+  // default to loop infinitely
   _loop_count = loop ? 0 : 1;
   _loop_count = loop ? 0 : 1;
+  FSOUND_Stream_SetLoopCount(_audio, _loop_count - 1);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::get_loop
+//       Access: public
+//  Description: Returns whether looping is on or off
+////////////////////////////////////////////////////////////////////
 bool FmodAudioSound::get_loop() const {
 bool FmodAudioSound::get_loop() const {
-  fmod_audio_debug("get_loop() returning "<<(_loop_count==0));
-  return (_loop_count == 0);
+  // 0 means loop forever,
+  // >1 means loop that many times
+  // So _loop_count != 1 means we're looping
+  fmod_audio_debug("get_loop() returning "<<(_loop_count != 1));
+  return (_loop_count != 1);
 }
 }
-  
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::set_loop_count
+//       Access: public
+//  Description: 
+////////////////////////////////////////////////////////////////////
 void FmodAudioSound::set_loop_count(unsigned long loop_count) {
 void FmodAudioSound::set_loop_count(unsigned long loop_count) {
-  audio_error("FmodAudioSound::set_loop_count() -- not yet implemented");
+  // Panda uses 0 to mean loop forever.
+  // Fmod uses negative numbers to mean loop forever.
+  // (0 means don't loop, 1 means play twice, etc.)
+  // We must convert!
+  
   fmod_audio_debug("set_loop_count() set to "<<loop_count);
   fmod_audio_debug("set_loop_count() set to "<<loop_count);
+  if (loop_count < 0) {
+      fmod_audio_debug("Value out of bounds. Default to loop infinitely.");
+      loop_count = 0;
+  }
   _loop_count = loop_count;
   _loop_count = loop_count;
+  loop_count -= 1; 
+  FSOUND_Stream_SetLoopCount(_audio, loop_count);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::get_loop_count
+//       Access: public
+//  Description: 
+////////////////////////////////////////////////////////////////////
 unsigned long FmodAudioSound::get_loop_count() const {
 unsigned long FmodAudioSound::get_loop_count() const {
   fmod_audio_debug("get_loop_count() returning "<<_loop_count);
   fmod_audio_debug("get_loop_count() returning "<<_loop_count);
   return _loop_count;
   return _loop_count;
 }
 }
-  
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::set_time
+//       Access: public
+//  Description: Sets the play position within the sound
+////////////////////////////////////////////////////////////////////
 void FmodAudioSound::set_time(float start_time) {
 void FmodAudioSound::set_time(float start_time) {
   if (start_time < 0.0f) {
   if (start_time < 0.0f) {
     fmod_audio_debug("set_time(): param "<<start_time<<" out of range.");
     fmod_audio_debug("set_time(): param "<<start_time<<" out of range.");
@@ -136,6 +267,11 @@ void FmodAudioSound::set_time(float start_time) {
   FSOUND_Stream_SetTime(_audio, (int)(start_time * 1000.0f));
   FSOUND_Stream_SetTime(_audio, (int)(start_time * 1000.0f));
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::get_time
+//       Access: public
+//  Description: Gets the play position within the sound
+////////////////////////////////////////////////////////////////////
 float FmodAudioSound::get_time() const {
 float FmodAudioSound::get_time() const {
   // A bug in stream WAV files causes FSOUND_Stream_GetTime() to
   // A bug in stream WAV files causes FSOUND_Stream_GetTime() to
   // divide-by-zero somewhere if the stream isn't currently playing.
   // divide-by-zero somewhere if the stream isn't currently playing.
@@ -150,6 +286,12 @@ float FmodAudioSound::get_time() const {
   return current_time;
   return current_time;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::set_volume
+//       Access: public
+//  Description: 0.0 to 1.0 scale of volume converted to Fmod's
+//               internal 0.0 to 255.0 scale.
+////////////////////////////////////////////////////////////////////
 void FmodAudioSound::set_volume(float vol) {
 void FmodAudioSound::set_volume(float vol) {
   if (vol < 0.0f) {
   if (vol < 0.0f) {
     fmod_audio_debug("set_volume(): param "<<vol<<" out of range.");
     fmod_audio_debug("set_volume(): param "<<vol<<" out of range.");
@@ -165,11 +307,21 @@ void FmodAudioSound::set_volume(float vol) {
   FSOUND_SetVolume(_channel, new_volume);
   FSOUND_SetVolume(_channel, new_volume);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::get_volume
+//       Access: public
+//  Description: 
+////////////////////////////////////////////////////////////////////
 float FmodAudioSound::get_volume() const {
 float FmodAudioSound::get_volume() const {
   fmod_audio_debug("get_volume() returning "<<_volume);
   fmod_audio_debug("get_volume() returning "<<_volume);
   return _volume;
   return _volume;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::set_balance
+//       Access: public
+//  Description: -1.0 to 1.0 scale
+////////////////////////////////////////////////////////////////////
 void FmodAudioSound::set_balance(float bal) {
 void FmodAudioSound::set_balance(float bal) {
   if (bal < -1.0f) {
   if (bal < -1.0f) {
     fmod_audio_debug("set_balance(): param "<<bal<<" out of range.");
     fmod_audio_debug("set_balance(): param "<<bal<<" out of range.");
@@ -185,11 +337,21 @@ void FmodAudioSound::set_balance(float bal) {
   FSOUND_SetPan(_channel, new_balance);
   FSOUND_SetPan(_channel, new_balance);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::get_balance
+//       Access: public
+//  Description: 
+////////////////////////////////////////////////////////////////////
 float FmodAudioSound::get_balance() const {
 float FmodAudioSound::get_balance() const {
   fmod_audio_debug("get_balance() returning "<<_balance);
   fmod_audio_debug("get_balance() returning "<<_balance);
   return _balance;
   return _balance;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::set_active
+//       Access: public
+//  Description: 
+////////////////////////////////////////////////////////////////////
 void FmodAudioSound::set_active(bool active) {
 void FmodAudioSound::set_active(bool active) {
   fmod_audio_debug("set_active(active="<<active<<")");
   fmod_audio_debug("set_active(active="<<active<<")");
   if (!active) {
   if (!active) {
@@ -200,20 +362,99 @@ void FmodAudioSound::set_active(bool active) {
   _active = active;
   _active = active;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::get_active
+//       Access: public
+//  Description: 
+////////////////////////////////////////////////////////////////////
 bool FmodAudioSound::get_active() const {
 bool FmodAudioSound::get_active() const {
   fmod_audio_debug("get_active() returning "<<_active);
   fmod_audio_debug("get_active() returning "<<_active);
   return _active;
   return _active;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::set_finished_event
+//       Access: public
+//  Description: Assign a string for the finished event to be referenced 
+//               by in python by an accept method
+////////////////////////////////////////////////////////////////////
+void FmodAudioSound::
+set_finished_event(const string& event) {
+  fmod_audio_debug("set_finished_event(event="<<event<<")");
+  _finished_event = event;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::get_finished_event
+//       Access: public
+//  Description: Return the string the finished event is referenced by
+////////////////////////////////////////////////////////////////////
+const string& FmodAudioSound::
+get_finished_event() const {
+  fmod_audio_debug("get_finished_event() returning "<<_finished_event);
+  return _finished_event;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::get_name
+//       Access: public
+//  Description: Get name of sound file
+////////////////////////////////////////////////////////////////////
 const string& FmodAudioSound::get_name() const {
 const string& FmodAudioSound::get_name() const {
-  //fmod_audio_debug("get_name() returning "<<_file_name);
+  fmod_audio_debug("get_name() returning "<<_file_name);
   return _file_name;
   return _file_name;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::length
+//       Access: public
+//  Description: Get length
+////////////////////////////////////////////////////////////////////
 float FmodAudioSound::length() const {
 float FmodAudioSound::length() const {
   return _length;
   return _length;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::set_3d_attributes
+//       Access: public
+//  Description: Set position and velocity of this sound
+////////////////////////////////////////////////////////////////////
+void FmodAudioSound::
+set_3d_attributes(float px, float py, float pz, float vx, float vy, float vz) {
+    fmod_audio_debug("Set 3d position and velocity (px="<<px<<", py="<<py<<", pz="<<pz<<", vx="<<vx<<", vy="<<vy<<", vz="<<vz<<")");
+    _pos[0] = px; _pos[1] = py; _pos[2] = pz;
+    _vel[0] = vx; _vel[1] = vy; _vel[2] = vz;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::get_3d_attributes
+//       Access: public
+//  Description: Get position and velocity of this sound
+////////////////////////////////////////////////////////////////////
+void FmodAudioSound::
+get_3d_attributes(float px, float py, float pz, float vx, float vy, float vz) {
+    audio_error("get3dAttributes: Currently unimplemented. Get the attributes of the attached object.");
+    // NOTE: swap the +y with the +z axis to convert between FMOD
+    //       coordinates and Panda3D coordinates
+    //float temp;
+    //temp = py;
+    //py = pz;
+    //pz = temp;
+
+    //temp = vy;
+    //vy = vz;
+    //vz = temp;
+
+    //float pos [] = {px, py, pz};
+    //float vel [] = {vx, vy, vz};
+    //FSOUND_3D_GetAttributes(_channel, pos, vel);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FmodAudioSound::status
+//       Access: public
+//  Description: Get status of the sound.
+////////////////////////////////////////////////////////////////////
 AudioSound::SoundStatus FmodAudioSound::status() const {
 AudioSound::SoundStatus FmodAudioSound::status() const {
   // If the stream's channel isn't playing anything, then the stream
   // If the stream's channel isn't playing anything, then the stream
   // definitely isn't playing.
   // definitely isn't playing.

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

@@ -20,7 +20,7 @@
 #ifndef __FMOD_AUDIO_SOUND_H__
 #ifndef __FMOD_AUDIO_SOUND_H__
 #define __FMOD_AUDIO_SOUND_H__
 #define __FMOD_AUDIO_SOUND_H__
 
 
-#include "pandabase.h"
+#include <pandabase.h>
 #ifdef HAVE_FMOD //[
 #ifdef HAVE_FMOD //[
 
 
 #include "audioSound.h"
 #include "audioSound.h"
@@ -78,20 +78,36 @@ public:
   // return: playing time in seconds.
   // return: playing time in seconds.
   float length() const;
   float length() const;
 
 
+  // Controls the position of this sound's emitter.
+  // pos is a pointer to an xyz triplet of the emitter's position.
+  // vel is a pointer to an xyz triplet of the emitter's velocity.
+  // You can pass NULL to either value for either function to ignore that value
+  // if you only want to set/get one of them for some reason.
+  void set_3d_attributes(float px = NULL, float py = NULL, float pz = NULL,
+                         float vx = NULL, float vy = NULL, float vz = NULL);
+  void get_3d_attributes(float px = NULL, float py = NULL, float pz = NULL, 
+                         float vx = NULL, float vy = NULL, float vz = NULL);
+  
   AudioSound::SoundStatus status() const;
   AudioSound::SoundStatus status() const;
 
 
+  void finished();
+
 protected:
 protected:
 
 
 private:
 private:
   PT(FmodAudioManager) _manager;
   PT(FmodAudioManager) _manager;
   FSOUND_STREAM *_audio;
   FSOUND_STREAM *_audio;
   string _file_name;
   string _file_name;
+  string _finished_event;
   float _volume; // 0..1.0
   float _volume; // 0..1.0
   float _balance; // -1..1
   float _balance; // -1..1
+  float _pos [3];
+  float _vel [3];
   unsigned long _loop_count;
   unsigned long _loop_count;
   mutable float _length; // in seconds.
   mutable float _length; // in seconds.
   bool _active;
   bool _active;
   bool _paused;
   bool _paused;
+  bool _bExclusive; //stops all other sounds before playing when true
   int _channel;
   int _channel;
 
 
   FmodAudioSound(FmodAudioManager* manager, FSOUND_STREAM *audio_data,
   FmodAudioSound(FmodAudioManager* manager, FSOUND_STREAM *audio_data,

+ 3 - 0
panda/src/audiotraits/milesAudioSound.h

@@ -108,6 +108,9 @@ public:
   // return: playing time in seconds.
   // return: playing time in seconds.
   float length() const;
   float length() const;
 
 
+  void set_3d_attributes(float* pos, float* vel);
+  void get_3d_attributes(float* pos, float* vel);
+
   AudioSound::SoundStatus status() const;
   AudioSound::SoundStatus status() const;
 
 
   void finished();
   void finished();

+ 3 - 3
panda/src/egg/eggTextureCollection.cxx

@@ -121,11 +121,11 @@ get_num_textures() const {
 //       Access: Published
 //       Access: Published
 //  Description: Returns the nth EggTexture in the collection.
 //  Description: Returns the nth EggTexture in the collection.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-EggTexture EggTextureCollection::
+EggTexture *EggTextureCollection::
 get_texture(int index) const {
 get_texture(int index) const {
-  nassertr(index >= 0 && index < (int)_ordered_textures.size(), EggTexture(0,0));
+  nassertr(index >= 0 && index < (int)_ordered_textures.size(), NULL);
 
 
-  return *_ordered_textures[index];
+  return _ordered_textures[index];
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 2 - 2
panda/src/egg/eggTextureCollection.h

@@ -66,7 +66,7 @@ PUBLISHED:
 
 
   bool is_empty() const;
   bool is_empty() const;
   int get_num_textures() const;
   int get_num_textures() const;
-  EggTexture get_texture(int index) const;
+  EggTexture *get_texture(int index) const;
 
 
 public:
 public:
   EggGroupNode::iterator insert_textures(EggGroupNode *node);
   EggGroupNode::iterator insert_textures(EggGroupNode *node);
@@ -84,9 +84,9 @@ PUBLISHED:
   void uniquify_trefs();
   void uniquify_trefs();
   void sort_by_tref();
   void sort_by_tref();
 
 
+public:
   // Can be used to traverse all the textures in the collection, in
   // Can be used to traverse all the textures in the collection, in
   // order as last sorted.
   // order as last sorted.
-public:
   INLINE iterator begin() const;
   INLINE iterator begin() const;
   INLINE iterator end() const;
   INLINE iterator end() const;
   INLINE bool empty() const;
   INLINE bool empty() const;

+ 9 - 0
pandatool/src/progbase/programBase.cxx

@@ -215,6 +215,15 @@ show_text(const string &prefix, int indent_width, string text) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void ProgramBase::
 void ProgramBase::
 parse_command_line(int argc, char *argv[]) {
 parse_command_line(int argc, char *argv[]) {
+
+
+  // Setting this variable to zero reinitializes the options parser
+  // This is only necessary for processing multiple command lines in
+  // the same program (mainly the MaxToEgg converter plugin)
+  extern int optind;
+  optind = 0;
+
+
   _program_name = Filename::from_os_specific(argv[0]);
   _program_name = Filename::from_os_specific(argv[0]);
   int i;
   int i;
   for (i = 1; i < argc; i++) {
   for (i = 1; i < argc; i++) {