浏览代码

miles streaming

David Rose 18 年之前
父节点
当前提交
15f2e539d6

+ 22 - 2
panda/src/audio/audioManager.cxx

@@ -209,7 +209,7 @@ setSpeakerSetup(SpeakerModeCategory cat) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: AudioManager::update()
-//       Access: Published
+//       Access: Published, Virtual
 //  Description: Must be called every frame.  Failure to call this
 //               every frame could cause problems for some audio
 //               managers.
@@ -296,7 +296,7 @@ float AudioManager::audio_3d_get_drop_off_factor() const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: AudioManager::get_dls_pathname
-//       Access: Public
+//       Access: Published, Static
 //  Description: Returns the full pathname to the DLS file, as
 //               specified by the Config.prc file, or the default for
 //               the current OS if appropriate.  Returns empty string
@@ -337,3 +337,23 @@ get_dls_pathname() {
   return Filename();
 #endif
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: AudioManager::output
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void AudioManager::
+output(ostream &out) const {
+  out << get_type();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AudioManager::write
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void AudioManager::
+write(ostream &out) const {
+  out << (*this) << "\n";
+}

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

@@ -216,7 +216,10 @@ PUBLISHED:
   virtual void audio_3d_set_drop_off_factor(float factor);
   virtual float audio_3d_get_drop_off_factor() const;
 
-  Filename get_dls_pathname();
+  static Filename get_dls_pathname();
+
+  virtual void output(ostream &out) const;
+  virtual void write(ostream &out) const;
 
 public:
   static void register_AudioManager_creator(Create_AudioManager_proc* proc);
@@ -251,4 +254,10 @@ private:
   static TypeHandle _type_handle;
 };
 
+inline ostream &
+operator << (ostream &out, const AudioManager &mgr) {
+  mgr.output(out);
+  return out;
+}
+
 #endif /* __AUDIO_MANAGER_H__ */

+ 45 - 6
panda/src/audio/audioSound.cxx

@@ -74,7 +74,7 @@ get_3d_max_distance() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AudioManager::add_dsp
+//     Function: AudioSound::add_dsp
 //       Access: Published
 //  Description: 
 ////////////////////////////////////////////////////////////////////
@@ -85,7 +85,7 @@ add_dsp(PT(AudioDSP) x) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AudioManager::remove_dsp
+//     Function: AudioSound::remove_dsp
 //       Access: Published
 //  Description: 
 ////////////////////////////////////////////////////////////////////
@@ -97,7 +97,7 @@ remove_dsp(PT(AudioDSP) x) {
 
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AudioManager::getSpeakerMix
+//     Function: AudioSound::getSpeakerMix
 //       Access: Published
 //  Description: 
 ////////////////////////////////////////////////////////////////////
@@ -108,7 +108,7 @@ get_speaker_mix(int speaker) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AudioManager::setSpeakerMix
+//     Function: AudioSound::setSpeakerMix
 //       Access: Published
 //  Description: 
 ////////////////////////////////////////////////////////////////////
@@ -119,7 +119,7 @@ set_speaker_mix(float frontleft, float frontright, float center, float sub, floa
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AudioManager::get_priority
+//     Function: AudioSound::get_priority
 //       Access: Published
 //  Description: 
 ////////////////////////////////////////////////////////////////////
@@ -130,7 +130,7 @@ get_priority() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AudioManager::set_priority
+//     Function: AudioSound::set_priority
 //       Access: Published
 //  Description: 
 ////////////////////////////////////////////////////////////////////
@@ -140,3 +140,42 @@ set_priority(int priority) {
 	;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: AudioSound::output
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void AudioSound::
+output(ostream &out) const {
+  out << get_type() << " " << get_name() << " " << status();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AudioSound::write
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void AudioSound::
+write(ostream &out) const {
+  out << (*this) << "\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AudioSound::SoundStatus::output operator
+//  Description: 
+////////////////////////////////////////////////////////////////////
+ostream &
+operator << (ostream &out, AudioSound::SoundStatus status) {
+  switch (status) {
+  case AudioSound::BAD:
+    return out << "BAD";
+
+  case AudioSound::READY:
+    return out << "READY";
+
+  case AudioSound::PLAYING:
+    return out << "PLAYING";
+  }
+
+  return out << "**invalid AudioSound::SoundStatus(" << (int)status << ")**";
+}

+ 141 - 130
panda/src/audio/audioSound.h

@@ -28,137 +28,148 @@
 
 class AudioManager;
 
-
 class EXPCL_PANDA_AUDIO AudioSound : public TypedReferenceCount {
-	PUBLISHED:
-		virtual ~AudioSound();
-		  
-		// For best compatability, set the loop_count,
-		// 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.
-		// - Calling play() a second time on the same sound before it is
-		//   finished will start the sound again (creating a skipping or
-		//   stuttering effect).
-		virtual void play() = 0;
-		virtual void stop() = 0;
-		  
-		// loop: false = play once; true = play forever.
-		// inits to false.
-		virtual void set_loop(bool loop=true) = 0;
-		virtual bool get_loop() const = 0;
-		  
-		// loop_count: 0 = forever; 1 = play once; n = play n times.
-		// inits to 1.
-		virtual void set_loop_count(unsigned long loop_count=1) = 0;
-		virtual unsigned long get_loop_count() const = 0;
-		  
-		// Control time position within the sound.
-		// This is similar (in concept) to the seek position within
-		// a file.
-		// time in seconds: 0 = beginning; length() = end.
-		// inits to 0.0.
-		// - Unlike the other get_* and set_* calls for a sound, the
-		//   current time position will change while the sound is playing.
-		//   To play the same sound from a time offset a second time,
-		//   explicitly set the time position again.  When looping, the
-		//   second and later loops will start from the beginning of the
-		//   sound.
-		// - If a sound is playing, calling get_time() repeatedly will
-		//   return different results over time.  e.g.:
-		//   float percent_complete = s.get_time() / s.length();
-		virtual void set_time(float start_time=0.0) = 0;
-		virtual float get_time() const = 0;
-		  
-		// 0 = minimum; 1.0 = maximum.
-		// inits to 1.0.
-		virtual void set_volume(float volume=1.0) = 0;
-		virtual float get_volume() const = 0;
-		  
-		// -1.0 is hard left
-		// 0.0 is centered
-		// 1.0 is hard right
-		// inits to 0.0.
-		virtual void set_balance(float balance_right=0.0) = 0;
-		virtual float get_balance() const = 0;
-		  
-		// play_rate is any positive float value.
-		// inits to 1.0.
-		virtual void set_play_rate(float play_rate=1.0f) = 0;
-		virtual float get_play_rate() const = 0;
-
-		// inits to manager's state.
-		virtual void set_active(bool flag=true) = 0;
-		virtual bool get_active() const = 0;
-
-		// Set (or clear) the event that will be thrown when the sound
-		// finishes playing.  To clear the event, pass an empty string.
-		virtual void set_finished_event(const string& event) = 0;
-		virtual const string& get_finished_event() const = 0;
-		  
-		// There is no set_name(), this is intentional.
-		virtual const string& get_name() const = 0;
-		  
-		// return: playing time in seconds.
-		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).
-		virtual void set_3d_attributes(float px, float py, float pz,
-										float vx, float vy, float vz);
-		virtual void get_3d_attributes(float *px, float *py, float *pz,
-										float *vx, float *vy, float *vz);
-
-
-		// Controls the distance (in units) that this sound begins to fall off.
-		// Also affects the rate it falls off.
-		// Default is 1.0
-		// Closer/Faster, <1.0
-		// Farther/Slower, >1.0
-		virtual void set_3d_min_distance(float dist);
-		virtual float get_3d_min_distance() const;
-
-		// Controls the maximum distance (in units) that this sound stops falling off.
-		// The sound does not stop at that point, it just doesn't get any quieter.
-		// You should rarely need to adjust this.
-		// Default is 1000000000.0
-		virtual void set_3d_max_distance(float dist);
-		virtual float get_3d_max_distance() const;
-
-		virtual bool add_dsp(PT(AudioDSP) x);
-		virtual bool remove_dsp(PT(AudioDSP) x);
-
-		virtual float get_speaker_mix(int speaker);
-		virtual void set_speaker_mix(float frontleft, float frontright, float center, float sub, float backleft, float backright, float sideleft, float  sideright);
-
-		virtual int get_priority();
-		virtual void set_priority(int priority);
-
-		enum SoundStatus { BAD, READY, PLAYING };
-		virtual SoundStatus status() const = 0;
-
-	protected:
-		AudioSound();
-
-		friend class AudioManager;
-
-	public:
-		static TypeHandle get_class_type() {
-			return _type_handle;
-		}
-		static void init_type() {
-			TypedReferenceCount::init_type();
-			register_type(_type_handle, "AudioSound",
-						TypedReferenceCount::get_class_type());
-		}
-		virtual TypeHandle get_type() const {
-			return get_class_type();
-		}
-		virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
-
-	private:
-		static TypeHandle _type_handle;
+PUBLISHED:
+  virtual ~AudioSound();
+          
+  // For best compatability, set the loop_count,
+  // 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.
+  // - Calling play() a second time on the same sound before it is
+  //   finished will start the sound again (creating a skipping or
+  //   stuttering effect).
+  virtual void play() = 0;
+  virtual void stop() = 0;
+          
+  // loop: false = play once; true = play forever.
+  // inits to false.
+  virtual void set_loop(bool loop=true) = 0;
+  virtual bool get_loop() const = 0;
+          
+  // loop_count: 0 = forever; 1 = play once; n = play n times.
+  // inits to 1.
+  virtual void set_loop_count(unsigned long loop_count=1) = 0;
+  virtual unsigned long get_loop_count() const = 0;
+          
+  // Control time position within the sound.
+  // This is similar (in concept) to the seek position within
+  // a file.
+  // time in seconds: 0 = beginning; length() = end.
+  // inits to 0.0.
+  // - Unlike the other get_* and set_* calls for a sound, the
+  //   current time position will change while the sound is playing.
+  //   To play the same sound from a time offset a second time,
+  //   explicitly set the time position again.  When looping, the
+  //   second and later loops will start from the beginning of the
+  //   sound.
+  // - If a sound is playing, calling get_time() repeatedly will
+  //   return different results over time.  e.g.:
+  //   float percent_complete = s.get_time() / s.length();
+  virtual void set_time(float start_time=0.0) = 0;
+  virtual float get_time() const = 0;
+          
+  // 0 = minimum; 1.0 = maximum.
+  // inits to 1.0.
+  virtual void set_volume(float volume=1.0) = 0;
+  virtual float get_volume() const = 0;
+          
+  // -1.0 is hard left
+  // 0.0 is centered
+  // 1.0 is hard right
+  // inits to 0.0.
+  virtual void set_balance(float balance_right=0.0) = 0;
+  virtual float get_balance() const = 0;
+          
+  // play_rate is any positive float value.
+  // inits to 1.0.
+  virtual void set_play_rate(float play_rate=1.0f) = 0;
+  virtual float get_play_rate() const = 0;
+
+  // inits to manager's state.
+  virtual void set_active(bool flag=true) = 0;
+  virtual bool get_active() const = 0;
+
+  // Set (or clear) the event that will be thrown when the sound
+  // finishes playing.  To clear the event, pass an empty string.
+  virtual void set_finished_event(const string& event) = 0;
+  virtual const string& get_finished_event() const = 0;
+          
+  // There is no set_name(), this is intentional.
+  virtual const string& get_name() const = 0;
+          
+  // return: playing time in seconds.
+  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).
+  virtual void set_3d_attributes(float px, float py, float pz,
+                                 float vx, float vy, float vz);
+  virtual void get_3d_attributes(float *px, float *py, float *pz,
+                                 float *vx, float *vy, float *vz);
+
+
+  // Controls the distance (in units) that this sound begins to fall off.
+  // Also affects the rate it falls off.
+  // Default is 1.0
+  // Closer/Faster, <1.0
+  // Farther/Slower, >1.0
+  virtual void set_3d_min_distance(float dist);
+  virtual float get_3d_min_distance() const;
+
+  // Controls the maximum distance (in units) that this sound stops falling off.
+  // The sound does not stop at that point, it just doesn't get any quieter.
+  // You should rarely need to adjust this.
+  // Default is 1000000000.0
+  virtual void set_3d_max_distance(float dist);
+  virtual float get_3d_max_distance() const;
+
+  virtual bool add_dsp(PT(AudioDSP) x);
+  virtual bool remove_dsp(PT(AudioDSP) x);
+
+  virtual float get_speaker_mix(int speaker);
+  virtual void set_speaker_mix(float frontleft, float frontright, float center, float sub, float backleft, float backright, float sideleft, float  sideright);
+
+  virtual int get_priority();
+  virtual void set_priority(int priority);
+
+  enum SoundStatus { BAD, READY, PLAYING };
+  virtual SoundStatus status() const = 0;
+
+  virtual void output(ostream &out) const;
+  virtual void write(ostream &out) const;
+
+protected:
+  AudioSound();
+
+  friend class AudioManager;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedReferenceCount::init_type();
+    register_type(_type_handle, "AudioSound",
+                  TypedReferenceCount::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
 };
 
+inline ostream &
+operator << (ostream &out, const AudioSound &sound) {
+  sound.output(out);
+  return out;
+}
+
+EXPCL_PANDA_AUDIO ostream &
+operator << (ostream &out, AudioSound::SoundStatus status);
+
 #endif /* __AUDIOSOUND_H__ */

+ 9 - 3
panda/src/audiotraits/Sources.pp

@@ -8,7 +8,7 @@
   #define BUILD_TARGET $[HAVE_RAD_MSS]
   #define USE_PACKAGES rad_mss
   #define BUILDING_DLL BUILDING_MILES_AUDIO
-  #define LOCAL_LIBS audio event
+  #define LOCAL_LIBS audio event pipeline
   #define WIN_SYS_LIBS $[WIN_SYS_LIBS] user32.lib advapi32.lib winmm.lib
   
   #define COMBINED_SOURCES $[TARGET]_composite1.cxx  
@@ -16,10 +16,16 @@
   #define SOURCES \
       config_milesAudio.h \
       milesAudioManager.h \
-      milesAudioSound.I milesAudioSound.h
+      milesAudioSound.I milesAudioSound.h \
+      milesAudioSample.I milesAudioSample.h \
+      milesAudioSequence.I milesAudioSequence.h \
+      milesAudioStream.I milesAudioStream.h \
+      globalMilesManager.I globalMilesManager.h
       
   #define INCLUDED_SOURCES \
-      config_milesAudio.cxx milesAudioManager.cxx milesAudioSound.cxx 
+      config_milesAudio.cxx milesAudioManager.cxx milesAudioSound.cxx \
+      milesAudioStream.cxx globalMilesManager.cxx milesAudioSample.cxx \
+      milesAudioSequence.cxx
 
 #end lib_target
 

+ 25 - 9
panda/src/audiotraits/config_milesAudio.cxx

@@ -22,6 +22,9 @@
 #include "config_milesAudio.h"
 #include "milesAudioManager.h"
 #include "milesAudioSound.h"
+#include "milesAudioSample.h"
+#include "milesAudioSequence.h"
+#include "milesAudioStream.h"
 #include "pandaSystem.h"
 #include "dconfig.h"
 
@@ -42,16 +45,26 @@ ConfigVariableInt miles_audio_expand_mp3_threshold
           "work around problems with Miles being unable to correctly "
           "report the length of, or seek within, a variable bit-rate encoded "
           "MP3 file.  Any MP3 file whose length in bytes is less than "
-          "this value will be expanded."));
+          "this value will be expanded.  This only applies to files "
+          "within the miles-audio-preload-threshold."));
 
-ConfigVariableInt miles_audio_calc_mp3_threshold
-("miles-audio-calc-mp3-threshold", 1048576,
- PRC_DESC("This is a second fallback for miles-audio-expand-mp3-threshold.  "
-          "Any MP3 file whose length in bytes is less than this value "
-          "will have its length calculated on demand, by running through "
-          "the entire file first.  This works around a Miles bug in "
-          "which variable bit-rate encoded MP3 files do not report an "
-          "accurate length."));
+ConfigVariableInt miles_audio_preload_threshold
+("miles-audio-preload-threshold", -1,
+ PRC_DESC("This is the last Miles fallback size, and should be no smaller "
+          "than both miles-audio-expand-mp3-threshold and "
+          "miles-audio-calc-mp3-threshold.  Files that are smaller "
+          "than this number of bytes will be preloaded and kept "
+          "resident in memory, while files that are this size or larger "
+          "will be streamed from disk.  Set this to -1 to preload "
+          "every file."));
+
+ConfigVariableBool miles_audio_panda_threads
+("miles-audio-panda-threads", true,
+ PRC_DESC("Set this true to service Miles background audio via Panda's "
+          "threading interface, instead of Miles' built-in threading "
+          "interface.  This gives Panda more control over the threading, "
+          "and ensures better lock protection within Panda.  This has "
+          "no meaning unless Panda is compiled with thread support."));
 
 ////////////////////////////////////////////////////////////////////
 //     Function: init_libMilesAudio
@@ -73,6 +86,9 @@ init_libMilesAudio() {
 
   MilesAudioManager::init_type();
   MilesAudioSound::init_type();
+  MilesAudioSample::init_type();
+  MilesAudioSequence::init_type();
+  MilesAudioStream::init_type();
 
   PandaSystem *ps = PandaSystem::get_global_ptr();
   ps->add_system("Miles");

+ 2 - 1
panda/src/audiotraits/config_milesAudio.h

@@ -32,7 +32,8 @@ NotifyCategoryDecl(milesAudio, EXPCL_MILES_AUDIO, EXPTP_MILES_AUDIO);
 
 extern ConfigVariableBool miles_audio_force_midi_reset;
 extern ConfigVariableInt miles_audio_expand_mp3_threshold;
-extern ConfigVariableInt miles_audio_calc_mp3_threshold;
+extern ConfigVariableInt miles_audio_preload_threshold;
+extern ConfigVariableBool miles_audio_panda_threads;
 
 extern EXPCL_MILES_AUDIO void init_libMilesAudio();
 

+ 29 - 0
panda/src/audiotraits/globalMilesManager.I

@@ -0,0 +1,29 @@
+// Filename: globalMilesManager.I
+// Created by:  drose (30Jul07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: GlobalMilesManager::is_open
+//       Access: Public
+//  Description: Returns true if the Miles Sound System is open (and
+//               active), false if it is not.
+////////////////////////////////////////////////////////////////////
+INLINE bool GlobalMilesManager::
+is_open() const {
+  return _is_open;
+}

+ 489 - 0
panda/src/audiotraits/globalMilesManager.cxx

@@ -0,0 +1,489 @@
+// Filename: globalMilesManager.cxx
+// Created by:  drose (26Jul07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "globalMilesManager.h"
+
+#ifdef HAVE_RAD_MSS //[
+
+#include "mutexHolder.h"
+#include "milesAudioManager.h"
+#include "milesAudioSample.h"
+#include "milesAudioSequence.h"
+
+GlobalMilesManager *GlobalMilesManager::_global_ptr;
+
+////////////////////////////////////////////////////////////////////
+//     Function: GlobalMilesManager::Constructor
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+GlobalMilesManager::
+GlobalMilesManager() : 
+  _managers_lock("GlobalMilesManager::_managers_lock"),
+  _samples_lock("GlobalMilesManager::_samples_lock"),
+  _sequences_lock("GlobalMilesManager::_sequences_lock")
+{
+  _digital_driver = 0;
+  _midi_driver = 0;
+  _dls_device = 0;
+  _dls_file = 0;
+  _is_open = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GlobalMilesManager::add_manager
+//       Access: Public
+//  Description: Records a new MilesAudioManager in the world.  This
+//               will open the Miles API when the first audio manager
+//               is added.
+////////////////////////////////////////////////////////////////////
+void GlobalMilesManager::
+add_manager(MilesAudioManager *manager) {
+  MutexHolder holder(_managers_lock);
+  _managers.insert(manager);
+  if (!_is_open) {
+    open_api();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GlobalMilesManager::remove_manager
+//       Access: Public
+//  Description: Records that a MilesAudioManager is destructing.
+//               This will clsoe the Miles API when the last audio
+//               manager is removed.
+////////////////////////////////////////////////////////////////////
+void GlobalMilesManager::
+remove_manager(MilesAudioManager *manager) {
+  MutexHolder holder(_managers_lock);
+  _managers.erase(manager);
+  if (_managers.empty() && _is_open) {
+    close_api();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GlobalMilesManager::cleanup
+//       Access: Public
+//  Description: Calls cleanup() on all MilesAudioManagers, to cause a
+//               clean shutdown.
+////////////////////////////////////////////////////////////////////
+void GlobalMilesManager::
+cleanup() {
+  MutexHolder holder(_managers_lock);
+  Managers::iterator mi;
+  for (mi = _managers.begin(); mi != _managers.end(); ++mi) {
+    (*mi)->cleanup();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GlobalMilesManager::get_sample
+//       Access: Public
+//  Description: Gets a sample handle from the global pool for the
+//               digital output device, to be used with the indicated
+//               AudioSound.  
+//
+//               If successful, sets the sample handle and the index
+//               (which should later be used to release the sample)
+//               and returns true.  If unsuccessful (because there are
+//               no more available handles), returns false.
+//
+//               This is a very limited resource; you should only get
+//               a sample just before playing a sound.
+////////////////////////////////////////////////////////////////////
+bool GlobalMilesManager::
+get_sample(HSAMPLE &sample, size_t &index, MilesAudioSample *sound) {
+  MutexHolder holder(_samples_lock);
+
+  for (size_t i = 0; i < _samples.size(); ++i) {
+    SampleData &smp = _samples[i];
+    if (AIL_sample_status(smp._sample) == SMP_DONE) {
+      if (smp._sound != NULL) {
+        // Tell the last sound that was using this sample that it's
+        // done now.
+        smp._sound->internal_stop();
+      }
+      smp._sound = sound;
+      sample = smp._sample;
+      index = i;
+      return true;
+    }
+  }
+
+  // No more already-allocated samples; get a new one from the system.
+  sample = AIL_allocate_sample_handle(_digital_driver);
+  if (sample == 0) {
+    return false;
+  }
+  
+  AIL_init_sample(sample, DIG_F_STEREO_16, 0);
+  index = _samples.size();
+
+  SampleData smp;
+  smp._sound = sound;
+  smp._sample = sample;
+  _samples.push_back(smp);
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GlobalMilesManager::release_sample
+//       Access: Public
+//  Description: Indicates that the indicated AudioSound no longer
+//               needs this sample.
+////////////////////////////////////////////////////////////////////
+void GlobalMilesManager::
+release_sample(size_t index, MilesAudioSample *sound) {
+  MutexHolder holder(_samples_lock);
+  nassertv(index < _samples.size());
+
+  SampleData &smp = _samples[index];
+  if (smp._sound == sound) {
+    smp._sound = NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GlobalMilesManager::get_sequence
+//       Access: Public
+//  Description: Gets a sequence handle from the global pool for the
+//               digital output device, to be used with the indicated
+//               AudioSound.  
+//
+//               If successful, sets the sequence handle and the index
+//               (which should later be used to release the sequence)
+//               and returns true.  If unsuccessful (because there are
+//               no more available handles), returns false.
+//
+//               This is a very limited resource; you should only get
+//               a sequence just before playing a sound.
+////////////////////////////////////////////////////////////////////
+bool GlobalMilesManager::
+get_sequence(HSEQUENCE &sequence, size_t &index, MilesAudioSequence *sound) {
+  MutexHolder holder(_sequences_lock);
+
+  for (size_t i = 0; i < _sequences.size(); ++i) {
+    SequenceData &seq = _sequences[i];
+    if (AIL_sequence_status(seq._sequence) == SEQ_DONE) {
+      if (seq._sound != NULL) {
+        // Tell the last sound that was using this sequence that it's
+        // done now.
+        seq._sound->internal_stop();
+      }
+      seq._sound = sound;
+      sequence = seq._sequence;
+      index = i;
+      return true;
+    }
+  }
+
+  // No more already-allocated sequences; get a new one from the system.
+  sequence = AIL_allocate_sequence_handle(_midi_driver);
+  if (sequence == 0) {
+    return false;
+  }
+  
+  index = _sequences.size();
+
+  SequenceData seq;
+  seq._sound = sound;
+  seq._sequence = sequence;
+  _sequences.push_back(seq);
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GlobalMilesManager::release_sequence
+//       Access: Public
+//  Description: Indicates that the indicated AudioSound no longer
+//               needs this sequence.
+////////////////////////////////////////////////////////////////////
+void GlobalMilesManager::
+release_sequence(size_t index, MilesAudioSequence *sound) {
+  MutexHolder holder(_sequences_lock);
+  nassertv(index < _sequences.size());
+
+  SequenceData &seq = _sequences[index];
+  if (seq._sound == sound) {
+    seq._sound = NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GlobalMilesManager::force_midi_reset
+//       Access: Public
+//  Description: Sometimes Miles seems to leave midi notes hanging,
+//               even after stop is called, so call this method to
+//               perform an explicit reset using winMM.dll calls, just
+//               to ensure silence.
+////////////////////////////////////////////////////////////////////
+void GlobalMilesManager::
+force_midi_reset() {
+  if (!miles_audio_force_midi_reset) {
+    audio_debug("MilesAudioManager::skipping force_midi_reset");  
+    return;
+  }
+  audio_debug("MilesAudioManager::force_midi_reset");
+
+#ifdef WIN32
+  if ((_midi_driver!=NULL) && (_midi_driver->deviceid != MIDI_NULL_DRIVER) && (_midi_driver->hMidiOut != NULL)) {
+    audio_debug("MilesAudioManager::calling midiOutReset");
+    midiOutReset(_midi_driver->hMidiOut);
+  }
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GlobalMilesManager::get_global_ptr
+//       Access: Public, Static
+//  Description: Returns the pointer to the one GlobalMilesManager
+//               object.
+////////////////////////////////////////////////////////////////////
+GlobalMilesManager *GlobalMilesManager::
+get_global_ptr() {
+  if (_global_ptr == NULL) {
+    _global_ptr = new GlobalMilesManager;
+  }
+  return _global_ptr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GlobalMilesManager::open_api
+//       Access: Private
+//  Description: Called internally to initialize the Miles API.
+////////////////////////////////////////////////////////////////////
+void GlobalMilesManager::
+open_api() {
+  audio_debug("GlobalMilesManager::open_api()")
+  nassertv(!_is_open);
+
+  bool use_digital = (audio_play_wave || audio_play_mp3);
+  if (audio_play_midi && audio_software_midi) {
+    use_digital = true;
+  }
+
+#ifdef IS_OSX
+  audio_software_midi = true;
+#endif
+  
+  audio_debug("  use_digital="<<use_digital);
+  audio_debug("  audio_play_midi="<<audio_play_midi);
+  audio_debug("  audio_software_midi="<<audio_software_midi);
+  audio_debug("  audio_output_rate="<<audio_output_rate);
+  audio_debug("  audio_output_bits="<<audio_output_bits);
+  audio_debug("  audio_output_channels="<<audio_output_channels);
+  audio_debug("  audio_software_midi="<<audio_software_midi);
+
+#if !defined(NDEBUG) && defined(AIL_MSS_version) //[
+  char version[8];
+  AIL_MSS_version(version, 8);
+  audio_debug("  Mss32.dll Version: "<<version);
+#endif //]
+
+  if (!AIL_startup()) {
+    milesAudio_cat.warning()
+      << "Miles Sound System already initialized!\n";
+  }
+
+  AIL_set_file_callbacks(open_callback, close_callback,
+                         seek_callback, read_callback);
+
+  if (use_digital) {
+    _digital_driver = 
+      AIL_open_digital_driver(audio_output_rate, audio_output_bits, 
+                              audio_output_channels, 0);
+  }
+
+  if (audio_play_midi) {
+    if (audio_software_midi) {
+      _midi_driver = AIL_open_XMIDI_driver(AIL_OPEN_XMIDI_NULL_DRIVER);
+
+      // Load the downloadable sounds file:
+      _dls_device = AIL_DLS_open(_midi_driver, _digital_driver, NULL, 0,
+                                 audio_output_rate, audio_output_bits,
+                                 audio_output_channels);
+      
+      Filename dls_pathname = AudioManager::get_dls_pathname();
+
+      VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+      vfs->resolve_filename(dls_pathname, get_sound_path()) ||
+        vfs->resolve_filename(dls_pathname, get_model_path());
+
+      _dls_data.clear();
+      PT(VirtualFile) file = vfs->get_file(dls_pathname);
+      if (file == (VirtualFile *)NULL) {
+        milesAudio_cat.warning()
+          << "DLS file does not exist: " << dls_pathname << "\n";
+
+      } else if (!file->read_file(_dls_data, true)) {
+        milesAudio_cat.warning()
+          << "Could not read DLS file: " << dls_pathname << "\n";
+        
+      } else if (_dls_data.empty()) {
+        milesAudio_cat.warning()
+          << "DLS file is empty: " << dls_pathname << "\n";
+
+      } else {
+        _dls_file = AIL_DLS_load_memory(_dls_device, &_dls_data[0], 0);
+      }
+      
+      if (_dls_file == 0) {
+        audio_error("  Could not get DLS file, switching to hardware MIDI.");
+        AIL_DLS_close(_dls_device, 0);
+        _dls_device = 0;
+        AIL_close_XMIDI_driver(_midi_driver);
+        _midi_driver = AIL_open_XMIDI_driver(0);
+        
+      } else {
+        audio_info("  using Miles software midi");
+      }
+    } else {
+      _midi_driver = AIL_open_XMIDI_driver(0);
+      audio_info("  using Miles hardware midi");
+    }
+  }
+    
+  _is_open = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GlobalMilesManager::close_api
+//       Access: Private
+//  Description: Called internally to shut down the Miles API.
+////////////////////////////////////////////////////////////////////
+void GlobalMilesManager::
+close_api() {
+  audio_debug("GlobalMilesManager::close_api()")
+  nassertv(_is_open);
+
+  Samples::iterator si;
+  for (si = _samples.begin(); si != _samples.end(); ++si) {
+    SampleData &smp = (*si);
+    AIL_release_sample_handle(smp._sample);
+  }
+  _samples.clear();
+
+  Sequences::iterator qi;
+  for (qi = _sequences.begin(); qi != _sequences.end(); ++qi) {
+    SequenceData &smp = (*qi);
+    AIL_release_sequence_handle(smp._sequence);
+  }
+  _sequences.clear();
+
+  if (_dls_file != 0) {
+    AIL_DLS_unload(_dls_device, _dls_file);
+    _dls_file = 0;
+  }
+
+  if (_dls_device != 0) {
+    AIL_DLS_close(_dls_device, 0);
+    _dls_device = 0;
+  }
+
+  if (_midi_driver != 0) {
+    AIL_close_XMIDI_driver(_midi_driver);
+    _midi_driver = 0;
+  }
+
+  if (_digital_driver != 0) {
+    AIL_close_digital_driver(_digital_driver);
+    _digital_driver = 0;
+  }
+
+  AIL_shutdown();
+
+  _is_open = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GlobalMilesManager::open_callback
+//       Access: Private, Static
+//  Description: This callback function is given to Miles to handle
+//               file I/O via the Panda VFS.  It's only used to
+//               implemented streaming audio files, since in all other
+//               cases we open files directly.
+////////////////////////////////////////////////////////////////////
+U32 AILCALLBACK GlobalMilesManager::
+open_callback(char const *filename, UINTa *file_handle) {
+  VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+  istream *strm = vfs->open_read_file(Filename::binary_filename(filename), true);
+  if (strm == NULL) {
+    // Failure.
+    return 0;
+  }
+  // Success.
+  (*file_handle) = (UINTa)strm;
+  return 1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GlobalMilesManager::close_callback
+//       Access: Private, Static
+//  Description: This callback function is given to Miles to handle
+//               file I/O via the Panda VFS.
+////////////////////////////////////////////////////////////////////
+void AILCALLBACK GlobalMilesManager::
+close_callback(UINTa file_handle) {
+  istream *strm = (istream *)file_handle;
+  VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+  vfs->close_read_file(strm);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GlobalMilesManager::seek_callback
+//       Access: Private, Static
+//  Description: This callback function is given to Miles to handle
+//               file I/O via the Panda VFS.
+////////////////////////////////////////////////////////////////////
+S32 AILCALLBACK GlobalMilesManager::
+seek_callback(UINTa file_handle, S32 offset, U32 type) {
+  istream *strm = (istream *)file_handle;
+  strm->clear();
+  switch (type) {
+  case AIL_FILE_SEEK_BEGIN:
+    strm->seekg(offset, ios::beg);
+    break;
+
+  case AIL_FILE_SEEK_CURRENT:
+    strm->seekg(offset, ios::cur);
+    break;
+
+  case AIL_FILE_SEEK_END:
+    strm->seekg(offset, ios::end);
+    break;
+  }
+
+  return strm->tellg();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GlobalMilesManager::read_callback
+//       Access: Private, Static
+//  Description: This callback function is given to Miles to handle
+//               file I/O via the Panda VFS.
+////////////////////////////////////////////////////////////////////
+U32 AILCALLBACK GlobalMilesManager::
+read_callback(UINTa file_handle, void *buffer, U32 bytes) {
+  istream *strm = (istream *)file_handle;
+  strm->read((char *)buffer, bytes);
+  return strm->gcount();
+}
+
+#endif //]
+

+ 114 - 0
panda/src/audiotraits/globalMilesManager.h

@@ -0,0 +1,114 @@
+// Filename: globalMilesManager.h
+// Created by:  drose (26Jul07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef GLOBALMILESMANAGER_H
+#define GLOBALMILESMANAGER_H
+
+#include "pandabase.h"
+#ifdef HAVE_RAD_MSS //[
+
+#include "mss.h"
+#include "pset.h"
+#include "pmutex.h"
+
+class MilesAudioSample;
+class MilesAudioSequence;
+
+////////////////////////////////////////////////////////////////////
+//       Class : GlobalMilesManager
+// Description : This is a wrapper around the parts of the Miles API
+//               that should only be created once.  This represents
+//               the global data common to all MilesAudioManagers.
+////////////////////////////////////////////////////////////////////
+class EXPCL_MILES_AUDIO GlobalMilesManager {
+private:
+  GlobalMilesManager();
+
+public:
+  void add_manager(MilesAudioManager *manager);
+  void remove_manager(MilesAudioManager *manager);
+  void cleanup();
+  INLINE bool is_open() const;
+
+  bool get_sample(HSAMPLE &sample, size_t &index, MilesAudioSample *sound);
+  void release_sample(size_t index, MilesAudioSample *sound);
+
+  bool get_sequence(HSEQUENCE &sequence, size_t &index, MilesAudioSequence *sound);
+  void release_sequence(size_t index, MilesAudioSequence *sound);
+
+  void force_midi_reset();
+
+  static GlobalMilesManager *get_global_ptr();
+
+public:
+  HDIGDRIVER _digital_driver;
+  HMDIDRIVER _midi_driver;
+
+  // For software MIDI:
+  HDLSDEVICE _dls_device;
+  HDLSFILEID _dls_file;
+  pvector<unsigned char> _dls_data;
+
+private:
+  void open_api();
+  void close_api();
+
+  static U32 AILCALLBACK open_callback(char const *filename, UINTa *file_handle);
+  static void AILCALLBACK close_callback(UINTa file_handle);
+  static S32 AILCALLBACK seek_callback(UINTa file_handle, S32 offset, U32 type);
+  static U32 AILCALLBACK read_callback(UINTa file_handle, void *buffer, U32 bytes);
+
+
+private:
+  bool _is_open;
+
+  typedef pset<MilesAudioManager *> Managers;
+  Managers _managers;
+  Mutex _managers_lock;
+
+  class SampleData {
+  public:
+    HSAMPLE _sample;
+    MilesAudioSample *_sound;
+  };
+
+  typedef pvector<SampleData> Samples;
+  Samples _samples;
+  Mutex _samples_lock;
+
+  class SequenceData {
+  public:
+    HSEQUENCE _sequence;
+    MilesAudioSequence *_sound;
+  };
+
+  typedef pvector<SequenceData> Sequences;
+  Sequences _sequences;
+  Mutex _sequences_lock;
+  
+  static GlobalMilesManager *_global_ptr;
+};
+
+#include "globalMilesManager.I"
+
+#endif //]
+
+#endif
+
+
+  

文件差异内容过多而无法显示
+ 430 - 351
panda/src/audiotraits/milesAudioManager.cxx


+ 65 - 46
panda/src/audiotraits/milesAudioManager.h

@@ -29,6 +29,9 @@
 #include "pmap.h"
 #include "pdeque.h"
 #include "pvector.h"
+#include "thread.h"
+#include "pmutex.h"
+#include "conditionVar.h"
 
 class MilesAudioSound;
 
@@ -37,35 +40,69 @@ public:
   // See AudioManager.h for documentation.
   
   MilesAudioManager();
-  ~MilesAudioManager();
-
+  virtual ~MilesAudioManager();
+  
   virtual void shutdown();
 
-  bool is_valid();
+  virtual bool is_valid();
   
-  virtual PT(AudioSound) get_sound(const string& file_name, bool positional = false);
-  void uncache_sound(const string& file_name);
-  void clear_cache();
-  void set_cache_limit(unsigned int count);
-  unsigned int get_cache_limit() const;
+  virtual PT(AudioSound) get_sound(const string &file_name, bool positional = false);
+  virtual void uncache_sound(const string &file_name);
+  virtual void clear_cache();
+  virtual void set_cache_limit(unsigned int count);
+  virtual unsigned int get_cache_limit() const;
 
-  void set_volume(float volume);
-  float get_volume() const;
+  virtual void set_volume(float volume);
+  virtual float get_volume() const;
 
   void set_play_rate(float play_rate);
   float get_play_rate() const;
   
-  void set_active(bool active);
-  bool get_active() const;
+  virtual void set_active(bool active);
+  virtual bool get_active() const;
+
+  virtual void set_concurrent_sound_limit(unsigned int limit = 0);
+  virtual unsigned int get_concurrent_sound_limit() const;
+
+  virtual void reduce_sounds_playing_to(unsigned int count);
+
+  virtual void stop_all_sounds();
+
+  virtual void update();
+
+  // Tell the manager that the sound dtor was called.
+  void release_sound(MilesAudioSound *audioSound);
+  void cleanup();
+
+  virtual void output(ostream &out) const;
+  virtual void write(ostream &out) const;
+
+private:
+  void start_service_stream(HSTREAM stream);
+  void stop_service_stream(HSTREAM stream);
+  
+  void most_recently_used(const string &path);
+  void uncache_a_sound();
 
-  void set_concurrent_sound_limit(unsigned int limit = 0);
-  unsigned int get_concurrent_sound_limit() const;
+  void starting_sound(MilesAudioSound *audio);
+  void stopping_sound(MilesAudioSound *audio);
 
-  void reduce_sounds_playing_to(unsigned int count);
+  class SoundData;
+  PT(SoundData) load(const Filename &file_name);
 
-  void stop_all_sounds();
+  void thread_main(volatile bool &keep_running);
+  void do_service_streams();
 
 private:
+  class StreamThread : public Thread {
+  public:
+    StreamThread(MilesAudioManager *mgr);
+    virtual void thread_main();
+
+    MilesAudioManager *_mgr;
+    volatile bool _keep_running;
+  };
+
   // The sound cache:
   class SoundData : public ReferenceCount {
   public:
@@ -73,8 +110,7 @@ private:
     ~SoundData();
     float get_length();
 
-    string _basename;
-    HAUDIO _audio;
+    Filename _basename;
     S32 _file_type;
     pvector<unsigned char> _raw_data;
     bool _has_length;
@@ -83,7 +119,7 @@ private:
   typedef pmap<string, PT(SoundData) > SoundMap;
   SoundMap _sounds;
 
-  typedef pset<MilesAudioSound* > AudioSet;
+  typedef pset<MilesAudioSound *> AudioSet;
   // The offspring of this manager:
   AudioSet _sounds_on_loan;
 
@@ -100,38 +136,16 @@ private:
   bool _active;
   int _cache_limit;
   bool _cleanup_required;
-  // keep a count for startup and shutdown:
-  static int _active_managers;
-  static bool _miles_active;
   unsigned int _concurrent_sound_limit;
   
   bool _is_valid;
   bool _hasMidiSounds;
 
-  // Optional Downloadable Sound field for software midi
-  static HDLSFILEID _dls_field;
-
-  typedef pset<MilesAudioManager *> Managers;
-  static Managers *_managers;
-  
-  PT(SoundData) load(Filename file_name);
-  // Tell the manager that the sound dtor was called.
-  void release_sound(MilesAudioSound* audioSound);
-  
-  void most_recently_used(const string& path);
-  void uncache_a_sound();
-
-  void starting_sound(MilesAudioSound* audio);
-  void stopping_sound(MilesAudioSound* audio);
-
-  // get the default dls file path:
-  void get_gm_file_path(string& result);
-
-  void force_midi_reset();
-  void cleanup();
-
-  friend class MilesAudioSound;
-
+  typedef pvector<HSTREAM> Streams;
+  PT(StreamThread) _stream_thread;
+  Streams _streams;
+  Mutex _streams_lock;
+  ConditionVar _streams_cvar;
 
 public:
   static TypeHandle get_class_type() {
@@ -149,6 +163,11 @@ public:
 
 private:
   static TypeHandle _type_handle;
+
+  friend class MilesAudioSound;
+  friend class MilesAudioSample;
+  friend class MilesAudioSequence;
+  friend class MilesAudioStream;
 };
 
 EXPCL_MILES_AUDIO PT(AudioManager) Create_AudioManager();

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

@@ -0,0 +1,24 @@
+// Filename: milesAudioSample.I
+// Created by:  skyler (June 6, 2001)
+// Prior system by: cary
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+
+
+
+

+ 309 - 0
panda/src/audiotraits/milesAudioSample.cxx

@@ -0,0 +1,309 @@
+// Filename: milesAudioSample.cxx
+// Created by:  skyler (June 6, 2001)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "milesAudioSample.h"
+
+#ifdef HAVE_RAD_MSS //[
+
+#include "milesAudioManager.h"
+
+
+TypeHandle MilesAudioSample::_type_handle;
+
+#undef miles_audio_debug
+
+#ifndef NDEBUG //[
+#define miles_audio_debug(x) \
+    audio_debug("MilesAudioSample \""<<get_name()<<"\" "<< x )
+#else //][
+#define miles_audio_debug(x) ((void)0)
+#endif //]
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::Constructor
+//       Access: Private
+//  Description: This constructor is called only by the
+//               MilesAudioManager.
+////////////////////////////////////////////////////////////////////
+MilesAudioSample::
+MilesAudioSample(MilesAudioManager *manager, MilesAudioManager::SoundData *sd, 
+                 const string &file_name) :
+  MilesAudioSound(manager, file_name),
+  _sd(sd)
+{
+  nassertv(sd != NULL);
+  audio_debug("MilesAudioSample(manager=0x"<<(void*)&manager
+              <<", sd=0x"<<(void*)sd<<", file_name="<<file_name<<")");
+
+  _sample = 0;
+  _sample_index = 0;
+  _original_playback_rate = 1.0f;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+MilesAudioSample::
+~MilesAudioSample() {
+  miles_audio_debug("~MilesAudioSample()");
+  cleanup();
+  _manager->release_sound(this);
+  miles_audio_debug("~MilesAudioSample() done");
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::play
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioSample::
+play() {
+  miles_audio_debug("play()");
+  if (_active) {
+    if (_sd->_raw_data.empty()) {
+      milesAudio_cat.warning()
+        << "Could not play " << _file_name << ": no data\n";
+    } else {
+      stop();
+      _manager->starting_sound(this);
+
+      nassertv(_sample == 0);
+
+      GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
+      if (!mgr->get_sample(_sample, _sample_index, this)){ 
+        milesAudio_cat.warning()
+          << "Could not play " << _file_name << ": too many open samples\n";
+        _sample = 0;
+      } else {
+        AIL_set_named_sample_file(_sample, _sd->_basename.c_str(), 
+                                  &_sd->_raw_data[0], _sd->_raw_data.size(),
+                                  0);
+        _original_playback_rate = AIL_sample_playback_rate(_sample);
+
+        set_volume(_volume);
+        set_play_rate(_play_rate);
+        AIL_set_sample_loop_count(_sample, _loop_count);
+        AIL_start_sample(_sample);
+      }
+    }
+  } else {
+    // In case _loop_count gets set to forever (zero):
+    audio_debug("  paused "<<_file_name );
+    _paused = true;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::stop
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioSample::
+stop() {
+  miles_audio_debug("stop()");
+  _manager->stopping_sound(this);
+  // The _paused flag should not be cleared here.  _paused is not like
+  // the Pause button on a cd/dvd player.  It is used as a flag to say
+  // that it was looping when it was set inactive.  There is no need to
+  // make this symmetrical with play().  set_active() is the 'owner' of
+  // _paused.  play() accesses _paused to help in the situation where
+  // someone calls play on an inactive sound().
+
+  if (_sample != 0) {
+    AIL_end_sample(_sample);
+
+    GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
+    mgr->release_sample(_sample_index, this);
+
+    _sample = 0;
+    _sample_index = 0;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::set_time
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioSample::
+set_time(float time) {
+  miles_audio_debug("set_time(time="<<time<<")");
+
+  if (_sample != 0) {
+    // Ensure we don't inadvertently run off the end of the sound.
+    float max_time = length();
+    if (time > max_time) {
+      milesAudio_cat.warning()
+        << "set_time(" << time << ") requested for sound of length " 
+        << max_time << "\n";
+      time = max_time;
+    }
+    
+    S32 time_ms = (S32)(1000.0f * time);
+    AIL_set_sample_ms_position(_sample, time_ms);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::get_time
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float MilesAudioSample::
+get_time() const {
+  if (_sample == 0) {
+    return 0.0f;
+  }
+
+  S32 current_ms;
+  AIL_sample_ms_position(_sample, NULL, &current_ms);
+  float time = float(current_ms * 0.001f);
+
+  return time;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::set_volume
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioSample::
+set_volume(float volume) {
+  miles_audio_debug("set_volume(volume="<<volume<<")");
+
+  // Set the volume even if our volume is not changing, because the
+  // MilesAudioManager will call set_volume() when *its* volume
+  // changes.
+
+  // Set the volume:
+  _volume = volume;
+
+  if (_sample != 0) {
+    volume *= _manager->get_volume();
+    
+    // Change to Miles volume, range 0 to 1.0:
+    F32 milesVolume = volume;
+    milesVolume = min(milesVolume, 1.0f);
+    milesVolume = max(milesVolume, 0.0f);
+    
+    // Convert balance of -1.0..1.0 to 0-1.0:
+    F32 milesBalance = (F32)((_balance + 1.0f) * 0.5f);
+    
+    AIL_set_sample_volume_pan(_sample, milesVolume, milesBalance);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::set_balance
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioSample::
+set_balance(float balance_right) {
+  miles_audio_debug("set_balance(balance_right="<<balance_right<<")");
+  _balance = balance_right;
+
+  // Call set_volume to effect the change:
+  set_volume(_volume);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::set_play_rate
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioSample::
+set_play_rate(float play_rate) {
+  miles_audio_debug("set_play_rate(play_rate="<<play_rate<<")");
+
+  // Set the play_rate:
+  _play_rate = play_rate;
+
+  if (_sample != 0) {
+    play_rate *= _manager->get_play_rate();
+
+    // wave and mp3 use sample rate (e.g. 44100)
+    S32 speed = (S32)(play_rate * (float)_original_playback_rate);
+    AIL_set_sample_playback_rate(_sample, speed);
+    audio_debug("  play_rate for this wav or mp3 is now " << speed);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::length
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float MilesAudioSample::
+length() const {
+  return _sd->get_length();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::status
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+AudioSound::SoundStatus MilesAudioSample::
+status() const {
+  if (_sample == 0) {
+    return AudioSound::READY;
+  }
+  switch (AIL_sample_status(_sample)) {
+  case SMP_DONE:
+  case SMP_STOPPED:
+  case SMP_FREE:
+    return AudioSound::READY;
+
+  case SMP_PLAYING:
+  case SMP_PLAYINGBUTRELEASED:
+    return AudioSound::PLAYING;
+
+  default:
+    return AudioSound::BAD;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::cleanup
+//       Access: Public, Virtual
+//  Description: Stops the sound from playing and releases any
+//               associated resources, in preparation for releasing
+//               the sound or shutting down the sound system.
+////////////////////////////////////////////////////////////////////
+void MilesAudioSample::
+cleanup() {
+  stop();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::internal_stop
+//       Access: Private
+//  Description: Called by the GlobalMilesManager when it is detected
+//               that this particular sound has already stopped, and
+//               its sample handle will be recycled.
+////////////////////////////////////////////////////////////////////
+void MilesAudioSample::
+internal_stop() {
+  _sample = 0;
+  _sample_index = 0;
+}
+
+#endif //]

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

@@ -0,0 +1,93 @@
+// Filename: milesAudioSample.h
+// Created by:  skyler (June 6, 2001)
+// Prior system by: cary
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef MILESAUDIOSAMPLE_H
+#define MILESAUDIOSAMPLE_H
+
+#include "pandabase.h"
+#ifdef HAVE_RAD_MSS //[
+
+#include "milesAudioSound.h"
+#include "milesAudioManager.h"
+#include "mss.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : MilesAudioSample
+// Description : A sound file, such as a WAV or MP3 file, that is
+//               preloaded into memory and played from memory.
+////////////////////////////////////////////////////////////////////
+class EXPCL_MILES_AUDIO MilesAudioSample : public MilesAudioSound {
+private:
+  MilesAudioSample(MilesAudioManager *manager, 
+                   MilesAudioManager::SoundData *sd,
+                   const string &file_name);
+
+public:
+  virtual ~MilesAudioSample();
+  
+  virtual void play();
+  virtual void stop();
+  
+  virtual void set_time(float time=0.0f);
+  virtual float get_time() const;
+  
+  virtual void set_volume(float volume=1.0f);
+  virtual void set_balance(float balance_right=0.0f);
+  virtual void set_play_rate(float play_rate=1.0f);
+  
+  virtual float length() const;
+
+  virtual AudioSound::SoundStatus status() const;
+
+  virtual void cleanup();
+
+private:
+  void internal_stop();
+
+  PT(MilesAudioManager::SoundData) _sd;
+  HSAMPLE _sample;
+  size_t _sample_index;
+  S32 _original_playback_rate;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    MilesAudioSound::init_type();
+    register_type(_type_handle, "MilesAudioSample",
+                  MilesAudioSound::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+
+  friend class GlobalMilesManager;
+  friend class MilesAudioManager;
+};
+
+#include "milesAudioSample.I"
+
+#endif //]
+
+#endif  /* MILESAUDIOSAMPLE_H */

+ 18 - 0
panda/src/audiotraits/milesAudioSequence.I

@@ -0,0 +1,18 @@
+// Filename: milesAudioSequence.I
+// Created by:  drose (31Jul07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+

+ 299 - 0
panda/src/audiotraits/milesAudioSequence.cxx

@@ -0,0 +1,299 @@
+// Filename: milesAudioSequence.cxx
+// Created by:  drose (31Jul07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "milesAudioSequence.h"
+
+#ifdef HAVE_RAD_MSS //[
+
+#include "milesAudioManager.h"
+
+
+TypeHandle MilesAudioSequence::_type_handle;
+
+#undef miles_audio_debug
+
+#ifndef NDEBUG //[
+#define miles_audio_debug(x) \
+    audio_debug("MilesAudioSequence \""<<get_name()<<"\" "<< x )
+#else //][
+#define miles_audio_debug(x) ((void)0)
+#endif //]
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSequence::Constructor
+//       Access: Private
+//  Description: This constructor is called only by the
+//               MilesAudioManager.
+////////////////////////////////////////////////////////////////////
+MilesAudioSequence::
+MilesAudioSequence(MilesAudioManager *manager, MilesAudioManager::SoundData *sd, 
+                 const string &file_name) :
+  MilesAudioSound(manager, file_name),
+  _sd(sd)
+{
+  nassertv(sd != NULL);
+  audio_debug("MilesAudioSequence(manager=0x"<<(void*)&manager
+              <<", sd=0x"<<(void*)sd<<", file_name="<<file_name<<")");
+
+  _sequence = 0;
+  _sequence_index = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSequence::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+MilesAudioSequence::
+~MilesAudioSequence() {
+  miles_audio_debug("~MilesAudioSequence()");
+  cleanup();
+  _manager->release_sound(this);
+  miles_audio_debug("~MilesAudioSequence() done");
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSequence::play
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioSequence::
+play() {
+  miles_audio_debug("play()");
+  if (_active) {
+    stop();
+    
+    if (_sd->_raw_data.empty()) {
+      milesAudio_cat.warning()
+        << "Could not play " << _file_name << ": no data\n";
+    } else {
+      _manager->starting_sound(this);
+      nassertv(_sequence == 0);
+
+      GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
+      if (!mgr->get_sequence(_sequence, _sequence_index, this)){ 
+        milesAudio_cat.warning()
+          << "Could not play " << _file_name << ": too many open sequences\n";
+        _sequence = 0;
+      } else {
+        AIL_init_sequence(_sequence, &_sd->_raw_data[0], 0);
+
+        set_volume(_volume);
+        set_play_rate(_play_rate);
+        AIL_set_sequence_loop_count(_sequence, _loop_count);
+        AIL_start_sequence(_sequence);
+      }
+    }
+  } else {
+    // In case _loop_count gets set to forever (zero):
+    audio_debug("  paused "<<_file_name );
+    _paused = true;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSequence::stop
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioSequence::
+stop() {
+  miles_audio_debug("stop()");
+  _manager->stopping_sound(this);
+  // The _paused flag should not be cleared here.  _paused is not like
+  // the Pause button on a cd/dvd player.  It is used as a flag to say
+  // that it was looping when it was set inactive.  There is no need to
+  // make this symmetrical with play().  set_active() is the 'owner' of
+  // _paused.  play() accesses _paused to help in the situation where
+  // someone calls play on an inactive sound().
+
+  if (_sequence != 0) {
+    AIL_end_sequence(_sequence);
+
+    GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
+    mgr->release_sequence(_sequence_index, this);
+
+    _sequence = 0;
+    _sequence_index = 0;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSequence::set_time
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioSequence::
+set_time(float time) {
+  miles_audio_debug("set_time(time="<<time<<")");
+
+  if (_sequence != 0) {
+    S32 time_ms = (S32)(1000.0f * time);
+
+    // Ensure we don't inadvertently run off the end of the sound.
+    S32 length_ms;
+    AIL_sequence_ms_position(_sequence, &length_ms, NULL);
+    time_ms = min(time_ms, length_ms);
+    
+    AIL_set_sequence_ms_position(_sequence, time_ms);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSequence::get_time
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float MilesAudioSequence::
+get_time() const {
+  if (_sequence == 0) {
+    return 0.0f;
+  }
+
+  S32 current_ms;
+  AIL_sequence_ms_position(_sequence, NULL, &current_ms);
+  float time = float(current_ms * 0.001f);
+
+  return time;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSequence::set_volume
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioSequence::
+set_volume(float volume) {
+  miles_audio_debug("set_volume(volume="<<volume<<")");
+
+  // Set the volume even if our volume is not changing, because the
+  // MilesAudioManager will call set_volume() when *its* volume
+  // changes.
+
+  // Set the volume:
+  _volume = volume;
+
+  if (_sequence != 0) {
+    volume *= _manager->get_volume();
+    
+    // Change to Miles volume, range 0 to 127:
+    S32 milesVolume = (S32)(volume * 127.0f);
+    milesVolume = min(milesVolume, 127);
+    milesVolume = max(milesVolume, 0);
+    
+    AIL_set_sequence_volume(_sequence, milesVolume, 0);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSequence::set_balance
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioSequence::
+set_balance(float balance_right) {
+  miles_audio_debug("set_balance(balance_right="<<balance_right<<")");
+  _balance = balance_right;
+
+  // Balance has no effect on a MIDI file.
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSequence::set_play_rate
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioSequence::
+set_play_rate(float play_rate) {
+  miles_audio_debug("set_play_rate(play_rate="<<play_rate<<")");
+
+  // Set the play_rate:
+  _play_rate = play_rate;
+
+  if (_sequence != 0) {
+    play_rate *= _manager->get_play_rate();
+
+    S32 percent = (S32)(play_rate * 100.0f);
+    AIL_set_sequence_tempo(_sequence, percent, 0);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSequence::length
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float MilesAudioSequence::
+length() const {
+  S32 length_ms;
+  AIL_sequence_ms_position(_sequence, &length_ms, NULL);
+  float time = (float)length_ms * 0.001f;
+  return time;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSequence::status
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+AudioSound::SoundStatus MilesAudioSequence::
+status() const {
+  if (_sequence == 0) {
+    return AudioSound::READY;
+  }
+  switch (AIL_sequence_status(_sequence)) {
+  case SEQ_DONE:
+  case SEQ_STOPPED:
+  case SEQ_FREE:
+    return AudioSound::READY;
+
+  case SEQ_PLAYING:
+  case SEQ_PLAYINGBUTRELEASED:
+    return AudioSound::PLAYING;
+
+  default:
+    return AudioSound::BAD;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSequence::cleanup
+//       Access: Public, Virtual
+//  Description: Stops the sound from playing and releases any
+//               associated resources, in preparation for releasing
+//               the sound or shutting down the sound system.
+////////////////////////////////////////////////////////////////////
+void MilesAudioSequence::
+cleanup() {
+  stop();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSequence::internal_stop
+//       Access: Private
+//  Description: Called by the GlobalMilesManager when it is detected
+//               that this particular sound has already stopped, and
+//               its sequence handle will be recycled.
+////////////////////////////////////////////////////////////////////
+void MilesAudioSequence::
+internal_stop() {
+  _sequence = 0;
+  _sequence_index = 0;
+}
+
+#endif //]

+ 91 - 0
panda/src/audiotraits/milesAudioSequence.h

@@ -0,0 +1,91 @@
+// Filename: milesAudioSequence.h
+// Created by:  drose (31Jul07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef MILESAUDIOSEQUENCE_H
+#define MILESAUDIOSEQUENCE_H
+
+#include "pandabase.h"
+#ifdef HAVE_RAD_MSS //[
+
+#include "milesAudioSound.h"
+#include "milesAudioManager.h"
+#include "mss.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : MilesAudioSequence
+// Description : A MIDI file, preloaded and played from a memory
+//               buffer.  MIDI files cannot be streamed.
+////////////////////////////////////////////////////////////////////
+class EXPCL_MILES_AUDIO MilesAudioSequence : public MilesAudioSound {
+private:
+  MilesAudioSequence(MilesAudioManager *manager, 
+                     MilesAudioManager::SoundData *sd,
+                     const string &file_name);
+
+public:
+  virtual ~MilesAudioSequence();
+  
+  virtual void play();
+  virtual void stop();
+  
+  virtual void set_time(float time=0.0f);
+  virtual float get_time() const;
+  
+  virtual void set_volume(float volume=1.0f);
+  virtual void set_balance(float balance_right=0.0f);
+  virtual void set_play_rate(float play_rate=1.0f);
+  
+  virtual float length() const;
+
+  virtual AudioSound::SoundStatus status() const;
+
+  virtual void cleanup();
+
+private:
+  void internal_stop();
+
+  PT(MilesAudioManager::SoundData) _sd;
+  HSEQUENCE _sequence;
+  size_t _sequence_index;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    MilesAudioSound::init_type();
+    register_type(_type_handle, "MilesAudioSequence",
+                  MilesAudioSound::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+
+  friend class GlobalMilesManager;
+  friend class MilesAudioManager;
+};
+
+#include "milesAudioSequence.I"
+
+#endif //]
+
+#endif  /* MILESAUDIOSEQUENCE_H */

+ 1 - 7
panda/src/audiotraits/milesAudioSound.I

@@ -1,6 +1,5 @@
 // Filename: milesAudioSound.I
-// Created by:  skyler (June 6, 2001)
-// Prior system by: cary
+// Created by:  drose (30Jul07)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -17,8 +16,3 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-
-
-
-
-

+ 51 - 479
panda/src/audiotraits/milesAudioSound.cxx

@@ -1,5 +1,5 @@
 // Filename: milesAudioSound.cxx
-// Created by:  skyler (June 6, 2001)
+// Created by:  drose (30Jul07)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -16,311 +16,70 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#include "pandabase.h"
+#include "milesAudioSound.h"
 #ifdef HAVE_RAD_MSS //[
 
-#include "throw_event.h"
-#include "milesAudioSound.h"
 #include "milesAudioManager.h"
 
-
 TypeHandle MilesAudioSound::_type_handle;
 
-
-#define NEED_MILES_LENGTH_WORKAROUND
-
-#if (((MSS_MAJOR_VERSION == 6) && (MSS_MINOR_VERSION >= 5)) || (MSS_MAJOR_VERSION >= 7))
-#define MILES_6_5_OR_HIGHER
-#endif
+#undef miles_audio_debug
 
 #ifndef NDEBUG //[
-namespace {
-  ////////////////////////////////////////////////////////////////////
-  //     Function: get_status_char
-  //       Access: 
-  //  Description: 
-  ////////////////////////////////////////////////////////////////////
-  char
-  get_status_char(HAUDIO audio) {
-    if (!audio) {
-      return '0'; // NULL.
-    }
-    switch (AIL_quick_status(audio)) {
-      case QSTAT_LOADED:
-      case QSTAT_DONE:
-        return 'r'; // Ready.
-      case QSTAT_PLAYING:
-        return 'p'; // Playing.
-      default:
-        return 'x'; // bad.
-    }
-  }
-  #define miles_audio_debug(x) \
-      audio_debug("MilesAudioSound "<<get_status_char(_audio)<<" \""<<get_name() \
-      <<"\" "<< x )
-}
+#define miles_audio_debug(x) \
+    audio_debug("MilesAudioSound \""<<get_name()<<"\" "<< x )
 #else //][
 #define miles_audio_debug(x) ((void)0)
 #endif //]
 
-namespace {
-  AILSEQUENCECB sequence_callback = 0;
-  AILSAMPLECB sample_callback = 0;
-  const int user_data_index = 7;
-
-  ////////////////////////////////////////////////////////////////////
-  //     Function: pandaAudioAilCallback_Sequence
-  //       Access: file scope
-  //  Description: This function is part of a hack for finish callbacks
-  //               when using the Miles quick API.
-  ////////////////////////////////////////////////////////////////////
-  void AILCALLBACK
-  pandaAudioAilCallback_Sequence(HSEQUENCE S) {
-    assert(S);
-    AutoAilLock milesLock;
-    audio_debug("pandaAudioAilCallback_Sequence(HSEQUENCE="<<((void*)S)<<")");
-    MilesAudioSound* sound = (MilesAudioSound*)AIL_sequence_user_data(
-        S, user_data_index);
-    assert(sound);
-    sound->finished();
-    if (sequence_callback) {
-      sequence_callback(S);
-    }
-  }
-
-  ////////////////////////////////////////////////////////////////////
-  //     Function: pandaAudioAilCallback_Sample
-  //       Access: file scope
-  //  Description: This function is part of a hack for finish callbacks
-  //               when using the Miles quick API.
-  ////////////////////////////////////////////////////////////////////
-  void AILCALLBACK
-  pandaAudioAilCallback_Sample(HSAMPLE S) {
-    assert(S);
-    AutoAilLock milesLock;
-    audio_debug("pandaAudioAilCallback_Sample(HSAMPLE="<<((void*)S)<<")");
-    MilesAudioSound* sound = (MilesAudioSound*)AIL_sample_user_data(
-        S, user_data_index);
-    assert(sound);
-    sound->finished();
-    if (sample_callback) {
-      sample_callback(S);
-    }
-  }
-
-  ////////////////////////////////////////////////////////////////////
-  //     Function: panda_AIL_quick_set_finished_callback
-  //       Access: file scope
-  //  Description: This function is part of a hack for finish callbacks
-  //               when using the Miles quick API.
-  //
-  //               This will determine whether the sound is a MIDI or
-  //               a wave sample and setup the correct callback.
-  ////////////////////////////////////////////////////////////////////
-  void
-  panda_AIL_quick_set_finished_callback(HAUDIO audio, MilesAudioSound* sound) {
-    audio_debug("panda_AIL_quick_set_finished_callback(audio="<<((void*)audio)
-        <<", sound="<<((void*)sound)<<")");
-    if (!audio || !sound) {
-      return;
-    }
-    AutoAilLock milesLock;
-    if (audio->handle != NULL) {
-      switch (audio->type) {
-      case AIL_QUICK_XMIDI_TYPE:
-        audio_debug("  AIL_register_sequence_callback");
-        AIL_set_sequence_user_data(
-            (HSEQUENCE)audio->handle, user_data_index, (long)sound);
-        sequence_callback=AIL_register_sequence_callback(
-            (HSEQUENCE)audio->handle, pandaAudioAilCallback_Sequence);
-        audio_debug(  "AILCALLBACK "<<((void*)sequence_callback));
-        break;
-      case AIL_QUICK_DIGITAL_TYPE:
-      case AIL_QUICK_MPEG_DIGITAL_TYPE:
-        audio_debug("  AIL_register_EOS_callback");
-        AIL_set_sample_user_data(
-            (HSAMPLE)audio->handle, user_data_index, (long)sound);
-        sample_callback=AIL_register_EOS_callback(
-            (HSAMPLE)audio->handle, pandaAudioAilCallback_Sample);
-        audio_debug("  AILCALLBACK "<<((void*)sample_callback));
-        break;
-      default:
-        audio_debug("  unknown audio type");
-        break;
-      }
-    }
-  }
-
-  S32
-  Get_playback_rate(HAUDIO audio) {
-    if (audio) {
-      switch (audio->type) {
-      case AIL_QUICK_XMIDI_TYPE:
-      case AIL_QUICK_DLS_XMIDI_TYPE:
-        return AIL_sequence_tempo((HSEQUENCE)audio->handle);
-        break;
-      case AIL_QUICK_DIGITAL_TYPE:
-      case AIL_QUICK_MPEG_DIGITAL_TYPE:
-        if (AIL_quick_status(audio) == QSTAT_PLAYING) {
-          return AIL_sample_playback_rate((HSAMPLE)audio->handle);
-        } else {
-          //HACK: The play rate is returning 0 unless it's playing
-          if (AIL_quick_play(audio, 1)) {
-            S32 rate = AIL_sample_playback_rate((HSAMPLE)audio->handle);
-            AIL_quick_halt(audio);
-            return rate;
-          }
-        }
-        break;
-      default:
-        audio_debug("Get_playback_rate unknown audio type");
-        break;
-      }
-    }
-    return 0;
-  }
-
-
-}
-
 ////////////////////////////////////////////////////////////////////
-//     Function: MilesAudioSound::MilesAudioSound
-//       Access: 
+//     Function: MilesAudioSound::Constructor
+//       Access: Private
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 MilesAudioSound::
-MilesAudioSound(MilesAudioManager* manager,
-    MilesAudioManager::SoundData *sd, string file_name, float length)
-    : _sd(sd), _manager(manager), _file_name(file_name),
-    _volume(1.0f), _balance(0),
-    _loop_count(1), _length(length),
-    _active(true), _paused(false) {
-  nassertv(sd != NULL);
+MilesAudioSound(MilesAudioManager *manager,
+                const string &file_name) :
+  _manager(manager),
+  _file_name(file_name),
+  _volume(1.0f), _balance(0), _play_rate(1.0f),
+  _loop_count(1), 
+  _active(true), _paused(false) 
+{
   nassertv(!file_name.empty());
-  audio_debug("MilesAudioSound(manager=0x"<<(void*)&manager
-      <<", sd=0x"<<(void*)sd<<", file_name="<<file_name<<")");
-  // Make our own copy of the sound header data:
-  _audio=AIL_quick_copy(sd->_audio);
-  _play_rate = 1.0f;
-  _original_playback_rate = Get_playback_rate(_audio);
-  audio_debug("MilesAudioSound: original_playback_rate " << _original_playback_rate);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: MilesAudioSound::~MilesAudioSound
-//       Access: 
-//  Description: 
-////////////////////////////////////////////////////////////////////
-MilesAudioSound::
-~MilesAudioSound() {
-  miles_audio_debug("~MilesAudioSound()");
-  cleanup();
-  _manager->release_sound(this);
-  miles_audio_debug("~MilesAudioSound() done");
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: MilesAudioSound::play
-//       Access: 
-//  Description: 
-////////////////////////////////////////////////////////////////////
-void MilesAudioSound::
-play() {
-  #if 0
-  if(_file_name.find(".mid")!=string::npos) {
-     miles_audio_debug("play() midi");
-  }
-  #endif
-  
-  miles_audio_debug("play()");
-  if (_active) {
-    if (status() == AudioSound::PLAYING) {
-      stop();
-    }
-    nassertv(_audio);
-    _manager->starting_sound(this);
-    // Start playing:
-    if (AIL_quick_play(_audio, _loop_count)) {
-      //#*#panda_AIL_quick_set_finished_callback(_audio, this);
-      // assert(status()==PLAYING);
-      audio_debug("  started sound " << _file_name );
-    } else {
-      audio_debug("  sound " << _file_name<<" failed to start, err: " <<AIL_last_error());
-    }
-  } else {
-    // In case _loop_count gets set to forever (zero):
-    audio_debug("  paused "<<_file_name );
-    _paused=true;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: MilesAudioSound::stop
-//       Access: 
-//  Description: 
-////////////////////////////////////////////////////////////////////
-void MilesAudioSound::
-stop() {
-  miles_audio_debug("stop()");
-  _manager->stopping_sound(this);
-  // The _paused flag should not be cleared here.  _paused is not like
-  // the Pause button on a cd/dvd player.  It is used as a flag to say
-  // that it was looping when it was set inactive.  There is no need to
-  // make this symmetrical with play().  set_active() is the 'owner' of
-  // _paused.  play() accesses _paused to help in the situation where
-  // someone calls play on an inactive sound().
-  nassertv(_audio);
-  AIL_quick_halt(_audio);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: MilesAudioSound::finished
-//       Access: 
-//  Description: 
-////////////////////////////////////////////////////////////////////
-void MilesAudioSound::
-finished() {
-  miles_audio_debug("finished()");
-  _manager->stopping_sound(this);
-  if (!_finished_event.empty()) {
-    throw_event(_finished_event);
-  }
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioSound::set_loop
-//       Access: 
+//       Access: Public, Virtual
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 void MilesAudioSound::
 set_loop(bool loop) {
-  miles_audio_debug("set_loop(loop="<<loop<<")");
   // loop count of 0 means always loop
   set_loop_count((loop)?0:1);
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioSound::get_loop
-//       Access: 
+//       Access: Public, Virtual
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 bool MilesAudioSound::
 get_loop() const {
-  miles_audio_debug("get_loop() returning "<<(_loop_count==0));
   return (_loop_count == 0);
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioSound::
-//       Access: 
+//       Access: Public, Virtual
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 void MilesAudioSound::
 set_loop_count(unsigned long loop_count) {
-  miles_audio_debug("set_loop_count(loop_count="<<loop_count<<")");
-  if (_loop_count!=loop_count) {
-    _loop_count=loop_count;
-    if (status()==PLAYING) {
+  if (_loop_count != loop_count) {
+    _loop_count = loop_count;
+    if (status() == PLAYING) {
       // hack:
       // For now, the loop count is picked up when the sound starts playing.
       // There may be a way to change the loop count of a playing sound, but
@@ -328,7 +87,6 @@ set_loop_count(unsigned long loop_count) {
       // need to stop and start the sound, feel free.  Or, maybe I'll spend
       // time on it in the future.  Please set the loop option before starting
       // the sound.
-      stop();
       play();
     }
   }
@@ -336,222 +94,68 @@ set_loop_count(unsigned long loop_count) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioSound::
-//       Access: 
+//       Access: Public, Virtual
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 unsigned long MilesAudioSound::
 get_loop_count() const {
-  miles_audio_debug("get_loop_count() returning "<<_loop_count);
   return _loop_count;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: MilesAudioSound::
-//       Access: 
-//  Description: 
-////////////////////////////////////////////////////////////////////
-void MilesAudioSound::
-set_time(float time) {
-  miles_audio_debug("set_time(time="<<time<<")");
-
-  nassertv(_audio);
-  // Ensure we don't inadvertently run off the end of the sound.
-  float max_time = length();
-  if (time > max_time) {
-    milesAudio_cat.warning()
-      << "set_time(" << time << ") requested for sound of length " 
-      << max_time << "\n";
-    time = max_time;
-  }
-
-  S32 millisecond_time=(S32)(1000*time);
-  AIL_quick_set_ms_position(_audio, millisecond_time);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: MilesAudioSound::
-//       Access: 
-//  Description: 
-////////////////////////////////////////////////////////////////////
-float MilesAudioSound::
-get_time() const {
-  nassertr(_audio, 0.0f);
-  S32 millisecond_time=AIL_quick_ms_position(_audio);
-  float time=float(millisecond_time*.001);
-  miles_audio_debug("get_time() returning "<<time);
-  return time;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: MilesAudioSound::
-//       Access: 
-//  Description: 
-////////////////////////////////////////////////////////////////////
-void MilesAudioSound::
-set_volume(float volume) {
-  miles_audio_debug("set_volume(volume="<<volume<<")");
-  nassertv(_audio);
-  // *Set the volume even if our volume is not changing, because the
-  // MilesAudioManager will call set_volume when *its* volume changes.
-  // Set the volume:
-  _volume=volume;
-  // Account for the category of sound:
-  volume*=_manager->get_volume();
-  #ifdef MILES_6_5_OR_HIGHER
-    // Change to Miles volume, range 0 to 1.0:
-    F32 milesVolume=volume;
-    milesVolume=min(milesVolume,1.0f);
-    milesVolume=max(milesVolume,0.0f);
-  #else
-    // Change to Miles volume, range 0 to 127:
-    S32 milesVolume=((S32)(127*volume))%128;
-  #endif
-  // Account for type:
-  S32 audioType=AIL_quick_type(_audio);
-  if ((audioType==AIL_QUICK_XMIDI_TYPE) || (audioType==AIL_QUICK_DLS_XMIDI_TYPE)) {
-    // ...it's a midi file.
-
-    // 0 delay, set to this volume immediately    
-    #ifdef MILES_6_5_OR_HIGHER
-      F32 midiVolDelay =0.0f; 
-    #else
-      S32 midiVolDelay =0;
-    #endif
-    
-    AIL_quick_set_volume(_audio, milesVolume, midiVolDelay); 
-    audio_debug("  volume for this midi is now "<<milesVolume);
-  } else {
-    // ...it's a wav or mp3.
-    #ifdef MILES_6_5_OR_HIGHER
-      // Convert balance of -1.0..1.0 to 0-1.0:
-      F32 milesBalance=(F32)((_balance+1.0f)*0.5f);
-    #else
-      // Convert balance of -1.0..1.0 to 0..127:
-      S32 milesBalance=((S32)(63.5f*(_balance+1.0f)))%128;  
-    #endif
-    AIL_quick_set_volume(_audio, milesVolume, milesBalance);
-    audio_debug("  volume for this wav or mp3 is now " << milesVolume
-        <<", balance="<<milesBalance);
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioSound::get_volume
-//       Access: 
+//       Access: Public, Virtual
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 float MilesAudioSound::
 get_volume() const {
-  miles_audio_debug("get_volume() returning "<<_volume);
   return _volume;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: MilesAudioSound::
-//       Access: 
-//  Description: 
-////////////////////////////////////////////////////////////////////
-void MilesAudioSound::
-set_play_rate(float play_rate) {
-  miles_audio_debug("set_play_rate(play_rate="<<play_rate<<")");
-  // Set the play_rate:
-  _play_rate=play_rate;
-  if (_audio) {
-    // Account for the category of sound:
-    play_rate*=_manager->get_play_rate();
-    switch (_audio->type) {
-    case AIL_QUICK_XMIDI_TYPE:
-    case AIL_QUICK_DLS_XMIDI_TYPE:
-      // midi uses whole percentage values 100 == 100%
-      _audio->speed = (S32)(play_rate*100.0f);
-      if ((_audio->speed != -1) && (AIL_quick_status(_audio) == QSTAT_PLAYING)) {
-        AIL_set_sequence_tempo((HSEQUENCE)_audio->handle, _audio->speed, 0);
-      }
-      audio_debug("  play_rate for this midi is now "<<_audio->speed);
-      break;
-    case AIL_QUICK_DIGITAL_TYPE:
-    case AIL_QUICK_MPEG_DIGITAL_TYPE:
-      // wave and mp3 use sample rate (e.g. 44100)
-      _audio->speed = (S32)(play_rate*float(_original_playback_rate));
-      if ((_audio->speed != -1) && (AIL_quick_status(_audio) == QSTAT_PLAYING)) {
-        AIL_set_sample_playback_rate((HSAMPLE)_audio->handle, _audio->speed);
-      }
-      audio_debug("  play_rate for this wav or mp3 is now "<<_audio->speed);
-      break;
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: MilesAudioSound::get_play_rate
-//       Access: 
-//  Description: 
-////////////////////////////////////////////////////////////////////
-float MilesAudioSound::
-get_play_rate() const {
-  miles_audio_debug("get_play_rate() returning "<<_play_rate);
-  return _play_rate;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: MilesAudioSound::set_balance
-//       Access: 
-//  Description: 
-////////////////////////////////////////////////////////////////////
-void MilesAudioSound::
-set_balance(float balance_right) {
-  miles_audio_debug("set_balance(balance_right="<<balance_right<<")");
-  _balance=balance_right;
-  // Call set_volume to effect the change:
-  set_volume(_volume);
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioSound::get_balance
-//       Access: 
+//       Access: Public, Virtual
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 float MilesAudioSound::
 get_balance() const {
-  audio_debug("MilesAudioSound::get_balance() returning "<<_balance);
   return _balance;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: MilesAudioSound::length
-//       Access: 
+//     Function: MilesAudioSound::get_play_rate
+//       Access: Public, Virtual
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 float MilesAudioSound::
-length() const {
-  return _sd->get_length();
+get_play_rate() const {
+  return _play_rate;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioSound::set_active
-//       Access: 
+//       Access: Public, Virtual
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 void MilesAudioSound::
 set_active(bool active) {
   miles_audio_debug("set_active(active="<<active<<")");
-  if (_active!=active) {
-    _active=active;
+  if (_active != active) {
+    _active = active;
     if (_active) {
       // ...activate the sound.
-      if (_paused
-          &&
-          _loop_count==0) {
+      if (_paused && _loop_count==0) {
         // ...this sound was looping when it was paused.
-        _paused=false;
+        _paused = false;
         play();
       }
+
     } else {
       // ...deactivate the sound.
-      if (status()==PLAYING) {
-        if (_loop_count==0) {
+      if (status() == PLAYING) {
+        if (_loop_count == 0) {
           // ...we're pausing a looping sound.
-          _paused=true;
+          _paused = true;
         }
         stop();
       }
@@ -561,85 +165,53 @@ set_active(bool active) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioSound::get_active
-//       Access: 
+//       Access: Public, Virtual
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 bool MilesAudioSound::
 get_active() const {
-  miles_audio_debug("get_active() returning "<<_active);
   return _active;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioSound::set_finished_event
-//       Access: 
-//  Description: 
+//       Access: Public, Virtual
+//  Description: This is no longer implemented.
 ////////////////////////////////////////////////////////////////////
 void MilesAudioSound::
-set_finished_event(const string& event) {
-  miles_audio_debug("set_finished_event(event="<<event<<")");
+set_finished_event(const string &event) {
   _finished_event = event;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioSound::get_finished_event
-//       Access: 
-//  Description: 
+//       Access: Public, Virtual
+//  Description: This is no longer implemented.
 ////////////////////////////////////////////////////////////////////
-const string& MilesAudioSound::
+const string &MilesAudioSound::
 get_finished_event() const {
-  miles_audio_debug("get_finished_event() returning "<<_finished_event);
   return _finished_event;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioSound::get_name
-//       Access: 
+//       Access: Public, Virtual
 //  Description: 
 ////////////////////////////////////////////////////////////////////
-const string& MilesAudioSound::
+const string &MilesAudioSound::
 get_name() const {
-  //audio_debug("MilesAudioSound::get_name() returning "<<_file_name);
   return _file_name;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: MilesAudioSound::status
-//       Access: 
-//  Description: 
-////////////////////////////////////////////////////////////////////
-AudioSound::SoundStatus MilesAudioSound::
-status() const {
-  if (!_audio) {
-    return AudioSound::BAD;
-  }
-  switch (AIL_quick_status(_audio)) {
-    case QSTAT_LOADED:
-    case QSTAT_DONE:
-      return AudioSound::READY;
-    case QSTAT_PLAYING:
-      return AudioSound::PLAYING;
-    default:
-      return AudioSound::BAD;
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioSound::cleanup
-//       Access: Private
-//  Description: Called to release any resources associated with the
-//               sound.
+//       Access: Public, Virtual
+//  Description: Stops the sound from playing and releases any
+//               associated resources, in preparation for releasing
+//               the sound or shutting down the sound system.
 ////////////////////////////////////////////////////////////////////
 void MilesAudioSound::
 cleanup() {
-  if (_audio) {
-    stop();
-    if (MilesAudioManager::_miles_active) {
-      AIL_quick_unload(_audio);
-    }
-    _audio = 0;
-  }
 }
 
-
-#endif //]
+#endif  //]

+ 38 - 111
panda/src/audiotraits/milesAudioSound.h

@@ -1,6 +1,5 @@
 // Filename: milesAudioSound.h
-// Created by:  skyler (June 6, 2001)
-// Prior system by: cary
+// Created by:  drose (30Jul07)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -17,8 +16,8 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#ifndef __MILES_AUDIO_SOUND_H__
-#define __MILES_AUDIO_SOUND_H__
+#ifndef MILESAUDIOSOUND_H
+#define MILESAUDIOSOUND_H
 
 #include "pandabase.h"
 #ifdef HAVE_RAD_MSS //[
@@ -26,117 +25,45 @@
 #include "audioSound.h"
 #include "milesAudioManager.h"
 #include "mss.h"
-  
-class AutoAilLock {
-  // This will lock and unlock the Miles AIL timer based
-  // on the current code block.  (Auto in the class name
-  // is referring to "auto variable").
-public:
-  AutoAilLock() {
-    AIL_lock();
-  }
-  ~AutoAilLock() {
-    AIL_unlock();
-  }
-};
 
+////////////////////////////////////////////////////////////////////
+//       Class : MilesAudioSound
+// Description : The base class for both MilesAudioStream and
+//               MilesAudioSample.
+////////////////////////////////////////////////////////////////////
 class EXPCL_MILES_AUDIO MilesAudioSound : public AudioSound {
-public:
-  ~MilesAudioSound();
-  
-  // For best compatability, set the loop_count,
-  // 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.
-  // - Calling play() a second time on the same sound before it is
-  //   finished will start the sound again (creating a skipping or
-  //   stuttering effect).
-  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;
-  
-  // Control time position within the sound.
-  // This is similar (in concept) to the seek position within
-  // a file.
-  // time in seconds: 0 = beginning; length() = end.
-  // inits to 0.0.
-  // - Unlike the other get_* and set_* calls for a sound, the
-  //   current time position will change while the sound is playing.
-  //   To play the same sound from a time offset a second time,
-  //   explicitly set the time position again.  When looping, the
-  //   second and later loops will start from the beginning of the
-  //   sound.
-  // - If a sound is playing, calling get_time() repeatedly will
-  //   return different results over time.  e.g.:
-  //   float percent_complete = s.get_time() / s.length();
-  void set_time(float time=0.0f);
-  float get_time() const;
-  
-  // 0 = minimum; 1.0 = maximum.
-  // inits to 1.0.
-  void set_volume(float volume=1.0f);
-  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.0f);
-  float get_balance() const;
-  
-  // play_rate is any positive float value.
-  // inits to 1.0.
-  void set_play_rate(float play_rate=1.0f);
-  float get_play_rate() const;
-
-  // inits to manager's state.
-  void set_active(bool active=true);
-  bool get_active() const;
-
-  // This is the string that throw_event() will throw
-  // when the sound finishes playing.  It is not triggered
-  // when the sound is stopped with stop().
-  void set_finished_event(const string& event);
-  const string& get_finished_event() const;
+protected:
+  MilesAudioSound(MilesAudioManager *manager, const string &file_name);
+
+public:  
+  virtual void set_loop(bool loop=true);
+  virtual bool get_loop() const;
   
-  const string& get_name() const;
+  virtual void set_loop_count(unsigned long loop_count=1);
+  virtual unsigned long get_loop_count() const;
   
-  // return: playing time in seconds.
-  float length() const;
+  virtual float get_volume() const;
+  virtual float get_balance() const;
+  virtual float get_play_rate() const;
 
-  void set_3d_attributes(float* pos, float* vel);
-  void get_3d_attributes(float* pos, float* vel);
+  virtual void set_active(bool active=true);
+  virtual bool get_active() const;
 
-  AudioSound::SoundStatus status() const;
+  virtual void set_finished_event(const string &event);
+  virtual const string &get_finished_event() const;
+  
+  virtual const string &get_name() const;
 
-  void finished();
+  virtual void cleanup();
 
-private:
-  PT(MilesAudioManager::SoundData) _sd;
-  HAUDIO _audio;
+protected:
   PT(MilesAudioManager) _manager;
+  string _file_name;
+
   float _volume; // 0..1.0
   float _balance; // -1..1
   float _play_rate; // 0..1.0
-  mutable float _length; // in seconds.
   unsigned long _loop_count;
-  S32 _original_playback_rate;
-  
-  // This is the string that throw_event() will throw
-  // when the sound finishes playing.  It is not triggered
-  // when the sound is stopped with stop().
-  string _finished_event;
-  
-  string _file_name;
   
   // _active is for things like a 'turn off sound effects' in
   // a preferences pannel.
@@ -146,15 +73,13 @@ private:
   
   // _paused is not like the Pause button on a cd/dvd player.
   // It is used as a flag to say that the sound was looping when
-  // itwas set inactive.
+  // it was set inactive.
   bool _paused;
-
-  MilesAudioSound(MilesAudioManager* manager, MilesAudioManager::SoundData *sd,
-                  string file_name, float length=0.0f);
-  void cleanup();
-
-  friend class MilesAudioManager;
-
+  
+  // This is the string that throw_event() will throw when the sound
+  // finishes playing.  It is not triggered when the sound is stopped
+  // with stop().  Note: no longer implemented.
+  string _finished_event;
 
 public:
   static TypeHandle get_class_type() {
@@ -172,10 +97,12 @@ public:
 
 private:
   static TypeHandle _type_handle;
+
+  friend class MilesAudioManager;
 };
 
 #include "milesAudioSound.I"
 
 #endif //]
 
-#endif /* __MILES_AUDIO_SOUND_H__ */
+#endif

+ 18 - 0
panda/src/audiotraits/milesAudioStream.I

@@ -0,0 +1,18 @@
+// Filename: milesAudioStream.I
+// Created by:  drose (26Jul07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+

+ 299 - 0
panda/src/audiotraits/milesAudioStream.cxx

@@ -0,0 +1,299 @@
+// Filename: milesAudioStream.cxx
+// Created by:  drose (26Jul07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "milesAudioStream.h"
+#ifdef HAVE_RAD_MSS //[
+
+#include "milesAudioManager.h"
+#include "pnotify.h"
+
+TypeHandle MilesAudioStream::_type_handle;
+
+#undef miles_audio_debug
+
+#ifndef NDEBUG //[
+#define miles_audio_debug(x) \
+    audio_debug("MilesAudioStream \""<<get_name()<<"\" "<< x )
+#else //][
+#define miles_audio_debug(x) ((void)0)
+#endif //]
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioStream::Constructor
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+MilesAudioStream::
+MilesAudioStream(MilesAudioManager *manager, const string &file_name,
+                 const Filename &path) :
+  MilesAudioSound(manager, file_name),
+  _path(path)
+{
+  _stream = 0;
+  _got_length = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioStream::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+MilesAudioStream::
+~MilesAudioStream() {
+  miles_audio_debug("~MilesAudioStream()");
+  cleanup();
+
+  _manager->release_sound(this);
+  miles_audio_debug("~MilesAudioStream() done");
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioStream::play
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioStream::
+play() {
+  miles_audio_debug("play()");
+  if (_active) {
+
+    _manager->starting_sound(this);
+
+    if (_stream == 0) {
+      GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
+      _stream = AIL_open_stream(mgr->_digital_driver, _path.c_str(), 0);
+    } else {
+      // We already had the stream open.  Keep it open; just restart
+      // it.
+      AIL_pause_stream(_stream, 1);
+      _manager->stop_service_stream(_stream);
+    }
+
+    if (_stream == 0) {
+      milesAudio_cat.warning()
+        << "Could not play " << _file_name << ": too many open streams\n";
+
+    } else {
+      // Start playing:
+      HSAMPLE sample = AIL_stream_sample_handle(_stream);
+      nassertv(sample != 0);
+      
+      _original_playback_rate = AIL_sample_playback_rate(sample);
+      set_volume(_volume);
+      set_play_rate(_play_rate);
+      
+      AIL_set_stream_loop_count(_stream, _loop_count);
+      
+      if (miles_audio_panda_threads) {
+        AIL_auto_service_stream(_stream, 0);
+        _manager->start_service_stream(_stream);
+      } else {
+        AIL_auto_service_stream(_stream, 1);
+      }
+      AIL_start_stream(_stream);
+    }
+
+  } else {
+    // In case _loop_count gets set to forever (zero):
+    audio_debug("  paused "<<_file_name );
+    _paused = true;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioStream::stop
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioStream::
+stop() {
+  miles_audio_debug("stop()");
+  _manager->stopping_sound(this);
+
+  // The _paused flag should not be cleared here.  _paused is not like
+  // the Pause button on a cd/dvd player.  It is used as a flag to say
+  // that it was looping when it was set inactive.  There is no need to
+  // make this symmetrical with play().  set_active() is the 'owner' of
+  // _paused.  play() accesses _paused to help in the situation where
+  // someone calls play on an inactive sound().
+  if (_stream != 0) {
+    _manager->stop_service_stream(_stream);
+
+    AIL_pause_stream(_stream, 1);
+    AIL_close_stream(_stream);
+    _stream = 0;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioStream::
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioStream::
+set_time(float time) {
+  if (_stream != 0) {
+    S32 time_ms = (S32)(1000.0f * time);
+
+    // Ensure we don't inadvertently run off the end of the sound.
+    S32 length_ms;
+    AIL_stream_ms_position(_stream, &length_ms, NULL);
+    time_ms = min(time_ms, length_ms);
+    
+    AIL_set_stream_ms_position(_stream, time_ms);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioStream::
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float MilesAudioStream::
+get_time() const {
+  nassertr(_stream, 0.0f);
+
+  S32 current_ms;
+  AIL_stream_ms_position(_stream, NULL, &current_ms);
+  float time = float(current_ms * 0.001f);
+
+  return time;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioStream::
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioStream::
+set_volume(float volume) {
+  _volume = volume;
+
+  if (_stream != 0) {
+    HSAMPLE sample = AIL_stream_sample_handle(_stream);
+    nassertv(sample != 0);
+
+    volume *= _manager->get_volume();
+    
+    // Change to Miles volume, range 0 to 1.0:
+    F32 milesVolume = volume;
+    milesVolume = min(milesVolume, 1.0f);
+    milesVolume = max(milesVolume, 0.0f);
+    
+    // Convert balance of -1.0..1.0 to 0-1.0:
+    F32 milesBalance = (F32)((_balance + 1.0f) * 0.5f);
+    
+    AIL_set_sample_volume_pan(sample, milesVolume, milesBalance);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioStream::set_balance
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioStream::
+set_balance(float balance_right) {
+  _balance = balance_right;
+
+  // Call set_volume to effect the change:
+  set_volume(_volume);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioStream::set_play_rate
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MilesAudioStream::
+set_play_rate(float play_rate) {
+  _play_rate = play_rate;
+
+  if (_stream != 0) {
+    HSAMPLE sample = AIL_stream_sample_handle(_stream);
+    nassertv(sample != 0);
+
+    play_rate *= _manager->get_play_rate();
+
+    // wave and mp3 use sample rate (e.g. 44100)
+    S32 speed = (S32)(play_rate * (float)_original_playback_rate);
+    AIL_set_sample_playback_rate(sample, speed);
+    audio_debug("  play_rate for this wav or mp3 is now " << speed);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioStream::length
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float MilesAudioStream::
+length() const {
+  if (!_got_length) {
+    if (_stream == 0) {
+      GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
+      ((MilesAudioStream *)this)->_stream = AIL_open_stream(mgr->_digital_driver, _path.c_str(), 0);
+    }
+    
+    S32 length_ms;
+    AIL_stream_ms_position(_stream, &length_ms, NULL);
+    _length = (float)length_ms * 0.001f;
+    _got_length = true;
+  }
+    
+  return _length;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioStream::status
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+AudioSound::SoundStatus MilesAudioStream::
+status() const {
+  if (!_stream) {
+    return AudioSound::READY;
+  }
+
+  switch (AIL_stream_status(_stream)) {
+  case SMP_STOPPED:
+  case SMP_DONE:
+    return AudioSound::READY;
+  case SMP_PLAYING:
+  case SMP_PLAYINGBUTRELEASED:
+    return AudioSound::PLAYING;
+  default:
+    return AudioSound::BAD;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioStream::cleanup
+//       Access: Public, Virtual
+//  Description: Called to release any resources associated with the
+//               sound.
+////////////////////////////////////////////////////////////////////
+void MilesAudioStream::
+cleanup() {
+  if (_stream) {
+    stop();
+  }
+}
+
+
+#endif //]

+ 91 - 0
panda/src/audiotraits/milesAudioStream.h

@@ -0,0 +1,91 @@
+// Filename: milesAudioStream.h
+// Created by:  drose (26Jul07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef MILESAUDIOSTREAM_H
+#define MILESAUDIOSTREAM_H
+
+#include "pandabase.h"
+#ifdef HAVE_RAD_MSS //[
+
+#include "milesAudioSound.h"
+#include "milesAudioManager.h"
+#include "mss.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : MilesAudioStream
+// Description : This represents a sound file played by the Miles
+//               Sound System, similar to MilesAudioSample, except
+//               that it is streamed from disk instead of preloaded
+//               into memory.
+////////////////////////////////////////////////////////////////////
+class EXPCL_MILES_AUDIO MilesAudioStream : public MilesAudioSound {
+private:
+  MilesAudioStream(MilesAudioManager *manager, const string &file_name,
+                   const Filename &path);
+
+public:
+  virtual ~MilesAudioStream();
+  
+  virtual void play();
+  virtual void stop();
+  
+  virtual void set_time(float time=0.0f);
+  virtual float get_time() const;
+  
+  virtual void set_volume(float volume=1.0f);
+  virtual void set_balance(float balance_right=0.0f);
+  virtual void set_play_rate(float play_rate=1.0f);
+  
+  virtual float length() const;
+
+  virtual AudioSound::SoundStatus status() const;
+
+  virtual void cleanup();
+
+private:
+  Filename _path;
+  HSTREAM _stream;
+  S32 _original_playback_rate;
+  mutable float _length;
+  mutable bool _got_length;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    MilesAudioSound::init_type();
+    register_type(_type_handle, "MilesAudioStream",
+                  MilesAudioSound::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+
+  friend class MilesAudioManager;
+};
+
+#include "milesAudioStream.I"
+
+#endif //]
+
+#endif

+ 4 - 0
panda/src/audiotraits/miles_audio_composite1.cxx

@@ -1,5 +1,9 @@
 
 #include "config_milesAudio.cxx"
 #include "milesAudioManager.cxx"
+#include "milesAudioSample.cxx"
+#include "milesAudioSequence.cxx"
 #include "milesAudioSound.cxx"
+#include "milesAudioStream.cxx"
+#include "globalMilesManager.cxx"
       

部分文件因为文件数量过多而无法显示