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
This commit is contained in:
Avuton Olrich 2007-02-02 03:51:07 +00:00
parent 96c5976ccc
commit 79ef8ba248
6 changed files with 156 additions and 11 deletions

View File

@ -11,6 +11,7 @@ AC_SUBST(MP4FF_LIB)
AC_SUBST(MP4FF_SUBDIR) AC_SUBST(MP4FF_SUBDIR)
AC_PROG_CC AC_PROG_CC
AM_PROG_CC_C_O
AC_PROG_INSTALL AC_PROG_INSTALL
AC_PROG_LIBTOOL AC_PROG_LIBTOOL
AC_PROG_MAKE_SET 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(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(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(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,[[ --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="") 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(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(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_C_BIGENDIAN
AC_CHECK_SIZEOF(short) 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])]) [enable_pulse=no;AC_MSG_WARN([PulseAudio not found -- disabling])])
fi 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 if test x$enable_mvp = xyes; then
AC_DEFINE(HAVE_MVP,1,[Define to enable Hauppauge Media MVP support]) AC_DEFINE(HAVE_MVP,1,[Define to enable Hauppauge Media MVP support])
fi fi
@ -777,8 +789,15 @@ if
fi fi
echo "" echo ""
echo " Other features:" 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 if test x$with_zeroconf != xno; then
echo " Zeroconf support ..............$with_zeroconf" echo " Zeroconf support ..............$with_zeroconf"
else else

View File

@ -126,6 +126,35 @@ This is the gain (in dB) applied to songs with ReplayGain tags.
.B volume_normalization <yes or no> .B volume_normalization <yes or no>
If yes, mpd will normalize the volume of songs as they play. Default is no. If yes, mpd will normalize the volume of songs as they play. Default is no.
.TP .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> .B audio_buffer_size <size in KiB>
This specifies the size of the audio output buffer that mpd uses. The default This specifies the size of the audio output buffer that mpd uses. The default
is 2048. is 2048.

View File

@ -123,6 +123,12 @@ error_file "~/.mpd/mpd.error"
# #
#audio_output_format "44100:16:2" #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>
#
################################################################ ################################################################

View File

@ -157,6 +157,7 @@ void initConf(void)
registerConfigParam(CONF_REPLAYGAIN, 0, 0); registerConfigParam(CONF_REPLAYGAIN, 0, 0);
registerConfigParam(CONF_REPLAYGAIN_PREAMP, 0, 0); registerConfigParam(CONF_REPLAYGAIN_PREAMP, 0, 0);
registerConfigParam(CONF_VOLUME_NORMALIZATION, 0, 0); registerConfigParam(CONF_VOLUME_NORMALIZATION, 0, 0);
registerConfigParam(CONF_SAMPLERATE_CONVERTER, 0, 0);
registerConfigParam(CONF_AUDIO_BUFFER_SIZE, 0, 0); registerConfigParam(CONF_AUDIO_BUFFER_SIZE, 0, 0);
registerConfigParam(CONF_BUFFER_BEFORE_PLAY, 0, 0); registerConfigParam(CONF_BUFFER_BEFORE_PLAY, 0, 0);
registerConfigParam(CONF_HTTP_BUFFER_SIZE, 0, 0); registerConfigParam(CONF_HTTP_BUFFER_SIZE, 0, 0);

View File

@ -43,6 +43,7 @@
#define CONF_REPLAYGAIN "replaygain" #define CONF_REPLAYGAIN "replaygain"
#define CONF_REPLAYGAIN_PREAMP "replaygain_preamp" #define CONF_REPLAYGAIN_PREAMP "replaygain_preamp"
#define CONF_VOLUME_NORMALIZATION "volume_normalization" #define CONF_VOLUME_NORMALIZATION "volume_normalization"
#define CONF_SAMPLERATE_CONVERTER "samplerate_converter"
#define CONF_AUDIO_BUFFER_SIZE "audio_buffer_size" #define CONF_AUDIO_BUFFER_SIZE "audio_buffer_size"
#define CONF_BUFFER_BEFORE_PLAY "buffer_before_play" #define CONF_BUFFER_BEFORE_PLAY "buffer_before_play"
#define CONF_HTTP_BUFFER_SIZE "http_buffer_size" #define CONF_HTTP_BUFFER_SIZE "http_buffer_size"

View File

@ -21,11 +21,16 @@
#include "mpd_types.h" #include "mpd_types.h"
#include "log.h" #include "log.h"
#include "utils.h" #include "utils.h"
#include "conf.h"
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include <assert.h> #include <assert.h>
#ifdef HAVE_LIBSAMPLERATE
#include <samplerate.h>
#endif
void pcm_volumeChange(char *buffer, int bufferSize, AudioFormat * format, void pcm_volumeChange(char *buffer, int bufferSize, AudioFormat * format,
int volume) int volume)
{ {
@ -46,6 +51,9 @@ void pcm_volumeChange(char *buffer, int bufferSize, AudioFormat * format,
while (bufferSize > 0) { while (bufferSize > 0) {
temp32 = *buffer16; temp32 = *buffer16;
temp32 *= volume; temp32 *= volume;
temp32 += rand() & 511;
temp32 -= rand() & 511;
temp32 += 500;
temp32 /= 1000; temp32 /= 1000;
*buffer16 = temp32 > 32767 ? 32767 : *buffer16 = temp32 > 32767 ? 32767 :
(temp32 < -32768 ? -32768 : temp32); (temp32 < -32768 ? -32768 : temp32);
@ -57,6 +65,9 @@ void pcm_volumeChange(char *buffer, int bufferSize, AudioFormat * format,
while (bufferSize > 0) { while (bufferSize > 0) {
temp32 = *buffer8; temp32 = *buffer8;
temp32 *= volume; temp32 *= volume;
temp32 += rand() & 511;
temp32 -= rand() & 511;
temp32 += 500;
temp32 /= 1000; temp32 /= 1000;
*buffer8 = temp32 > 127 ? 127 : *buffer8 = temp32 > 127 ? 127 :
(temp32 < -128 ? -128 : temp32); (temp32 < -128 ? -128 : temp32);
@ -86,7 +97,11 @@ static void pcm_add(char *buffer1, char *buffer2, size_t bufferSize1,
while (bufferSize1 > 0 && bufferSize2 > 0) { while (bufferSize1 > 0 && bufferSize2 > 0) {
temp32 = temp32 =
(vol1 * (*buffer16_1) + (vol1 * (*buffer16_1) +
vol2 * (*buffer16_2)) / 1000; vol2 * (*buffer16_2));
temp32 += rand() & 511;
temp32 -= rand() & 511;
temp32 += 500;
temp32 /= 1000;
*buffer16_1 = *buffer16_1 =
temp32 > 32767 ? 32767 : (temp32 < temp32 > 32767 ? 32767 : (temp32 <
-32768 ? -32768 : temp32); -32768 ? -32768 : temp32);
@ -101,7 +116,11 @@ static void pcm_add(char *buffer1, char *buffer2, size_t bufferSize1,
case 8: case 8:
while (bufferSize1 > 0 && bufferSize2 > 0) { while (bufferSize1 > 0 && bufferSize2 > 0) {
temp32 = 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 = *buffer8_1 =
temp32 > 127 ? 127 : (temp32 < temp32 > 127 ? 127 : (temp32 <
-128 ? -128 : temp32); -128 ? -128 : temp32);
@ -133,6 +152,38 @@ void pcm_mix(char *buffer1, char *buffer2, size_t bufferSize1,
format); 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! */ /* outFormat bits must be 16 and channels must be 2! */
void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer, size_t void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer, size_t
inSize, AudioFormat * outFormat, char *outBuffer) inSize, AudioFormat * outFormat, char *outBuffer)
@ -234,6 +285,47 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer, size_t
if (inFormat->sampleRate == outFormat->sampleRate) { if (inFormat->sampleRate == outFormat->sampleRate) {
memcpy(outBuffer, dataChannelConv, dataChannelLen); memcpy(outBuffer, dataChannelConv, dataChannelLen);
} else { } 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! */ /* only works if outFormat is 16-bit stereo! */
/* resampling code blatantly ripped from ESD */ /* resampling code blatantly ripped from ESD */
mpd_uint32 rd_dat = 0; mpd_uint32 rd_dat = 0;
@ -241,11 +333,7 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer, size_t
mpd_sint16 lsample, rsample; mpd_sint16 lsample, rsample;
mpd_sint16 *out = (mpd_sint16 *) outBuffer; mpd_sint16 *out = (mpd_sint16 *) outBuffer;
mpd_sint16 *in = (mpd_sint16 *) dataChannelConv; mpd_sint16 *in = (mpd_sint16 *) dataChannelConv;
const int shift = sizeof(mpd_sint16) * outFormat->channels; mpd_uint32 nlen = pcm_sizeOfOutputBufferForAudioFormatConversion(inFormat, inSize, outFormat) / sizeof(mpd_sint16);
mpd_uint32 nlen = (((dataChannelLen / shift) *
(mpd_uint32) (outFormat->sampleRate)) /
inFormat->sampleRate);
nlen *= outFormat->channels;
switch (outFormat->channels) { switch (outFormat->channels) {
case 1: case 1:
@ -272,6 +360,7 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer, size_t
} }
break; break;
} }
#endif
} }
return; return;
@ -306,9 +395,9 @@ size_t pcm_sizeOfOutputBufferForAudioFormatConversion(AudioFormat * inFormat,
} }
} }
outSize = (((outSize / shift) * (mpd_uint32) (outFormat->sampleRate)) / outSize /= shift;
inFormat->sampleRate); outSize = floor(0.5 + (double)outSize *
((double)outFormat->sampleRate / (double)inFormat->sampleRate));
outSize *= shift; outSize *= shift;
return outSize; return outSize;