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

Closes #1347
This commit is contained in:
Disyer 2022-08-04 14:49:14 +03:00 committed by rdb
parent d1d0dab990
commit c28bd047b3
7 changed files with 104 additions and 6 deletions

View File

@ -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

View File

@ -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.
}

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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 {

View File

@ -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.