Skip to content

Commit

Permalink
Add support for loop points
Browse files Browse the repository at this point in the history
  • Loading branch information
N00byKing committed Mar 12, 2022
1 parent 4949127 commit 7acd82c
Showing 1 changed file with 101 additions and 5 deletions.
106 changes: 101 additions & 5 deletions desktop_version/src/Music.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

#include <SDL.h>
#include <FAudio.h>

#include <physfsrwops.h>

//For stb_vorbis
Expand Down Expand Up @@ -171,6 +170,11 @@ class MusicTrack

decoded_buf_playing = (Uint8*)SDL_malloc(size);
decoded_buf_reserve = (Uint8*)SDL_malloc(size);

loopbegin = 0;
looplength = 0;
stb_vorbis_comment vorbis_comment = stb_vorbis_get_comment(vorbis);
parseComments(this, vorbis_comment.comment_list, vorbis_comment.comment_list_length);
}

void Dispose()
Expand All @@ -188,6 +192,8 @@ class MusicTrack
bool Play(bool loop)
{
/* Create/Validate static FAudioSourceVoice, begin streaming */
shouldloop = loop;
sample_pos = 0;
stb_vorbis_seek_start(vorbis);

if (IsHalted()) {
Expand All @@ -202,10 +208,15 @@ class MusicTrack

FAudioBuffer faudio_buffer;
SDL_memset(&faudio_buffer, 0, sizeof(FAudioBuffer));
faudio_buffer.PlayLength = stb_vorbis_get_samples_float_interleaved(vorbis, channels, (float*)decoded_buf_playing, size/sizeof(float));
if (looplength == 0) {
faudio_buffer.PlayLength = stb_vorbis_get_samples_float_interleaved(vorbis, channels, (float*)decoded_buf_playing, size/sizeof(float));
} else {
faudio_buffer.PlayLength = std::min(stb_vorbis_get_samples_float_interleaved(vorbis, channels, (float*)decoded_buf_playing, size/sizeof(float)), (loopbegin+looplength)-sample_pos);
}
faudio_buffer.AudioBytes = size;
faudio_buffer.pAudioData = decoded_buf_playing;
faudio_buffer.pContext = this;
sample_pos += faudio_buffer.PlayLength;
if (FAudioSourceVoice_SubmitSourceBuffer(musicVoice, &faudio_buffer, NULL)) {
vlog_error("Unable to queue sound buffer");
return false;
Expand Down Expand Up @@ -249,6 +260,9 @@ class MusicTrack
stb_vorbis* vorbis = NULL;
int channels;
Uint32 size;
int loopbegin;
int looplength;
int sample_pos; //stb_vorbis offset not yet functional on pulldata API. TODO Replace when fixed

FAudioVoiceCallback callbacks;
FAudioWaveFormatEx format;
Expand All @@ -264,25 +278,107 @@ class MusicTrack
MusicTrack* t = (MusicTrack*)ctx;
FAudioBuffer faudio_buffer;
SDL_memset(&faudio_buffer, 0, sizeof(FAudioBuffer));
faudio_buffer.PlayLength = stb_vorbis_get_samples_float_interleaved(t->vorbis, t->channels, (float*)t->decoded_buf_reserve, t->size/sizeof(float));
if (t->looplength == 0) {
faudio_buffer.PlayLength = stb_vorbis_get_samples_float_interleaved(t->vorbis, t->channels, (float*)t->decoded_buf_reserve, t->size/sizeof(float));
} else {
faudio_buffer.PlayLength = std::min(stb_vorbis_get_samples_float_interleaved(t->vorbis, t->channels, (float*)t->decoded_buf_reserve, t->size/sizeof(float)), (t->loopbegin+t->looplength)-t->sample_pos);
}
faudio_buffer.AudioBytes = t->size;
faudio_buffer.pAudioData = t->decoded_buf_reserve;
faudio_buffer.pContext = t;
if (faudio_buffer.PlayLength == 0) {
if (t->shouldloop) {
stb_vorbis_seek_start(t->vorbis);
faudio_buffer.PlayLength = stb_vorbis_get_samples_float_interleaved(t->vorbis, t->channels, (float*)t->decoded_buf_reserve, t->size/sizeof(float));
stb_vorbis_seek(t->vorbis, t->loopbegin);
t->sample_pos = t->loopbegin;
if (t->looplength != 0) {
faudio_buffer.PlayLength = std::min(stb_vorbis_get_samples_float_interleaved(t->vorbis, t->channels, (float*)t->decoded_buf_reserve, t->size/sizeof(float)), t->looplength);
} else {
faudio_buffer.PlayLength = stb_vorbis_get_samples_float_interleaved(t->vorbis, t->channels, (float*)t->decoded_buf_reserve, t->size/sizeof(float));
}
if (faudio_buffer.PlayLength == 0) return;
} else {
return;
}
}
t->sample_pos += faudio_buffer.PlayLength;
FAudioSourceVoice_SubmitSourceBuffer(musicVoice, &faudio_buffer, NULL);
}
static void swapBuffers(FAudioVoiceCallback* callback, void* ctx) {
MusicTrack* t = (MusicTrack*)ctx;
std::swap(t->decoded_buf_playing, t->decoded_buf_reserve);
}

//Lifted from sdl_mixer
static void parseComments(MusicTrack* t, char** comments, int comment_list_length) {
int loopend = 0;
for (int i = 0; i < comment_list_length; i++) {
char *param = SDL_strdup(comments[i]);
char *argument = param;
char *value = SDL_strchr(param, '=');
if (value == NULL) {
value = param + SDL_strlen(param);
} else {
*(value++) = '\0';
}

/* Want to match LOOP-START, LOOP_START, etc. Remove - or _ from
* string if it is present at position 4. */
//_Mix_IsLoopTag inlined
char buf[5];
SDL_strlcpy(buf, argument, 5);
if (SDL_strcasecmp(buf, "LOOP") == 0 && ((argument[4] == '_') || (argument[4] == '-'))) {
SDL_memmove(argument + 4, argument + 5, SDL_strlen(argument) - 4);
}

if (SDL_strcasecmp(argument, "LOOPSTART") == 0)
t->loopbegin = _Mix_ParseTime(value, t->format.nSamplesPerSec);
else if (SDL_strcasecmp(argument, "LOOPLENGTH") == 0) {
t->looplength = SDL_strtoll(value, NULL, 10);
} else if (SDL_strcasecmp(argument, "LOOPEND") == 0) {
loopend = _Mix_ParseTime(value, t->format.nSamplesPerSec);
}

SDL_free(param);
}
if (loopend != 0) {
t->looplength = loopend - t->loopbegin;
}
}
//_Mix_ParseTime
static int _Mix_ParseTime(char *time, long samplerate_hz) {
char *num_start, *p;
Sint64 result;
char c;
int val;

/* Time is directly expressed as a sample position */
if (SDL_strchr(time, ':') == NULL) {
return SDL_strtoll(time, NULL, 10);
}

result = 0;
num_start = time;

for (p = time; *p != '\0'; ++p) {
if (*p == '.' || *p == ':') {
c = *p; *p = '\0';
if ((val = SDL_atoi(num_start)) < 0)
return -1;
result = result * 60 + val;
num_start = p + 1;
*p = c;
}

if (*p == '.') {
double val_f = SDL_atof(p);
if (val_f < 0) return -1;
return result * samplerate_hz + (Sint64) (val_f * samplerate_hz);
}
}

if ((val = SDL_atoi(num_start)) < 0) return -1;
return (result * 60 + val) * samplerate_hz;
}
};
FAudioSourceVoice* MusicTrack::musicVoice = NULL;

Expand Down

0 comments on commit 7acd82c

Please sign in to comment.