From c28bd047b3737d066082ba6e7ebb61595f3fc462 Mon Sep 17 00:00:00 2001 From: Disyer Date: Thu, 4 Aug 2022 14:49:14 +0300 Subject: [PATCH] audio: Add support for setting the loop start time of sounds Closes #1347 --- panda/src/audio/audioSound.h | 4 ++ panda/src/audio/nullAudioSound.cxx | 8 ++++ panda/src/audio/nullAudioSound.h | 3 ++ panda/src/audiotraits/fmodAudioSound.cxx | 43 ++++++++++++++++++++++ panda/src/audiotraits/fmodAudioSound.h | 4 ++ panda/src/audiotraits/openalAudioSound.cxx | 37 +++++++++++++++++-- panda/src/audiotraits/openalAudioSound.h | 11 ++++-- 7 files changed, 104 insertions(+), 6 deletions(-) diff --git a/panda/src/audio/audioSound.h b/panda/src/audio/audioSound.h index 7e54c489ae..474020f9be 100644 --- a/panda/src/audio/audioSound.h +++ b/panda/src/audio/audioSound.h @@ -42,6 +42,10 @@ PUBLISHED: virtual void set_loop_count(unsigned long loop_count=1) = 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 * concept) to the seek position within a file. The value starts at 0.0 (the diff --git a/panda/src/audio/nullAudioSound.cxx b/panda/src/audio/nullAudioSound.cxx index 0fbdf14672..558932c8f5 100644 --- a/panda/src/audio/nullAudioSound.cxx +++ b/panda/src/audio/nullAudioSound.cxx @@ -58,6 +58,14 @@ unsigned long NullAudioSound::get_loop_count() const { 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) { // Intentionally blank. } diff --git a/panda/src/audio/nullAudioSound.h b/panda/src/audio/nullAudioSound.h index 8ce58de054..b1ba18f868 100644 --- a/panda/src/audio/nullAudioSound.h +++ b/panda/src/audio/nullAudioSound.h @@ -37,6 +37,9 @@ public: void set_loop_count(unsigned long); unsigned long get_loop_count() const; + void set_loop_start(PN_stdfloat); + PN_stdfloat get_loop_start() const; + void set_time(PN_stdfloat); PN_stdfloat get_time() const; diff --git a/panda/src/audiotraits/fmodAudioSound.cxx b/panda/src/audiotraits/fmodAudioSound.cxx index 260228225a..4908ccdfac 100644 --- a/panda/src/audiotraits/fmodAudioSound.cxx +++ b/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 * already playing, skips to that time immediatey. diff --git a/panda/src/audiotraits/fmodAudioSound.h b/panda/src/audiotraits/fmodAudioSound.h index 112a078138..7762b413d3 100644 --- a/panda/src/audiotraits/fmodAudioSound.h +++ b/panda/src/audiotraits/fmodAudioSound.h @@ -91,6 +91,10 @@ public: void set_loop_count(unsigned long loop_count=1); 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. void set_time(PN_stdfloat start_time=0.0); PN_stdfloat get_time() const; diff --git a/panda/src/audiotraits/openalAudioSound.cxx b/panda/src/audiotraits/openalAudioSound.cxx index 60319249b2..29b92700bc 100644 --- a/panda/src/audiotraits/openalAudioSound.cxx +++ b/panda/src/audiotraits/openalAudioSound.cxx @@ -53,6 +53,7 @@ OpenALAudioSound(OpenALAudioManager* manager, _drop_off_factor(1.0f), _length(0.0), _loop_count(1), + _loop_start(0), _desired_mode(mode), _start_time(0.0), _current_time(0.0), @@ -279,6 +280,36 @@ get_loop_count() const { 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. * 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); if (samples <= 0) { _loops_completed += 1; - cursor->seek(0.0); + cursor->seek(_loop_start); continue; } if (_sd->_stream->ready() == 0) { @@ -411,7 +442,7 @@ read_stream_data(int bytelen, unsigned char *buffer) { } if (samples == 0) { _loops_completed += 1; - cursor->seek(0.0); + cursor->seek(_loop_start); if (_playing_loops >= 1000000000) { // Prevent infinite loop if endlessly looping empty sound return fill; @@ -535,7 +566,7 @@ push_fresh_buffers() { if (_sd->_sample) { while ((_loops_completed < _playing_loops) && (_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; } } else { diff --git a/panda/src/audiotraits/openalAudioSound.h b/panda/src/audiotraits/openalAudioSound.h index 46fbaadca6..24918c5656 100644 --- a/panda/src/audiotraits/openalAudioSound.h +++ b/panda/src/audiotraits/openalAudioSound.h @@ -50,6 +50,10 @@ public: void set_loop_count(unsigned long loop_count=1); 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. void set_time(PN_stdfloat time=0.0); PN_stdfloat get_time() const; @@ -156,10 +160,11 @@ private: PN_stdfloat _max_dist; 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 // periodically corrected thereafter.