aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--src/Makefile.am8
-rw-r--r--src/pcm_resample.c26
-rw-r--r--src/pcm_resample.h63
-rw-r--r--src/pcm_resample_fallback.c61
-rw-r--r--src/pcm_resample_libsamplerate.c140
-rw-r--r--src/pcm_utils.c168
-rw-r--r--src/pcm_utils.h16
8 files changed, 308 insertions, 176 deletions
diff --git a/configure.ac b/configure.ac
index 8fdec792..76f4badb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -390,6 +390,8 @@ if test x$enable_lsr = xyes; then
[enable_lsr=no;AC_MSG_WARN([libsamplerate not found -- disabling])])
fi
+AM_CONDITIONAL(HAVE_LIBSAMPLERATE, test x$enable_lsr = xyes)
+
if test x$enable_fifo = xyes; then
AC_CHECK_FUNC([mkfifo],
[enable_fifo=yes;AC_DEFINE([HAVE_FIFO], 1, [Define to enable support for writing audio to a FIFO])],
diff --git a/src/Makefile.am b/src/Makefile.am
index f2bf55eb..47a12148 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -66,6 +66,7 @@ mpd_headers = \
path.h \
mapper.h \
pcm_utils.h \
+ pcm_resample.h \
pcm_dither.h \
permission.h \
player_thread.h \
@@ -146,6 +147,7 @@ mpd_SOURCES = \
path.c \
mapper.c \
pcm_utils.c \
+ pcm_resample.c \
pcm_dither.c \
permission.c \
player_thread.c \
@@ -176,6 +178,12 @@ mpd_SOURCES = \
stored_playlist.c \
timer.c
+if HAVE_LIBSAMPLERATE
+mpd_SOURCES += pcm_resample_libsamplerate.c
+else
+mpd_SOURCES += pcm_resample_fallback.c
+endif
+
if HAVE_ID3TAG
mpd_SOURCES += tag_id3.c
endif
diff --git a/src/pcm_resample.c b/src/pcm_resample.c
new file mode 100644
index 00000000..097e1392
--- /dev/null
+++ b/src/pcm_resample.c
@@ -0,0 +1,26 @@
+/* the Music Player Daemon (MPD)
+ * Copyright (C) 2008 Max Kellermann <max@duempel.org>
+ * This project's homepage is: http://www.musicpd.org
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "pcm_resample.h"
+
+#include <string.h>
+
+void pcm_resample_init(struct pcm_resample_state *state)
+{
+ memset(state, 0, sizeof(*state));
+}
diff --git a/src/pcm_resample.h b/src/pcm_resample.h
new file mode 100644
index 00000000..d6001550
--- /dev/null
+++ b/src/pcm_resample.h
@@ -0,0 +1,63 @@
+/* the Music Player Daemon (MPD)
+ * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
+ * Copyright (C) 2008 Max Kellermann <max@duempel.org>
+ * This project's homepage is: http://www.musicpd.org
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef MPD_PCM_RESAMPLE_H
+#define MPD_PCM_RESAMPLE_H
+
+#include "config.h"
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#ifdef HAVE_LIBSAMPLERATE
+#include <samplerate.h>
+#endif
+
+struct pcm_resample_state {
+#ifdef HAVE_LIBSAMPLERATE
+ SRC_STATE *state;
+ SRC_DATA data;
+ size_t data_in_size;
+ size_t data_out_size;
+
+ struct {
+ unsigned src_rate;
+ unsigned dest_rate;
+ uint8_t channels;
+ } prev;
+
+ bool error;
+#else
+ /* struct must not be empty */
+ int dummy;
+#endif
+};
+
+void pcm_resample_init(struct pcm_resample_state *state);
+
+size_t
+pcm_resample_16(uint8_t channels,
+ unsigned src_rate,
+ const int16_t *src_buffer, size_t src_size,
+ unsigned dest_rate,
+ int16_t *dest_buffer, size_t dest_size,
+ struct pcm_resample_state *state);
+
+#endif
diff --git a/src/pcm_resample_fallback.c b/src/pcm_resample_fallback.c
new file mode 100644
index 00000000..4ab58616
--- /dev/null
+++ b/src/pcm_resample_fallback.c
@@ -0,0 +1,61 @@
+/* the Music Player Daemon (MPD)
+ * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
+ * Copyright (C) 2008 Max Kellermann <max@duempel.org>
+ * This project's homepage is: http://www.musicpd.org
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "pcm_resample.h"
+#include "gcc.h"
+
+/* resampling code blatantly ripped from ESD */
+size_t
+pcm_resample_16(uint8_t channels,
+ unsigned src_rate,
+ const int16_t *src_buffer, mpd_unused size_t src_size,
+ unsigned dest_rate,
+ int16_t *dest_buffer, size_t dest_size,
+ mpd_unused struct pcm_resample_state *state)
+{
+ unsigned src_pos, dest_pos = 0;
+ unsigned dest_samples = dest_size / 2;
+ int16_t lsample, rsample;
+
+ switch (channels) {
+ case 1:
+ while (dest_pos < dest_samples) {
+ src_pos = dest_pos * src_rate / dest_rate;
+
+ lsample = src_buffer[src_pos++];
+
+ dest_buffer[dest_pos++] = lsample;
+ }
+ break;
+ case 2:
+ while (dest_pos < dest_samples) {
+ src_pos = dest_pos * src_rate / dest_rate;
+ src_pos &= ~1;
+
+ lsample = src_buffer[src_pos++];
+ rsample = src_buffer[src_pos++];
+
+ dest_buffer[dest_pos++] = lsample;
+ dest_buffer[dest_pos++] = rsample;
+ }
+ break;
+ }
+
+ return dest_size;
+}
diff --git a/src/pcm_resample_libsamplerate.c b/src/pcm_resample_libsamplerate.c
new file mode 100644
index 00000000..5321c0e0
--- /dev/null
+++ b/src/pcm_resample_libsamplerate.c
@@ -0,0 +1,140 @@
+/* the Music Player Daemon (MPD)
+ * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
+ * Copyright (C) 2008 Max Kellermann <max@duempel.org>
+ * This project's homepage is: http://www.musicpd.org
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "pcm_resample.h"
+#include "conf.h"
+#include "log.h"
+#include "utils.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+static int pcm_resample_get_converter(void)
+{
+ const char *conf = getConfigParamValue(CONF_SAMPLERATE_CONVERTER);
+ long convalgo;
+ char *test;
+ const char *test2;
+ size_t len;
+
+ if (!conf) {
+ convalgo = SRC_SINC_FASTEST;
+ goto out;
+ }
+
+ convalgo = strtol(conf, &test, 10);
+ if (*test == '\0' && src_get_name(convalgo))
+ goto out;
+
+ len = strlen(conf);
+ for (convalgo = 0 ; ; convalgo++) {
+ test2 = src_get_name(convalgo);
+ if (!test2) {
+ convalgo = SRC_SINC_FASTEST;
+ break;
+ }
+ if (strncasecmp(test2, conf, len) == 0)
+ goto out;
+ }
+
+ ERROR("unknown samplerate converter \"%s\"\n", conf);
+out:
+ DEBUG("selecting samplerate converter \"%s\"\n",
+ src_get_name(convalgo));
+
+ return convalgo;
+}
+
+size_t
+pcm_resample_16(uint8_t channels,
+ unsigned src_rate,
+ const int16_t *src_buffer, size_t src_size,
+ unsigned dest_rate,
+ int16_t *dest_buffer, size_t dest_size,
+ struct pcm_resample_state *state)
+{
+ static int convalgo = -1;
+ SRC_DATA *data = &state->data;
+ size_t data_in_size;
+ size_t data_out_size;
+ int error;
+
+ if (convalgo < 0)
+ convalgo = pcm_resample_get_converter();
+
+ /* (re)set the state/ratio if the in or out format changed */
+ if (channels != state->prev.channels ||
+ src_rate != state->prev.src_rate ||
+ dest_rate != state->prev.dest_rate) {
+ state->error = false;
+ state->prev.channels = channels;
+ state->prev.src_rate = src_rate;
+ state->prev.dest_rate = dest_rate;
+
+ if (state->state)
+ state->state = src_delete(state->state);
+
+ state->state = src_new(convalgo, channels, &error);
+ if (!state->state) {
+ ERROR("cannot create new libsamplerate state: %s\n",
+ src_strerror(error));
+ state->error = true;
+ return 0;
+ }
+
+ data->src_ratio = (double)dest_rate / (double)src_rate;
+ DEBUG("setting samplerate conversion ratio to %.2lf\n",
+ data->src_ratio);
+ src_set_ratio(state->state, data->src_ratio);
+ }
+
+ /* there was an error previously, and nothing has changed */
+ if (state->error)
+ return 0;
+
+ data->input_frames = src_size / 2 / channels;
+ data_in_size = data->input_frames * sizeof(float) * channels;
+ if (data_in_size > state->data_in_size) {
+ state->data_in_size = data_in_size;
+ data->data_in = xrealloc(data->data_in, data_in_size);
+ }
+
+ data->output_frames = dest_size / 2 / channels;
+ data_out_size = data->output_frames * sizeof(float) * channels;
+ if (data_out_size > state->data_out_size) {
+ state->data_out_size = data_out_size;
+ data->data_out = xrealloc(data->data_out, data_out_size);
+ }
+
+ src_short_to_float_array(src_buffer, data->data_in,
+ data->input_frames * channels);
+
+ error = src_process(state->state, data);
+ if (error) {
+ ERROR("error processing samples with libsamplerate: %s\n",
+ src_strerror(error));
+ state->error = true;
+ return 0;
+ }
+
+ src_float_to_short_array(data->data_out, dest_buffer,
+ data->output_frames_gen * channels);
+
+ return data->output_frames_gen * 2 * channels;
+}
diff --git a/src/pcm_utils.c b/src/pcm_utils.c
index 8d5bed99..6d76aba9 100644
--- a/src/pcm_utils.c
+++ b/src/pcm_utils.c
@@ -209,166 +209,10 @@ void pcm_convert_init(struct pcm_convert_state *state)
{
memset(state, 0, sizeof(*state));
+ pcm_resample_init(&state->resample);
pcm_dither_24_init(&state->dither);
}
-#ifdef HAVE_LIBSAMPLERATE
-static int pcm_resample_get_converter(void)
-{
- const char *conf = getConfigParamValue(CONF_SAMPLERATE_CONVERTER);
- long convalgo;
- char *test;
- const char *test2;
- size_t len;
-
- if (!conf) {
- convalgo = SRC_SINC_FASTEST;
- goto out;
- }
-
- convalgo = strtol(conf, &test, 10);
- if (*test == '\0' && src_get_name(convalgo))
- goto out;
-
- len = strlen(conf);
- for (convalgo = 0 ; ; convalgo++) {
- test2 = src_get_name(convalgo);
- if (!test2) {
- convalgo = SRC_SINC_FASTEST;
- break;
- }
- if (strncasecmp(test2, conf, len) == 0)
- goto out;
- }
-
- ERROR("unknown samplerate converter \"%s\"\n", conf);
-out:
- DEBUG("selecting samplerate converter \"%s\"\n",
- src_get_name(convalgo));
-
- return convalgo;
-}
-#endif
-
-#ifdef HAVE_LIBSAMPLERATE
-static size_t pcm_resample(int8_t channels, uint32_t inSampleRate,
- const int16_t *src, size_t src_size,
- uint32_t outSampleRate, int16_t *outBuffer,
- size_t outSize,
- struct pcm_convert_state *convState)
-{
- static int convalgo = -1;
- SRC_DATA *data = &convState->data;
- size_t dataInSize;
- size_t dataOutSize;
- int error;
-
- if (convalgo < 0)
- convalgo = pcm_resample_get_converter();
-
- /* (re)set the state/ratio if the in or out format changed */
- if ((channels != convState->lastChannels) ||
- (inSampleRate != convState->lastInSampleRate) ||
- (outSampleRate != convState->lastOutSampleRate)) {
- convState->error = 0;
- convState->lastChannels = channels;
- convState->lastInSampleRate = inSampleRate;
- convState->lastOutSampleRate = outSampleRate;
-
- if (convState->state)
- convState->state = src_delete(convState->state);
-
- convState->state = src_new(convalgo, channels, &error);
- if (!convState->state) {
- ERROR("cannot create new libsamplerate state: %s\n",
- src_strerror(error));
- convState->error = 1;
- return 0;
- }
-
- data->src_ratio = (double)outSampleRate / (double)inSampleRate;
- DEBUG("setting samplerate conversion ratio to %.2lf\n",
- data->src_ratio);
- src_set_ratio(convState->state, data->src_ratio);
- }
-
- /* there was an error previously, and nothing has changed */
- if (convState->error)
- return 0;
-
- data->input_frames = src_size / 2 / channels;
- dataInSize = data->input_frames * sizeof(float) * channels;
- if (dataInSize > convState->dataInSize) {
- convState->dataInSize = dataInSize;
- data->data_in = xrealloc(data->data_in, dataInSize);
- }
-
- data->output_frames = outSize / 2 / channels;
- dataOutSize = data->output_frames * sizeof(float) * channels;
- if (dataOutSize > convState->dataOutSize) {
- convState->dataOutSize = dataOutSize;
- data->data_out = xrealloc(data->data_out, dataOutSize);
- }
-
- src_short_to_float_array((const short *)src, data->data_in,
- data->input_frames * channels);
-
- error = src_process(convState->state, data);
- if (error) {
- ERROR("error processing samples with libsamplerate: %s\n",
- src_strerror(error));
- convState->error = 1;
- return 0;
- }
-
- src_float_to_short_array(data->data_out, (short *)outBuffer,
- data->output_frames_gen * channels);
-
- return data->output_frames_gen * 2 * channels;
-}
-#else /* !HAVE_LIBSAMPLERATE */
-/* resampling code blatantly ripped from ESD */
-static size_t pcm_resample(int8_t channels, uint32_t inSampleRate,
- const int16_t *src, mpd_unused size_t src_size,
- uint32_t outSampleRate, char *outBuffer,
- size_t outSize,
- mpd_unused struct pcm_convert_state *convState)
-{
- uint32_t rd_dat = 0;
- uint32_t wr_dat = 0;
- const int16_t *in = (const int16_t *)src;
- int16_t *out = (int16_t *)outBuffer;
- uint32_t nlen = outSize / 2;
- int16_t lsample, rsample;
-
- switch (channels) {
- case 1:
- while (wr_dat < nlen) {
- rd_dat = wr_dat * inSampleRate / outSampleRate;
-
- lsample = in[rd_dat++];
-
- out[wr_dat++] = lsample;
- }
- break;
- case 2:
- while (wr_dat < nlen) {
- rd_dat = wr_dat * inSampleRate / outSampleRate;
- rd_dat &= ~1;
-
- lsample = in[rd_dat++];
- rsample = in[rd_dat++];
-
- out[wr_dat++] = lsample;
- out[wr_dat++] = rsample;
- }
- break;
- }
-
- return outSize;
-}
-#endif /* !HAVE_LIBSAMPLERATE */
-
static void
pcm_convert_channels_1_to_2(int16_t *dest, const int16_t *src,
unsigned num_frames)
@@ -542,11 +386,11 @@ size_t pcm_convert(const struct audio_format *inFormat,
assert(dest_size >= len);
memcpy(outBuffer, buf, len);
} else {
- len = pcm_resample(outFormat->channels,
- inFormat->sample_rate, buf, len,
- outFormat->sample_rate,
- (int16_t*)outBuffer,
- dest_size, convState);
+ len = pcm_resample_16(outFormat->channels,
+ inFormat->sample_rate, buf, len,
+ outFormat->sample_rate,
+ (int16_t*)outBuffer,
+ dest_size, &convState->resample);
if (len == 0)
exit(EXIT_FAILURE);
}
diff --git a/src/pcm_utils.h b/src/pcm_utils.h
index 835ba187..3599b707 100644
--- a/src/pcm_utils.h
+++ b/src/pcm_utils.h
@@ -19,28 +19,16 @@
#ifndef PCM_UTILS_H
#define PCM_UTILS_H
-#include "../config.h"
+#include "pcm_resample.h"
#include "pcm_dither.h"
#include <stdint.h>
#include <stddef.h>
-#ifdef HAVE_LIBSAMPLERATE
-#include <samplerate.h>
-#endif
-
struct audio_format;
struct pcm_convert_state {
-#ifdef HAVE_LIBSAMPLERATE
- SRC_STATE *state;
- SRC_DATA data;
- size_t dataInSize;
- size_t dataOutSize;
- int8_t lastChannels;
- uint32_t lastInSampleRate;
- uint32_t lastOutSampleRate;
-#endif
+ struct pcm_resample_state resample;
struct pcm_dither_24 dither;