diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/audio.c | 152 | ||||
-rw-r--r-- | src/audio.h | 3 | ||||
-rw-r--r-- | src/audioOutput.c | 38 | ||||
-rw-r--r-- | src/decode.c | 2 | ||||
-rw-r--r-- | src/inputPlugins/mp3_plugin.c | 224 | ||||
-rw-r--r-- | src/inputPlugins/mpc_plugin.c | 42 | ||||
-rw-r--r-- | src/mpd_types.h | 2 | ||||
-rw-r--r-- | src/outputBuffer.c | 76 | ||||
-rw-r--r-- | src/pcm_utils.c | 669 | ||||
-rw-r--r-- | src/playerData.h | 3 | ||||
-rw-r--r-- | src/replayGain.c | 110 |
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 } |