Browse Source

audio: Add support for setting the loop start time of sounds

Closes #1347
Disyer 3 years ago
parent
commit
c28bd047b3

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

@@ -42,6 +42,10 @@ PUBLISHED:
   virtual void set_loop_count(unsigned long loop_count=1) = 0;
   virtual void set_loop_count(unsigned long loop_count=1) = 0;
   virtual unsigned long get_loop_count() const = 0;
   virtual unsigned long get_loop_count() const = 0;
 
 
+  // loop_start: 0 = beginning.  expressed in seconds.  inits to 0.
+  virtual void set_loop_start(PN_stdfloat loop_start=0) = 0;
+  virtual PN_stdfloat get_loop_start() const = 0;
+
   /**
   /**
    * Control time position within the sound, in seconds.  This is similar (in
    * Control time position within the sound, in seconds.  This is similar (in
    * concept) to the seek position within a file.  The value starts at 0.0 (the
    * concept) to the seek position within a file.  The value starts at 0.0 (the

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

@@ -58,6 +58,14 @@ unsigned long NullAudioSound::get_loop_count() const {
   return 0;
   return 0;
 }
 }
 
 
+void NullAudioSound::set_loop_start(PN_stdfloat) {
+  // Intentionally blank.
+}
+
+PN_stdfloat NullAudioSound::get_loop_start() const {
+  return 0;
+}
+
 void NullAudioSound::set_time(PN_stdfloat) {
 void NullAudioSound::set_time(PN_stdfloat) {
   // Intentionally blank.
   // Intentionally blank.
 }
 }

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

@@ -37,6 +37,9 @@ public:
   void set_loop_count(unsigned long);
   void set_loop_count(unsigned long);
   unsigned long get_loop_count() const;
   unsigned long get_loop_count() const;
 
 
+  void set_loop_start(PN_stdfloat);
+  PN_stdfloat get_loop_start() const;
+
   void set_time(PN_stdfloat);
   void set_time(PN_stdfloat);
   PN_stdfloat get_time() const;
   PN_stdfloat get_time() const;
 
 

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

@@ -339,6 +339,49 @@ get_loop_count() const {
   }
   }
 }
 }
 
 
+/**
+ * Sets the time at which subsequent loops will begin.
+ * A value of 0 indicates the beginning of the audio.
+ */
+void FmodAudioSound::
+set_loop_start(PN_stdfloat loop_start) {
+  ReMutexHolder holder(FmodAudioManager::_lock);
+  audio_debug("FmodAudioSound::set_loop_start()   Setting the sound's loop start to: " << loop_start);
+
+  FMOD_RESULT result;
+  unsigned int length;
+
+  result = _sound->getLength(&length, FMOD_TIMEUNIT_MS);
+  fmod_audio_errcheck("_sound->getLength()", result);
+
+  unsigned int loop_start_int = (unsigned int) (loop_start * 1000.0);
+
+  if (loop_start_int >= length) {
+    audio_debug("FmodAudioSound::set_loop_start()   Would loop after end of track, setting start to 0");
+    loop_start_int = 0;
+  }
+
+  result = _sound->setLoopPoints(loop_start_int, FMOD_TIMEUNIT_MS, length, FMOD_TIMEUNIT_MS);
+  fmod_audio_errcheck("_sound->setLoopPoints()", result);
+  audio_debug("FmodAudioSound::set_loop_start()   Sound's loop start should be set to: " << loop_start);
+}
+
+/**
+ * Return the time at which subsequent loops will begin.
+ * A value of 0 indicates the beginning of the audio.
+ */
+PN_stdfloat FmodAudioSound::
+get_loop_start() const {
+  ReMutexHolder holder(FmodAudioManager::_lock);
+  FMOD_RESULT result;
+  unsigned int loop_start;
+
+  result = _sound->getLoopPoints(&loop_start, FMOD_TIMEUNIT_MS, nullptr, FMOD_TIMEUNIT_MS);
+  fmod_audio_errcheck("_sound->getLoopPoints()", result);
+
+  return ((double)loop_start) / 1000.0;
+}
+
 /**
 /**
  * Sets the time at which the next play() operation will begin.  If we are
  * Sets the time at which the next play() operation will begin.  If we are
  * already playing, skips to that time immediatey.
  * already playing, skips to that time immediatey.

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

@@ -91,6 +91,10 @@ public:
   void set_loop_count(unsigned long loop_count=1);
   void set_loop_count(unsigned long loop_count=1);
   unsigned long get_loop_count() const;
   unsigned long get_loop_count() const;
 
 
+  // loop_start: 0 = beginning.  expressed in seconds.  inits to 0.
+  void set_loop_start(PN_stdfloat loop_start=0);
+  PN_stdfloat get_loop_start() const;
+
   // 0 = beginning; length() = end.  inits to 0.0.
   // 0 = beginning; length() = end.  inits to 0.0.
   void set_time(PN_stdfloat start_time=0.0);
   void set_time(PN_stdfloat start_time=0.0);
   PN_stdfloat get_time() const;
   PN_stdfloat get_time() const;

+ 34 - 3
panda/src/audiotraits/openalAudioSound.cxx

@@ -53,6 +53,7 @@ OpenALAudioSound(OpenALAudioManager* manager,
   _drop_off_factor(1.0f),
   _drop_off_factor(1.0f),
   _length(0.0),
   _length(0.0),
   _loop_count(1),
   _loop_count(1),
+  _loop_start(0),
   _desired_mode(mode),
   _desired_mode(mode),
   _start_time(0.0),
   _start_time(0.0),
   _current_time(0.0),
   _current_time(0.0),
@@ -279,6 +280,36 @@ get_loop_count() const {
   return _loop_count;
   return _loop_count;
 }
 }
 
 
+/**
+ * Sets the time at which subsequent loops will begin.
+ * A value of 0 indicates the beginning of the audio.
+ */
+void OpenALAudioSound::
+set_loop_start(PN_stdfloat loop_start) {
+  ReMutexHolder holder(OpenALAudioManager::_lock);
+
+  if (!is_valid()) {
+    return;
+  }
+
+  if (loop_start >= _length) {
+    // This loop would begin after the song ends.
+    // Not a good idea.
+    loop_start = 0;
+  }
+
+  _loop_start = loop_start;
+}
+
+/**
+ * Return the time at which subsequent loops will begin.
+ * A value of 0 indicates the beginning of the audio.
+ */
+PN_stdfloat OpenALAudioSound::
+get_loop_start() const {
+  return _loop_start;
+}
+
 /**
 /**
  * When streaming audio, the computer is supposed to keep OpenAL's queue full.
  * When streaming audio, the computer is supposed to keep OpenAL's queue full.
  * However, there are times when the computer is running slow and the queue
  * However, there are times when the computer is running slow and the queue
@@ -389,7 +420,7 @@ read_stream_data(int bytelen, unsigned char *buffer) {
     int samples = (int)(remain * rate);
     int samples = (int)(remain * rate);
     if (samples <= 0) {
     if (samples <= 0) {
       _loops_completed += 1;
       _loops_completed += 1;
-      cursor->seek(0.0);
+      cursor->seek(_loop_start);
       continue;
       continue;
     }
     }
     if (_sd->_stream->ready() == 0) {
     if (_sd->_stream->ready() == 0) {
@@ -411,7 +442,7 @@ read_stream_data(int bytelen, unsigned char *buffer) {
     }
     }
     if (samples == 0) {
     if (samples == 0) {
       _loops_completed += 1;
       _loops_completed += 1;
-      cursor->seek(0.0);
+      cursor->seek(_loop_start);
       if (_playing_loops >= 1000000000) {
       if (_playing_loops >= 1000000000) {
         // Prevent infinite loop if endlessly looping empty sound
         // Prevent infinite loop if endlessly looping empty sound
         return fill;
         return fill;
@@ -535,7 +566,7 @@ push_fresh_buffers() {
   if (_sd->_sample) {
   if (_sd->_sample) {
     while ((_loops_completed < _playing_loops) &&
     while ((_loops_completed < _playing_loops) &&
            (_stream_queued.size() < 100)) {
            (_stream_queued.size() < 100)) {
-      queue_buffer(_sd->_sample, 0,_loops_completed, 0.0);
+      queue_buffer(_sd->_sample, 0,_loops_completed, _loop_start);
       _loops_completed += 1;
       _loops_completed += 1;
     }
     }
   } else {
   } else {

+ 8 - 3
panda/src/audiotraits/openalAudioSound.h

@@ -50,6 +50,10 @@ public:
   void set_loop_count(unsigned long loop_count=1);
   void set_loop_count(unsigned long loop_count=1);
   unsigned long get_loop_count() const;
   unsigned long get_loop_count() const;
 
 
+  // loop_start: 0 = beginning.  expressed in seconds.  inits to 0.
+  void set_loop_start(PN_stdfloat loop_start=0);
+  PN_stdfloat get_loop_start() const;
+
   // 0 = beginning; length() = end.  inits to 0.0.
   // 0 = beginning; length() = end.  inits to 0.0.
   void set_time(PN_stdfloat time=0.0);
   void set_time(PN_stdfloat time=0.0);
   PN_stdfloat get_time() const;
   PN_stdfloat get_time() const;
@@ -156,10 +160,11 @@ private:
   PN_stdfloat _max_dist;
   PN_stdfloat _max_dist;
   PN_stdfloat _drop_off_factor;
   PN_stdfloat _drop_off_factor;
 
 
-  double _length;
-  int    _loop_count;
+  double      _length;
+  int         _loop_count;
+  PN_stdfloat _loop_start;
 
 
-  int    _desired_mode;
+  int         _desired_mode;
 
 
   // The calibrated clock is initialized when the sound starts playing, and is
   // The calibrated clock is initialized when the sound starts playing, and is
   // periodically corrected thereafter.
   // periodically corrected thereafter.