summaryrefslogtreecommitdiff
path: root/plugins/flac
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/flac
parent743cf8e3a236a18080de2fb9467185d54e60afe4 (diff)
gapless playback 2nd iteration - sample-accurate seeking on flac and ape
Diffstat (limited to 'plugins/flac')
-rw-r--r--plugins/flac/flac.c82
1 files changed, 21 insertions, 61 deletions
diff --git a/plugins/flac/flac.c b/plugins/flac/flac.c
index 5188947e..b7d0277e 100644
--- a/plugins/flac/flac.c
+++ b/plugins/flac/flac.c
@@ -33,6 +33,8 @@ static char buffer[BUFFERSIZE]; // this buffer always has int32 samples
static int remaining; // bytes remaining in buffer from last read
static float timestart;
static float timeend;
+static int startsample;
+static int endsample;
static FLAC__StreamDecoderWriteStatus
cflac_write_callback (const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const inputbuffer[], void *client_data) {
@@ -142,8 +144,10 @@ cflac_init (DB_playItem_t *it) {
}
timestart = it->timestart;
timeend = it->timeend;
+ startsample = it->startsample;
+ endsample = it->endsample;
if (timeend > timestart || timeend < 0) {
- plugin.seek (0);
+ plugin.seek_sample (0);
}
plugin.info.readpos = 0;
@@ -256,6 +260,17 @@ cflac_seek (float time) {
return 0;
}
+static int
+cflac_seek_sample (int sample) {
+ sample += startsample;
+ if (!FLAC__stream_decoder_seek_absolute (decoder, (FLAC__uint64)(sample))) {
+ return -1;
+ }
+ remaining = 0;
+ plugin.info.readpos = (float)sample / plugin.info.samplerate - timestart;
+ return 0;
+}
+
static FLAC__StreamDecoderWriteStatus
cflac_init_write_callback (const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const inputbuffer[], void *client_data) {
if (frame->header.blocksize == 0 || cflac_init_stop_decoding) {
@@ -271,6 +286,7 @@ typedef struct {
int samplerate;
int nchannels;
float duration;
+ int totalsamples;
} cue_cb_data_t;
static void
@@ -283,65 +299,8 @@ cflac_init_cue_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC_
cb->samplerate = metadata->data.stream_info.sample_rate;
cb->nchannels = metadata->data.stream_info.channels;
cb->duration = metadata->data.stream_info.total_samples / (float)metadata->data.stream_info.sample_rate;
+ cb->totalsamples = metadata->data.stream_info.total_samples;
}
- // {{{ disabled
-#if 0
- else if (metadata->type == FLAC__METADATA_TYPE_CUESHEET) {
- //printf ("loading embedded cuesheet!\n");
- const FLAC__StreamMetadata_CueSheet *cue = &metadata->data.cue_sheet;
- DB_playItem_t *prev = NULL;
- for (int i = 0; i < cue->num_tracks; i++) {
- FLAC__StreamMetadata_CueSheet_Track *t = &cue->tracks[i];
- if (t->type == 0 && t->num_indices > 0) {
- FLAC__StreamMetadata_CueSheet_Index *idx = t->indices;
- DB_playItem_t *it = malloc (sizeof (DB_playItem_t));
- memset (it, 0, sizeof (DB_playItem_t));
- it->decoder = &plugin;
- it->fname = strdup (cb->fname);
- it->tracknum = t->number;
- it->timestart = (float)t->offset / cb->samplerate;
- it->timeend = -1; // will be filled by next read
- if (prev) {
- prev->timeend = it->timestart;
- prev->duration = prev->timeend - prev->timestart;
- }
- it->filetype = "FLAC";
- //printf ("N: %d, t: %f, bps=%d\n", it->tracknum, it->timestart/60.f, cb->samplerate);
- DB_playItem_t *ins = deadbeef->pl_insert_item (cb->last, it);
- if (ins) {
- cb->last = ins;
- }
- else {
- deadbeef->pl_item_free (it);
- it = NULL;
- }
- prev = it;
- }
- }
- if (prev) {
- prev->timeend = cb->duration;
- prev->duration = prev->timeend - prev->timestart;
- }
- }
- else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
- DB_playItem_t *it = NULL;
- if (cb->after) {
- it = cb->after->next[PL_MAIN];
- }
- else if (cb->last) {
- it = playlist_head[PL_MAIN];
- }
- if (it) {
- for (; it != cb->last->next[PL_MAIN]; it = it->next[PL_MAIN]) {
- char str[10];
- snprintf (str, 10, "%d", it->tracknum);
- pl_add_meta (it, "track", str);
- pl_add_meta (it, "title", NULL);
- }
- }
- }
-#endif
-// }}}
else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
const FLAC__StreamMetadata_VorbisComment *vc = &metadata->data.vorbis_comment;
for (int i = 0; i < vc->num_comments; i++) {
@@ -351,7 +310,7 @@ cflac_init_cue_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC_
s[c->length] = 0;
memcpy (s, c->entry, c->length);
if (!strncasecmp (s, "cuesheet=", 9)) {
- cb->last = deadbeef->pl_insert_cue_from_buffer (cb->after, cb->fname, s+9, c->length-9, &plugin, "FLAC", cb->duration);
+ cb->last = deadbeef->pl_insert_cue_from_buffer (cb->after, cb->fname, s+9, c->length-9, &plugin, "FLAC", cb->totalsamples, cb->samplerate);
}
}
}
@@ -463,7 +422,7 @@ cflac_insert (DB_playItem_t *after, const char *fname) {
}
// try external cue
- DB_playItem_t *cue_after = deadbeef->pl_insert_cue (after, fname, &plugin, "flac", cb.duration);
+ DB_playItem_t *cue_after = deadbeef->pl_insert_cue (after, fname, &plugin, "flac", cb.totalsamples, cb.samplerate);
if (cue_after) {
cue_after->timeend = cb.duration;
cue_after->duration = cue_after->timeend - cue_after->timestart;
@@ -527,6 +486,7 @@ static DB_decoder_t plugin = {
.read_int16 = cflac_read_int16,
.read_float32 = cflac_read_float32,
.seek = cflac_seek,
+ .seek_sample = cflac_seek_sample,
.insert = cflac_insert,
.exts = exts,
.id = "stdflac",