From a8e25c3e6edd1bcd7feccbc3c93765f6a70e20ed Mon Sep 17 00:00:00 2001 From: waker Date: Sun, 21 Nov 2010 22:43:15 +0100 Subject: moved libsamplerate code to separate plugin --- Makefile.am | 1 - configure.ac | 30 ++++-- deadbeef.h | 15 ++- plugins/dsp_libsrc/Makefile.am | 11 ++ plugins/dsp_libsrc/src.c | 223 +++++++++++++++++++++++++++++++++++++++++ plugins/dsp_libsrc/src.h | 39 +++++++ scripts/quickinstall.sh | 1 + src.c | 177 -------------------------------- src.h | 46 --------- streamer.c | 85 +++++++++------- 10 files changed, 354 insertions(+), 274 deletions(-) create mode 100644 plugins/dsp_libsrc/Makefile.am create mode 100644 plugins/dsp_libsrc/src.c create mode 100644 plugins/dsp_libsrc/src.h delete mode 100644 src.c delete mode 100644 src.h diff --git a/Makefile.am b/Makefile.am index 8219b914..cab4aa3b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,7 +21,6 @@ deadbeef_SOURCES =\ plugins.c plugins.h moduleconf.h\ playlist.c playlist.h \ streamer.c streamer.h\ - src.c src.h\ premix.c premix.h\ messagepump.c messagepump.h\ conf.c conf.h\ diff --git a/configure.ac b/configure.ac index eacf3af7..5e7a092b 100644 --- a/configure.ac +++ b/configure.ac @@ -54,6 +54,9 @@ esac test "x$prefix" = xNONE && prefix=$ac_default_prefix + +PKG_CHECK_MODULES(DEPS, samplerate) + dnl INSANE_CFLAGS="-Wformat -Wdisabled-optimization -Wcomment -Wchar-subscripts -Wunused-function -Wunused-value -Wuninitialized -Wtype-limits -Wbad-function-cast" dnl INSANE_CXXFLAGS="-Wcomment -Wchar-subscripts -Wunused-function -Wunused-value -Wuninitialized -Wtype-limits" @@ -97,6 +100,7 @@ AC_ARG_ENABLE(ao, [AS_HELP_STRING([--disable-ao ], [disable audio ove AC_ARG_ENABLE(mpris, [AS_HELP_STRING([ --enable-mpris enable Ubuntu Sound Menu plugin (default: disabled)])], [enable_mpris=$enableval], [enable_mpris=no]) AC_ARG_ENABLE(staticlink, [AS_HELP_STRING([ --enable-staticlink link everything statically (default: disabled)])], [enable_staticlink=$enableval], [enable_staticlink=no]) AC_ARG_ENABLE(portable, [AS_HELP_STRING([ --enable-portable make portable build (default: disabled, opts: yes,no,full)])], [enable_portable=$enableval], [enable_portable=no]) +AC_ARG_ENABLE(src, [AS_HELP_STRING([ --enable-src build libsamplerate (SRC) plugin (default: auto)])], [enable_src=$enableval], [enable_src=yes]) if test "x$enable_staticlink" != "xno" ; then AC_DEFINE_UNQUOTED([STATICLINK], [1], [Define if building static version]) @@ -121,14 +125,6 @@ fi CXXFLAGS="$CXXFLAGS $INSANE_CXXFLAGS -D_GNU_SOURCE $PREFIXFLAGS" CFLAGS="$CFLAGS $INSANE_CFLAGS -D_GNU_SOURCE $PREFIXFLAGS" -PKG_CHECK_MODULES(DEPS, samplerate) -if test "x$enable_staticlink" != "xno" ; then - DEPS_LIBS="$LIB/libsamplerate.a -lpthread -ldl" - AC_SUBST(DEPS_LIBS) -else - PKG_CHECK_MODULES(DEPS, samplerate) -fi - if test "x$enable_gtkui" != "xno" ; then if test "x$enable_gtk3" == "xyes" ; then PKG_CHECK_MODULES(GTKUI_DEPS, gtk+-3.0 >= 2.90 gthread-2.0 glib-2.0, HAVE_GTK=yes, HAVE_GTK=no) @@ -411,6 +407,19 @@ if test "x$enable_nullout" != "xno" ; then HAVE_NULLOUT=yes fi +if test "x$enable_src" != "xno" ; then +if test "x$enable_staticlink" != "xno" ; then + LIBSAMPLERATE_DEPS_LIBS="$LIB/libsamplerate.a -lpthread -ldl" + AC_SUBST(LIBSAMPLERATE_DEPS_LIBS) + HAVE_DSP_SRC=yes +else + PKG_CHECK_MODULES(LIBSAMPLERATE_DEPS, samplerate, HAVE_LIBSAMPLERATE=yes, HAVE_LIBSAMPLERATE=no) + if test "x$HAVE_LIBSAMPLERATE" = "xyes" ; then + HAVE_DSP_SRC=yes + fi +fi +fi + if test "x$enable_supereq" != "xno" ; then HAVE_SUPEREQ=yes fi @@ -494,7 +503,7 @@ if test "x$enable_mpris" != "xno" ; then PKG_CHECK_MODULES(MPRIS_DEPS, indicate >= 0.4.4 glib-2.0 >= 2.26.0, HAVE_MPRIS=yes, HAVE_MPRIS=no) fi -PLUGINS_DIRS="plugins/lastfm plugins/mpgmad plugins/vorbis plugins/flac plugins/wavpack plugins/sndfile plugins/vfs_curl plugins/cdda plugins/gtkui plugins/alsa plugins/ffmpeg plugins/hotkeys plugins/oss plugins/artwork plugins/adplug plugins/ffap plugins/sid plugins/nullout plugins/supereq plugins/vtx plugins/gme plugins/dumb plugins/pulse plugins/notify plugins/musepack plugins/wildmidi plugins/tta plugins/dca plugins/aac plugins/mms plugins/shn plugins/ao plugins/shellexec plugins/mpris" +PLUGINS_DIRS="plugins/lastfm plugins/mpgmad plugins/vorbis plugins/flac plugins/wavpack plugins/sndfile plugins/vfs_curl plugins/cdda plugins/gtkui plugins/alsa plugins/ffmpeg plugins/hotkeys plugins/oss plugins/artwork plugins/adplug plugins/ffap plugins/sid plugins/nullout plugins/supereq plugins/vtx plugins/gme plugins/dumb plugins/pulse plugins/notify plugins/musepack plugins/wildmidi plugins/tta plugins/dca plugins/aac plugins/mms plugins/shn plugins/ao plugins/shellexec plugins/mpris plugins/dsp_libsrc" AM_CONDITIONAL(HAVE_VORBIS, test "x$HAVE_VORBISPLUGIN" = "xyes") AM_CONDITIONAL(HAVE_FLAC, test "x$HAVE_FLACPLUGIN" = "xyes") @@ -533,6 +542,7 @@ AM_CONDITIONAL(HAVE_MPRIS, test "x$HAVE_MPRIS" = "xyes") AM_CONDITIONAL(STATICLINK, test "x$STATICLINK" = "xyes") AM_CONDITIONAL(PORTABLE, test "x$PORTABLE" = "xyes") AM_CONDITIONAL(PORTABLE_FULL, test "x$PORTABLE_FULL" = "xyes") +AM_CONDITIONAL(HAVE_DSP_SRC, test "x$HAVE_DSP_SRC" = "xyes") AC_SUBST(PLUGINS_DIRS) @@ -594,6 +604,7 @@ PRINT_PLUGIN_INFO([mms],[mms streaming support],[test "x$HAVE_MMS" = "xyes"]) PRINT_PLUGIN_INFO([shn],[shorten player based on xmms-shn],[test "x$HAVE_SHN" = "xyes"]) PRINT_PLUGIN_INFO([ao],[psf1/psf2/spu/ssf player using Audio Overload],[test "x$HAVE_AO" = "xyes"]) PRINT_PLUGIN_INFO([mpris],[Ubuntu Sound Menu integration],[test "x$HAVE_MPRIS" = "xyes"]) +PRINT_PLUGIN_INFO([dsp_src],[High quality samplerate conversion using libsamplerate],[test "x$HAVE_DSP_SRC" = "xyes"]) echo @@ -635,6 +646,7 @@ plugins/mms/Makefile plugins/shn/Makefile plugins/ao/Makefile plugins/mpris/Makefile +plugins/dsp_libsrc/Makefile intl/Makefile po/Makefile.in deadbeef.desktop diff --git a/deadbeef.h b/deadbeef.h index ce77478c..049cfa2e 100644 --- a/deadbeef.h +++ b/deadbeef.h @@ -740,8 +740,14 @@ typedef struct DB_output_s { } DB_output_t; // dsp plugin +#define DDB_INIT_DSP_INSTANCE(var,type) {\ + memset(var,0,sizeof(type));\ + strncpy (var->inst.id, id, 9);\ + var->inst.id[9]=0;\ +} typedef struct DB_dsp_instance_s { + char id[10]; struct DB_dsp_instance_s *next; unsigned enabled : 1; } DB_dsp_instance_t; @@ -749,15 +755,16 @@ typedef struct DB_dsp_instance_s { typedef struct DB_dsp_s { DB_plugin_t plugin; - DB_dsp_instance_t (*open) (void); + // id is a unique name used to get configuration settings + DB_dsp_instance_t* (*open) (const char *id); void (*close) (DB_dsp_instance_t *inst); - // process gets called before SRC - // stereo samples are stored in interleaved format - // stereo sample is counted as 1 sample + // samples are interleaved + // returned value is number of output frames int (*process) (DB_dsp_instance_t *inst, float *samples, int frames, int channels); } DB_dsp_t; + // misc plugin // purpose is to provide extra services // e.g. scrobbling, converting, tagging, custom gui, etc. diff --git a/plugins/dsp_libsrc/Makefile.am b/plugins/dsp_libsrc/Makefile.am new file mode 100644 index 00000000..90a5ec19 --- /dev/null +++ b/plugins/dsp_libsrc/Makefile.am @@ -0,0 +1,11 @@ +if HAVE_DSP_SRC +pkglib_LTLIBRARIES = dsp_libsrc.la + +dsp_libsrc_la_SOURCES = src.c src.h + +dsp_libsrc_la_LDFLAGS = -module + +dsp_libsrc_la_LIBADD = $(LDADD) + +AM_CFLAGS = -std=c99 +endif diff --git a/plugins/dsp_libsrc/src.c b/plugins/dsp_libsrc/src.c new file mode 100644 index 00000000..19317b68 --- /dev/null +++ b/plugins/dsp_libsrc/src.c @@ -0,0 +1,223 @@ +/* + DeaDBeeF - ultimate music player for GNU/Linux systems with X11 + Copyright (C) 2009-2010 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 +#include +#include +#include +#include "conf.h" +#include "threading.h" +#include "deadbeef.h" +#include "src.h" + +//#define trace(...) { fprintf(stderr, __VA_ARGS__); } +#define trace(fmt,...) + +DB_functions_t *deadbeef; + +#define SRC_BUFFER 16000 +#define SRC_MAX_CHANNELS 8 + +ddb_dsp_src_t plugin; + +typedef struct { + DB_dsp_instance_t inst; + + int quality; + SRC_STATE *src; + SRC_DATA srcdata; + int remaining; // number of input samples in SRC buffer + __attribute__((__aligned__(16))) char in_fbuffer[sizeof(float)*SRC_BUFFER*SRC_MAX_CHANNELS]; +// __attribute__((__aligned__(16))) float out_fbuffer[SRC_BUFFER*SRC_MAX_CHANNELS]; + uintptr_t mutex; +} ddb_src_libsamplerate_t; + +DB_dsp_instance_t* ddb_src_open (const char *id) { + ddb_src_libsamplerate_t *src = malloc (sizeof (ddb_src_libsamplerate_t)); + DDB_INIT_DSP_INSTANCE (src,ddb_src_libsamplerate_t); + + src->mutex = deadbeef->mutex_create (); + char var[20]; + snprintf (var, sizeof (var), "%s.quality"); + src->quality = deadbeef->conf_get_int (var, 2); + src->src = src_new (src->quality, 2, NULL); + if (!src->src) { + plugin.dsp.close ((DB_dsp_instance_t *)src); + return NULL; + } + return (DB_dsp_instance_t *)src; +} + +void +ddb_src_close (DB_dsp_instance_t *_src) { + ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src; + if (src->mutex) { + deadbeef->mutex_free (src->mutex); + src->mutex = 0; + } + if (src->src) { + src_delete (src->src); + src->src = NULL; + } + free (src); +} + +void +ddb_src_lock (DB_dsp_instance_t *_src) { + ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src; + deadbeef->mutex_lock (src->mutex); +} + +void +ddb_src_unlock (DB_dsp_instance_t *_src) { + ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src; + deadbeef->mutex_unlock (src->mutex); +} + +void +ddb_src_reset (DB_dsp_instance_t *_src, int full) { + ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src; + src->remaining = 0; + if (full) { + char var[20]; + snprintf (var, sizeof (var), "%s.quality"); + int q = deadbeef->conf_get_int (var, 2); + if (q != src->quality && q >= SRC_SINC_BEST_QUALITY && q <= SRC_LINEAR) { + ddb_src_lock (_src); + trace ("changing src->quality from %d to %d\n", src->quality, q); + src->quality = q; + if (src) { + src_delete (src->src); + src->src = NULL; + } + memset (&src->srcdata, 0, sizeof (src->srcdata)); + src->src = src_new (src->quality, 2, NULL); + ddb_src_unlock (_src); + } + else { + src_reset (src->src); + } + } +} + +void +ddb_src_set_ratio (DB_dsp_instance_t *_src, float ratio) { + ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src; + src->srcdata.src_ratio = ratio; + src_set_ratio (src->src, ratio); +} + +int +//ddb_src_process (DB_dsp_instance_t *_src, const char * restrict input, int nframes, char * restrict output, int buffersize, float ratio, int nchannels) { +ddb_src_process (DB_dsp_instance_t *_src, float *samples, int nframes, int nchannels) { + ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src; + + int numoutframes = nframes * src->srcdata.src_ratio; + float outbuf[numoutframes*nchannels]; + int buffersize = sizeof (outbuf); + char *output = outbuf; + float *input = samples; + int inputsize = numoutframes; + + int samplesize = nchannels * sizeof (float); + + do { + // add more frames to input SRC buffer + int n = nframes; + if (n >= SRC_BUFFER - src->remaining) { + n = SRC_BUFFER - src->remaining; + } + + if (n > 0) { + memcpy (&src->in_fbuffer[src->remaining*samplesize], samples, n * samplesize); + + src->remaining += n; + samples += n * nchannels; + nframes -= n; + } + if (!src->remaining) { + //trace ("WARNING: SRC input buffer starved\n"); + break; + } + + // call libsamplerate + src->srcdata.data_in = (float *)src->in_fbuffer; + src->srcdata.data_out = (float *)output; + src->srcdata.input_frames = src->remaining; + src->srcdata.output_frames = inputsize; + src->srcdata.end_of_input = 0; + ddb_src_lock (_src); + trace ("src input: %d, ratio %f, buffersize: %d\n", src->srcdata.input_frames, src->srcdata.src_ratio, buffersize); + int src_err = src_process (src->src, &src->srcdata); + trace ("src output: %d, used: %d\n", src->srcdata.output_frames_gen, src->srcdata.input_frames_used); + + ddb_src_unlock (_src); + if (src_err) { + const char *err = src_strerror (src_err) ; + fprintf (stderr, "src_process error %s\n" + "srcdata.data_in=%p, srcdata.data_out=%p, srcdata.input_frames=%d, srcdata.output_frames=%d, srcdata.src_ratio=%f", err, src->srcdata.data_in, src->srcdata.data_out, (int)src->srcdata.input_frames, (int)src->srcdata.output_frames, src->srcdata.src_ratio); + exit (-1); + } + + inputsize -= src->srcdata.output_frames_gen; + output += src->srcdata.output_frames_gen * samplesize; + + // calculate how many unused input samples left + src->remaining -= src->srcdata.input_frames_used; + // copy spare samples for next update + if (src->remaining > 0 && src->srcdata.input_frames_used > 0) { + memmove (src->in_fbuffer, &src->in_fbuffer[src->srcdata.input_frames_used*samplesize], src->remaining * samplesize); + } + if (src->srcdata.output_frames_gen == 0) { + break; + } + } while (nframes > 0); + + memcpy (input, outbuf, sizeof (outbuf)); + //static FILE *out = NULL; + //if (!out) { + // out = fopen ("out.raw", "w+b"); + //} + //fwrite (input, 1, numoutframes*sizeof(float)*nchannels, out); + + return numoutframes; +} + +ddb_dsp_src_t plugin = { + .dsp.plugin.api_vmajor = DB_API_VERSION_MAJOR, + .dsp.plugin.api_vminor = DB_API_VERSION_MINOR, + .dsp.open = ddb_src_open, + .dsp.close = ddb_src_close, + .dsp.process = ddb_src_process, + .dsp.plugin.version_major = 0, + .dsp.plugin.version_minor = 1, + .dsp.plugin.id = "dsp_src", + .dsp.plugin.name = "dsp_src", + .dsp.plugin.descr = "Samplerate converter using libsamplerate", + .dsp.plugin.author = "Alexey Yakovenko", + .dsp.plugin.email = "waker@users.sf.net", + .dsp.plugin.website = "http://deadbeef.sf.net", + .reset = ddb_src_reset, + .set_ratio = ddb_src_set_ratio, +}; + +DB_plugin_t * +dsp_libsrc_load (DB_functions_t *f) { + deadbeef = f; + return &plugin.dsp.plugin; +} diff --git a/plugins/dsp_libsrc/src.h b/plugins/dsp_libsrc/src.h new file mode 100644 index 00000000..09f6a27f --- /dev/null +++ b/plugins/dsp_libsrc/src.h @@ -0,0 +1,39 @@ +/* + DeaDBeeF - ultimate music player for GNU/Linux systems with X11 + Copyright (C) 2009-2010 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. +*/ +#ifndef __SRC_H +#define __SRC_H + +typedef struct { + DB_dsp_t dsp; + void (*reset) (DB_dsp_instance_t *inst, int full); + void (*set_ratio) (DB_dsp_instance_t *inst, float ratio); +} ddb_dsp_src_t; + +#if 0 +void +ddb_src_reset (ddb_src_t *src, int full); + +void +ddb_src_confchanged (ddb_src_t *src); + +int +ddb_src_process (ddb_src_t *_src, const char * restrict input, int nframes, char * restrict output, int buffersize, float ratio, int nchannels); +#endif + +#endif diff --git a/scripts/quickinstall.sh b/scripts/quickinstall.sh index 28fccb1c..3806e3db 100755 --- a/scripts/quickinstall.sh +++ b/scripts/quickinstall.sh @@ -34,4 +34,5 @@ cp ./plugins/mms/.libs/mms.so /usr/local/lib/deadbeef/ cp ./plugins/shn/.libs/shn.so /usr/local/lib/deadbeef/ cp ./plugins/ao/.libs/ao.so /usr/local/lib/deadbeef/ cp ./plugins/shellexec/.libs/shellexec.so /usr/local/lib/deadbeef/ +cp ./plugins/dsp_libsrc/.libs/dsp_libsrc.so /usr/local/lib/deadbeef/ diff --git a/src.c b/src.c deleted file mode 100644 index edeccff4..00000000 --- a/src.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - DeaDBeeF - ultimate music player for GNU/Linux systems with X11 - Copyright (C) 2009-2010 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 -#include -#include -#include -#include "conf.h" -#include "threading.h" -#include "src.h" - -//#define trace(...) { fprintf(stderr, __VA_ARGS__); } -#define trace(fmt,...) - -#define SRC_BUFFER 16000 -#define SRC_MAX_CHANNELS 8 - -typedef struct { - ddb_src_t ddb_src; - - int quality; - SRC_STATE *src; - SRC_DATA srcdata; - int remaining; // number of input samples in SRC buffer - __attribute__((__aligned__(16))) char in_fbuffer[sizeof(float)*SRC_BUFFER*SRC_MAX_CHANNELS]; -// __attribute__((__aligned__(16))) float out_fbuffer[SRC_BUFFER*SRC_MAX_CHANNELS]; - uintptr_t mutex; -} ddb_src_libsamplerate_t; - -ddb_src_t * -ddb_src_init (void) { - ddb_src_libsamplerate_t *src = malloc (sizeof (ddb_src_libsamplerate_t)); - memset (src, 0, sizeof (ddb_src_libsamplerate_t)); - src->mutex = mutex_create (); - src->quality = conf_get_int ("src->quality", 2); - src->src = src_new (src->quality, 2, NULL); - if (!src->src) { - ddb_src_free ((ddb_src_t *)src); - return NULL; - } - return (ddb_src_t *)src; -} - -void -ddb_src_free (ddb_src_t *_src) { - ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src; - if (src->mutex) { - mutex_free (src->mutex); - src->mutex = 0; - } - if (src->src) { - src_delete (src->src); - src->src = NULL; - } - free (src); -} - -void -ddb_src_lock (ddb_src_t *_src) { - ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src; - mutex_lock (src->mutex); -} - -void -ddb_src_unlock (ddb_src_t *_src) { - ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src; - mutex_unlock (src->mutex); -} - -void -ddb_src_reset (ddb_src_t *_src, int full) { - ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src; - src->remaining = 0; - if (full) { - src_reset (src->src); - } -} - -void -ddb_src_confchanged (ddb_src_t *_src) { - ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src; - int q = conf_get_int ("src->quality", 2); - if (q != src->quality && q >= SRC_SINC_BEST_QUALITY && q <= SRC_LINEAR) { - ddb_src_lock (_src); - trace ("changing src->quality from %d to %d\n", src->quality, q); - src->quality = q; - if (src) { - src_delete (src->src); - src->src = NULL; - } - memset (&src->srcdata, 0, sizeof (src->srcdata)); - src->src = src_new (src->quality, 2, NULL); - ddb_src_unlock (_src); - } -} - -int -ddb_src_process (ddb_src_t *_src, const char * restrict input, int nframes, char * restrict output, int buffersize, float ratio, int nchannels) { - ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src; - -extern FILE *out; - int initsize = buffersize; - int samplesize = nchannels * sizeof (float); - - do { - // add more frames to input SRC buffer - int n = nframes; - if (n >= SRC_BUFFER - src->remaining) { - n = SRC_BUFFER - src->remaining; - } - - if (n > 0) { - memcpy (&src->in_fbuffer[src->remaining*samplesize], input, n * samplesize); - - src->remaining += n; - input += n * nchannels; - nframes -= n; - } - if (!src->remaining) { - //trace ("WARNING: SRC input buffer starved\n"); - break; - } - - // call libsamplerate - src->srcdata.data_in = (float *)src->in_fbuffer; - src->srcdata.data_out = (float *)output; - src->srcdata.input_frames = src->remaining; - src->srcdata.output_frames = buffersize/samplesize; - src->srcdata.src_ratio = ratio; - src->srcdata.end_of_input = 0; - ddb_src_lock (_src); - src_set_ratio (src->src, ratio); - trace ("src input: %d, ratio %f, buffersize: %d\n", src->srcdata.input_frames, ratio, buffersize); - int src_err = src_process (src->src, &src->srcdata); - trace ("src output: %d, used: %d\n", src->srcdata.output_frames_gen, src->srcdata.input_frames_used); - - ddb_src_unlock (_src); - if (src_err) { - const char *err = src_strerror (src_err) ; - fprintf (stderr, "src_process error %s\n" - "srcdata.data_in=%p, srcdata.data_out=%p, srcdata.input_frames=%d, srcdata.output_frames=%d, srcdata.src_ratio=%f", err, src->srcdata.data_in, src->srcdata.data_out, (int)src->srcdata.input_frames, (int)src->srcdata.output_frames, ratio); - exit (-1); - } - - buffersize -= src->srcdata.output_frames_gen * samplesize; - output += src->srcdata.output_frames_gen * samplesize; - - // calculate how many unused input samples left - src->remaining -= src->srcdata.input_frames_used; - // copy spare samples for next update - if (src->remaining > 0 && src->srcdata.input_frames_used > 0) { - memmove (src->in_fbuffer, &src->in_fbuffer[src->srcdata.input_frames_used*samplesize], src->remaining * samplesize); - } - if (src->srcdata.output_frames_gen == 0) { - break; - } - } while (nframes > 0); - - trace ("src processed: %d bytes\n", initsize-buffersize); - return initsize - buffersize; -} - diff --git a/src.h b/src.h deleted file mode 100644 index 74bf9e75..00000000 --- a/src.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - DeaDBeeF - ultimate music player for GNU/Linux systems with X11 - Copyright (C) 2009-2010 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. -*/ -#ifndef __SRC_H -#define __SRC_H - -typedef struct { -} ddb_src_t; - -ddb_src_t * -ddb_src_init (void); - -void -ddb_src_free (ddb_src_t *src); - -void -ddb_src_lock (ddb_src_t *_src); - -void -ddb_src_unlock (ddb_src_t *src); - -void -ddb_src_reset (ddb_src_t *src, int full); - -void -ddb_src_confchanged (ddb_src_t *src); - -int -ddb_src_process (ddb_src_t *_src, const char * restrict input, int nframes, char * restrict output, int buffersize, float ratio, int nchannels); - -#endif diff --git a/streamer.c b/streamer.c index d19cbe74..c26a1f61 100644 --- a/streamer.c +++ b/streamer.c @@ -36,7 +36,7 @@ #include "volume.h" #include "vfs.h" #include "premix.h" -#include "src.h" +#include "plugins/dsp_libsrc/src.h" //#define trace(...) { fprintf(stderr, __VA_ARGS__); } #define trace(fmt,...) @@ -48,7 +48,8 @@ FILE *out; #endif static intptr_t streamer_tid; -static ddb_src_t *src; +static ddb_dsp_src_t *srcplug; +static DB_dsp_instance_t *src; static int conf_replaygain_mode = 0; static int conf_replaygain_scale = 1; @@ -747,7 +748,7 @@ streamer_start_new_song (void) { int initsng = nextsong; int pstate = nextsong_pstate; nextsong = -1; - ddb_src_reset (src, 0); + srcplug->reset (src, 0); streamer_unlock (); if (badsong == sng) { trace ("looped to bad file. stopping...\n"); @@ -844,7 +845,7 @@ streamer_thread (void *ctx) { #ifdef __linux__ prctl (PR_SET_NAME, "deadbeef-stream", 0, 0, 0, 0); #endif - ddb_src_reset (src, 0); +// srcplug->reset (src, 0); while (!streaming_terminate) { struct timeval tm1; @@ -1061,7 +1062,7 @@ streamer_thread (void *ctx) { int alloc_time = 1000 / (bytes_in_one_second * output->fmt.channels / blocksize); streamer_lock (); - if (streambuffer_fill < (STREAM_BUFFER_SIZE-blocksize)) { + if (streambuffer_fill < (STREAM_BUFFER_SIZE-blocksize*2)) { int sz = STREAM_BUFFER_SIZE - streambuffer_fill; int minsize = blocksize; @@ -1072,7 +1073,7 @@ streamer_thread (void *ctx) { } sz = min (minsize, sz); assert ((sz&3) == 0); - char buf[sz]; + char buf[sz*2]; // buffer must be 2x large to accomodate resamplers/pitchers/... streamer_unlock (); // ensure that size is possible with current format @@ -1083,7 +1084,7 @@ streamer_thread (void *ctx) { int bytesread = streamer_read_async (buf,sz); streamer_lock (); - memcpy (streambuffer+streambuffer_fill, buf, sz); + memcpy (streambuffer+streambuffer_fill, buf, bytesread); if (bytesread > 0) { streambuffer_fill += bytesread; } @@ -1132,10 +1133,13 @@ streamer_init (void) { #endif mutex = mutex_create (); decodemutex = mutex_create (); - src = ddb_src_init (); - if (!src) { - return -1; + + // find src plugin, and use it if found + srcplug = (ddb_dsp_src_t*)plug_get_for_id ("dsp_src"); + if (srcplug) { + src = srcplug->dsp.open ("strm_src"); } + conf_replaygain_mode = conf_get_int ("replaygain_mode", 0); conf_replaygain_scale = conf_get_int ("replaygain_scale", 1); streamer_tid = thread_start (streamer_thread, NULL); @@ -1167,8 +1171,8 @@ streamer_free (void) { decodemutex = 0; mutex_free (mutex); mutex = 0; - if (src) { - ddb_src_free (src); + if (srcplug && src) { + srcplug->dsp.close (src); src = NULL; } } @@ -1179,14 +1183,13 @@ streamer_reset (int full) { // must be called when current song changes by exter fprintf (stderr, "ERROR: someone called streamer_reset after exit\n"); return; // failsafe, in case someone calls streamer reset after deinit } - ddb_src_lock (src); if (full) { streamer_lock (); streambuffer_pos = 0; streambuffer_fill = 0; streamer_unlock (); } - ddb_src_reset (src, 1); + srcplug->reset (src, 1); #if 0 // !!!! FIXME !!!! // reset dsp DB_dsp_t **dsp = deadbeef->plug_get_dsp_list (); @@ -1197,7 +1200,6 @@ streamer_reset (int full) { // must be called when current song changes by exter } } #endif - ddb_src_unlock (src); } int replaygain = 1; @@ -1328,8 +1330,6 @@ streamer_read_async (char *bytes, int size) { #define SRC_NUM_SAMPLES 1024 char outbuf[SRC_NUM_SAMPLES * output->fmt.channels * sizeof (float)]; - char *src_data = NULL; - int src_data_size = 0; bytesread = 0; ddb_waveformat_t srcfmt; memcpy (&srcfmt, &output->fmt, sizeof (srcfmt)); @@ -1337,9 +1337,15 @@ streamer_read_async (char *bytes, int size) { srcfmt.is_float = 1; int inputsize = (ftoi (SRC_NUM_SAMPLES * ratio) + 100) * inputsamplesize; char input[inputsize]; - char tempbuf[inputsize/inputsamplesize * sizeof (float) * output->fmt.channels]; + char tempbuf[inputsize/inputsamplesize * sizeof (float) * output->fmt.channels * 2]; while (1) { - int converted_bytes = 0; + // read more samples for src + inputsize = fileinfo->plugin->read (fileinfo, input, (ftoi (SRC_NUM_SAMPLES * ratio) + 100) * inputsamplesize); + // convert to float + int tempsize = pcm_convert (&fileinfo->fmt, input, &srcfmt, tempbuf, inputsize); + assert (tempsize <= sizeof (tempbuf)/2); + + int converted_frames = 0; // drain src int n = sizeof (outbuf); @@ -1347,31 +1353,28 @@ streamer_read_async (char *bytes, int size) { if (n > remaining) { n = remaining; } - converted_bytes = ddb_src_process (src, src_data, src_data_size/(sizeof(float)*output->fmt.channels), outbuf, n, ratio, srcfmt.channels); - - src_data = NULL; - src_data_size = 0; - if (converted_bytes > 0) { - bytesread += pcm_convert (&srcfmt, outbuf, &output->fmt, bytes + bytesread, converted_bytes); - assert (bytesread <= size); - if (bytesread == size) { + srcplug->set_ratio (src, ratio); + //printf ("asked for %d frames\n", src_data_size/(sizeof(float)*output->fmt.channels)); + converted_frames = srcplug->dsp.process (src, (float *)tempbuf, tempsize/(sizeof(float)*output->fmt.channels), srcfmt.channels); + //printf ("received %d frames\n", converted_frames); + + if (converted_frames > 0) { + //fwrite (tempbuf, 1, converted_frames * sizeof(float)*output->fmt.channels, out); + int n = pcm_convert (&srcfmt, tempbuf, &output->fmt, bytes + bytesread, converted_frames * (sizeof(float)*output->fmt.channels)); + //fwrite (bytes + bytesread, 1, n, out); + + bytesread += n; + assert (bytesread <= (size * 2)); + if (bytesread >= size) { break; } continue; } - // read more samples for src - inputsize = fileinfo->plugin->read (fileinfo, input, (ftoi (SRC_NUM_SAMPLES * ratio) + 100) * inputsamplesize); - if (!inputsize && !converted_bytes) { + if (!inputsize && !converted_frames) { break; // eof } - // convert to float - int tempsize = pcm_convert (&fileinfo->fmt, input, &srcfmt, tempbuf, inputsize); - assert (tempsize <= sizeof (tempbuf)); - - src_data = tempbuf; - src_data_size = tempsize; } } else { @@ -1446,6 +1449,8 @@ streamer_read_async (char *bytes, int size) { return initsize; } else { + break; +#if 0 // that means EOF trace ("streamer: EOF! buns: %d\n", bytes_until_next_song); @@ -1461,6 +1466,7 @@ streamer_read_async (char *bytes, int size) { } } break; +#endif } } return initsize - size; @@ -1559,12 +1565,17 @@ streamer_is_buffering (void) { } } +void +src_conf_changed (void) { + +} + void streamer_configchanged (void) { conf_replaygain_mode = conf_get_int ("replaygain_mode", 0); conf_replaygain_scale = conf_get_int ("replaygain_scale", 1); - ddb_src_confchanged (src); + srcplug->reset (src, 1); } void -- cgit v1.2.3