aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/audioOutput.c10
-rw-r--r--src/audioOutput.h2
-rw-r--r--src/outputBuffer.c3
-rw-r--r--src/outputBuffer.h2
-rw-r--r--src/pcm_utils.c81
-rw-r--r--src/pcm_utils.h22
-rw-r--r--src/playerData.c1
7 files changed, 85 insertions, 36 deletions
diff --git a/src/audioOutput.c b/src/audioOutput.c
index 7a99dfd68..ccc701451 100644
--- a/src/audioOutput.c
+++ b/src/audioOutput.c
@@ -135,6 +135,7 @@ int initAudioOutput(AudioOutput *ao, ConfigParam * param)
memset(&ao->inAudioFormat, 0, sizeof(AudioFormat));
memset(&ao->outAudioFormat, 0, sizeof(AudioFormat));
memset(&ao->reqAudioFormat, 0, sizeof(AudioFormat));
+ memset(&ao->convState, 0, sizeof(ConvState));
if (format) {
ao->convertAudioFormat = 1;
@@ -205,10 +206,11 @@ static void convertAudioFormat(AudioOutput * audioOutput, char **chunkArgPtr,
}
pcm_convertAudioFormat(&(audioOutput->inAudioFormat),
- *chunkArgPtr,
- *sizeArgPtr,
- &(audioOutput->outAudioFormat),
- audioOutput->convBuffer);
+ *chunkArgPtr,
+ *sizeArgPtr,
+ &(audioOutput->outAudioFormat),
+ audioOutput->convBuffer,
+ &audioOutput->convState);
*sizeArgPtr = size;
*chunkArgPtr = audioOutput->convBuffer;
diff --git a/src/audioOutput.h b/src/audioOutput.h
index cba445a3c..bcbe7997d 100644
--- a/src/audioOutput.h
+++ b/src/audioOutput.h
@@ -21,6 +21,7 @@
#include "../config.h"
+#include "pcm_utils.h"
#include "mpd_types.h"
#include "audio.h"
#include "tag.h"
@@ -66,6 +67,7 @@ struct _AudioOutput {
AudioFormat inAudioFormat;
AudioFormat outAudioFormat;
AudioFormat reqAudioFormat;
+ ConvState convState;
char *convBuffer;
int convBufferLen;
int sameInAndOutFormats;
diff --git a/src/outputBuffer.c b/src/outputBuffer.c
index 36e15a78f..d9cbcdc60 100644
--- a/src/outputBuffer.c
+++ b/src/outputBuffer.c
@@ -90,7 +90,8 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
}
data = convBuffer;
pcm_convertAudioFormat(&(dc->audioFormat), dataIn, dataInLen,
- &(cb->audioFormat), data);
+ &(cb->audioFormat), data,
+ &(cb->convState));
}
if (replayGainInfo && (replayGainState != REPLAYGAIN_OFF))
diff --git a/src/outputBuffer.h b/src/outputBuffer.h
index fecff91e0..f690941d4 100644
--- a/src/outputBuffer.h
+++ b/src/outputBuffer.h
@@ -19,6 +19,7 @@
#ifndef OUTPUT_BUFFER_H
#define OUTPUT_BUFFER_H
+#include "pcm_utils.h"
#include "mpd_types.h"
#include "decode.h"
#include "audio.h"
@@ -39,6 +40,7 @@ typedef struct _OutputBuffer {
mpd_sint16 volatile begin;
mpd_sint16 volatile end;
AudioFormat audioFormat;
+ ConvState convState;
MetadataChunk metadataChunks[BUFFERED_METACHUNKS];
mpd_sint8 metaChunkSet[BUFFERED_METACHUNKS];
mpd_sint8 *volatile metaChunk;
diff --git a/src/pcm_utils.c b/src/pcm_utils.c
index b3c6689ae..8cc19a9d4 100644
--- a/src/pcm_utils.c
+++ b/src/pcm_utils.c
@@ -27,10 +27,6 @@
#include <math.h>
#include <assert.h>
-#ifdef HAVE_LIBSAMPLERATE
-#include <samplerate.h>
-#endif
-
void pcm_volumeChange(char *buffer, int bufferSize, AudioFormat * format,
int volume)
{
@@ -189,47 +185,74 @@ static int pcm_getSampleRateConverter(void)
static int pcm_convertSampleRate(mpd_sint8 channels, mpd_uint32 inSampleRate,
char *inBuffer, size_t inSize,
mpd_uint32 outSampleRate, char *outBuffer,
- size_t outSize)
+ size_t outSize, ConvState *convState)
{
static int convalgo = -1;
- static SRC_DATA data;
- static size_t dataInSize;
- static size_t dataOutSize;
- size_t curDataInSize;
- size_t curDataOutSize;
+ SRC_DATA *data = &convState->data;
+ size_t dataInSize;
+ size_t dataOutSize;
int error;
if (convalgo < 0)
convalgo = pcm_getSampleRateConverter();
- data.src_ratio = (double)outSampleRate / (double)inSampleRate;
+ /* (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 = inSize / 2 / channels;
- curDataInSize = data.input_frames * sizeof(float) * channels;
- if (curDataInSize > dataInSize) {
- dataInSize = curDataInSize;
- data.data_in = xrealloc(data.data_in, dataInSize);
+ data->input_frames = inSize / 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;
- curDataOutSize = data.output_frames * sizeof(float) * channels;
- if (curDataOutSize > dataOutSize) {
- dataOutSize = curDataOutSize;
- data.data_out = xrealloc(data.data_out, dataOutSize);
+ 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((short *)inBuffer, data.data_in,
- data.input_frames * channels);
+ src_short_to_float_array((short *)inBuffer, data->data_in,
+ data->input_frames * channels);
- error = src_simple(&data, convalgo, 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);
+ src_float_to_short_array(data->data_out, (short *)outBuffer,
+ data->output_frames_gen * channels);
return 1;
}
@@ -238,7 +261,7 @@ static int pcm_convertSampleRate(mpd_sint8 channels, mpd_uint32 inSampleRate,
static int pcm_convertSampleRate(mpd_sint8 channels, mpd_uint32 inSampleRate,
char *inBuffer, size_t inSize,
mpd_uint32 outSampleRate, char *outBuffer,
- size_t outSize)
+ size_t outSize, ConvState *convState)
{
mpd_uint32 rd_dat = 0;
mpd_uint32 wr_dat = 0;
@@ -370,7 +393,7 @@ static char *pcm_convertTo16bit(mpd_sint8 bits, char *inBuffer, size_t inSize,
/* outFormat bits must be 16 and channels must be 1 or 2! */
void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer,
size_t inSize, AudioFormat * outFormat,
- char *outBuffer)
+ char *outBuffer, ConvState *convState)
{
char *buf;
size_t len;
@@ -397,7 +420,7 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer,
if (!pcm_convertSampleRate(outFormat->channels,
inFormat->sampleRate, buf, len,
outFormat->sampleRate, outBuffer,
- outSize))
+ outSize, convState))
exit(EXIT_FAILURE);
}
}
diff --git a/src/pcm_utils.h b/src/pcm_utils.h
index 5142db17b..800ac27f4 100644
--- a/src/pcm_utils.h
+++ b/src/pcm_utils.h
@@ -25,14 +25,32 @@
#include <stdlib.h>
+#ifdef HAVE_LIBSAMPLERATE
+#include <samplerate.h>
+#endif
+
+typedef struct _ConvState {
+#ifdef HAVE_LIBSAMPLERATE
+ SRC_STATE *state;
+ SRC_DATA data;
+ size_t dataInSize;
+ size_t dataOutSize;
+ mpd_sint8 lastChannels;
+ mpd_sint32 lastInSampleRate;
+ mpd_sint32 lastOutSampleRate;
+ int error;
+#endif
+} ConvState;
+
void pcm_volumeChange(char *buffer, int bufferSize, AudioFormat * format,
int volume);
void pcm_mix(char *buffer1, char *buffer2, size_t bufferSize1,
size_t bufferSize2, AudioFormat * format, float portion1);
-void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer, size_t
- inSize, AudioFormat * outFormat, char *outBuffer);
+void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer,
+ size_t inSize, AudioFormat * outFormat,
+ char *outBuffer, ConvState *convState);
size_t pcm_sizeOfConvBuffer(AudioFormat * inFormat, size_t inSize,
AudioFormat * outFormat);
diff --git a/src/playerData.c b/src/playerData.c
index 31f27540c..0d5e6e9e4 100644
--- a/src/playerData.c
+++ b/src/playerData.c
@@ -116,6 +116,7 @@ void initPlayerData(void)
allocationSize - device_array_size;
buffer = &(playerData_pd->buffer);
+ memset(&buffer->convState, 0, sizeof(ConvState));
buffer->chunks = ((char *)playerData_pd) + sizeof(PlayerData);
buffer->chunkSize = (mpd_uint16 *) (((char *)buffer->chunks) +
buffered_chunks * CHUNK_SIZE);