aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/audio.c152
-rw-r--r--src/audio.h3
-rw-r--r--src/audioOutput.c38
-rw-r--r--src/decode.c2
-rw-r--r--src/inputPlugins/mp3_plugin.c224
-rw-r--r--src/inputPlugins/mpc_plugin.c42
-rw-r--r--src/mpd_types.h2
-rw-r--r--src/outputBuffer.c76
-rw-r--r--src/pcm_utils.c669
-rw-r--r--src/playerData.h3
-rw-r--r--src/replayGain.c110
11 files changed, 891 insertions, 430 deletions
diff --git a/src/audio.c b/src/audio.c
index 8f67c17f7..0fb2b3e2d 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -104,22 +104,44 @@ void initAudioDriver() {
}
} while((param = getNextConfigParam(CONF_AUDIO_OUTPUT, param)));
}
+void getInternalAudioFormat(AudioFormat * inAudioFormat,
+ AudioFormat * outAudioFormat)
+{
+ /*TODO add #define for integer version */
+
+ /* take the input format... */
+ copyAudioFormat(outAudioFormat,inAudioFormat);
+#ifdef MPD_FIXED_POINT
+ /* .. change to 16 bit integer */
+ outAudioFormat->bits = 16;
+ outAudioFormat->floatSamples = 0;
+#else
+ /* .. change to 32 bit float */
+ outAudioFormat->bits = 32;
+ outAudioFormat->floatSamples = 1;
+#endif
+ /* if forced output sample rate - use that as internal sample rate */
+ if(audio_configFormat && (audio_configFormat->sampleRate != 0))
+ outAudioFormat->sampleRate = audio_configFormat->sampleRate;
+}
void getOutputAudioFormat(AudioFormat * inAudioFormat,
- AudioFormat * outAudioFormat)
+ AudioFormat * outAudioFormat)
{
- if(audio_configFormat) {
- copyAudioFormat(outAudioFormat,audio_configFormat);
- }
- else copyAudioFormat(outAudioFormat,inAudioFormat);
+ /* this function is deprecated
+ * for plugins who still use this we copy the format from in to out
+ * these plugin don't know about the floatSample flag so we set it
+ * for them - in both in and out */
+ inAudioFormat->floatSamples = 0;
+ copyAudioFormat(outAudioFormat,inAudioFormat);
}
void initAudioConfig() {
- ConfigParam * param = getConfigParam(CONF_AUDIO_OUTPUT_FORMAT);
+ ConfigParam * param = getConfigParam(CONF_AUDIO_OUTPUT_FORMAT);
- if(NULL == param || NULL == param->value) return;
+ if(NULL == param || NULL == param->value) return;
- audio_configFormat = malloc(sizeof(AudioFormat));
+ audio_configFormat = malloc(sizeof(AudioFormat));
if(0 != parseAudioConfig(audio_configFormat, param->value)) {
ERROR("error parsing \"%s\" at line %i\n",
@@ -129,73 +151,77 @@ void initAudioConfig() {
}
int parseAudioConfig(AudioFormat * audioFormat, char * conf) {
- char * test;
+ char * test;
+ memset(audioFormat,0,sizeof(AudioFormat));
+ audioFormat->sampleRate = strtol(conf,&test,10);
- memset(audioFormat,0,sizeof(AudioFormat));
-
- audioFormat->sampleRate = strtol(conf,&test,10);
-
- if(*test!=':') {
- ERROR("error parsing audio output format: %s\n",conf);
- return -1;
- }
-
- /*switch(audioFormat->sampleRate) {
- case 48000:
- case 44100:
- case 32000:
- case 16000:
- break;
- default:
- ERROR("sample rate %i can not be used for audio output\n",
- (int)audioFormat->sampleRate);
- return -1
- }*/
-
- if(audioFormat->sampleRate <= 0) {
- ERROR("sample rate %i is not >= 0\n",
- (int)audioFormat->sampleRate);
+ if(*test!=':') {
+ ERROR("error parsing audio output format: %s\n",conf);
return -1;
- }
+ }
- audioFormat->bits = strtol(test+1,&test,10);
-
- if(*test!=':') {
- ERROR("error parsing audio output format: %s\n",conf);
- return -1;
- }
-
- switch(audioFormat->bits) {
- case 16:
- break;
- default:
- ERROR("bits %i can not be used for audio output\n",
- (int)audioFormat->bits);
+ /*switch(audioFormat->sampleRate) {
+ case 48000:
+ case 44100:
+ case 32000:
+ case 16000:
+ break;
+ default:
+ ERROR("sample rate %i can not be used for audio output\n",
+ (int)audioFormat->sampleRate);
+ return -1
+ }*/
+
+ /* a sample rate of 0 == "same as input" */
+ if(audioFormat->sampleRate < 0) {
+ ERROR("sample rate %i is not >= 0\n",
+ (int)audioFormat->sampleRate);
return -1;
- }
+ }
+
+ audioFormat->bits = strtol(test+1,&test,10);
- audioFormat->channels = strtol(test+1,&test,10);
-
- if(*test!='\0') {
- ERROR("error parsing audio output format: %s\n",conf);
+ if(*test!=':') {
+ ERROR("error parsing audio output format: %s\n",conf);
return -1;
- }
-
- switch(audioFormat->channels) {
- case 1:
- case 2:
- break;
- default:
- ERROR("channels %i can not be used for audio output\n",
- (int)audioFormat->channels);
+ }
+
+ switch(audioFormat->bits) {
+ case 32:
+ case 16:
+ case 8:
+ break;
+ default:
+ ERROR("bits %i can not be used for audio output\n",
+ (int)audioFormat->bits);
+ return -1;
+ }
+
+ audioFormat->channels = strtol(test+1,&test,10);
+
+ if(*test!='\0') {
+ ERROR("error parsing audio output format: %s\n",conf);
return -1;
- }
+ }
+
+ switch(audioFormat->channels) {
+ case 1:
+ case 2:
+ break;
+ default:
+ ERROR("channels %i can not be used for audio output\n",
+ (int)audioFormat->channels);
+ return -1;
+ }
+
+ /* audioFormat is never float */
+ audioFormat->floatSamples = 0;
return 0;
}
void finishAudioConfig() {
- if(audio_configFormat) free(audio_configFormat);
+ if(audio_configFormat) free(audio_configFormat);
}
void finishAudioDriver() {
diff --git a/src/audio.h b/src/audio.h
index 87c265568..0cc879b28 100644
--- a/src/audio.h
+++ b/src/audio.h
@@ -34,12 +34,15 @@ typedef struct _AudioFormat {
volatile mpd_sint8 channels;
volatile mpd_uint32 sampleRate;
volatile mpd_sint8 bits;
+ volatile mpd_sint8 floatSamples;
} AudioFormat;
void copyAudioFormat(AudioFormat * dest, AudioFormat * src);
int cmpAudioFormat(AudioFormat * dest, AudioFormat * src);
+void getInternalAudioFormat(AudioFormat * inFormat, AudioFormat * outFormat);
+
void getOutputAudioFormat(AudioFormat * inFormat, AudioFormat * outFormat);
int parseAudioConfig(AudioFormat * audioFormat, char * conf);
diff --git a/src/audioOutput.c b/src/audioOutput.c
index 632d1b8dc..dcb264e45 100644
--- a/src/audioOutput.c
+++ b/src/audioOutput.c
@@ -51,9 +51,20 @@ AudioOutput * newAudioOutput(ConfigParam * param) {
BlockParam * bp = NULL;
AudioOutputPlugin * plugin = NULL;
+ ret = malloc(sizeof(AudioOutput));
+ ret->convertAudioFormat = 0;
+ ret->sameInAndOutFormats = 0;
+ ret->convBuffer = NULL;
+ ret->convBufferLen = 0;
+
+ memset(&ret->inAudioFormat, 0, sizeof(AudioFormat));
+ memset(&ret->outAudioFormat, 0, sizeof(AudioFormat));
+ memset(&ret->reqAudioFormat, 0, sizeof(AudioFormat));
+
if(param) {
getBlockParam(AUDIO_OUTPUT_NAME, name, 1);
getBlockParam(AUDIO_OUTPUT_TYPE, type, 1);
+ getBlockParam(AUDIO_OUTPUT_FORMAT, format, 0);
if(!findInList(audioOutputPluginList, type, &data)) {
ERROR("couldn't find audio output plugin for type "
@@ -66,13 +77,12 @@ AudioOutput * newAudioOutput(ConfigParam * param) {
if(format) {
ret->convertAudioFormat = 1;
-
if(0 != parseAudioConfig(&ret->reqAudioFormat, format))
{
- ERROR("error parsing format at line %i\n",
+ ERROR("error parsing format at line %i\n",
bp->line);
- exit(EXIT_FAILURE);
- }
+ exit(EXIT_FAILURE);
+ }
}
}
else {
@@ -106,7 +116,6 @@ AudioOutput * newAudioOutput(ConfigParam * param) {
type = plugin->name;
}
- ret = malloc(sizeof(AudioOutput));
ret->name = strdup(name);
ret->type = strdup(type);
ret->finishDriverFunc = plugin->finishDriverFunc;
@@ -117,14 +126,7 @@ AudioOutput * newAudioOutput(ConfigParam * param) {
ret->sendMetdataFunc = plugin->sendMetdataFunc;
ret->open = 0;
- ret->convertAudioFormat = 0;
- ret->sameInAndOutFormats = 0;
- ret->convBuffer = NULL;
- ret->convBufferLen = 0;
- memset(&ret->inAudioFormat, 0, sizeof(AudioFormat));
- memset(&ret->outAudioFormat, 0, sizeof(AudioFormat));
- memset(&ret->reqAudioFormat, 0, sizeof(AudioFormat));
if(plugin->initDriverFunc(ret, param) != 0) {
free(ret);
@@ -151,16 +153,24 @@ int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat) {
if(audioOutput->convertAudioFormat) {
copyAudioFormat(&audioOutput->outAudioFormat,
&audioOutput->reqAudioFormat);
+ /* if sample rate is not specified - use same rate as input */
+ if(!audioOutput->outAudioFormat.sampleRate) {
+ audioOutput->outAudioFormat.sampleRate =
+ audioOutput->inAudioFormat.sampleRate;
+ }
}
else {
copyAudioFormat(&audioOutput->outAudioFormat,
&audioOutput->inAudioFormat);
+ /* default to 16 bit integer samples */
+ audioOutput->outAudioFormat.bits = 16;
+ audioOutput->outAudioFormat.floatSamples = 0;
}
-
+
ret = audioOutput->openDeviceFunc(audioOutput);
if(cmpAudioFormat(&audioOutput->inAudioFormat,
- &audioOutput->outAudioFormat) == 0)
+ &audioOutput->outAudioFormat) == 0)
{
audioOutput->sameInAndOutFormats = 1;
}
diff --git a/src/decode.c b/src/decode.c
index fc91cd708..b15828bf0 100644
--- a/src/decode.c
+++ b/src/decode.c
@@ -474,7 +474,7 @@ void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb) {
int currentChunkSent = 1;
int end;
int next = -1;
-
+
memset(silence,0,CHUNK_SIZE);
if(waitOnDecode(pc,dc,cb,&decodeWaitedOn)<0) return;
diff --git a/src/inputPlugins/mp3_plugin.c b/src/inputPlugins/mp3_plugin.c
index 33087e134..471a173a1 100644
--- a/src/inputPlugins/mp3_plugin.c
+++ b/src/inputPlugins/mp3_plugin.c
@@ -53,8 +53,8 @@
#define DECODE_CONT -1
#define DECODE_OK 0
-#define MUTEFRAME_SKIP 1
-#define MUTEFRAME_SEEK 2
+#define MUTEFRAME_SKIP 1
+#define MUTEFRAME_SEEK 2
/* this is stolen from mpg321! */
struct audio_dither {
@@ -74,7 +74,7 @@ signed long audio_linear_dither(unsigned int bits, mad_fixed_t sample, struct au
MIN = -MAD_F_ONE,
MAX = MAD_F_ONE - 1
};
-
+
sample += dither->error[0] - dither->error[1] + dither->error[2];
dither->error[2] = dither->error[1];
@@ -97,7 +97,7 @@ signed long audio_linear_dither(unsigned int bits, mad_fixed_t sample, struct au
sample = MAX;
}
else if (output < MIN) {
- output = MIN;
+ output = MIN;
if (sample < MIN)
sample = MIN;
@@ -148,11 +148,11 @@ void initMp3DecodeData(mp3DecodeData * data, InputStream * inStream) {
data->times = NULL;
data->currentFrame = 0;
data->flush = 1;
- data->inStream = inStream;
+ data->inStream = inStream;
memset(&(data->dither), 0, sizeof(struct audio_dither));
mad_stream_init(&data->stream);
- data->stream.options |= MAD_OPTION_IGNORECRC;
+ data->stream.options |= MAD_OPTION_IGNORECRC;
mad_frame_init(&data->frame);
mad_synth_init(&data->synth);
mad_timer_reset(&data->timer);
@@ -160,8 +160,8 @@ void initMp3DecodeData(mp3DecodeData * data, InputStream * inStream) {
int seekMp3InputBuffer(mp3DecodeData * data, long offset) {
if(seekInputStream(data->inStream,offset,SEEK_SET) < 0) {
- return -1;
- }
+ return -1;
+ }
mad_stream_buffer(&data->stream,data->readBuffer,0);
(data->stream).error = 0;
@@ -172,7 +172,7 @@ int seekMp3InputBuffer(mp3DecodeData * data, long offset) {
int fillMp3InputBuffer(mp3DecodeData * data) {
size_t readSize;
size_t remaining;
- size_t readed;
+ size_t readed;
unsigned char * readStart;
if((data->stream).next_frame!=NULL) {
@@ -354,57 +354,57 @@ int decodeNextFrame(mp3DecodeData * data) {
# define XING_MAGIC (('X' << 24) | ('i' << 16) | ('n' << 8) | 'g')
struct xing {
- long flags; /* valid fields (see below) */
- unsigned long frames; /* total number of frames */
- unsigned long bytes; /* total number of bytes */
- unsigned char toc[100]; /* 100-point seek table */
- long scale; /* ?? */
+ long flags; /* valid fields (see below) */
+ unsigned long frames; /* total number of frames */
+ unsigned long bytes; /* total number of bytes */
+ unsigned char toc[100]; /* 100-point seek table */
+ long scale; /* ?? */
};
enum {
- XING_FRAMES = 0x00000001L,
- XING_BYTES = 0x00000002L,
- XING_TOC = 0x00000004L,
- XING_SCALE = 0x00000008L
+ XING_FRAMES = 0x00000001L,
+ XING_BYTES = 0x00000002L,
+ XING_TOC = 0x00000004L,
+ XING_SCALE = 0x00000008L
};
int parse_xing(struct xing *xing, struct mad_bitptr ptr, unsigned int bitlen)
{
- if (bitlen < 64 || mad_bit_read(&ptr, 32) != XING_MAGIC) goto fail;
-
- xing->flags = mad_bit_read(&ptr, 32);
- bitlen -= 64;
-
- if (xing->flags & XING_FRAMES) {
- if (bitlen < 32) goto fail;
- xing->frames = mad_bit_read(&ptr, 32);
- bitlen -= 32;
- }
-
- if (xing->flags & XING_BYTES) {
- if (bitlen < 32) goto fail;
- xing->bytes = mad_bit_read(&ptr, 32);
- bitlen -= 32;
- }
-
- if (xing->flags & XING_TOC) {
- int i;
- if (bitlen < 800) goto fail;
- for (i = 0; i < 100; ++i) xing->toc[i] = mad_bit_read(&ptr, 8);
- bitlen -= 800;
- }
-
- if (xing->flags & XING_SCALE) {
- if (bitlen < 32) goto fail;
- xing->scale = mad_bit_read(&ptr, 32);
- bitlen -= 32;
- }
+ if (bitlen < 64 || mad_bit_read(&ptr, 32) != XING_MAGIC) goto fail;
+
+ xing->flags = mad_bit_read(&ptr, 32);
+ bitlen -= 64;
+
+ if (xing->flags & XING_FRAMES) {
+ if (bitlen < 32) goto fail;
+ xing->frames = mad_bit_read(&ptr, 32);
+ bitlen -= 32;
+ }
+
+ if (xing->flags & XING_BYTES) {
+ if (bitlen < 32) goto fail;
+ xing->bytes = mad_bit_read(&ptr, 32);
+ bitlen -= 32;
+ }
+
+ if (xing->flags & XING_TOC) {
+ int i;
+ if (bitlen < 800) goto fail;
+ for (i = 0; i < 100; ++i) xing->toc[i] = mad_bit_read(&ptr, 8);
+ bitlen -= 800;
+ }
+
+ if (xing->flags & XING_SCALE) {
+ if (bitlen < 32) goto fail;
+ xing->scale = mad_bit_read(&ptr, 32);
+ bitlen -= 32;
+ }
return 1;
fail:
- xing->flags = 0;
- return 0;
+ xing->flags = 0;
+ return 0;
}
int decodeFirstFrame(mp3DecodeData * data, DecoderControl * dc,
@@ -479,11 +479,11 @@ void mp3DecodeDataFinalize(mp3DecodeData * data) {
/* this is primarily used for getting total time for tags */
int getMp3TotalTime(char * file) {
- InputStream inStream;
+ InputStream inStream;
mp3DecodeData data;
int ret;
- if(openInputStream(&inStream, file) < 0) return -1;
+ if(openInputStream(&inStream, file) < 0) return -1;
initMp3DecodeData(&data,&inStream);
if(decodeFirstFrame(&data, NULL, NULL)<0) ret = -1;
else ret = data.totalTime+0.5;
@@ -536,18 +536,18 @@ int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc) {
data->elapsedTime = ((float)mad_timer_count(data->timer,MAD_UNITS_MILLISECONDS))/1000;
switch(data->muteFrame) {
- case MUTEFRAME_SKIP:
+ case MUTEFRAME_SKIP:
data->muteFrame = 0;
- break;
- case MUTEFRAME_SEEK:
+ break;
+ case MUTEFRAME_SEEK:
if(dc->seekWhere<=data->elapsedTime) {
- data->outputPtr = data->outputBuffer;
- clearOutputBuffer(cb);
+ data->outputPtr = data->outputBuffer;
+ clearOutputBuffer(cb);
data->muteFrame = 0;
dc->seek = 0;
}
- break;
- default:
+ break;
+ default:
mad_synth_frame(&data->synth,&data->frame);
if(data->inStream->metaTitle) {
@@ -566,8 +566,8 @@ int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc) {
}
for(i=0;i<(data->synth).pcm.length;i++) {
+#ifdef MPD_FIXED_POINT
mpd_sint16 * sample;
-
sample = (mpd_sint16 *)data->outputPtr;
*sample = (mpd_sint16) audio_linear_dither(16,
(data->synth).pcm.samples[0][i],
@@ -581,27 +581,41 @@ int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc) {
&(data->dither));
data->outputPtr+=2;
}
+#else
+ mpd_float32 * sample;
+ sample = (mpd_float32 *)data->outputPtr;
+ *sample = (mpd_float32) mad_f_todouble(
+ (data->synth).pcm.samples[0][i]);
+ data->outputPtr+=4;
+
+ if(MAD_NCHANNELS(&(data->frame).header)==2) {
+ sample = (mpd_sint16 *)data->outputPtr;
+ *sample = (mpd_float32) mad_f_todouble(
+ (data->synth).pcm.samples[0][i]);
+ data->outputPtr+=4;
+ }
+#endif
if(data->outputPtr>=data->outputBufferEnd) {
- long ret;
- ret = sendDataToOutputBuffer(cb,
- data->inStream,
- dc,
- data->inStream->seekable,
- data->outputBuffer,
- data->outputPtr-
+ long ret;
+ ret = sendDataToOutputBuffer(cb,
+ data->inStream,
+ dc,
+ data->inStream->seekable,
data->outputBuffer,
- data->elapsedTime,
- data->bitRate/1000,
+ data->outputPtr-
+ data->outputBuffer,
+ data->elapsedTime,
+ data->bitRate/1000,
NULL);
- if(ret == OUTPUT_BUFFER_DC_STOP) {
+ if(ret == OUTPUT_BUFFER_DC_STOP) {
data->flush = 0;
- return DECODE_BREAK;
- }
+ return DECODE_BREAK;
+ }
- data->outputPtr = data->outputBuffer;
+ data->outputPtr = data->outputBuffer;
- if(ret == OUTPUT_BUFFER_DC_SEEK) break;
+ if(ret == OUTPUT_BUFFER_DC_SEEK) break;
}
}
@@ -617,20 +631,20 @@ int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc) {
if(i<data->highestFrame) {
if(seekMp3InputBuffer(data,
data->frameOffset[i]) == 0)
- {
- data->outputPtr = data->outputBuffer;
- clearOutputBuffer(cb);
- data->currentFrame = i;
- }
- else dc->seekError = 1;
+ {
+ data->outputPtr = data->outputBuffer;
+ clearOutputBuffer(cb);
+ data->currentFrame = i;
+ }
+ else dc->seekError = 1;
data->muteFrame = 0;
dc->seek = 0;
}
}
- else if(dc->seek && !data->inStream->seekable) {
- dc->seek = 0;
- dc->seekError = 1;
- }
+ else if(dc->seek && !data->inStream->seekable) {
+ dc->seek = 0;
+ dc->seekError = 1;
+ }
}
while(1) {
@@ -653,7 +667,13 @@ int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc) {
}
void initAudioFormatFromMp3DecodeData(mp3DecodeData * data, AudioFormat * af) {
+#ifdef MPD_FIXED_POINT
af->bits = 16;
+ af->floatSamples = 0;
+#else
+ af->bits = 32;
+ af->floatSamples = 1;
+#endif
af->sampleRate = (data->frame).header.samplerate;
af->channels = MAD_NCHANNELS(&(data->frame).header);
}
@@ -665,19 +685,19 @@ int mp3_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) {
if(openMp3FromInputStream(inStream, &data, dc, &tag) < 0) {
closeInputStream(inStream);
if(!dc->stop) {
- ERROR("Input does not appear to be a mp3 bit stream.\n");
- return -1;
- }
- else {
- dc->state = DECODE_STATE_STOP;
- dc->stop = 0;
- }
- return 0;
+ ERROR("Input does not appear to be a mp3 bit stream.\n");
+ return -1;
+ }
+ else {
+ dc->state = DECODE_STATE_STOP;
+ dc->stop = 0;
+ }
+ return 0;
}
initAudioFormatFromMp3DecodeData(&data, &(dc->audioFormat));
- getOutputAudioFormat(&(dc->audioFormat), &(cb->audioFormat));
-
+ getInternalAudioFormat(&(dc->audioFormat), &(cb->audioFormat));
+
dc->totalTime = data.totalTime;
if(inStream->metaTitle) {
@@ -716,21 +736,21 @@ int mp3_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) {
while(mp3Read(&data,cb,dc)!=DECODE_BREAK);
/* send last little bit if not dc->stop */
- if(!dc->stop && data.outputPtr!=data.outputBuffer && data.flush) {
- sendDataToOutputBuffer(cb, NULL, dc,
- data.inStream->seekable,
- data.outputBuffer,
- data.outputPtr-data.outputBuffer,
- data.elapsedTime,data.bitRate/1000,
+ if(!dc->stop && data.outputPtr!=data.outputBuffer && data.flush) {
+ sendDataToOutputBuffer(cb, NULL, dc,
+ data.inStream->seekable,
+ data.outputBuffer,
+ data.outputPtr-data.outputBuffer,
+ data.elapsedTime,data.bitRate/1000,
NULL);
}
closeInputStream(inStream);
if(dc->seek && data.muteFrame == MUTEFRAME_SEEK) {
- clearOutputBuffer(cb);
- dc->seek = 0;
- }
+ clearOutputBuffer(cb);
+ dc->seek = 0;
+ }
flushOutputBuffer(cb);
mp3DecodeDataFinalize(&data);
diff --git a/src/inputPlugins/mpc_plugin.c b/src/inputPlugins/mpc_plugin.c
index f4c1aa8df..107792125 100644
--- a/src/inputPlugins/mpc_plugin.c
+++ b/src/inputPlugins/mpc_plugin.c
@@ -129,6 +129,7 @@ static int mpc_decode(OutputBuffer * cb, DecoderControl * dc,
int chunkpos = 0;
long bitRate = 0;
mpd_sint16 * s16 = (mpd_sint16 *) chunk;
+ float * f32 = (float *) chunk;
unsigned long samplePos = 0;
mpc_uint32_t vbrUpdateAcc;
mpc_uint32_t vbrUpdateBits;
@@ -176,12 +177,12 @@ static int mpc_decode(OutputBuffer * cb, DecoderControl * dc,
dc->totalTime = mpc_streaminfo_get_length(&info);
- dc->audioFormat.bits = 16;
+ dc->audioFormat.bits = 32;
+ dc->audioFormat.floatSamples = 1;
dc->audioFormat.channels = info.channels;
dc->audioFormat.sampleRate = info.sample_freq;
- getOutputAudioFormat(&(dc->audioFormat), &(cb->audioFormat));
-
+ getInternalAudioFormat(&(dc->audioFormat), &(cb->audioFormat));
replayGainInfo = newReplayGainInfo();
replayGainInfo->albumGain = info.gain_album * 0.01;
replayGainInfo->albumPeak = info.peak_album / 32767.0;
@@ -194,15 +195,15 @@ static int mpc_decode(OutputBuffer * cb, DecoderControl * dc,
if(dc->seek) {
samplePos = dc->seekWhere * dc->audioFormat.sampleRate;
if(mpc_decoder_seek_sample(&decoder, samplePos)) {
- clearOutputBuffer(cb);
- chunkpos = 0;
- }
- else dc->seekError = 1;
+ clearOutputBuffer(cb);
+ chunkpos = 0;
+ }
+ else dc->seekError = 1;
dc->seek = 0;
}
ret = mpc_decoder_decode(&decoder, sample_buffer,
- &vbrUpdateAcc, &vbrUpdateBits);
+ &vbrUpdateAcc, &vbrUpdateBits);
if(ret <= 0 || dc->stop ) {
eof = 1;
@@ -215,28 +216,33 @@ static int mpc_decode(OutputBuffer * cb, DecoderControl * dc,
ret *= 2;
for(i = 0; i < ret; i++) {
- /* 16 bit audio again */
+ /* 16 bit audio again
*s16 = convertSample(sample_buffer[i]);
chunkpos += 2;
- s16++;
-
- if(chunkpos >= MPC_CHUNK_SIZE) {
- time = ((float)samplePos) /
- dc->audioFormat.sampleRate;
+ s16++; */
+
+ *f32 = (float)(sample_buffer[i]);
+ chunkpos += 4;
+ f32++;
+
+ if(chunkpos >= MPC_CHUNK_SIZE) {
+ time = ((float)samplePos) /
+ dc->audioFormat.sampleRate;
bitRate = vbrUpdateBits *
- dc->audioFormat.sampleRate /
- (MPC_CHUNK_SIZE);
-
+ dc->audioFormat.sampleRate /
+ (MPC_CHUNK_SIZE);
+
sendDataToOutputBuffer(cb, inStream, dc,
inStream->seekable,
- chunk, chunkpos,
+ chunk, chunkpos,
time,
bitRate,
replayGainInfo);
chunkpos = 0;
s16 = (mpd_sint16 *)chunk;
+ f32 = (float*)chunk;
if(dc->stop) {
eof = 1;
break;
diff --git a/src/mpd_types.h b/src/mpd_types.h
index 7a81fef63..1ef87afd8 100644
--- a/src/mpd_types.h
+++ b/src/mpd_types.h
@@ -40,4 +40,6 @@ typedef unsigned long mpd_uint32;
typedef signed long mpd_sint32;
#endif
+typedef float mpd_float32;
+
#endif
diff --git a/src/outputBuffer.c b/src/outputBuffer.c
index e52c6e1a4..ff15a7795 100644
--- a/src/outputBuffer.c
+++ b/src/outputBuffer.c
@@ -62,19 +62,21 @@ void flushOutputBuffer(OutputBuffer * cb) {
}
}
-int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
- DecoderControl * dc, int seekable, char * dataIn,
- long dataInLen, float time, mpd_uint16 bitRate,
+int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
+ DecoderControl * dc, int seekable, char * dataIn,
+ long dataInLen, float time, mpd_uint16 bitRate,
ReplayGainInfo * replayGainInfo)
{
- mpd_uint16 dataToSend;
+ mpd_uint16 dataToSend;
mpd_uint16 chunkLeft;
char * data;
size_t datalen;
static char * convBuffer = NULL;
static long convBufferLen = 0;
- if(memcmp(&(cb->audioFormat),&(dc->audioFormat),sizeof(AudioFormat))==0)
+ /* make sure the data is in the internal format */
+ getInternalAudioFormat(&(dc->audioFormat), &(cb->audioFormat));
+ if(cmpAudioFormat(&(dc->audioFormat), &(cb->audioFormat)) == 0)
{
data = dataIn;
datalen = dataInLen;
@@ -91,34 +93,34 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
pcm_convertAudioFormat(&(dc->audioFormat), dataIn, dataInLen,
&(cb->audioFormat),data);
}
-
+
if(replayGainInfo) {
doReplayGain(replayGainInfo, data, datalen, &cb->audioFormat);
}
- while(datalen) {
+ while(datalen) {
if(currentChunk != cb->end) {
- int next = cb->end+1;
- if(next>=buffered_chunks) {
- next = 0;
- }
- while(cb->begin==next && !dc->stop) {
- if(dc->seek) {
- if(seekable) {
- return OUTPUT_BUFFER_DC_SEEK;
- }
- else {
- dc->seekError = 1;
- dc->seek = 0;
- }
- }
- if(!inStream ||
- bufferInputStream(inStream) <= 0)
- {
- my_usleep(10000);
- }
+ int next = cb->end+1;
+ if(next>=buffered_chunks) {
+ next = 0;
+ }
+ while(cb->begin==next && !dc->stop) {
+ if(dc->seek) {
+ if(seekable) {
+ return OUTPUT_BUFFER_DC_SEEK;
+ }
+ else {
+ dc->seekError = 1;
+ dc->seek = 0;
+ }
+ }
+ if(!inStream ||
+ bufferInputStream(inStream) <= 0)
+ {
+ my_usleep(10000);
+ }
}
- if(dc->stop) return OUTPUT_BUFFER_DC_STOP;
+ if(dc->stop) return OUTPUT_BUFFER_DC_STOP;
currentChunk = cb->end;
cb->chunkSize[currentChunk] = 0;
@@ -127,24 +129,24 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
cb->metaChunk[currentChunk] = currentMetaChunk;
}
else cb->metaChunk[currentChunk] = -1;
- cb->bitRate[currentChunk] = bitRate;
- cb->times[currentChunk] = time;
+ cb->bitRate[currentChunk] = bitRate;
+ cb->times[currentChunk] = time;
}
chunkLeft = CHUNK_SIZE-cb->chunkSize[currentChunk];
- dataToSend = datalen > chunkLeft ? chunkLeft : datalen;
+ dataToSend = datalen > chunkLeft ? chunkLeft : datalen;
- memcpy(cb->chunks+currentChunk*CHUNK_SIZE+
- cb->chunkSize[currentChunk],
- data, dataToSend);
- cb->chunkSize[currentChunk]+= dataToSend;
- datalen-= dataToSend;
- data+= dataToSend;
+ memcpy(cb->chunks+currentChunk*CHUNK_SIZE+
+ cb->chunkSize[currentChunk],
+ data, dataToSend);
+ cb->chunkSize[currentChunk]+= dataToSend;
+ datalen-= dataToSend;
+ data+= dataToSend;
if(cb->chunkSize[currentChunk] == CHUNK_SIZE) {
flushOutputBuffer(cb);
}
- }
+ }
return 0;
}
diff --git a/src/pcm_utils.c b/src/pcm_utils.c
index adcc90122..bfb11e3ff 100644
--- a/src/pcm_utils.c
+++ b/src/pcm_utils.c
@@ -22,31 +22,72 @@
#include "mpd_types.h"
#include "log.h"
+#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>
+#include <time.h>
void pcm_changeBufferEndianness(char * buffer, int bufferSize, int bits) {
- char temp;
-
+
+ERROR("pcm_changeBufferEndianess\n");
switch(bits) {
case 16:
while(bufferSize) {
- temp = *buffer;
+ char temp = *buffer;
*buffer = *(buffer+1);
*(buffer+1) = temp;
bufferSize-=2;
}
break;
+ case 32:
+ /* I'm not sure if this code is correct */
+ /* I guess it is OK for 32 bit int, but how about float? */
+ while(bufferSize) {
+ char temp = *buffer;
+ char temp1 = *(buffer+1);
+ *buffer = *(buffer+3);
+ *(buffer+1) = *(buffer+2);
+ *(buffer+2) = temp1;
+ *(buffer+3) = temp;
+ bufferSize-=4;
+ }
+ break;
}
}
void pcm_volumeChange(char * buffer, int bufferSize, AudioFormat * format,
int volume)
{
- mpd_sint32 temp32;
+#ifdef MPD_FIXED_POINT
+ mpd_sint16 * buffer16 = (mpd_sint16 *)buffer;
+ mpd_sint32 sample32;
+
+ if(volume>=1000) return;
+
+ if(volume<=0) {
+ memset(buffer,0,bufferSize);
+ return;
+ }
+
+ if(format->bits!=16 || format.channels!=2 || format->floatSamples) {
+ ERROR("Only 16 bit stereo is supported in fixed point mode!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ while(bufferSize) {
+ sample32 = (mpd_sint32)(*buffer16) * volume;
+ /* no need to check boundaries - can't overflow */
+ *buffer16 = sample32 >> 10;
+ bufferSize -= 2;
+ }
+ return;
+#else
mpd_sint8 * buffer8 = (mpd_sint8 *)buffer;
mpd_sint16 * buffer16 = (mpd_sint16 *)buffer;
+ mpd_sint32 * buffer32 = (mpd_sint32 *)buffer;
+ float * bufferFloat = (float *)buffer;
+ float fvolume = volume * 0.001;
if(volume>=1000) return;
@@ -55,26 +96,50 @@ void pcm_volumeChange(char * buffer, int bufferSize, AudioFormat * format,
return;
}
+/* DEBUG */
+ if(bufferSize % (format->channels * 4)) {
+ ERROR("pcm_volumeChange: bufferSize=%i not multipel of %i\n",
+ bufferSize, format->channels * 4);
+ }
+ if(!format->floatSamples)
+ ERROR("pcm_volumeChange: not floatSamples\n");
+/* /DEBUG */
+
+ if(format->floatSamples) {
+ if(format->bits==32) {
+ while(bufferSize) {
+ *bufferFloat *= fvolume;
+ bufferFloat++;
+ bufferSize-=4;
+ }
+ return;
+ }
+ else {
+ ERROR("%i bit float not supported by pcm_volumeChange!\n",
+ format->bits);
+ exit(EXIT_FAILURE);
+ }
+ }
+
switch(format->bits) {
+ case 32:
+ while(bufferSize) {
+ double sample = (double)(*buffer32) * fvolume;
+ *buffer32++ = rint(sample);
+ bufferSize-=4;
+ }
+ break;
case 16:
- while(bufferSize>0) {
- temp32 = *buffer16;
- temp32*= volume;
- temp32/=1000;
- *buffer16 = temp32>32767 ? 32767 :
- (temp32<-32768 ? -32768 : temp32);
- buffer16++;
+ while(bufferSize) {
+ float sample = *buffer16 * fvolume;
+ *buffer16++ = rintf(sample);
bufferSize-=2;
}
break;
case 8:
- while(bufferSize>0) {
- temp32 = *buffer8;
- temp32*= volume;
- temp32/=1000;
- *buffer8 = temp32>127 ? 127 :
- (temp32<-128 ? -128 : temp32);
- buffer8++;
+ while(bufferSize) {
+ float sample = *buffer8 * fvolume;
+ *buffer8++ = rintf(sample);
bufferSize--;
}
break;
@@ -83,46 +148,115 @@ void pcm_volumeChange(char * buffer, int bufferSize, AudioFormat * format,
format->bits);
exit(EXIT_FAILURE);
}
+#endif
}
void pcm_add(char * buffer1, char * buffer2, size_t bufferSize1,
size_t bufferSize2, int vol1, int vol2, AudioFormat * format)
{
- mpd_sint32 temp32;
+#ifdef MPD_FIXED_POINT
+ mpd_sint16 * buffer16_1 = (mpd_sint16 *)buffer1;
+ mpd_sint16 * buffer16_2 = (mpd_sint16 *)buffer2;
+ mpd_sint32 sample;
+
+ if(format->bits!=16 || format.channels!=2 || format->floatSamples) {
+ ERROR("Only 16 bit stereo is supported in fixed point mode!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ while(bufferSize1 && bufferSize2) {
+ sample = ((mpd_sint32)(*buffer16_1) * vol1 +
+ (mpd_sint32)(*buffer16_2) * vol2) >> 10;
+ *buffer16_1 = sample>32767 ? 32767 :
+ (sample<-32768 ? -32768 : sample);
+ bufferSize1 -= 2;
+ bufferSize2 -= 2;
+ }
+ if(bufferSize2) memcpy(buffer16_1,buffer16_2,bufferSize2);
+ return;
+#else
+/* DEBUG */
+ if(bufferSize1 % (format->channels * 4)) {
+ ERROR("pcm_add: bufferSize1=%i not multipel of %i\n",
+ bufferSize1, format->channels * 4);
+ }
+ if(bufferSize2 % (format->channels * 4)) {
+ ERROR("pcm_add: bufferSize2=%i not multipel of %i\n",
+ bufferSize2, format->channels * 4);
+ }
+ if(!format->floatSamples)
+ ERROR("pcm_add: not floatSamples\n");
+/* /DEBUG */
mpd_sint8 * buffer8_1 = (mpd_sint8 *)buffer1;
mpd_sint8 * buffer8_2 = (mpd_sint8 *)buffer2;
mpd_sint16 * buffer16_1 = (mpd_sint16 *)buffer1;
mpd_sint16 * buffer16_2 = (mpd_sint16 *)buffer2;
-
+ mpd_sint32 * buffer32_1 = (mpd_sint32 *)buffer1;
+ mpd_sint32 * buffer32_2 = (mpd_sint32 *)buffer2;
+ float * bufferFloat_1 = (float *)buffer1;
+ float * bufferFloat_2 = (float *)buffer2;
+ float fvol1 = vol1 * 0.001;
+ float fvol2 = vol2 * 0.001;
+ float sample;
+
+ if(format->floatSamples) {
+ /* 32 bit float */
+ while(bufferSize1 && bufferSize2) {
+ *bufferFloat_1 = fvol1*(*bufferFloat_1) +
+ fvol2*(*bufferFloat_2);
+ bufferFloat_1++;
+ bufferFloat_2++;
+ bufferSize1-=4;
+ bufferSize2-=4;
+ }
+ if(bufferSize2) memcpy(bufferFloat_1,bufferFloat_2,bufferSize2);
+ }
+
switch(format->bits) {
+ case 32:
+ while(bufferSize1 && bufferSize2) {
+ sample = fvol1*(*buffer32_1) + fvol2*(*buffer32_2);
+ if(sample>2147483647.0) *buffer32_1 = 2147483647;
+ else if(sample<-2147483647.0) *buffer32_1 = -2147483647;
+ else *buffer32_1 = rintf(sample);
+ bufferFloat_1++;
+ bufferFloat_2++;
+ bufferSize1-=4;
+ bufferSize2-=4;
+ }
+ if(bufferSize2) memcpy(bufferFloat_1,bufferFloat_2,bufferSize2);
+ break;
case 16:
- while(bufferSize1>0 && bufferSize2>0) {
- temp32 = (vol1*(*buffer16_1)+vol2*(*buffer16_2))/1000;
- *buffer16_1 = temp32>32767 ? 32767 :
- (temp32<-32768 ? -32768 : temp32);
+ while(bufferSize1 && bufferSize2) {
+ sample = fvol1*(*buffer16_1) + fvol2*(*buffer16_2);
+ *buffer16_1 = sample>32767.0 ? 32767 :
+ (sample<-32768.0 ? -32768 :
+ rintf(sample));
buffer16_1++;
buffer16_2++;
bufferSize1-=2;
bufferSize2-=2;
}
- if(bufferSize2>0) memcpy(buffer16_1,buffer16_2,bufferSize2);
+ if(bufferSize2) memcpy(buffer16_1,buffer16_2,bufferSize2);
break;
case 8:
- while(bufferSize1>0 && bufferSize2>0) {
- temp32 = (vol1*(*buffer8_1)+vol2*(*buffer8_2))/1000;
- *buffer8_1 = temp32>127 ? 127 :
- (temp32<-128 ? -128 : temp32);
+ while(bufferSize1 && bufferSize2) {
+ sample = fvol1*(*buffer8_1) + fvol2*(*buffer8_2);
+ *buffer8_1 = sample>127.0 ? 127 :
+ (sample<-128.0 ? -128 :
+ rintf(sample));
buffer8_1++;
buffer8_2++;
bufferSize1--;
bufferSize2--;
}
- if(bufferSize2>0) memcpy(buffer8_1,buffer8_2,bufferSize2);
+ if(bufferSize2) memcpy(buffer8_1,buffer8_2,bufferSize2);
break;
default:
ERROR("%i bits not supported by pcm_add!\n",format->bits);
exit(EXIT_FAILURE);
}
+#endif
}
void pcm_mix(char * buffer1, char * buffer2, size_t bufferSize1,
@@ -138,183 +272,390 @@ void pcm_mix(char * buffer1, char * buffer2, size_t bufferSize1,
pcm_add(buffer1,buffer2,bufferSize1,bufferSize2,vol1,1000-vol1,format);
}
-
-/* outFormat bits must be 16 and channels must be 2! */
-void pcm_convertAudioFormat(AudioFormat * inFormat, char * inBuffer, size_t
- inSize, AudioFormat * outFormat, char * outBuffer)
+void pcm_convertToFloat(AudioFormat * inFormat, char * inBuffer, size_t
+ samples, char * outBuffer)
{
- static char * bitConvBuffer = NULL;
- static int bitConvBufferLength = 0;
- static char * channelConvBuffer = NULL;
- static int channelConvBufferLength = 0;
- char * dataChannelConv;
- int dataChannelLen;
- char * dataBitConv;
- int dataBitLen;
-
- assert(outFormat->bits==16);
- assert(outFormat->channels==2 || outFormat->channels==1);
-
- /* converts */
+ mpd_sint8 * in8 = (mpd_sint8 *)inBuffer;
+ mpd_sint16 * in16 = (mpd_sint16 *)inBuffer;
+ mpd_sint32 * in32 = (mpd_sint32 *)inBuffer;
+ float * out = (float *)outBuffer;
+ float multiplier;
+
switch(inFormat->bits) {
case 8:
- dataBitLen = inSize << 1;
- if(dataBitLen > bitConvBufferLength) {
- bitConvBuffer = realloc(bitConvBuffer, dataBitLen);
- bitConvBufferLength = dataBitLen;
- }
- dataBitConv = bitConvBuffer;
- {
- mpd_sint8 * in = (mpd_sint8 *)inBuffer;
- mpd_sint16 * out = (mpd_sint16 *)dataBitConv;
- int i;
- for(i=0; i<inSize; i++) {
- *out++ = (*in++) << 8;
- }
+ multiplier = 1.0 / 128.0;
+ while(samples--) {
+ *out++ = (*in8++) * multiplier;
}
break;
case 16:
- dataBitConv = inBuffer;
- dataBitLen = inSize;
+ multiplier = 1.0 / 32768.0;
+ while(samples--) {
+ *out++ = (*in16++) * multiplier;
+ }
break;
- case 24:
- /* put dithering code from mp3_decode here */
+/* case 32:
+ multiplier = 1.0 / (1L << 31);
+ while(samples--) {
+ *out++ = (*in32++) * multiplier;
+ }
+ break; */
default:
- ERROR("only 8 or 16 bits are supported for conversion!\n");
+ ERROR("%i bit samples are not supported for conversion!\n",
+ inFormat->bits);
exit(EXIT_FAILURE);
}
+}
+
+
+char *pcm_convertSampleRate(AudioFormat *inFormat, char *inBuffer, size_t inFrames,
+ AudioFormat *outFormat, size_t outFrames)
+{
+ /* Input must be float32, 1 or 2 channels */
+ /* Interpolate using a second order polynom */
+ /* k0 = s0 *
+ * k2 = (s0 - 2*s1 + s2) * 0.5 *
+ * k1 = s1 - s0 - k2 *
+ * s[t] = k0 + k1*t +k2*t*t */
+
+ static float * sampleConvBuffer = NULL;
+ static int sampleConvBufferLength = 0;
+ size_t dataSampleLen = 0;
+
+ float *out;
+ float *in = (float *)inBuffer;
+
+ static float shift;
+ static float offset;
+ static float sample0l;
+ static float sample0r;
+ static float sample1l;
+ static float sample1r;
+
+ static int rateCheck = 0;
+ static time_t timeCheck = 0;
+ size_t c_rate = inFormat->sampleRate + inFormat->channels;
+ time_t c_time = time(NULL);
+
+ /* reset static data if changed samplerate ...*/
+ if(c_rate != rateCheck || c_time != timeCheck) {
+ ERROR("reset resampling\n",c_rate, rateCheck);
+ rateCheck = c_rate;
+ shift = (float)inFrames / (float)outFrames;
+ offset = 1.5;
+ sample0l = 0.0;
+ sample0r = 0.0;
+ sample1l = 0.0;
+ sample1r = 0.0;
+ }
+ else {
+ /* ... otherwise check that shift is within bounds */
+ float s = offset + (outFrames * shift) - inFrames;
+ if(s > 1.5) {
+ shift = (1.5-offset+(float)inFrames) / (float)outFrames;
+ }
+ else if(s < 0.5) {
+ shift = (0.5-offset+(float)inFrames) / (float)outFrames;
+ }
+ }
+ timeCheck = c_time;
- /* converts only between 16 bit audio between mono and stereo */
- if(inFormat->channels == outFormat->channels)
+ /* allocate data */
+ dataSampleLen = 8 * outFrames;
+ if(dataSampleLen > sampleConvBufferLength) {
+ sampleConvBuffer = (float *)realloc(sampleConvBuffer,dataSampleLen);
+ sampleConvBufferLength = dataSampleLen;
+ }
+ out = sampleConvBuffer;
+
+
+ /* convert */
+ switch(outFormat->channels) {
+ case 1:
+ {
+ float sample2l;
+ float k0l, k1l, k2l;
+ while(inFrames--) {
+ sample2l = *in++;
+ /* set coefficients */
+ k0l = sample0l;
+ k2l = (sample0l - 2.0 * sample1l + sample2l) * 0.5;
+ k1l = sample1l - sample0l - k2l;
+ /* calculate sample(s) */
+ while(offset <= 1.5 && outFrames--) {
+ *out++ = k0l + k1l*offset + k2l*offset*offset;
+ offset += shift;
+ }
+ /* prepare for next frame */
+ sample0l = sample1l;
+ sample1l = sample2l;
+ offset -= 1.0;
+ }
+
+ /* fill the last frames */
+ while(outFrames--) {
+ *out++ = k0l + k1l*offset + k2l*offset*offset;
+ offset += shift;
+ }
+ }
+ break;
+ case 2:
{
- dataChannelConv = dataBitConv;
- dataChannelLen = dataBitLen;
+ float *out = sampleConvBuffer;
+ float *in = (float *)inBuffer;
+ float sample2l;
+ float sample2r;
+ float k0l, k1l, k2l;
+ float k0r, k1r, k2r;
+ while(inFrames--) {
+ sample2l = *in++;
+ sample2r = *in++;
+ /* set coefficients */
+ k0l = sample0l;
+ k0r = sample0r;
+ k2l = (sample0l - 2.0 * sample1l + sample2l) * 0.5;
+ k2r = (sample0r - 2.0 * sample1r + sample2r) * 0.5;
+ k1l = sample1l - sample0l - k2l;
+ k1r = sample1r - sample0r - k2r;
+ /* calculate sample(s) */
+ while(offset <= 1.5 && outFrames--) {
+ if(offset<0.5)
+ ERROR("offset to small in resampling - %f\n",offset);
+ *out++ = k0l + k1l*offset + k2l*offset*offset;
+ *out++ = k0r + k1r*offset + k2r*offset*offset;
+ offset += shift;
+ }
+ /* prepare for next frame */
+ sample0l = sample1l;
+ sample0r = sample1r;
+ sample1l = sample2l;
+ sample1r = sample2r;
+ offset -= 1.0;
+ }
+
+ /* fill the last frame(s) */
+ while(outFrames--) {
+ if(offset>2.0)
+ ERROR("offset to big in resampling - %f\n",offset);
+ *out++ = k0l + k1l*offset + k2l*offset*offset;
+ *out++ = k0r+ k1r*offset + k2r*offset*offset;
+ offset += shift;
+ }
+ }
+ break;
+ }
+ return (char *)sampleConvBuffer;
+}
+
+
+/* now support conversions between sint8, sint16, sint32 and float32,
+ * 1 or 2 channels and (although badly) all sample rates */
+void pcm_convertAudioFormat(AudioFormat * inFormat, char * inBuffer, size_t
+ inSize, AudioFormat * outFormat, char * outBuffer)
+{
+#ifdef MPD_FIXED_POINT
+ /* In fixed mode the conversion support is limited... */
+ if(inFormat->bits != outFormat->bits || inFormat->bits != 16) {
+ ERROR("Only 16 bit samples supported in fixed point mode!\n");
+ exit(EXIT_FAILURE);
+ }
+ if(inFormat->sampleRate || outFormat->sampleRate) {
+ ERROR("Sample rate conversions not supported in fixed point mode!\n");
+ exit(EXIT_FAILURE);
+ }
+ if(inFormat->channels == 2 && outFormat->channels == 1) {
+ size_t frames = inSize >> 2; /* 16 bit stereo == 4 bytes */
+ mpd_sint16 *in = (mpd_sint16 *)inBuffer;
+ mpd_sint16 *out = (mpd_sint16 *)outBuffer;
+ while(frames--) {
+ *out++ = *in++;
+ *in++; /* skip the other channel */
+ }
+ }
+ if(inFormat->channels == 1 && outFormat->channels == 2) {
+ size_t frames = inSize >> 1; /* 16 bit mono == 2 bytes */
+ mpd_sint16 *in = (mpd_sint16 *)inBuffer;
+ mpd_sint16 *out = (mpd_sint16 *)outBuffer;
+ while(frames--) {
+ *out++ = *in;
+ *out++ = *in++; /* duplicate the channel */
+ }
+ }
+ else {
+ ERROR("More then 2 channels are not supported!\n");
+ exit(EXIT_FAILURE);
+ }
+ return;
+
+#else
+/* DEBUG */
+ if(inSize % (inFormat->channels * 4)) {
+ ERROR("pcm_convertAudioFormat: inSize=%i not multipel of %i\n",
+ inSize, inFormat->channels * 4);
+ }
+/* /DEBUG */
+
+ static char *convBuffer = NULL;
+ static int convBufferLength = 0;
+ char * dataConv;
+ int dataLen;
+ static float ditherAmount = 2.0 / RAND_MAX;
+ const size_t inSamples = (inSize << 3) / inFormat->bits;
+ const size_t inFrames = inSamples / inFormat->channels;
+ const size_t outFrames = (inFrames * (mpd_uint32)(outFormat->sampleRate)) /
+ inFormat->sampleRate;
+ const size_t outSamples = outFrames * outFormat->channels;
+
+ /* make sure convBuffer is big enough for 2 channels of float samples */
+ dataLen = inFrames << 3;
+ if(dataLen > convBufferLength) {
+ convBuffer = (char *) realloc(convBuffer, dataLen);
+ if(!convBuffer)
+ {
+ ERROR("Could not allocate more memory for convBuffer!\n");
+ exit(EXIT_FAILURE);
+ }
+ convBufferLength = dataLen;
+ }
+
+ /* make sure dataConv points to 32 bit float samples */
+ if(inFormat->floatSamples && inFormat->bits==32) {
+ dataConv = inBuffer;
+ }
+ else if(!inFormat->floatSamples) {
+ dataConv = convBuffer;
+ pcm_convertToFloat(inFormat, inBuffer, inSamples, dataConv);
}
else {
+ ERROR("%i bit float are not supported for conversion!\n",
+ inFormat->bits);
+ exit(EXIT_FAILURE);
+ }
+
+ /* convert between mono and stereo samples*/
+ if(inFormat->channels != outFormat->channels) {
+ float *in = ((float *)dataConv)+inFrames;
switch(inFormat->channels) {
/* convert from 1 -> 2 channels */
case 1:
- dataChannelLen = (dataBitLen >> 1) << 2;
- if(dataChannelLen > channelConvBufferLength) {
- channelConvBuffer = realloc(channelConvBuffer,
- dataChannelLen);
- channelConvBufferLength = dataChannelLen;
- }
- dataChannelConv = channelConvBuffer;
{
- mpd_sint16 * in = (mpd_sint16 *)dataBitConv;
- mpd_sint16 * out = (mpd_sint16 *)dataChannelConv;
- int i, inSamples = dataBitLen >> 1;
- for(i=0;i<inSamples;i++) {
- *out++ = *in;
- *out++ = *in++;
- }
+ float *out = ((float *)convBuffer)+(inFrames<<1);
+ int f = inFrames;
+ while(f--) {
+ *out-- = *in;
+ *out-- = *in--;
+ }
}
break;
/* convert from 2 -> 1 channels */
case 2:
- dataChannelLen = dataBitLen >> 1;
- if(dataChannelLen > channelConvBufferLength) {
- channelConvBuffer = realloc(channelConvBuffer,
- dataChannelLen);
- channelConvBufferLength = dataChannelLen;
- }
- dataChannelConv = channelConvBuffer;
{
- mpd_sint16 * in = (mpd_sint16 *)dataBitConv;
- mpd_sint16 * out = (mpd_sint16 *)dataChannelConv;
- int i, inSamples = dataBitLen >> 2;
- for(i=0;i<inSamples;i++) {
- *out = (*in++)/2;
- *out++ += (*in++)/2;
- }
+ float * out = (float *)convBuffer;
+ int f = inFrames;
+ while(f--) {
+ *out = (*in++)*0.5;
+ *out++ += (*in++)*0.5;
+ }
}
break;
default:
ERROR("only 1 or 2 channels are supported for conversion!\n");
exit(EXIT_FAILURE);
}
+ dataConv = convBuffer;
}
- if(inFormat->sampleRate == outFormat->sampleRate) {
- memcpy(outBuffer,dataChannelConv,dataChannelLen);
+ /* convert sample rate */
+ if(inFormat->sampleRate != outFormat->sampleRate) {
+ dataConv = pcm_convertSampleRate(
+ inFormat, dataConv, inFrames,
+ outFormat, outFrames);
}
- else {
- /* only works if outFormat is 16-bit stereo! */
- /* resampling code blatantly ripped from ESD */
- mpd_uint32 rd_dat = 0;
- mpd_uint32 wr_dat = 0;
- 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;
-
- switch(outFormat->channels) {
- case 1:
- while( wr_dat < nlen) {
- rd_dat = wr_dat * inFormat->sampleRate /
- outFormat->sampleRate;
-
- lsample = in[ rd_dat++ ];
-
- out[ wr_dat++ ] = lsample;
- }
- break;
- case 2:
- while( wr_dat < nlen) {
- rd_dat = wr_dat * inFormat->sampleRate /
- outFormat->sampleRate;
- rd_dat &= ~1;
- lsample = in[ rd_dat++ ];
- rsample = in[ rd_dat++ ];
-
- out[ wr_dat++ ] = lsample;
- out[ wr_dat++ ] = rsample;
- }
- break;
- }
+ /* convert to output format */
+ if(outFormat->floatSamples && outFormat->bits==32) {
+ if(outBuffer != dataConv)
+ memcpy(outBuffer, dataConv, outSamples << 2);
+ return;
}
-
- return;
-}
-
-size_t pcm_sizeOfOutputBufferForAudioFormatConversion(AudioFormat * inFormat,
- size_t inSize, AudioFormat * outFormat)
-{
- const int shift = sizeof(mpd_sint16)*outFormat->channels;
- size_t outSize = inSize;
-
- switch(inFormat->bits) {
+ else if(outFormat->floatSamples) {
+ ERROR("%i bit float are not supported for conversion!\n",
+ outFormat->bits);
+ exit(EXIT_FAILURE);
+ }
+
+ switch(outFormat->bits) {
case 8:
- outSize = outSize << 1;
+ {
+ /* add triangular dither and convert to sint8 */
+ float * in = (float *)dataConv;
+ mpd_sint8 * out = (mpd_sint8 *)outBuffer;
+ int s = outSamples;
+ while(s--) {
+ float sample = (*in++) * 128.0 +
+ ditherAmount*(rand()-rand());
+ *out++ = sample>127.0 ? 127 :
+ (sample<-128.0 ? -128 :
+ rintf(sample));
+ }
+ }
break;
case 16:
+ {
+ /* add triangular dither and convert to sint16 */
+ float * in = (float *)dataConv;
+ mpd_sint16 * out = (mpd_sint16 *)outBuffer;
+ int s = outSamples;
+ while(s--) {
+ float sample = (*in++) * 32766.0 +
+ ditherAmount*(rand()-rand());
+ *out++ = sample>32767.0 ? 32767 :
+ (sample<-32768.0 ? -32768 :
+ rintf(sample));
+ }
+ }
break;
+ case 32:
+ {
+ /* convert to sint32 */
+ float * in = (float *)dataConv;
+ mpd_sint32 * out = (mpd_sint32 *)outBuffer;
+ int s = outSamples;
+ while(s--) {
+ float sample = (*in++) * 2147483647.0;
+ if(sample>2147483647.0) *out++ = 2147483647;
+ else if(sample<-2147483647.0) *out++ = -2147483647;
+ else *out++ = rintf(sample);
+ }
+ }
+ break;
+ case 24: /* how do we store 24 bit? Maybe sint32 is all we need? */
default:
- ERROR("only 8 or 16 bits are supported for conversion!\n");
+ ERROR("%i bits are not supported for conversion!\n", outFormat->bits);
exit(EXIT_FAILURE);
}
- if(inFormat->channels != outFormat->channels) {
- switch(inFormat->channels) {
- case 1:
- outSize = (outSize >> 1) << 2;
- break;
- case 2:
- outSize >>= 1;
- break;
- }
+ return;
+#endif
+}
+
+size_t pcm_sizeOfOutputBufferForAudioFormatConversion(AudioFormat * inFormat,
+ size_t inSize, AudioFormat * outFormat)
+{
+/* DEBUG */
+ if(inSize % (inFormat->channels * 4)) {
+ ERROR("pcm_sizeOOBFAFC: inSize=%i not multipel of %i\n",
+ inSize, inFormat->channels * 4);
}
+/* /DEBUG */
+ const int inShift = (inFormat->bits * inFormat->channels) >> 3;
+ const int outShift = (outFormat->bits * outFormat->channels) >> 3;
+
+ size_t inFrames = inSize / inShift;
+ size_t outFrames = (inFrames * (mpd_uint32)(outFormat->sampleRate)) /
+ inFormat->sampleRate;
+
+ size_t outSize = outFrames * outShift;
- outSize = (((outSize / shift) * (mpd_uint32)(outFormat->sampleRate)) /
- inFormat->sampleRate);
-
- outSize *= shift;
-
return outSize;
}
diff --git a/src/playerData.h b/src/playerData.h
index b8fdf1a2b..e615e7d16 100644
--- a/src/playerData.h
+++ b/src/playerData.h
@@ -28,7 +28,8 @@
#include "outputBuffer.h"
/* pick 1020 since its devisible for 8,16,24, and 32-bit audio */
-#define CHUNK_SIZE 1020
+/* changed (by ancl) to 2016 since that is divisible also by all in stereo*/
+#define CHUNK_SIZE 2016
extern int buffered_before_play;
extern int buffered_chunks;
diff --git a/src/replayGain.c b/src/replayGain.c
index ea521d728..f052c68bc 100644
--- a/src/replayGain.c
+++ b/src/replayGain.c
@@ -107,13 +107,20 @@ void freeReplayGainInfo(ReplayGainInfo * info) {
void doReplayGain(ReplayGainInfo * info, char * buffer, int bufferSize,
AudioFormat * format)
{
- mpd_sint16 * buffer16;
- mpd_sint8 * buffer8;
- mpd_sint32 temp32;
+ float * bufferFloat = (float *)buffer;
+ mpd_sint32 * buffer32 = (mpd_sint32 *)buffer;
+ mpd_sint16 * buffer16 = (mpd_sint16 *)buffer;
+ mpd_sint8 * buffer8 = (mpd_sint8 *)buffer;
float scale;
+ mpd_sint32 iScale;
if(replayGainState == REPLAYGAIN_OFF || !info) return;
+/* DEBUG */
+ if(bufferSize % (format->channels * 4))
+ ERROR("doReplayGain: bufferSize=%i not multipel of %i\n",
+ bufferSize, format->channels);
+/* /DEBUG */
if(info->scale < 0) {
switch(replayGainState) {
case REPLAYGAIN_TRACK:
@@ -127,35 +134,78 @@ void doReplayGain(ReplayGainInfo * info, char * buffer, int bufferSize,
}
}
- if(info->scale <= 1.01 && info->scale >= 0.99) return;
-
- buffer16 = (mpd_sint16 *)buffer;
- buffer8 = (mpd_sint8 *)buffer;
+#ifdef MPD_FIXED_POINT
+ if(format->bits!=16 || format.channels!=2 || format->floatSamples) {
+ ERROR("Only 16 bit stereo is supported in fixed point mode!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* If the volume change is very small then we hardly here the
+ * difference anyway, and if the change is positiv then clipping
+ * may occur. We don't want that. */
+ if(info->scale > 0.99) return;
+
+ iScale = scale * 32768.0; /* << 15 */
+
+ while(bufferSize) {
+ sample32 = (mpd_sint32)(*buffer16) * iScale;
+ /* no need to check boundaries - we only lower the volume*/
+ /* It would be good to add some kind of dither here... TODO?! */
+ *buffer16 = (sample32 >> 15);
+ bufferSize -= 2;
+ }
+ return;
+#else
scale = info->scale;
-
- switch(format->bits) {
- case 16:
- while(bufferSize > 0){
- temp32 = *buffer16;
- temp32 *= scale;
- *buffer16 = temp32>32767 ? 32767 :
- (temp32<-32768 ? -32768 : temp32);
- buffer16++;
- bufferSize-=2;
- }
- break;
- case 8:
- while(bufferSize>0){
- temp32 = *buffer8;
- temp32 *= scale;
- *buffer8 = temp32>127 ? 127 :
- (temp32<-128 ? -128 : temp32);
- buffer8++;
- bufferSize--;
+
+ if(format->floatSamples) {
+ if(format->bits==32) {
+ while(bufferSize) {
+ *bufferFloat *= scale;
+ bufferFloat++;
+ bufferSize-=4;
}
- break;
- default:
- ERROR("%i bits not supported by doReplaygain!\n", format->bits);
+ return;
+ }
+ else {
+ ERROR("%i bit float not supported by doReplaygain!\n",
+ format->bits);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ switch(format->bits) {
+ case 32:
+ while(bufferSize) {
+ double sample = (double)(*buffer32) * scale;
+ if(sample>2147483647.0) *buffer32 = 2147483647;
+ else if(sample<-2147483647.0) *buffer32 = -2147483647;
+ else *buffer32 = rintf(sample);
+ *buffer32++;
+ bufferSize-=4;
+ }
+ break;
+ case 16:
+ while(bufferSize){
+ float sample = *buffer16 * scale;
+ *buffer16 = sample>32767.0 ? 32767 :
+ (sample<-32768.0 ? -32768 : rintf(sample));
+ buffer16++;
+ bufferSize-=2;
+ }
+ break;
+ case 8:
+ while(bufferSize){
+ float sample = *buffer8 * scale;
+ *buffer8 = sample>127.0 ? 127 :
+ (sample<-128.0 ? -128 : rintf(sample));
+ buffer8++;
+ bufferSize--;
+ }
+ break;
+ default:
+ ERROR("%i bits not supported by doReplaygain!\n", format->bits);
}
+#endif
}