summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/converter/Makefile23
-rw-r--r--plugins/converter/converter.c774
-rw-r--r--plugins/converter/converter.h137
3 files changed, 934 insertions, 0 deletions
diff --git a/plugins/converter/Makefile b/plugins/converter/Makefile
new file mode 100644
index 00000000..2c58d6a3
--- /dev/null
+++ b/plugins/converter/Makefile
@@ -0,0 +1,23 @@
+OUT=converter.so
+
+CC=gcc
+
+CFLAGS+=-Wall -D_GNU_SOURCE -std=c99 -I../..
+
+LDFLAGS+=-module -shared -fPIC
+
+SOURCES=converter.c
+
+OBJECTS=$(SOURCES:.c=.o)
+
+all: $(SOURCES) $(OUT)
+
+$(OUT): $(OBJECTS)
+ $(CC) $(LDFLAGS) $(OBJECTS) -o $@
+
+.c.o:
+ $(CC) $(CFLAGS) $< -c -o $@
+
+clean:
+ rm $(OBJECTS) $(OUT)
+
diff --git a/plugins/converter/converter.c b/plugins/converter/converter.c
new file mode 100644
index 00000000..54d21245
--- /dev/null
+++ b/plugins/converter/converter.c
@@ -0,0 +1,774 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include "converter.h"
+#include <deadbeef.h>
+
+#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+//#define trace(fmt,...)
+
+static ddb_converter_t plugin;
+static DB_functions_t *deadbeef;
+
+static ddb_encoder_preset_t *encoder_presets;
+static ddb_dsp_preset_t *dsp_presets;
+
+ddb_encoder_preset_t *
+encoder_preset_alloc (void) {
+ ddb_encoder_preset_t *p = malloc (sizeof (ddb_encoder_preset_t));
+ if (!p) {
+ fprintf (stderr, "failed to alloc ddb_encoder_preset_t\n");
+ return NULL;
+ }
+ memset (p, 0, sizeof (ddb_encoder_preset_t));
+ return p;
+}
+
+void
+encoder_preset_free (ddb_encoder_preset_t *p) {
+ if (p) {
+ if (p->title) {
+ free (p->title);
+ }
+ if (p->fname) {
+ free (p->fname);
+ }
+ if (p->encoder) {
+ free (p->encoder);
+ }
+ free (p);
+ }
+}
+
+ddb_encoder_preset_t *
+encoder_preset_load (const char *fname) {
+ int err = 1;
+ FILE *fp = fopen (fname, "rt");
+ if (!fp) {
+ return NULL;
+ }
+ ddb_encoder_preset_t *p = encoder_preset_alloc ();
+
+ char str[1024];
+ while (fgets (str, sizeof (str), fp)) {
+ // chomp
+ char *cr = str + strlen (str) - 1;
+ while (*cr == '\n') {
+ cr--;
+ }
+ cr++;
+ *cr = 0;
+
+ char *sp = strchr (str, ' ');
+ if (!sp) {
+ continue;
+ }
+
+ *sp = 0;
+ char *item = sp + 1;
+
+ if (!strcmp (str, "title")) {
+ p->title = strdup (item);
+ }
+ else if (!strcmp (str, "fname")) {
+ p->fname = strdup (item);
+ }
+ else if (!strcmp (str, "encoder")) {
+ p->encoder = strdup (item);
+ }
+ else if (!strcmp (str, "method")) {
+ p->method = atoi (item);
+ }
+ else if (!strcmp (str, "formats")) {
+ sscanf (item, "%X", &p->formats);
+ }
+ }
+
+ err = 0;
+error:
+ if (err) {
+ encoder_preset_free (p);
+ p = NULL;
+ }
+ if (fp) {
+ fclose (fp);
+ }
+ return p;
+}
+
+// @return -1 on path/write error, -2 if file already exists
+int
+encoder_preset_save (ddb_encoder_preset_t *p, int overwrite) {
+ const char *confdir = deadbeef->get_config_dir ();
+ char path[1024];
+ if (snprintf (path, sizeof (path), "%s/presets", confdir) < 0) {
+ return -1;
+ }
+ mkdir (path, 0755);
+ if (snprintf (path, sizeof (path), "%s/presets/encoders", confdir) < 0) {
+ return -1;
+ }
+ mkdir (path, 0755);
+ if (snprintf (path, sizeof (path), "%s/presets/encoders/%s.txt", confdir, p->title) < 0) {
+ return -1;
+ }
+
+ if (!overwrite) {
+ FILE *fp = fopen (path, "rb");
+ if (fp) {
+ fclose (fp);
+ return -2;
+ }
+ }
+
+ FILE *fp = fopen (path, "w+b");
+ if (!fp) {
+ return -1;
+ }
+
+ fprintf (fp, "title %s\n", p->title);
+ fprintf (fp, "fname %s\n", p->fname);
+ fprintf (fp, "encoder %s\n", p->encoder);
+ fprintf (fp, "method %d\n", p->method);
+ fprintf (fp, "formats %08X\n", p->formats);
+
+ fclose (fp);
+ return 0;
+}
+
+ddb_encoder_preset_t *
+encoder_preset_get_list (void) {
+ return encoder_presets;
+}
+
+ddb_encoder_preset_t *
+encoder_preset_get_for_idx (int idx) {
+ ddb_encoder_preset_t *p = encoder_presets;
+ while (p && idx--) {
+ p = p->next;
+ }
+ return p;
+}
+
+void
+encoder_preset_append (ddb_encoder_preset_t *p) {
+ // append
+ ddb_encoder_preset_t *tail = encoder_presets;
+ while (tail && tail->next) {
+ tail = tail->next;
+ }
+ if (tail) {
+ tail->next = p;
+ }
+ else {
+ encoder_presets = p;
+ }
+}
+
+void
+encoder_preset_remove (ddb_encoder_preset_t *p) {
+ ddb_encoder_preset_t *prev = encoder_presets;
+ while (prev && prev->next != p) {
+ prev = prev->next;
+ }
+ if (prev) {
+ prev->next = p->next;
+ }
+ else {
+ encoder_presets = p->next;
+ }
+}
+
+void
+encoder_preset_replace (ddb_encoder_preset_t *from, ddb_encoder_preset_t *to) {
+ ddb_encoder_preset_t *prev = encoder_presets;
+ while (prev && prev->next != from) {
+ prev = prev->next;
+ }
+ if (prev) {
+ prev->next = to;
+ }
+ else {
+ encoder_presets = to;
+ }
+ to->next = from->next;
+}
+
+ddb_dsp_preset_t *
+dsp_preset_alloc (void) {
+ ddb_dsp_preset_t *p = malloc (sizeof (ddb_dsp_preset_t));
+ if (!p) {
+ fprintf (stderr, "failed to alloc ddb_dsp_preset_t\n");
+ return NULL;
+ }
+ memset (p, 0, sizeof (ddb_dsp_preset_t));
+ return p;
+}
+
+void
+dsp_preset_free (ddb_dsp_preset_t *p) {
+ if (p) {
+ if (p->title) {
+ free (p->title);
+ }
+ while (p->chain) {
+ DB_dsp_instance_t *next = p->chain->next;
+ p->chain->plugin->close (p->chain);
+ p->chain = next;
+ }
+ free (p);
+ }
+}
+
+void
+dsp_preset_copy (ddb_dsp_preset_t *to, ddb_dsp_preset_t *from) {
+ to->title = strdup (from->title);
+ DB_dsp_instance_t *tail = NULL;
+ DB_dsp_instance_t *dsp = from->chain;
+ while (dsp) {
+ DB_dsp_instance_t *i = dsp->plugin->open ();
+ if (dsp->plugin->num_params) {
+ int n = dsp->plugin->num_params ();
+ for (int j = 0; j < n; j++) {
+ i->plugin->set_param (i, j, dsp->plugin->get_param (dsp, j));
+ }
+ }
+ if (tail) {
+ tail->next = i;
+ tail = i;
+ }
+ else {
+ to->chain = tail = i;
+ }
+ dsp = dsp->next;
+ }
+}
+
+ddb_dsp_preset_t *
+dsp_preset_get_list (void) {
+ return dsp_presets;
+}
+
+ddb_dsp_preset_t *
+dsp_preset_load (const char *fname) {
+ int err = 1;
+ FILE *fp = fopen (fname, "rt");
+ if (!fp) {
+ return NULL;
+ }
+ ddb_dsp_preset_t *p = dsp_preset_alloc ();
+ if (!p) {
+ goto error;
+ }
+
+ // title
+ char temp[100];
+ if (1 != fscanf (fp, "title %100[^\n]\n", temp)) {
+ goto error;
+ }
+ p->title = strdup (temp);
+ DB_dsp_instance_t *tail = NULL;
+
+ for (;;) {
+ // plugin {
+ int err = fscanf (fp, "%100s {\n", temp);
+ if (err == EOF) {
+ break;
+ }
+ else if (1 != err) {
+ fprintf (stderr, "error plugin name\n");
+ goto error;
+ }
+
+ DB_dsp_t *plug = (DB_dsp_t *)deadbeef->plug_get_for_id (temp);
+ if (!plug) {
+ fprintf (stderr, "ddb_dsp_preset_load: plugin %s not found. preset will not be loaded\n", temp);
+ goto error;
+ }
+ DB_dsp_instance_t *inst = plug->open ();
+ if (!inst) {
+ fprintf (stderr, "ddb_dsp_preset_load: failed to open instance of plugin %s\n", temp);
+ goto error;
+ }
+
+ if (tail) {
+ tail->next = inst;
+ tail = inst;
+ }
+ else {
+ tail = p->chain = inst;
+ }
+
+ int n = 0;
+ for (;;) {
+ float value;
+ if (!fgets (temp, sizeof (temp), fp)) {
+ fprintf (stderr, "unexpected eof while reading plugin params\n");
+ goto error;
+ }
+ if (!strcmp (temp, "}\n")) {
+ break;
+ }
+ else if (1 != sscanf (temp, "\t%f\n", &value)) {
+ fprintf (stderr, "error loading param %d\n", n);
+ goto error;
+ }
+ if (plug->num_params) {
+ plug->set_param (inst, n, value);
+ }
+ n++;
+ }
+ }
+
+ err = 0;
+error:
+ if (err) {
+ fprintf (stderr, "error loading %s\n", fname);
+ }
+ if (fp) {
+ fclose (fp);
+ }
+ if (err && p) {
+ dsp_preset_free (p);
+ p = NULL;
+ }
+ return p;
+}
+
+int
+dsp_preset_save (ddb_dsp_preset_t *p, int overwrite) {
+ const char *confdir = deadbeef->get_config_dir ();
+ char path[1024];
+ if (snprintf (path, sizeof (path), "%s/presets", confdir) < 0) {
+ return -1;
+ }
+ mkdir (path, 0755);
+ if (snprintf (path, sizeof (path), "%s/presets/dsp", confdir) < 0) {
+ return -1;
+ }
+ mkdir (path, 0755);
+ if (snprintf (path, sizeof (path), "%s/presets/dsp/%s.txt", confdir, p->title) < 0) {
+ return -1;
+ }
+
+ if (!overwrite) {
+ FILE *fp = fopen (path, "rb");
+ if (fp) {
+ fclose (fp);
+ return -2;
+ }
+ }
+
+ FILE *fp = fopen (path, "w+b");
+ if (!fp) {
+ return -1;
+ }
+
+ fprintf (fp, "title %s\n", p->title);
+
+ DB_dsp_instance_t *inst = p->chain;
+ while (inst) {
+ fprintf (fp, "%s {\n", inst->plugin->plugin.id);
+ if (inst->plugin->num_params) {
+ int n = inst->plugin->num_params ();
+ int i;
+ for (i = 0; i < n; i++) {
+ float v = inst->plugin->get_param (inst, i);
+ fprintf (fp, "\t%f\n", v);
+ }
+ }
+ fprintf (fp, "}\n");
+ inst = inst->next;
+ }
+
+ fclose (fp);
+ return 0;
+}
+
+static int dirent_alphasort (const struct dirent **a, const struct dirent **b) {
+ return strcmp ((*a)->d_name, (*b)->d_name);
+}
+
+int
+scandir_preset_filter (const struct dirent *ent) {
+ char *ext = strrchr (ent->d_name, '.');
+ if (ext && !strcasecmp (ext, ".txt")) {
+ return 1;
+ }
+ return 0;
+}
+
+int
+load_encoder_presets (void) {
+ ddb_encoder_preset_t *tail = NULL;
+ char path[1024];
+ if (snprintf (path, sizeof (path), "%s/presets/encoders", deadbeef->get_config_dir ()) < 0) {
+ return -1;
+ }
+ struct dirent **namelist = NULL;
+ int n = scandir (path, &namelist, scandir_preset_filter, dirent_alphasort);
+ int i;
+ for (i = 0; i < n; i++) {
+ char s[1024];
+ if (snprintf (s, sizeof (s), "%s/%s", path, namelist[i]->d_name) > 0){
+ ddb_encoder_preset_t *p = encoder_preset_load (s);
+ if (p) {
+ if (tail) {
+ tail->next = p;
+ tail = p;
+ }
+ else {
+ encoder_presets = tail = p;
+ }
+ }
+ }
+ free (namelist[i]);
+ }
+ free (namelist);
+ return 0;
+}
+
+int
+load_dsp_presets (void) {
+ ddb_dsp_preset_t *tail = NULL;
+ char path[1024];
+ if (snprintf (path, sizeof (path), "%s/presets/dsp", deadbeef->get_config_dir ()) < 0) {
+ return -1;
+ }
+ struct dirent **namelist = NULL;
+ int n = scandir (path, &namelist, scandir_preset_filter, dirent_alphasort);
+ int i;
+ for (i = 0; i < n; i++) {
+ char s[1024];
+ if (snprintf (s, sizeof (s), "%s/%s", path, namelist[i]->d_name) > 0){
+ ddb_dsp_preset_t *p = dsp_preset_load (s);
+ if (p) {
+ if (tail) {
+ tail->next = p;
+ tail = p;
+ }
+ else {
+ dsp_presets = tail = p;
+ }
+ }
+ }
+ free (namelist[i]);
+ }
+ free (namelist);
+ return 0;
+}
+
+ddb_dsp_preset_t *
+dsp_preset_get_for_idx (int idx) {
+ ddb_dsp_preset_t *p = dsp_presets;
+ while (p && idx--) {
+ p = p->next;
+ }
+ return p;
+}
+
+void
+dsp_preset_append (ddb_dsp_preset_t *p) {
+ // append
+ ddb_dsp_preset_t *tail = dsp_presets;
+ while (tail && tail->next) {
+ tail = tail->next;
+ }
+ if (tail) {
+ tail->next = p;
+ }
+ else {
+ dsp_presets = p;
+ }
+}
+
+void
+dsp_preset_remove (ddb_dsp_preset_t *p) {
+ ddb_dsp_preset_t *prev = dsp_presets;
+ while (prev && prev->next != p) {
+ prev = prev->next;
+ }
+ if (prev) {
+ prev->next = p->next;
+ }
+ else {
+ dsp_presets = p->next;
+ }
+}
+
+void
+dsp_preset_replace (ddb_dsp_preset_t *from, ddb_dsp_preset_t *to) {
+ ddb_dsp_preset_t *prev = dsp_presets;
+ while (prev && prev->next != from) {
+ prev = prev->next;
+ }
+ if (prev) {
+ prev->next = to;
+ }
+ else {
+ dsp_presets = to;
+ }
+ to->next = from->next;
+}
+
+int
+convert (DB_playItem_t *it, const char *outfolder, int selected_format, ddb_encoder_preset_t *encoder_preset, ddb_dsp_preset_t *dsp_preset) {
+ DB_decoder_t *dec = NULL;
+ dec = (DB_decoder_t *)deadbeef->plug_get_for_id (it->decoder_id);
+ if (dec) {
+ DB_fileinfo_t *fileinfo = dec->open (0);
+ if (fileinfo && dec->init (fileinfo, DB_PLAYITEM (it)) != 0) {
+ dec->free (fileinfo);
+ fileinfo = NULL;
+ }
+ if (fileinfo) {
+ char fname[1024];
+ int idx = deadbeef->pl_get_idx_of (it);
+ deadbeef->pl_format_title (it, idx, fname, sizeof (fname), -1, encoder_preset->fname);
+ char out[1024];
+ snprintf (out, sizeof (out), "%s/%s", outfolder, fname);
+ char enc[1024];
+ snprintf (enc, sizeof (enc), encoder_preset->encoder, out);
+ fprintf (stderr, "executing: %s\n", enc);
+ FILE *enc_pipe = NULL;
+ FILE *temp_file = NULL;
+
+ if (!encoder_preset->encoder[0]) {
+ // write to wave file
+ temp_file = fopen (out, "w+b");
+ if (!temp_file) {
+ fprintf (stderr, "converter: failed to open output wave file %s\n", out);
+ if (fileinfo) {
+ dec->free (fileinfo);
+ }
+ return -1;
+ }
+ }
+ else if (encoder_preset->method == DDB_ENCODER_METHOD_FILE) {
+ const char *temp_file_name = "/tmp/deadbeef-converter.wav"; // FIXME
+ temp_file = fopen (temp_file_name, "w+b");
+ if (!temp_file) {
+ fprintf (stderr, "converter: failed to open temp file %s\n", temp_file_name);
+ if (fileinfo) {
+ dec->free (fileinfo);
+ }
+ return -1;
+ }
+ }
+ else {
+ enc_pipe = popen (enc, "w");
+ if (!enc_pipe) {
+ fprintf (stderr, "converter: failed to open encoder\n");
+ if (temp_file) {
+ fclose (temp_file);
+ }
+ if (fileinfo) {
+ dec->free (fileinfo);
+ }
+ return -1;
+ }
+ }
+
+ if (!temp_file) {
+ temp_file = enc_pipe;
+ }
+
+ // write wave header
+ char wavehdr[] = {
+ 0x52, 0x49, 0x46, 0x46, 0x24, 0x70, 0x0d, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61
+ };
+ int header_written = 0;
+ uint32_t outsize = 0;
+ uint32_t outsr = fileinfo->fmt.samplerate;
+ uint16_t outch = fileinfo->fmt.channels;
+ uint16_t outbps = fileinfo->fmt.bps;
+ if (selected_format != 0) {
+ switch (selected_format) {
+ case 1 ... 4:
+ outbps = selected_format * 8;
+ break;
+ case 5:
+ outbps = 32;
+ break;
+ }
+ }
+
+ int samplesize = fileinfo->fmt.channels * fileinfo->fmt.bps / 8;
+ int bs = 10250 * samplesize;
+ char buffer[bs * 4];
+ int dspsize = bs / samplesize * sizeof (float) * fileinfo->fmt.channels;
+ char dspbuffer[dspsize * 4];
+ int eof = 0;
+ for (;;) {
+ if (eof) {
+ break;
+ }
+ int sz = dec->read (fileinfo, buffer, bs);
+
+ if (sz != bs) {
+ eof = 1;
+ }
+ if (dsp_preset) {
+ ddb_waveformat_t fmt;
+ ddb_waveformat_t outfmt;
+ memcpy (&fmt, &fileinfo->fmt, sizeof (fmt));
+ memcpy (&outfmt, &fileinfo->fmt, sizeof (fmt));
+ fmt.bps = 32;
+ fmt.is_float = 1;
+ deadbeef->pcm_convert (&fileinfo->fmt, buffer, &fmt, dspbuffer, sz);
+
+ DB_dsp_instance_t *dsp = dsp_preset->chain;
+ int frames = sz / samplesize;
+ while (dsp) {
+ frames = dsp->plugin->process (dsp, (float *)dspbuffer, frames, &fmt.samplerate, &fmt.channels);
+ dsp = dsp->next;
+ }
+
+ outsr = fmt.samplerate;
+ outch = fmt.channels;
+
+ outfmt.bps = outbps;
+ outfmt.channels = outch;
+ outfmt.samplerate = outsr;
+
+ int n = deadbeef->pcm_convert (&fmt, dspbuffer, &outfmt, buffer, frames * sizeof (float) * fmt.channels);
+ sz = n;
+ }
+ else if (fileinfo->fmt.bps != outbps) {
+ ddb_waveformat_t outfmt;
+ memcpy (&outfmt, &fileinfo->fmt, sizeof (outfmt));
+ outfmt.bps = outbps;
+ outfmt.channels = outch;
+ outfmt.samplerate = outsr;
+
+ int frames = sz / samplesize;
+ int n = deadbeef->pcm_convert (&fileinfo->fmt, buffer, &outfmt, dspbuffer, frames * samplesize);
+ memcpy (buffer, dspbuffer, n);
+ sz = n;
+ }
+ outsize += sz;
+
+ if (!header_written) {
+ uint32_t size = (it->endsample-it->startsample) * outch * outbps / 8;
+ if (!size) {
+ size = deadbeef->pl_get_item_duration (it) * fileinfo->fmt.samplerate * outch * outbps / 8;
+
+ }
+
+ if (outsr != fileinfo->fmt.samplerate) {
+ uint64_t temp = size;
+ temp *= outsr;
+ temp /= fileinfo->fmt.samplerate;
+ size = temp;
+ }
+
+ memcpy (&wavehdr[22], &outch, 2);
+ memcpy (&wavehdr[24], &outsr, 4);
+ uint16_t blockalign = outch * outbps / 8;
+ memcpy (&wavehdr[32], &blockalign, 2);
+ memcpy (&wavehdr[34], &outbps, 2);
+
+ fwrite (wavehdr, 1, sizeof (wavehdr), temp_file);
+ fwrite (&size, 1, sizeof (size), temp_file);
+ header_written = 1;
+ }
+
+ fwrite (buffer, 1, sz, temp_file);
+ }
+ if (temp_file && temp_file != enc_pipe) {
+ fclose (temp_file);
+ }
+
+ if (encoder_preset->encoder[0] && encoder_preset->method == DDB_ENCODER_METHOD_FILE) {
+ enc_pipe = popen (enc, "w");
+ }
+
+ if (enc_pipe) {
+ pclose (enc_pipe);
+ }
+ dec->free (fileinfo);
+ }
+ }
+ return 0;
+}
+
+int
+converter_cmd (int cmd, ...) {
+ return -1;
+}
+
+int
+converter_start (void) {
+ load_encoder_presets ();
+ load_dsp_presets ();
+
+ return 0;
+}
+
+int
+converter_stop (void) {
+ return 0;
+}
+
+// define plugin interface
+static ddb_converter_t plugin = {
+ .misc.plugin.api_vmajor = DB_API_VERSION_MAJOR,
+ .misc.plugin.api_vminor = DB_API_VERSION_MINOR,
+ .misc.plugin.version_major = 1,
+ .misc.plugin.version_minor = 0,
+ .misc.plugin.type = DB_PLUGIN_MISC,
+ .misc.plugin.name = "Converter",
+ .misc.plugin.id = "converter",
+ .misc.plugin.descr = "Converts any supported formats to other formats",
+ .misc.plugin.author = "Alexey Yakovenko",
+ .misc.plugin.email = "waker@users.sourceforge.net",
+ .misc.plugin.website = "http://deadbeef.sf.net",
+ .misc.plugin.start = converter_start,
+ .misc.plugin.stop = converter_stop,
+ .misc.plugin.command = converter_cmd,
+ .encoder_preset_alloc = encoder_preset_alloc,
+ .encoder_preset_free = encoder_preset_free,
+ .encoder_preset_load = encoder_preset_load,
+ .encoder_preset_save = encoder_preset_save,
+ .encoder_preset_get_list = encoder_preset_get_list,
+ .encoder_preset_get_for_idx = encoder_preset_get_for_idx,
+ .encoder_preset_append = encoder_preset_append,
+ .encoder_preset_remove = encoder_preset_remove,
+ .encoder_preset_replace = encoder_preset_replace,
+ .dsp_preset_alloc = dsp_preset_alloc,
+ .dsp_preset_free = dsp_preset_free,
+ .dsp_preset_load = dsp_preset_load,
+ .dsp_preset_save = dsp_preset_save,
+ .dsp_preset_copy = dsp_preset_copy,
+ .dsp_preset_get_list = dsp_preset_get_list,
+ .dsp_preset_get_for_idx = dsp_preset_get_for_idx,
+ .dsp_preset_append = dsp_preset_append,
+ .dsp_preset_remove = dsp_preset_remove,
+ .dsp_preset_replace = dsp_preset_replace,
+ .convert = convert,
+};
+
+DB_plugin_t *
+converter_load (DB_functions_t *api) {
+ deadbeef = api;
+ return DB_PLUGIN (&plugin);
+}
diff --git a/plugins/converter/converter.h b/plugins/converter/converter.h
new file mode 100644
index 00000000..6b90857b
--- /dev/null
+++ b/plugins/converter/converter.h
@@ -0,0 +1,137 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+#ifndef __CONVERTER_H
+#define __CONVERTER_H
+
+#include <stdint.h>
+#include <deadbeef.h>
+
+enum {
+ DDB_ENCODER_METHOD_PIPE = 0,
+ DDB_ENCODER_METHOD_FILE = 1,
+};
+
+enum {
+ DDB_ENCODER_FMT_8BIT = 0x1,
+ DDB_ENCODER_FMT_16BIT = 0x2,
+ DDB_ENCODER_FMT_24BIT = 0x4,
+ DDB_ENCODER_FMT_32BIT = 0x8,
+ DDB_ENCODER_FMT_32BITFLOAT = 0x10,
+};
+
+typedef struct ddb_preset_s {
+ char *title;
+ struct ddb_preset_s *next;
+} ddb_preset_t;
+
+typedef struct ddb_encoder_preset_s {
+ char *title;
+ struct ddb_encoder_preset_s *next;
+ char *fname;
+ char *encoder;
+ int method; // pipe or file
+ uint32_t formats; // combination of supported flags (FMT_*)
+} ddb_encoder_preset_t;
+
+typedef struct ddb_dsp_preset_s {
+ char *title;
+ struct ddb_dsp_preset_s *next;
+ DB_dsp_instance_t *chain;
+} ddb_dsp_preset_t;
+
+typedef struct {
+ DB_misc_t misc;
+
+ /////////////////////////////
+ // encoder preset management
+ /////////////////////////////
+
+ ddb_encoder_preset_t *
+ (*encoder_preset_alloc) (void);
+
+ void
+ (*encoder_preset_free) (ddb_encoder_preset_t *p);
+
+ ddb_encoder_preset_t *
+ (*encoder_preset_load) (const char *fname);
+
+ // @return -1 on path/write error, -2 if file already exists
+ int
+ (*encoder_preset_save) (ddb_encoder_preset_t *p, int overwrite);
+
+ ddb_encoder_preset_t *
+ (*encoder_preset_get_list) (void);
+
+ ddb_encoder_preset_t *
+ (*encoder_preset_get_for_idx) (int idx);
+
+ void
+ (*encoder_preset_append) (ddb_encoder_preset_t *p);
+
+ void
+ (*encoder_preset_remove) (ddb_encoder_preset_t *p);
+
+ void
+ (*encoder_preset_replace) (ddb_encoder_preset_t *from, ddb_encoder_preset_t *to);
+
+ /////////////////////////////
+ // dsp preset management
+ /////////////////////////////
+
+ ddb_dsp_preset_t *
+ (*dsp_preset_alloc) (void);
+
+ void
+ (*dsp_preset_free) (ddb_dsp_preset_t *p);
+
+ ddb_dsp_preset_t *
+ (*dsp_preset_load) (const char *fname);
+
+ // @return -1 on path/write error, -2 if file already exists
+ int
+ (*dsp_preset_save) (ddb_dsp_preset_t *p, int overwrite);
+
+ void
+ (*dsp_preset_copy) (ddb_dsp_preset_t *to, ddb_dsp_preset_t *from);
+
+ ddb_dsp_preset_t *
+ (*dsp_preset_get_list) (void);
+
+ ddb_dsp_preset_t *
+ (*dsp_preset_get_for_idx) (int idx);
+
+ void
+ (*dsp_preset_append) (ddb_dsp_preset_t *p);
+
+ void
+ (*dsp_preset_remove) (ddb_dsp_preset_t *p);
+
+ void
+ (*dsp_preset_replace) (ddb_dsp_preset_t *from, ddb_dsp_preset_t *to);
+
+ /////////////////////////////
+ // converter
+ /////////////////////////////
+
+ int
+ (*convert) (DB_playItem_t *it, const char *outfolder, int selected_format, ddb_encoder_preset_t *encoder_preset, ddb_dsp_preset_t *dsp_preset);
+
+} ddb_converter_t;
+
+#endif