summaryrefslogtreecommitdiff
path: root/plugins/ffap
diff options
context:
space:
mode:
authorGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-09-16 21:27:08 +0200
committerGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-09-16 21:27:08 +0200
commit6d505b25848c8db7363e54a6902aebc859f53bc7 (patch)
treeea8bd4b5d748f61c838214de550997d734c95aec /plugins/ffap
parent743cf8e3a236a18080de2fb9467185d54e60afe4 (diff)
gapless playback 2nd iteration - sample-accurate seeking on flac and ape
Diffstat (limited to 'plugins/ffap')
-rw-r--r--plugins/ffap/ffap.c46
1 files changed, 41 insertions, 5 deletions
diff --git a/plugins/ffap/ffap.c b/plugins/ffap/ffap.c
index 8e7d0748..f995f9b2 100644
--- a/plugins/ffap/ffap.c
+++ b/plugins/ffap/ffap.c
@@ -38,11 +38,16 @@
#define ENABLE_DEBUG 0
+#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+//#define trace(fmt,...)
+
static DB_decoder_t plugin;
static DB_functions_t *deadbeef;
-float timestart;
-float timeend;
+static float timestart;
+static float timeend;
+static int startsample;
+static int endsample;
#define PACKET_BUFFER_SIZE 100000
@@ -695,13 +700,18 @@ ffap_init(DB_playItem_t *it)
plugin.info.channels = ape_ctx.channels;
plugin.info.readpos = 0;
if (it->timeend > 0) {
+ startsample = it->startsample;
+ endsample = it->endsample;
timestart = it->timestart;
timeend = it->timeend;
- plugin.seek (0);
+ plugin.seek_sample (0);
+ trace ("start: %d/%f, end: %d/%f\n", startsample, timestart, endsample, timeend);
}
else {
timestart = 0;
timeend = it->duration;
+ startsample = 0;
+ endsample = ape_ctx.totalsamples-1;
}
return 0;
}
@@ -1632,7 +1642,7 @@ ffap_insert (DB_playItem_t *after, const char *fname) {
float duration = ape_ctx.totalsamples / (float)ape_ctx.samplerate;
DB_playItem_t *it;
- it = deadbeef->pl_insert_cue (after, fname, &plugin, "APE", duration);
+ it = deadbeef->pl_insert_cue (after, fname, &plugin, "APE", ape_ctx.totalsamples, ape_ctx.samplerate);
if (it) {
fclose (fp);
ape_free_ctx (&ape_ctx);
@@ -1707,6 +1717,31 @@ ffap_read_int16 (char *buffer, int size) {
}
static int
+ffap_seek_sample (int sample) {
+ sample += startsample;
+ trace ("seeking to %d/%d\n", sample, ape_ctx.totalsamples);
+ uint32_t newsample = sample;
+ if (newsample > ape_ctx.totalsamples) {
+ trace ("eof\n");
+ return -1;
+ }
+ int nframe = newsample / ape_ctx.blocksperframe;
+ if (nframe >= ape_ctx.totalframes) {
+ trace ("eof2\n");
+ return -1;
+ }
+ ape_ctx.currentframe = nframe;
+ ape_ctx.samplestoskip = newsample - nframe * ape_ctx.blocksperframe;
+
+ // reset decoder
+ ape_ctx.packet_remaining = 0;
+ ape_ctx.samples = 0;
+ ape_ctx.currentsample = newsample;
+ plugin.info.readpos = (float)newsample/ape_ctx.samplerate-timestart;
+ return 0;
+}
+
+static int
ffap_seek (float seconds) {
seconds += timestart;
uint32_t newsample = seconds * plugin.info.samplerate;
@@ -1724,7 +1759,7 @@ ffap_seek (float seconds) {
ape_ctx.packet_remaining = 0;
ape_ctx.samples = 0;
ape_ctx.currentsample = newsample;
- plugin.info.readpos = seconds - timestart;
+ plugin.info.readpos = (float)newsample / ape_ctx.samplerate - timestart;
return 0;
}
@@ -1745,6 +1780,7 @@ static DB_decoder_t plugin = {
.free = ffap_free,
.read_int16 = ffap_read_int16,
.seek = ffap_seek,
+ .seek_sample = ffap_seek_sample,
.insert = ffap_insert,
.exts = exts,
.id = "ffap",