Implement OGG looping support; musicians rejoice!

Loops are controlled by two tags in the Vorbis Comment, both in PCM samples.

LOOP_START holds the beginning of the loop, the position to which playback returns at the end of the loop.

LOOP_END is optional; it holds the end of the loop, after which the game seeks to LOOP_START. If undefined, the end of the OGG is the end of the loop. The primary purpose of LOOP_END is if you want to give your file a proper ending for listening outside the game.

To preview a looped OGG you have assembled, give it a ".logg" extension and play it using the vgmstream plugin for Winamp or foobar2000.

git-svn-id: https://svn.eduke32.com/eduke32@3218 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
hendricks266 2012-11-24 09:12:15 +00:00
parent 6c59071155
commit 1f0693eca4

View file

@ -158,13 +158,27 @@ static playbackstatus MV_GetNextVorbisBlock
do { do {
bytes = ov_read(&vd->vf, vd->block + bytesread, BLOCKSIZE - bytesread, 0, 2, 1, &bitstream); bytes = ov_read(&vd->vf, vd->block + bytesread, BLOCKSIZE - bytesread, 0, 2, 1, &bitstream);
//fprintf(stderr, "ov_read = %d\n", bytes); //fprintf(stderr, "ov_read = %d\n", bytes);
if (bytes > 0) { bytesread += bytes; continue; } if (bytes > 0) {
bytesread += bytes;
if ((ogg_int64_t)(intptr_t)voice->LoopEnd > 0
&& ov_pcm_tell(&vd->vf) >= (ogg_int64_t)(intptr_t)voice->LoopEnd) {
err = ov_pcm_seek(&vd->vf,(ogg_int64_t)(intptr_t)voice->LoopStart);
if (err != 0) {
MV_Printf("MV_GetNextVorbisBlock ov_pcm_seek: LOOP_START %l, LOOP_END %l, err %d\n",
(ogg_int64_t)(intptr_t)voice->LoopStart, (ogg_int64_t)(intptr_t)voice->LoopEnd, err);
} else {
continue;
}
}
continue;
}
else if (bytes == OV_HOLE) continue; else if (bytes == OV_HOLE) continue;
else if (bytes == 0) { else if (bytes == 0) {
if (voice->LoopStart) { if (voice->LoopSize > 0) {
err = ov_pcm_seek_page(&vd->vf, 0); err = ov_pcm_seek(&vd->vf,(ogg_int64_t)(intptr_t)voice->LoopStart);
if (err != 0) { if (err != 0) {
MV_Printf("MV_GetNextVorbisBlock ov_pcm_seek_page_lap: err %d\n", err); MV_Printf("MV_GetNextVorbisBlock ov_pcm_seek: LOOP_START %l, err %d\n",
(ogg_int64_t)(intptr_t)voice->LoopStart, err);
} else { } else {
continue; continue;
} }
@ -320,8 +334,6 @@ int32_t MV_PlayLoopedVorbis
vorbis_data * vd = 0; vorbis_data * vd = 0;
vorbis_info * vi = 0; vorbis_info * vi = 0;
UNREFERENCED_PARAMETER(loopend);
if ( !MV_Installed ) if ( !MV_Installed )
{ {
MV_SetErrorCode( MV_NotInstalled ); MV_SetErrorCode( MV_NotInstalled );
@ -387,9 +399,39 @@ int32_t MV_PlayLoopedVorbis
voice->prev = NULL; voice->prev = NULL;
voice->priority = priority; voice->priority = priority;
voice->callbackval = callbackval; voice->callbackval = callbackval;
voice->LoopStart = (char *) (intptr_t)(loopstart >= 0 ? TRUE : FALSE);
voice->LoopEnd = 0; voice->LoopStart = (char *) (intptr_t)(loopstart >= 0 ? loopstart : 0);
voice->LoopSize = 0; voice->LoopEnd = (char *) (intptr_t)(loopstart >= 0 && loopend > 0 ? loopend : 0);
voice->LoopSize = (loopstart >= 0 ? 1 : 0);
// load loop tags from metadata
if (loopstart < 1)
{
vorbis_comment * vc = ov_comment(&vd->vf, 0);
if (vc != NULL)
{
char *vc_loopstart = vorbis_comment_query(vc, "LOOP_START", 0);
if (vc_loopstart != NULL)
{
ogg_int64_t ov_loopstart = atol(vc_loopstart);
if (ov_loopstart >= 0)
{
char *vc_loopend = vorbis_comment_query(vc, "LOOP_END", 0);
voice->LoopStart = (char *) (intptr_t) ov_loopstart;
voice->LoopSize = 1;
if (vc_loopend != NULL)
{
ogg_int64_t ov_loopend = atol(vc_loopend);
if (ov_loopend > 0)
voice->LoopEnd = (char *) (intptr_t) ov_loopend;
}
}
}
}
}
voice->Playing = TRUE; voice->Playing = TRUE;
voice->Paused = FALSE; voice->Paused = FALSE;