Unverified Commit 6ca8d9f3 authored by Jake Stine's avatar Jake Stine Committed by GitHub
Browse files

Source: Implement seek by 'seconds' and fix a bug when calling source:seek (#179)

The bug would cause the seek position to become out of date form the file position and trigger an assertion. Note that audio playback was correct if the assertion was disabled.
parent 5baf7c54
......@@ -9,6 +9,7 @@
#include <audio/conversion/float_to_s16.h>
#include <math.h>
#include <assert.h>
#include <errno.h>
/* TODO/FIXME - no sound on big-endian */
......@@ -285,6 +286,8 @@ int audio_newSource(lua_State *L)
audio_Source* self = (audio_Source*)lua_newuserdata(L, sizeof(audio_Source));
self->oggData = NULL;
self->wavData = NULL;
self->sndta = NULL;
self->lua_ref_sndta = LUA_REFNIL;
void *p = lua_touserdata(L, 1);
if (p == NULL)
......@@ -460,18 +463,64 @@ int source_seek(lua_State *L)
return luaL_error(L, "Source:seek requires 3 arguments, %d given.", n);
audio_Source* self = (audio_Source*)luaL_checkudata(L, 1, "Source");
//currently assuming samples vs seconds
//TODO: check if 3rd param is "seconds" or "samples"
self->sndpos = luaL_checkinteger(L, 2);
const char* type = lua_tostring(L, 3);
intmax_t npSamples = 0;
if (type)
{
if (strcmp(type, "seconds") == 0)
{
double npSeconds = luaL_checknumber(L, 2);
npSamples = npSeconds * 44100.0;
}
else if(strcmp(type, "samples") == 0)
{
npSamples = luaL_checkinteger(L, 2);
}
else
{
return luaL_error(L, "Source:seek third argument is invalid, '%s' given. Expected either 'seconds' or 'samples'.\n", type);
}
}
else
{
// assume samples if third paramter is unspecified
npSamples = luaL_checkinteger(L, 2);
}
if (self->wavData)
decWav_seek(self->wavData, self->sndpos);
{
if (!decWav_seek(self->wavData, npSamples))
{
// TODO: it'd be nice to log with the full lua FILE(LINE): context that's normally prefixed by lua_error,
// in a manner that allows us to log it without stopping the system. --jstine
fprintf(stderr, "WAV decoder seek failed: %s\n", strerror(errno));
fflush(stdout);
}
self->sndpos = decWav_sampleTell(self->wavData);
}
if (self->oggData)
decOgg_seek(self->oggData, self->sndpos);
{
decOgg_seek(self->oggData, npSamples);
self->sndpos = decWav_sampleTell(self->wavData);
}
if (self->sndta)
{
self->sndpos = npSamples;
if (self->sndpos > self->sndta->numSamples)
self->sndpos = self->sndta->numSamples;
}
if (npSamples != self->sndpos)
{
// the underlying media source will fixup the seek position...
fprintf(stderr, "warning: seek asked for sample pos %jd, got pos %jd\n", npSamples, self->sndpos);
fflush(stderr);
}
return 0;
}
......
......@@ -4,6 +4,7 @@
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include "decoder.h"
#include "audio.h"
......@@ -210,12 +211,14 @@ bool decWav_init(dec_WavData *data, const char *filename)
return 0;
fprintf(stderr, "Failed to open wavfile '%s': %s\n", filename, strerror(err));
fflush(stderr);
return 0;
}
if (fread(&data->head, WAV_HEADER_SIZE, 1, fp) == 0)
{
fprintf(stderr, "%s is not a valid wav file or is truncated.\n", filename);
fflush(stderr);
fclose(fp);
return 0;
}
......@@ -228,14 +231,31 @@ bool decWav_init(dec_WavData *data, const char *filename)
bool decWav_seek(dec_WavData *data, intmax_t samplepos)
{
int bps = ((data->head.BitsPerSample + 7) / 8) * data->head.NumChannels;
intmax_t bytepos = samplepos * bps;
int numSamples = data->head.Subchunk2Size;
// fseek will let us seek past the end of file without returning an error.
// So it is best to verify positions against the know sample size.
// TODO: Verify Love2D Behavior? Love2D doesn't specify behavior in this case.
// Options are set the seekpos to 0, or set the seekpos to numSamples.
if (!fseek(data->fp, WAV_HEADER_SIZE + bytepos, SEEK_SET))
if (samplepos > numSamples)
{
// set to numSamples
// * if the sample is set to loop it will restart immediately from loop pos
// * If not set to loop, it will stop immediately.
samplepos = numSamples;
}
intmax_t bytepos = samplepos * bps;
if (fseek(data->fp, WAV_HEADER_SIZE + bytepos, SEEK_SET))
{
// logging here could be unnecessarily spammy. If we add a log it should be gated by
// some audio diagnostic output switch/mode.
//fprintf(stderr, "WAV decoder seek failed: %s\n", strerror(errno));
//fflush(stdout);
return 0;
}
data->pos = samplepos * bps;
return 1;
}
......@@ -256,6 +276,7 @@ intmax_t decWav_sampleTell(dec_WavData *data)
data->head.NumChannels,
ret
);
fflush(stderr);
}
}
return ret / bps;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment