diff options
author | waker <wakeroid@gmail.com> | 2011-01-02 12:24:03 +0100 |
---|---|---|
committer | waker <wakeroid@gmail.com> | 2011-01-02 12:24:03 +0100 |
commit | 4c90be31a1be29701c3fcca0cd67cb2114e18e15 (patch) | |
tree | 3351347735b93706e58b5da8358514415d41f34c /examples/decoder_template.c | |
parent | be0631a8bbf54616547a54121efa1d7c7cf606bb (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.c | 221 |
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); +} + |