Commit 2814b7cf authored by J. Alexander Treuman's avatar J. Alexander Treuman

Reverting to the full lsr API. Turns out the simple API needs all of the

audio at once, so it won't work for us. The old full API code was still heavily broken, as each call to pcm_convertSampleRate() used the same state, even if it was processing two streams of audio. The new code keeps a separate state for each audio stream that's being converted. git-svn-id: https://svn.musicpd.org/mpd/trunk@6255 09075e82-0dd4-0310-85a5-a0d7c8717e4f
parent 7ba357a0
...@@ -135,6 +135,7 @@ int initAudioOutput(AudioOutput *ao, ConfigParam * param) ...@@ -135,6 +135,7 @@ int initAudioOutput(AudioOutput *ao, ConfigParam * param)
memset(&ao->inAudioFormat, 0, sizeof(AudioFormat)); memset(&ao->inAudioFormat, 0, sizeof(AudioFormat));
memset(&ao->outAudioFormat, 0, sizeof(AudioFormat)); memset(&ao->outAudioFormat, 0, sizeof(AudioFormat));
memset(&ao->reqAudioFormat, 0, sizeof(AudioFormat)); memset(&ao->reqAudioFormat, 0, sizeof(AudioFormat));
memset(&ao->convState, 0, sizeof(ConvState));
if (format) { if (format) {
ao->convertAudioFormat = 1; ao->convertAudioFormat = 1;
...@@ -205,10 +206,11 @@ static void convertAudioFormat(AudioOutput * audioOutput, char **chunkArgPtr, ...@@ -205,10 +206,11 @@ static void convertAudioFormat(AudioOutput * audioOutput, char **chunkArgPtr,
} }
pcm_convertAudioFormat(&(audioOutput->inAudioFormat), pcm_convertAudioFormat(&(audioOutput->inAudioFormat),
*chunkArgPtr, *chunkArgPtr,
*sizeArgPtr, *sizeArgPtr,
&(audioOutput->outAudioFormat), &(audioOutput->outAudioFormat),
audioOutput->convBuffer); audioOutput->convBuffer,
&audioOutput->convState);
*sizeArgPtr = size; *sizeArgPtr = size;
*chunkArgPtr = audioOutput->convBuffer; *chunkArgPtr = audioOutput->convBuffer;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "../config.h" #include "../config.h"
#include "pcm_utils.h"
#include "mpd_types.h" #include "mpd_types.h"
#include "audio.h" #include "audio.h"
#include "tag.h" #include "tag.h"
...@@ -66,6 +67,7 @@ struct _AudioOutput { ...@@ -66,6 +67,7 @@ struct _AudioOutput {
AudioFormat inAudioFormat; AudioFormat inAudioFormat;
AudioFormat outAudioFormat; AudioFormat outAudioFormat;
AudioFormat reqAudioFormat; AudioFormat reqAudioFormat;
ConvState convState;
char *convBuffer; char *convBuffer;
int convBufferLen; int convBufferLen;
int sameInAndOutFormats; int sameInAndOutFormats;
......
...@@ -90,7 +90,8 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream, ...@@ -90,7 +90,8 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
} }
data = convBuffer; data = convBuffer;
pcm_convertAudioFormat(&(dc->audioFormat), dataIn, dataInLen, pcm_convertAudioFormat(&(dc->audioFormat), dataIn, dataInLen,
&(cb->audioFormat), data); &(cb->audioFormat), data,
&(cb->convState));
} }
if (replayGainInfo && (replayGainState != REPLAYGAIN_OFF)) if (replayGainInfo && (replayGainState != REPLAYGAIN_OFF))
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#ifndef OUTPUT_BUFFER_H #ifndef OUTPUT_BUFFER_H
#define OUTPUT_BUFFER_H #define OUTPUT_BUFFER_H
#include "pcm_utils.h"
#include "mpd_types.h" #include "mpd_types.h"
#include "decode.h" #include "decode.h"
#include "audio.h" #include "audio.h"
...@@ -39,6 +40,7 @@ typedef struct _OutputBuffer { ...@@ -39,6 +40,7 @@ typedef struct _OutputBuffer {
mpd_sint16 volatile begin; mpd_sint16 volatile begin;
mpd_sint16 volatile end; mpd_sint16 volatile end;
AudioFormat audioFormat; AudioFormat audioFormat;
ConvState convState;
MetadataChunk metadataChunks[BUFFERED_METACHUNKS]; MetadataChunk metadataChunks[BUFFERED_METACHUNKS];
mpd_sint8 metaChunkSet[BUFFERED_METACHUNKS]; mpd_sint8 metaChunkSet[BUFFERED_METACHUNKS];
mpd_sint8 *volatile metaChunk; mpd_sint8 *volatile metaChunk;
......
...@@ -27,10 +27,6 @@ ...@@ -27,10 +27,6 @@
#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)
{ {
...@@ -189,47 +185,74 @@ static int pcm_getSampleRateConverter(void) ...@@ -189,47 +185,74 @@ static int pcm_getSampleRateConverter(void)
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, char *inBuffer, size_t inSize,
mpd_uint32 outSampleRate, char *outBuffer, mpd_uint32 outSampleRate, char *outBuffer,
size_t outSize) size_t outSize, ConvState *convState)
{ {
static int convalgo = -1; static int convalgo = -1;
static SRC_DATA data; SRC_DATA *data = &convState->data;
static size_t dataInSize; size_t dataInSize;
static size_t dataOutSize; size_t dataOutSize;
size_t curDataInSize;
size_t curDataOutSize;
int error; int error;
if (convalgo < 0) if (convalgo < 0)
convalgo = pcm_getSampleRateConverter(); 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; data->input_frames = inSize / 2 / channels;
curDataInSize = data.input_frames * sizeof(float) * channels; dataInSize = data->input_frames * sizeof(float) * channels;
if (curDataInSize > dataInSize) { if (dataInSize > convState->dataInSize) {
dataInSize = curDataInSize; convState->dataInSize = dataInSize;
data.data_in = xrealloc(data.data_in, dataInSize); data->data_in = xrealloc(data->data_in, dataInSize);
} }
data.output_frames = outSize / 2 / channels; data->output_frames = outSize / 2 / channels;
curDataOutSize = data.output_frames * sizeof(float) * channels; dataOutSize = data->output_frames * sizeof(float) * channels;
if (curDataOutSize > dataOutSize) { if (dataOutSize > convState->dataOutSize) {
dataOutSize = curDataOutSize; convState->dataOutSize = dataOutSize;
data.data_out = xrealloc(data.data_out, dataOutSize); data->data_out = xrealloc(data->data_out, dataOutSize);
} }
src_short_to_float_array((short *)inBuffer, data.data_in, src_short_to_float_array((short *)inBuffer, data->data_in,
data.input_frames * channels); data->input_frames * channels);
error = src_simple(&data, convalgo, channels); error = src_process(convState->state, data);
if (error) { if (error) {
ERROR("error processing samples with libsamplerate: %s\n", ERROR("error processing samples with libsamplerate: %s\n",
src_strerror(error)); src_strerror(error));
convState->error = 1;
return 0; return 0;
} }
src_float_to_short_array(data.data_out, (short *)outBuffer, src_float_to_short_array(data->data_out, (short *)outBuffer,
data.output_frames_gen * channels); data->output_frames_gen * channels);
return 1; return 1;
} }
...@@ -238,7 +261,7 @@ static int pcm_convertSampleRate(mpd_sint8 channels, mpd_uint32 inSampleRate, ...@@ -238,7 +261,7 @@ static int pcm_convertSampleRate(mpd_sint8 channels, mpd_uint32 inSampleRate,
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, char *inBuffer, size_t inSize,
mpd_uint32 outSampleRate, char *outBuffer, mpd_uint32 outSampleRate, char *outBuffer,
size_t outSize) size_t outSize, ConvState *convState)
{ {
mpd_uint32 rd_dat = 0; mpd_uint32 rd_dat = 0;
mpd_uint32 wr_dat = 0; mpd_uint32 wr_dat = 0;
...@@ -370,7 +393,7 @@ static char *pcm_convertTo16bit(mpd_sint8 bits, char *inBuffer, size_t inSize, ...@@ -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! */ /* outFormat bits must be 16 and channels must be 1 or 2! */
void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer, void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer,
size_t inSize, AudioFormat * outFormat, size_t inSize, AudioFormat * outFormat,
char *outBuffer) char *outBuffer, ConvState *convState)
{ {
char *buf; char *buf;
size_t len; size_t len;
...@@ -397,7 +420,7 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer, ...@@ -397,7 +420,7 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer,
if (!pcm_convertSampleRate(outFormat->channels, if (!pcm_convertSampleRate(outFormat->channels,
inFormat->sampleRate, buf, len, inFormat->sampleRate, buf, len,
outFormat->sampleRate, outBuffer, outFormat->sampleRate, outBuffer,
outSize)) outSize, convState))
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
......
...@@ -25,14 +25,32 @@ ...@@ -25,14 +25,32 @@
#include <stdlib.h> #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, void pcm_volumeChange(char *buffer, int bufferSize, AudioFormat * format,
int volume); int volume);
void pcm_mix(char *buffer1, char *buffer2, size_t bufferSize1, void pcm_mix(char *buffer1, char *buffer2, size_t bufferSize1,
size_t bufferSize2, AudioFormat * format, float portion1); size_t bufferSize2, AudioFormat * format, float portion1);
void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer, size_t void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer,
inSize, AudioFormat * outFormat, char *outBuffer); size_t inSize, AudioFormat * outFormat,
char *outBuffer, ConvState *convState);
size_t pcm_sizeOfConvBuffer(AudioFormat * inFormat, size_t inSize, size_t pcm_sizeOfConvBuffer(AudioFormat * inFormat, size_t inSize,
AudioFormat * outFormat); AudioFormat * outFormat);
......
...@@ -116,6 +116,7 @@ void initPlayerData(void) ...@@ -116,6 +116,7 @@ void initPlayerData(void)
allocationSize - device_array_size; allocationSize - device_array_size;
buffer = &(playerData_pd->buffer); buffer = &(playerData_pd->buffer);
memset(&buffer->convState, 0, sizeof(ConvState));
buffer->chunks = ((char *)playerData_pd) + sizeof(PlayerData); buffer->chunks = ((char *)playerData_pd) + sizeof(PlayerData);
buffer->chunkSize = (mpd_uint16 *) (((char *)buffer->chunks) + buffer->chunkSize = (mpd_uint16 *) (((char *)buffer->chunks) +
buffered_chunks * CHUNK_SIZE); buffered_chunks * CHUNK_SIZE);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment