summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvuton Olrich <avuton@gmail.com>2007-02-02 03:51:07 +0000
committerAvuton Olrich <avuton@gmail.com>2007-02-02 03:51:07 +0000
commit79ef8ba2480eef73d5863945e270c539e7b4aac6 (patch)
treeb94bfd1ebf394208ee0c5f4bfc9ad2008b00771f
parent96c5976cccf61e0310879e69f51ba235e6b1729d (diff)
Add libsamplerate support, old resampling is still an option, but this sounds much better for those who need it and don't want to use pulseaudio. Reviewed by shank/avuton.
git-svn-id: https://svn.musicpd.org/mpd/trunk@5316 09075e82-0dd4-0310-85a5-a0d7c8717e4f
-rw-r--r--configure.ac21
-rw-r--r--doc/mpd.conf.529
-rw-r--r--doc/mpdconf.example6
-rw-r--r--src/conf.c1
-rw-r--r--src/conf.h1
-rw-r--r--src/pcm_utils.c109
6 files changed, 156 insertions, 11 deletions
diff --git a/configure.ac b/configure.ac
index 8b41bbad0..95386d296 100644
--- a/configure.ac
+++ b/configure.ac
@@ -11,6 +11,7 @@ AC_SUBST(MP4FF_LIB)
AC_SUBST(MP4FF_SUBDIR)
AC_PROG_CC
+AM_PROG_CC_C_O
AC_PROG_INSTALL
AC_PROG_LIBTOOL
AC_PROG_MAKE_SET
@@ -79,6 +80,7 @@ AC_ARG_ENABLE(audiofile,[ --disable-audiofile disable audiofile support, di
AC_ARG_ENABLE(mod,[ --enable-mod enable MOD support (default: disable],[enable_mod=$enableval],[enable_mod=yes])
AC_ARG_ENABLE(mpc,[ --disable-mpc disable musepack (MPC) support (default: enable)],[enable_mpc=$enableval],[enable_mpc=yes])
AC_ARG_ENABLE(id3,[ --disable-id3 disable id3 support (default: enable)],[enable_id3=$enableval],[enable_id3=yes])
+AC_ARG_ENABLE(lsr,[ --disable-lsr disable libsamplerate support (default: enable)],[enable_lsr=$enableval],[enable_lsr=yes])
AC_ARG_WITH(tremor,[[ --with-tremor[=PFX] Use Tremor(vorbisidec) integer Ogg-Vorbis decoder (with optional prefix)]], use_tremor=yes; test x$withval != xyes && tremor_prefix="$withval",)
AC_ARG_WITH(tremor-libraries,[ --with-tremor-libraries=DIR Directory where Tremor library is installed (optional)], tremor_libraries="$withval", tremor_libraries="")
@@ -101,6 +103,10 @@ AC_ARG_WITH(faad-libraries,[ --with-faad-libraries=DIR Directory where faad2
AC_ARG_WITH(faad-includes,[ --with-faad-includes=DIR Directory where faad2 header files are installed (optional)], faad_includes="$withval", faad_includes="")
AC_ARG_WITH(zeroconf,[[ --with-zeroconf=[auto|avahi|bonjour|no] Enable zeroconf backend (default=auto)]], with_zeroconf="$withval", with_zeroconf="auto")
+AC_ARG_WITH(lsr,[ --with-src=PFX Prefix where libsamplerate is installed], src_prefix="$withval", src_prefix="")
+AC_ARG_WITH(lsr-libraries,[ --with-lsr-libraries=DIR Directory where libsamplerate library is installed (optional)], lsr_libraries="$withval", lsr_libraries="")
+AC_ARG_WITH(lsr-includes,[ --with-lsr-includes=DIR Directory where libsamplerate header files are installed (optional)], lsr_includes="$withval", lsr_includes="")
+
AC_C_BIGENDIAN
AC_CHECK_SIZEOF(short)
@@ -186,6 +192,12 @@ if test x$enable_pulse = xyes; then
[enable_pulse=no;AC_MSG_WARN([PulseAudio not found -- disabling])])
fi
+if test x$enable_lsr = xyes; then
+ PKG_CHECK_MODULES([SAMPLERATE], [samplerate >= 0.0.15],
+ [enable_lsr=yes;AC_DEFINE([HAVE_LIBSAMPLERATE], 1, [Define to enable libsamplerate])] MPD_LIBS="$MPD_LIBS $SAMPLERATE_LIBS" MPD_CFLAGS="$MPD_CFLAGS $SAMPLERATE_CFLAGS",
+ [enable_lsr=no;AC_MSG_WARN([libsamplerate not found -- disabling])])
+fi
+
if test x$enable_mvp = xyes; then
AC_DEFINE(HAVE_MVP,1,[Define to enable Hauppauge Media MVP support])
fi
@@ -777,8 +789,15 @@ if
fi
echo ""
-
echo " Other features:"
+
+if test x$enable_lsr = xyes; then
+ echo " libsamplerate support .........enabled"
+else
+ echo " libsamplerate support .........disabled"
+fi
+
+
if test x$with_zeroconf != xno; then
echo " Zeroconf support ..............$with_zeroconf"
else
diff --git a/doc/mpd.conf.5 b/doc/mpd.conf.5
index 821500e8b..572738234 100644
--- a/doc/mpd.conf.5
+++ b/doc/mpd.conf.5
@@ -126,6 +126,35 @@ This is the gain (in dB) applied to songs with ReplayGain tags.
.B volume_normalization <yes or no>
If yes, mpd will normalize the volume of songs as they play. Default is no.
.TP
+.B samplerate_converter <integer or prefix>
+Specifies the libsamplerate converter to use.
+The supplied value should either be an integer or a prefix of the name of a converter.
+The list of available converters at the time of writing is below.
+More converters may exist, consult the
+documentation of the Secret Rabbit Code libsamplerate (at http://www.mega-nerd.com/SRC/) for details.
+.RS
+.HP
+Best Sinc Interpolator (0)
+
+Band limited sinc interpolation, best quality, 97dB SNR, 96% BW.
+.HP
+Medium Sinc Interpolator (1)
+
+Band limited sinc interpolation, medium quality, 97dB SNR, 90% BW.
+.HP
+Fastest Sinc Interpolator (2, default)
+
+Band limited sinc interpolation, fastest, 97dB SNR, 80% BW.
+.HP
+ZOH Interpolator (3)
+
+Zero order hold interpolator, very fast, very poor quality with audible distortions.
+.HP
+Linear Interpolator (4)
+
+Linear interpolator, very fast, poor quality.
+.RE
+.TP
.B audio_buffer_size <size in KiB>
This specifies the size of the audio output buffer that mpd uses. The default
is 2048.
diff --git a/doc/mpdconf.example b/doc/mpdconf.example
index c7a294214..20ab89ec4 100644
--- a/doc/mpdconf.example
+++ b/doc/mpdconf.example
@@ -123,6 +123,12 @@ error_file "~/.mpd/mpd.error"
#
#audio_output_format "44100:16:2"
#
+# Specifies the libsamplerate converter to use (if compiled in),
+# see man 5 mpd.conf for more information.
+#
+#samplerate_converter <integer or prefix>
+#
+
################################################################
diff --git a/src/conf.c b/src/conf.c
index 0960dfbbc..7dfea6327 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -157,6 +157,7 @@ void initConf(void)
registerConfigParam(CONF_REPLAYGAIN, 0, 0);
registerConfigParam(CONF_REPLAYGAIN_PREAMP, 0, 0);
registerConfigParam(CONF_VOLUME_NORMALIZATION, 0, 0);
+ registerConfigParam(CONF_SAMPLERATE_CONVERTER, 0, 0);
registerConfigParam(CONF_AUDIO_BUFFER_SIZE, 0, 0);
registerConfigParam(CONF_BUFFER_BEFORE_PLAY, 0, 0);
registerConfigParam(CONF_HTTP_BUFFER_SIZE, 0, 0);
diff --git a/src/conf.h b/src/conf.h
index e2f568525..1cd4cf322 100644
--- a/src/conf.h
+++ b/src/conf.h
@@ -43,6 +43,7 @@
#define CONF_REPLAYGAIN "replaygain"
#define CONF_REPLAYGAIN_PREAMP "replaygain_preamp"
#define CONF_VOLUME_NORMALIZATION "volume_normalization"
+#define CONF_SAMPLERATE_CONVERTER "samplerate_converter"
#define CONF_AUDIO_BUFFER_SIZE "audio_buffer_size"
#define CONF_BUFFER_BEFORE_PLAY "buffer_before_play"
#define CONF_HTTP_BUFFER_SIZE "http_buffer_size"
diff --git a/src/pcm_utils.c b/src/pcm_utils.c
index b56ed33ac..f6b308258 100644
--- a/src/pcm_utils.c
+++ b/src/pcm_utils.c
@@ -21,11 +21,16 @@
#include "mpd_types.h"
#include "log.h"
#include "utils.h"
+#include "conf.h"
#include <string.h>
#include <math.h>
#include <assert.h>
+#ifdef HAVE_LIBSAMPLERATE
+#include <samplerate.h>
+#endif
+
void pcm_volumeChange(char *buffer, int bufferSize, AudioFormat * format,
int volume)
{
@@ -46,6 +51,9 @@ void pcm_volumeChange(char *buffer, int bufferSize, AudioFormat * format,
while (bufferSize > 0) {
temp32 = *buffer16;
temp32 *= volume;
+ temp32 += rand() & 511;
+ temp32 -= rand() & 511;
+ temp32 += 500;
temp32 /= 1000;
*buffer16 = temp32 > 32767 ? 32767 :
(temp32 < -32768 ? -32768 : temp32);
@@ -57,6 +65,9 @@ void pcm_volumeChange(char *buffer, int bufferSize, AudioFormat * format,
while (bufferSize > 0) {
temp32 = *buffer8;
temp32 *= volume;
+ temp32 += rand() & 511;
+ temp32 -= rand() & 511;
+ temp32 += 500;
temp32 /= 1000;
*buffer8 = temp32 > 127 ? 127 :
(temp32 < -128 ? -128 : temp32);
@@ -86,7 +97,11 @@ static void pcm_add(char *buffer1, char *buffer2, size_t bufferSize1,
while (bufferSize1 > 0 && bufferSize2 > 0) {
temp32 =
(vol1 * (*buffer16_1) +
- vol2 * (*buffer16_2)) / 1000;
+ vol2 * (*buffer16_2));
+ temp32 += rand() & 511;
+ temp32 -= rand() & 511;
+ temp32 += 500;
+ temp32 /= 1000;
*buffer16_1 =
temp32 > 32767 ? 32767 : (temp32 <
-32768 ? -32768 : temp32);
@@ -101,7 +116,11 @@ static void pcm_add(char *buffer1, char *buffer2, size_t bufferSize1,
case 8:
while (bufferSize1 > 0 && bufferSize2 > 0) {
temp32 =
- (vol1 * (*buffer8_1) + vol2 * (*buffer8_2)) / 1000;
+ (vol1 * (*buffer8_1) + vol2 * (*buffer8_2));
+ temp32 += rand() & 511;
+ temp32 -= rand() & 511;
+ temp32 += 500;
+ temp32 /= 1000;
*buffer8_1 =
temp32 > 127 ? 127 : (temp32 <
-128 ? -128 : temp32);
@@ -133,6 +152,38 @@ void pcm_mix(char *buffer1, char *buffer2, size_t bufferSize1,
format);
}
+#ifdef HAVE_LIBSAMPLERATE
+static int pcm_getSamplerateConverter(void) {
+ const char *conf, *test;
+ int convalgo = SRC_SINC_FASTEST;
+ int newalgo;
+ size_t len;
+
+ conf = getConfigParamValue(CONF_SAMPLERATE_CONVERTER);
+ if(conf) {
+ newalgo = strtol(conf, (char **)&test, 10);
+ if(*test) {
+ len = strlen(conf);
+ for(newalgo = 0; ; newalgo++) {
+ test = src_get_name(newalgo);
+ if(!test)
+ break; /* FAIL */
+ if(!strncasecmp(test, conf, len)) {
+ convalgo = newalgo;
+ break;
+ }
+ }
+ } else {
+ if(src_get_name(newalgo))
+ convalgo = newalgo;
+ /* else FAIL */
+ }
+ }
+ DEBUG("Selecting samplerate converter '%s'\n", src_get_name(convalgo));
+ return convalgo;
+}
+#endif
+
/* outFormat bits must be 16 and channels must be 2! */
void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer, size_t
inSize, AudioFormat * outFormat, char *outBuffer)
@@ -234,6 +285,47 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer, size_t
if (inFormat->sampleRate == outFormat->sampleRate) {
memcpy(outBuffer, dataChannelConv, dataChannelLen);
} else {
+#ifdef HAVE_LIBSAMPLERATE
+ static SRC_STATE *state = NULL;
+ static SRC_DATA data;
+ int error;
+ static double ratio = 0;
+ double newratio;
+
+ if(!state) {
+ state = src_new(pcm_getSamplerateConverter(), outFormat->channels, &error);
+ if(!state) {
+ ERROR("Cannot create new samplerate state: %s\n", src_strerror(error));
+ exit(EXIT_FAILURE);
+ } else {
+ DEBUG("Samplerate converter initialized\n");
+ }
+ }
+
+ newratio = (double)outFormat->sampleRate / (double)inFormat->sampleRate;
+ if(newratio != ratio) {
+ src_set_ratio(state, ratio = newratio);
+ DEBUG("Setting samplerate conversion ratio to %.2lf\n", ratio);
+ }
+
+ data.input_frames = dataChannelLen / 2 / outFormat->channels;
+ data.output_frames = pcm_sizeOfOutputBufferForAudioFormatConversion(inFormat, dataChannelLen, outFormat) / 2 / outFormat->channels;
+ data.src_ratio = (double)data.output_frames / (double)data.input_frames;
+
+ float conversionInBuffer[data.input_frames * outFormat->channels];
+ float conversionOutBuffer[data.output_frames * outFormat->channels];
+ data.data_in = conversionInBuffer;
+ data.data_out = conversionOutBuffer;
+
+ src_short_to_float_array((short *)dataChannelConv, data.data_in, data.input_frames * outFormat->channels);
+ error = src_process(state, &data);
+ if(error) {
+ ERROR("Cannot process samples: %s\n", src_strerror(error));
+ exit(EXIT_FAILURE);
+ }
+
+ src_float_to_short_array(data.data_out, (short *)outBuffer, data.output_frames * outFormat->channels);
+#else
/* only works if outFormat is 16-bit stereo! */
/* resampling code blatantly ripped from ESD */
mpd_uint32 rd_dat = 0;
@@ -241,11 +333,7 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer, size_t
mpd_sint16 lsample, rsample;
mpd_sint16 *out = (mpd_sint16 *) outBuffer;
mpd_sint16 *in = (mpd_sint16 *) dataChannelConv;
- const int shift = sizeof(mpd_sint16) * outFormat->channels;
- mpd_uint32 nlen = (((dataChannelLen / shift) *
- (mpd_uint32) (outFormat->sampleRate)) /
- inFormat->sampleRate);
- nlen *= outFormat->channels;
+ mpd_uint32 nlen = pcm_sizeOfOutputBufferForAudioFormatConversion(inFormat, inSize, outFormat) / sizeof(mpd_sint16);
switch (outFormat->channels) {
case 1:
@@ -272,6 +360,7 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer, size_t
}
break;
}
+#endif
}
return;
@@ -306,9 +395,9 @@ size_t pcm_sizeOfOutputBufferForAudioFormatConversion(AudioFormat * inFormat,
}
}
- outSize = (((outSize / shift) * (mpd_uint32) (outFormat->sampleRate)) /
- inFormat->sampleRate);
-
+ outSize /= shift;
+ outSize = floor(0.5 + (double)outSize *
+ ((double)outFormat->sampleRate / (double)inFormat->sampleRate));
outSize *= shift;
return outSize;