summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-09-27 16:05:44 +0200
committerGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-09-27 16:05:44 +0200
commit326604c8c1ff97f99490d557e1f964b86ec630fa (patch)
tree372328d1f92ef16e50ef6f620aa950a34f919a3c
parent5bf2da4cc9e1e15bbccca82d686203dd1bb408ca (diff)
initial wavpack support
-rw-r--r--Makefile.am3
-rw-r--r--configure.ac10
-rw-r--r--plugins/wavpack/Makefile.am7
-rw-r--r--plugins/wavpack/wavpack.c187
4 files changed, 206 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am
index 4b29261a..7f6d1a57 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,7 +12,8 @@ SUBDIRS = gme/Game_Music_Emu-0.5.2\
${LFM_DIR}\
${MPGMAD_DIR}\
${VORBIS_DIR}\
- ${FLAC_DIR}
+ ${FLAC_DIR}\
+ ${WAVPACK_DIR}
dumbpath=@top_srcdir@/dumb
sidpath=@top_srcdir@/sid/sidplay-libs-2.1.0
diff --git a/configure.ac b/configure.ac
index 794c404c..b8d856d8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -86,6 +86,15 @@ if test ${HAVE_FLAC} ; then
AC_SUBST(FLAC_DIR)
fi
+dnl wavpack plugin
+AC_CHECK_LIB([wavpack], [main], [HAVE_WAVPACK=1])
+
+if test ${HAVE_WAVPACK} ; then
+ WAVPACK_LIBS="-lwavpack"
+ WAVPACK_DIR="plugins/wavpack"
+ AC_SUBST(WAVPACK_LIBS)
+ AC_SUBST(WAVPACK_DIR)
+fi
AC_OUTPUT([
Makefile
@@ -101,6 +110,7 @@ plugins/ffap/Makefile
plugins/mpgmad/Makefile
plugins/vorbis/Makefile
plugins/flac/Makefile
+plugins/wavpack/Makefile
deadbeef.desktop
])
diff --git a/plugins/wavpack/Makefile.am b/plugins/wavpack/Makefile.am
new file mode 100644
index 00000000..9a86351f
--- /dev/null
+++ b/plugins/wavpack/Makefile.am
@@ -0,0 +1,7 @@
+wavpackdir = $(libdir)/$(PACKAGE)
+pkglib_LTLIBRARIES = wavpack.la
+wavpack_la_SOURCES = wavpack.c
+wavpack_la_LDFLAGS = -module
+
+wavpack_la_LIBADD = $(LDADD) $(WAVPACK_LIBS)
+AM_CFLAGS = $(CFLAGS) -std=c99
diff --git a/plugins/wavpack/wavpack.c b/plugins/wavpack/wavpack.c
new file mode 100644
index 00000000..717bf2e5
--- /dev/null
+++ b/plugins/wavpack/wavpack.c
@@ -0,0 +1,187 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009 Alexey Yakovenko
+
+ 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 <string.h>
+#include <wavpack/wavpack.h>
+#include "../../deadbeef.h"
+
+#define min(x,y) ((x)<(y)?(x):(y))
+#define max(x,y) ((x)>(y)?(x):(y))
+
+#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+//#define trace(fmt,...)
+
+static DB_decoder_t plugin;
+static DB_functions_t *deadbeef;
+
+typedef struct {
+ WavpackContext *ctx;
+ int startsample;
+ int endsample;
+} wvctx_t;
+
+static wvctx_t wvctx;
+
+static int
+wv_init (DB_playItem_t *it) {
+ memset (&wvctx, 0, sizeof (wvctx));
+ wvctx.ctx = WavpackOpenFileInput (it->fname, NULL, 0, 0);
+ if (!wvctx.ctx) {
+ return -1;
+ }
+ plugin.info.bps = WavpackGetBitsPerSample (wvctx.ctx);
+ plugin.info.channels = WavpackGetNumChannels (wvctx.ctx);
+ plugin.info.samplerate = WavpackGetSampleRate (wvctx.ctx);
+ plugin.info.readpos = 0;
+ if (it->endsample > 0) {
+ wvctx.startsample = it->startsample;
+ wvctx.endsample = it->endsample;
+ if (plugin.seek_sample (0) < 0) {
+ plugin.free ();
+ return -1;
+ }
+ }
+ else {
+ wvctx.startsample = 0;
+ wvctx.endsample = WavpackGetNumSamples (wvctx.ctx)-1;
+ }
+ return 0;
+}
+
+static void
+wv_free (void) {
+ if (wvctx.ctx) {
+ WavpackCloseFile (wvctx.ctx);
+ }
+ memset (&wvctx, 0, sizeof (wvctx));
+}
+
+
+static int
+wv_read_int16 (char *bytes, int size) {
+ int currentsample = WavpackGetSampleIndex (wvctx.ctx);
+ if (size / (2 * plugin.info.channels) + currentsample > wvctx.endsample) {
+ size = (wvctx.endsample - currentsample + 1) * 2 * plugin.info.channels;
+ trace ("wv: size truncated to %d bytes, cursample=%d, endsample=%d\n", size, currentsample, wvctx.endsample);
+ if (size <= 0) {
+ return 0;
+ }
+ }
+ int32_t buffer[size/2];
+ int nchannels = WavpackGetNumChannels (wvctx.ctx);
+ int n = WavpackUnpackSamples (wvctx.ctx, buffer, size/(2*nchannels));
+ size = n * 2 * nchannels;
+ // convert to int16
+ int32_t *p = buffer;
+ n *= nchannels;
+ while (n > 0) {
+ *((int16_t *)bytes) = (int16_t)(*p);
+ bytes += sizeof (int16_t);
+ p++;
+ n--;
+ }
+ plugin.info.readpos = (float)(WavpackGetSampleIndex (wvctx.ctx)-wvctx.startsample)/WavpackGetSampleRate (wvctx.ctx);
+ return size;
+}
+
+static int
+wv_seek_sample (int sample) {
+ WavpackSeekSample (wvctx.ctx, sample + wvctx.startsample);
+ plugin.info.readpos = (float)(WavpackGetSampleIndex (wvctx.ctx) - wvctx.startsample) / WavpackGetSampleRate (wvctx.ctx);
+ return 0;
+}
+
+static int
+wv_seek (float sec) {
+ return wv_seek_sample (sec * WavpackGetSampleRate (wvctx.ctx));
+}
+
+static DB_playItem_t *
+wv_insert (DB_playItem_t *after, const char *fname) {
+ WavpackContext *ctx = WavpackOpenFileInput (fname, NULL, 0, 0);
+ if (!ctx) {
+ trace ("WavpackOpenFileInput failed");
+ return NULL;
+ }
+ int totalsamples = WavpackGetNumSamples (ctx);
+ int samplerate = WavpackGetSampleRate (ctx);
+ float duration = (float)totalsamples / samplerate;
+ DB_playItem_t *cue_after = deadbeef->pl_insert_cue (after, fname, &plugin, "wv", totalsamples, samplerate);
+ if (cue_after) {
+ WavpackCloseFile (ctx);
+ return cue_after;
+ }
+
+ DB_playItem_t *it = deadbeef->pl_item_alloc ();
+ it->decoder = &plugin;
+ it->fname = strdup (fname);
+ it->filetype = "wv";
+ it->duration = duration;
+ WavpackCloseFile (ctx);
+
+ trace ("wv: totalsamples=%d, samplerate=%d, duration=%f\n", totalsamples, samplerate, duration);
+
+ FILE *fp = fopen (fname, "rb");
+ if (fp) {
+ int apeerr = deadbeef->junk_read_ape (it, fp);
+ if (!apeerr) {
+ trace ("wv: ape tag found\n");
+ }
+ int v1err = deadbeef->junk_read_id3v1 (it, fp);
+ if (!v1err) {
+ trace ("wv: id3v1 tag found\n");
+ }
+ fclose (fp);
+ }
+ deadbeef->pl_add_meta (it, "title", NULL);
+ after = deadbeef->pl_insert_item (after, it);
+
+ return after;
+}
+
+static const char * exts[] = { "wv", NULL };
+static const char *filetypes[] = { "wv", NULL };
+
+// 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 = "WavPack decoder",
+ .plugin.author = "Alexey Yakovenko",
+ .plugin.email = "waker@users.sourceforge.net",
+ .plugin.website = "http://deadbeef.sf.net",
+ .init = wv_init,
+ .free = wv_free,
+ .read_int16 = wv_read_int16,
+// .read_float32 = wv_read_float32,
+ .seek = wv_seek,
+ .seek_sample = wv_seek_sample,
+ .insert = wv_insert,
+ .exts = exts,
+ .id = "wv",
+ .filetypes = filetypes
+};
+
+DB_plugin_t *
+wavpack_load (DB_functions_t *api) {
+ deadbeef = api;
+ return DB_PLUGIN (&plugin);
+}