summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deadbeef.h12
-rw-r--r--playlist.c47
-rw-r--r--playlist.h6
-rw-r--r--plugins.c4
-rw-r--r--plugins/ffap/ffap.c46
-rw-r--r--plugins/flac/flac.c82
-rw-r--r--plugins/mpgmad/mpgmad.c3
-rw-r--r--plugins/vorbis/vorbis.c2
-rw-r--r--streamer.c4
9 files changed, 114 insertions, 92 deletions
diff --git a/deadbeef.h b/deadbeef.h
index fc9fd897..05fb499c 100644
--- a/deadbeef.h
+++ b/deadbeef.h
@@ -54,7 +54,7 @@ extern "C" {
// DON'T release plugins without DB_PLUGIN_SET_API_VERSION
#define DB_API_VERSION_MAJOR 0
-#define DB_API_VERSION_MINOR 1
+#define DB_API_VERSION_MINOR 2
#define DB_PLUGIN_SET_API_VERSION\
.plugin.api_vmajor = DB_API_VERSION_MAJOR,\
@@ -64,11 +64,13 @@ extern "C" {
// playlist structures
// playlist item
-// there are "public" fields, available to plugins
+// these are "public" fields, available to plugins
typedef struct {
char *fname; // full pathname
struct DB_decoder_s *decoder; // codec to use with this file
int tracknum; // used for stuff like sid, nsf, cue (will be ignored by most codecs)
+ int startsample;
+ int endsample;
float timestart; // start time of cue track, or -1
float timeend; // end time of cue track, or -1
float duration; // in seconds
@@ -164,8 +166,8 @@ typedef struct {
void (*pl_add_meta) (DB_playItem_t *it, const char *key, const char *value);
const char *(*pl_find_meta) (DB_playItem_t *song, const char *meta);
// cuesheet support
- DB_playItem_t *(*pl_insert_cue_from_buffer) (DB_playItem_t *after, const char *fname, const uint8_t *buffer, int buffersize, struct DB_decoder_s *decoder, const char *ftype, float duration);
- DB_playItem_t * (*pl_insert_cue) (DB_playItem_t *after, const char *filename, struct DB_decoder_s *decoder, const char *ftype, float duration);
+ DB_playItem_t *(*pl_insert_cue_from_buffer) (DB_playItem_t *after, const char *fname, const uint8_t *buffer, int buffersize, struct DB_decoder_s *decoder, const char *ftype, int numsamples, int samplerate);
+ DB_playItem_t * (*pl_insert_cue) (DB_playItem_t *after, const char *filename, struct DB_decoder_s *decoder, const char *ftype, int numsamples, int samplerate);
// volume control
void (*volume_set_db) (float dB);
float (*volume_get_db) (void);
@@ -239,7 +241,7 @@ typedef struct DB_decoder_s {
// perform seeking in samples (if possible)
// return -1 if failed, or 0 on success
// if -1 is returned, that will mean that streamer must skip that song
- int (*seek_sample) (int64_t samples);
+ int (*seek_sample) (int sample);
// 'insert' is called to insert new item to playlist
// decoder is responsible to calculate duration, split it into subsongs, load cuesheet, etc
diff --git a/playlist.c b/playlist.c
index bbe99e3e..191168df 100644
--- a/playlist.c
+++ b/playlist.c
@@ -35,12 +35,8 @@
#include "plugins.h"
#include "junklib.h"
-//#include "cvorbis.h"
-//#include "cdumb.h"
-//#include "cmp3.h"
-//#include "cgme.h"
-//#include "cflac.h"
-//#include "csid.h"
+#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+//#define trace(fmt,...)
#define SKIP_BLANK_CUE_TRACKS 1
@@ -146,7 +142,7 @@ pl_cue_parse_time (const char *p) {
}
static playItem_t *
-pl_process_cue_track (playItem_t *after, const char *fname, playItem_t **prev, char *track, char *index00, char *index01, char *pregap, char *title, char *performer, char *albumtitle, struct DB_decoder_s *decoder, const char *ftype) {
+pl_process_cue_track (playItem_t *after, const char *fname, playItem_t **prev, char *track, char *index00, char *index01, char *pregap, char *title, char *performer, char *albumtitle, struct DB_decoder_s *decoder, const char *ftype, int samplerate) {
if (!track[0]) {
return after;
}
@@ -181,6 +177,11 @@ pl_process_cue_track (playItem_t *after, const char *fname, playItem_t **prev, c
// no pregap
(*prev)->timeend = f_index01;
}
+ else {
+ return after;
+ }
+ (*prev)->endsample = ((*prev)->timeend * samplerate) - 1;
+ trace ("calc endsample=%d, timeend=%f, samplerate=%d\n", (*prev)->endsample, (*prev)->timeend, samplerate);
(*prev)->duration = (*prev)->timeend - (*prev)->timestart;
}
// non-compliant hack to handle tracks which only store pregap info
@@ -199,6 +200,7 @@ pl_process_cue_track (playItem_t *after, const char *fname, playItem_t **prev, c
else {
it->timestart = f_index00;
}
+ it->startsample = it->timestart * samplerate;
it->timeend = -1; // will be filled by next read, or by decoder
it->filetype = ftype;
@@ -212,7 +214,8 @@ pl_process_cue_track (playItem_t *after, const char *fname, playItem_t **prev, c
}
playItem_t *
-pl_insert_cue_from_buffer (playItem_t *after, const char *fname, const uint8_t *buffer, int buffersize, struct DB_decoder_s *decoder, const char *ftype, float duration) {
+pl_insert_cue_from_buffer (playItem_t *after, const char *fname, const uint8_t *buffer, int buffersize, struct DB_decoder_s *decoder, const char *ftype, int numsamples, int samplerate) {
+ trace ("pl_insert_cue_from_buffer numsamples=%d, samplerate=%d\n", numsamples, samplerate);
char performer[256] = "";
char albumtitle[256] = "";
char track[256] = "";
@@ -258,7 +261,7 @@ pl_insert_cue_from_buffer (playItem_t *after, const char *fname, const uint8_t *
}
else if (!strncmp (p, "TRACK ", 6)) {
// add previous track
- after = pl_process_cue_track (after, fname, &prev, track, index00, index01, pregap, title, performer, albumtitle, decoder, ftype);
+ after = pl_process_cue_track (after, fname, &prev, track, index00, index01, pregap, title, performer, albumtitle, decoder, ftype, samplerate);
track[0] = 0;
title[0] = 0;
pregap[0] = 0;
@@ -284,16 +287,18 @@ pl_insert_cue_from_buffer (playItem_t *after, const char *fname, const uint8_t *
// fprintf (stderr, "got unknown line:\n%s\n", p);
}
}
- after = pl_process_cue_track (after, fname, &prev, track, index00, index01, pregap, title, performer, albumtitle, decoder, ftype);
+ after = pl_process_cue_track (after, fname, &prev, track, index00, index01, pregap, title, performer, albumtitle, decoder, ftype, samplerate);
if (after) {
- after->timeend = duration;
+ after->endsample = numsamples-1;
+ after->timeend = (float)numsamples/samplerate;
after->duration = after->timeend - after->timestart;
}
return after;
}
playItem_t *
-pl_insert_cue (playItem_t *after, const char *fname, struct DB_decoder_s *decoder, const char *ftype, float duration) {
+pl_insert_cue (playItem_t *after, const char *fname, struct DB_decoder_s *decoder, const char *ftype, int numsamples, int samplerate) {
+ trace ("pl_insert_cue numsamples=%d, samplerate=%d\n", numsamples, samplerate);
int len = strlen (fname);
char cuename[len+5];
strcpy (cuename, fname);
@@ -323,7 +328,7 @@ pl_insert_cue (playItem_t *after, const char *fname, struct DB_decoder_s *decode
return NULL;
}
fclose (fp);
- return pl_insert_cue_from_buffer (after, fname, buf, sz, decoder, ftype, duration);
+ return pl_insert_cue_from_buffer (after, fname, buf, sz, decoder, ftype, numsamples, samplerate);
}
playItem_t *
@@ -590,6 +595,8 @@ pl_item_copy (playItem_t *out, playItem_t *it) {
out->fname = strdup (it->fname);
out->decoder = it->decoder;
out->tracknum = it->tracknum;
+ out->startsample = it->startsample;
+ out->endsample = it->endsample;
out->timestart = it->timestart;
out->timeend = it->timeend;
out->duration = it->duration;
@@ -1027,6 +1034,12 @@ pl_save (const char *fname) {
if (fwrite (&l, 1, 2, fp) != 2) {
goto save_fail;
}
+ if (fwrite (&it->startsample, 1, 4, fp) != 4) {
+ goto save_fail;
+ }
+ if (fwrite (&it->endsample, 1, 4, fp) != 4) {
+ goto save_fail;
+ }
if (fwrite (&it->timestart, 1, 4, fp) != 4) {
goto save_fail;
}
@@ -1158,6 +1171,14 @@ pl_load (const char *fname) {
goto load_fail;
}
it->tracknum = l;
+ // startsample
+ if (fread (&it->startsample, 1, 4, fp) != 4) {
+ goto load_fail;
+ }
+ // endsample
+ if (fread (&it->endsample, 1, 4, fp) != 4) {
+ goto load_fail;
+ }
// timestart
if (fread (&it->timestart, 1, 4, fp) != 4) {
goto load_fail;
diff --git a/playlist.h b/playlist.h
index 40fdc7db..21754102 100644
--- a/playlist.h
+++ b/playlist.h
@@ -35,6 +35,8 @@ typedef struct playItem_s {
char *fname; // full pathname
struct DB_decoder_s *decoder; // codec to use with this file
int tracknum; // used for stuff like sid, nsf, cue (will be ignored by most codecs)
+ int startsample;
+ int endsample;
float timestart; // start time of cue track, or -1
float timeend; // end time of cue track, or -1
float duration; // in seconds
@@ -103,10 +105,10 @@ int
pl_get_idx_of (playItem_t *it);
playItem_t *
-pl_insert_cue_from_buffer (playItem_t *after, const char *fname, const uint8_t *buffer, int buffersize, struct DB_decoder_s *decoder, const char *ftype, float duration);
+pl_insert_cue_from_buffer (playItem_t *after, const char *fname, const uint8_t *buffer, int buffersize, struct DB_decoder_s *decoder, const char *ftype, int numsamples, int samplerate);
playItem_t *
-pl_insert_cue (playItem_t *after, const char *cuename, struct DB_decoder_s *decoder, const char *ftype, float duration);
+pl_insert_cue (playItem_t *after, const char *cuename, struct DB_decoder_s *decoder, const char *ftype, int numsamples, int samplerate);
//int
//pl_set_current (playItem_t *it);
diff --git a/plugins.c b/plugins.c
index 4a91641b..85067630 100644
--- a/plugins.c
+++ b/plugins.c
@@ -85,8 +85,8 @@ static DB_functions_t deadbeef_api = {
.pl_add_meta = (void (*) (DB_playItem_t *, const char *, const char *))pl_add_meta,
.pl_find_meta = (const char *(*) (DB_playItem_t *, const char *))pl_find_meta,
// cuesheet support
- .pl_insert_cue_from_buffer = (DB_playItem_t *(*) (DB_playItem_t *after, const char *fname, const uint8_t *buffer, int buffersize, struct DB_decoder_s *decoder, const char *ftype, float duration))pl_insert_cue_from_buffer,
- .pl_insert_cue = (DB_playItem_t *(*)(DB_playItem_t *, const char *, struct DB_decoder_s *, const char *ftype, float duration))pl_insert_cue,
+ .pl_insert_cue_from_buffer = (DB_playItem_t *(*) (DB_playItem_t *after, const char *fname, const uint8_t *buffer, int buffersize, struct DB_decoder_s *decoder, const char *ftype, int numsamples, int samplerate))pl_insert_cue_from_buffer,
+ .pl_insert_cue = (DB_playItem_t *(*)(DB_playItem_t *, const char *, struct DB_decoder_s *, const char *ftype, int numsamples, int samplerate))pl_insert_cue,
// volume control
.volume_set_db = plug_volume_set_db,
.volume_get_db = volume_get_db,
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",
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",
diff --git a/plugins/mpgmad/mpgmad.c b/plugins/mpgmad/mpgmad.c
index 74847f37..c083b2c8 100644
--- a/plugins/mpgmad/mpgmad.c
+++ b/plugins/mpgmad/mpgmad.c
@@ -952,7 +952,8 @@ cmp3_insert (DB_playItem_t *after, const char *fname) {
break;
}
}
- DB_playItem_t *cue_after = deadbeef->pl_insert_cue (after, fname, &plugin, ftype, buffer.duration);
+ // FIXME! bad numsamples passed to cue
+ DB_playItem_t *cue_after = deadbeef->pl_insert_cue (after, fname, &plugin, ftype, buffer.duration*buffer.samplerate, buffer.samplerate);
if (cue_after) {
fclose (fp);
return cue_after;
diff --git a/plugins/vorbis/vorbis.c b/plugins/vorbis/vorbis.c
index 6daba52a..d0eef1a9 100644
--- a/plugins/vorbis/vorbis.c
+++ b/plugins/vorbis/vorbis.c
@@ -153,7 +153,7 @@ cvorbis_insert (DB_playItem_t *after, const char *fname) {
return NULL;
}
float duration = ov_time_total (&vorbis_file, -1);
- DB_playItem_t *cue_after = deadbeef->pl_insert_cue (after, fname, &plugin, "OggVorbis", duration);
+ DB_playItem_t *cue_after = deadbeef->pl_insert_cue (after, fname, &plugin, "OggVorbis", duration, vi->rate);
if (cue_after) {
ov_clear (&vorbis_file);
return cue_after;
diff --git a/streamer.c b/streamer.c
index dd012003..e74866f1 100644
--- a/streamer.c
+++ b/streamer.c
@@ -63,8 +63,8 @@ playItem_t str_streaming_song;
static playItem_t *orig_playing_song;
static playItem_t *orig_streaming_song;
-#define trace(...) { fprintf(stderr, __VA_ARGS__); }
-//#define trace(fmt,...)
+//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+#define trace(fmt,...)
// playlist must call that whenever item was removed
void