summaryrefslogtreecommitdiff
path: root/examples/decoder_template.c
diff options
context:
space:
mode:
authorGravatar waker <wakeroid@gmail.com>2011-01-02 12:24:03 +0100
committerGravatar waker <wakeroid@gmail.com>2011-01-02 12:24:03 +0100
commit4c90be31a1be29701c3fcca0cd67cb2114e18e15 (patch)
tree3351347735b93706e58b5da8358514415d41f34c /examples/decoder_template.c
parentbe0631a8bbf54616547a54121efa1d7c7cf606bb (diff)
slightly updater decoder_template; added dsp_template; moved plugin templates to examples folder
Diffstat (limited to 'examples/decoder_template.c')
-rw-r--r--examples/decoder_template.c221
1 files changed, 221 insertions, 0 deletions
diff --git a/examples/decoder_template.c b/examples/decoder_template.c
new file mode 100644
index 00000000..b6e6585b
--- /dev/null
+++ b/examples/decoder_template.c
@@ -0,0 +1,221 @@
+// this is a decoder plugin skeleton
+// use to create new decoder plugins
+
+#include <stdlib.h>
+#include <string.h>
+#include <deadbeef/deadbeef.h>
+
+#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+
+static DB_decoder_t plugin;
+static DB_functions_t *deadbeef;
+
+typedef struct {
+ DB_fileinfo_t info;
+ int startsample;
+ int endsample;
+ int currentsample;
+} example_info_t;
+
+static const char * exts[] = { "example", NULL }; // e.g. mp3
+static const char *filetypes[] = { "example", NULL }; // e.g. MP3
+
+// allocate codec control structure
+static DB_fileinfo_t *
+example_open (uint32_t hints) {
+ DB_fileinfo_t *_info = malloc (sizeof (example_info_t));
+ example_info_t *info = (example_info_t *)_info;
+ memset (info, 0, sizeof (example_info_t));
+ return _info;
+}
+
+// prepare to decode the track, fill in mandatory plugin fields
+// return -1 on failure
+static int
+example_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
+ example_info_t *info = (example_info_t *)_info;
+
+ // take this parameters from your input file
+ // we set constants for clarity sake
+ _info->fmt.bps = 16;
+ _info->fmt.channels = 2;
+ _info->fmt.samplerate = 44100;
+ for (int i = 0; i < _info->fmt.channels; i++) {
+ _info->fmt.channelmask |= 1 << i;
+ }
+ _info->readpos = 0;
+ _info->plugin = &plugin;
+
+ if (it->endsample > 0) {
+ info->startsample = it->startsample;
+ info->endsample = it->endsample;
+ plugin.seek_sample (_info, 0);
+ }
+ else {
+ info->startsample = 0;
+ int TOTALSAMPLES = 1000; // calculate from file
+ info->endsample = TOTALSAMPLES-1;
+ }
+ return 0;
+}
+
+// free everything allocated in _init
+static void
+example_free (DB_fileinfo_t *_info) {
+ example_info_t *info = (example_info_t *)_info;
+ if (info) {
+ free (info);
+ }
+}
+
+
+// try decode `size' bytes
+// return number of decoded bytes
+// or 0 on EOF/error
+static int
+example_read (DB_fileinfo_t *_info, char *bytes, int size) {
+ example_info_t *info = (example_info_t *)_info;
+ info->currentsample += size / (_info->fmt.channels * _info->fmt.bps/8);
+ return size;
+}
+
+// seek to specified sample (frame)
+// return 0 on success
+// return -1 on failure
+static int
+example_seek_sample (DB_fileinfo_t *_info, int sample) {
+ example_info_t *info = (example_info_t *)_info;
+
+ info->currentsample = sample + info->startsample;
+ _info->readpos = (float)sample / _info->fmt.samplerate;
+ return 0;
+}
+
+// seek to specified time in seconds
+// return 0 on success
+// return -1 on failure
+static int
+example_seek (DB_fileinfo_t *_info, float time) {
+ return example_seek_sample (_info, time * _info->fmt.samplerate);
+}
+
+// read information from the track
+// load/process cuesheet if exists
+// insert track into playlist
+// return track pointer on success
+// return NULL on failure
+
+static DB_playItem_t *
+example_insert (DB_playItem_t *after, const char *fname) {
+ // open file
+ DB_FILE *fp = deadbeef->fopen (fname);
+ if (!fp) {
+ trace ("example: failed to fopen %s\n", fname);
+ return NULL;
+ }
+ decoder_info_t *di = decoder_open ();
+ if (!di) {
+ trace ("example: failed to init decoder\n");
+ return NULL;
+ }
+ // read track info/tags
+ track_info_t ti;
+ if (decoder_read_info (&ti) < 0) {
+ trace ("example: failed to read info\n");
+ decoder_free (di);
+ return NULL;
+ }
+
+ // now we should have track duration, and can try loading cuesheet
+ // 1st try embedded cuesheet
+ if (ti.embeddedcuesheet[0]) {
+ DB_playItem_t *cue = deadbeef->pl_insert_cue_from_buffer (after, fname, ti.embeddedcuesheet, strlen (ti.embeddedcuesheet), &plugin, plugin.filetypes[0], ti.total_num_samples, ti.samplerate);
+ if (cue) {
+ // cuesheet loaded
+ decoder_free (di);
+ return cue;
+ }
+ }
+
+ // embedded cuesheet not found, try external one
+ DB_playItem_t *cue = deadbeef->pl_insert_cue (after, fname, &plugin, plugin.filetypes[0], ti.total_num_samples, ti.samplerate);
+ if (cue) {
+ // cuesheet loaded
+ decoder_free (di);
+ return cue;
+ }
+
+ // no cuesheet, prepare track for addition
+ DB_playItem_t *it = deadbeef->pl_item_alloc ();
+ it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
+ it->fname = strdup (fname);
+ it->filetype = filetypes[0];
+ deadbeef->pl_set_item_duration (it, (float)ti.total_num_samples/ti.samplerate);
+
+ // add metainfo
+ if (!strlen (ti.title)) {
+ // title is empty, this call will set track title to filename without extension
+ deadbeef->pl_add_meta (it, "title", NULL);
+ }
+ else {
+ deadbeef->pl_add_meta (it, "title", ti.title);
+ }
+ deadbeef->pl_add_meta (it, "artist", ti.artist);
+ // ... etc ...
+
+ // free decoder
+ decoder_free (di);
+
+ // now the track is ready, insert into playlist
+ after = deadbeef->pl_insert_item (after, it);
+ deadbeef->pl_item_unref (it);
+ return after;
+}
+
+static int
+example_start (void) {
+ // do one-time plugin initialization here
+ // e.g. starting threads for background processing, subscribing to events, etc
+ // return 0 on success
+ // return -1 on failure
+ return 0;
+}
+
+static int
+example_stop (void) {
+ // undo everything done in _start here
+ // return 0 on success
+ // return -1 on failure
+ return 0;
+}
+
+// define plugin interface
+static DB_decoder_t plugin = {
+ DB_PLUGIN_SET_API_VERSION
+ .plugin.version_major = 0,
+ .plugin.version_minor = 1,
+ .plugin.type = DB_PLUGIN_DECODER,
+ .plugin.name = "short plugin name",
+ .plugin.descr = "plugin description",
+ .plugin.author = "author name",
+ .plugin.email = "author email",
+ .plugin.website = "author/plugin website",
+ .plugin.start = example_start,
+ .plugin.stop = example_stop,
+ .init = example_init,
+ .free = example_free,
+ .read = example_read,
+ .seek = example_seek,
+ .seek_sample = example_seek_sample,
+ .insert = example_insert,
+ .exts = exts,
+ .id = "example",
+ .filetypes = filetypes
+};
+
+DB_plugin_t *
+example_load (DB_functions_t *api) {
+ deadbeef = api;
+ return DB_PLUGIN (&plugin);
+}
+