From 54679d9028117360e50a85a1f4b4f376f13ad6a3 Mon Sep 17 00:00:00 2001 From: Warren Dukes Date: Tue, 2 Nov 2004 19:56:59 +0000 Subject: [PATCH] rewrite replaygain code, needs testing git-svn-id: https://svn.musicpd.org/mpd/trunk@2482 09075e82-0dd4-0310-85a5-a0d7c8717e4f --- TODO | 4 -- src/inputPlugins/aac_plugin.c | 2 +- src/inputPlugins/audiofile_plugin.c | 3 +- src/inputPlugins/flac_plugin.c | 50 +++++++++++------------ src/inputPlugins/mod_plugin.c | 2 +- src/inputPlugins/mp3_plugin.c | 6 ++- src/inputPlugins/mp4_plugin.c | 2 +- src/inputPlugins/ogg_plugin.c | 62 +++++++++++------------------ src/outputBuffer.c | 5 ++- src/outputBuffer.h | 14 +++++-- src/replayGain.c | 62 +++++++++++++++++++++++------ src/replayGain.h | 22 +++++++--- 12 files changed, 136 insertions(+), 98 deletions(-) diff --git a/TODO b/TODO index 72a7b8647..0e824dd99 100644 --- a/TODO +++ b/TODO @@ -7,10 +7,6 @@ *) Steal resampling code from ices (i think this code works only for 16-bit) *) Rewrite replaygain stuff: - *) Replay gain struct with album and track gain's and peak's - *) Pass these to replaygain function - *) Don't have deocder plugins inquire weather or not to use replaygain, - they should just parse tags and pass these to replaygain func *) If replaygain tag info present, average the replaygain gain's and peak's on the fly *) If NULL replaygain struct, then use the average replaygain gains diff --git a/src/inputPlugins/aac_plugin.c b/src/inputPlugins/aac_plugin.c index 9f78fc2a1..1d844426a 100644 --- a/src/inputPlugins/aac_plugin.c +++ b/src/inputPlugins/aac_plugin.c @@ -362,7 +362,7 @@ int aac_decode(OutputBuffer * cb, DecoderControl * dc, char * path) { sampleBufferLen = sampleCount*2; sendDataToOutputBuffer(cb, NULL, dc, 0, sampleBuffer, - sampleBufferLen, time, bitRate); + sampleBufferLen, time, bitRate, NULL); if(dc->seek) { dc->seekError = 1; dc->seek = 0; diff --git a/src/inputPlugins/audiofile_plugin.c b/src/inputPlugins/audiofile_plugin.c index 818ba553e..0c205888d 100644 --- a/src/inputPlugins/audiofile_plugin.c +++ b/src/inputPlugins/audiofile_plugin.c @@ -116,7 +116,8 @@ int audiofile_decode(OutputBuffer * cb, DecoderControl * dc, char * path) { ret*fs, (float)current / (float)dc->audioFormat.sampleRate, - bitRate); + bitRate, + NULL); if(dc->stop) break; } } diff --git a/src/inputPlugins/flac_plugin.c b/src/inputPlugins/flac_plugin.c index 1adf5a349..d038f1418 100644 --- a/src/inputPlugins/flac_plugin.c +++ b/src/inputPlugins/flac_plugin.c @@ -44,8 +44,8 @@ typedef struct { OutputBuffer * cb; DecoderControl * dc; InputStream inStream; - float replayGainScale; char * path; + ReplayGainInfo * replayGainInfo; } FlacData; /* this code is based on flac123, from flac-tools */ @@ -82,7 +82,7 @@ int flac_decode(OutputBuffer * cb, DecoderControl *dc, char * path) { data.bitRate = 0; data.cb = cb; data.dc = dc; - data.replayGainScale = 1.0; + data.replayGainInfo = NULL; data.path = path; if(openInputStream(&(data.inStream), path)<0) { @@ -195,6 +195,8 @@ int flac_decode(OutputBuffer * cb, DecoderControl *dc, char * path) { else dc->state = DECODE_STATE_STOP; fail: + if(data.replayGainInfo) freeReplayGainInfo(data.replayGainInfo); + if(streamOpen) closeInputStream(&(data.inStream)); if(flacDec) FLAC__seekable_stream_decoder_delete(flacDec); @@ -338,30 +340,28 @@ int flacFindVorbisCommentFloat(const FLAC__StreamMetadata * block, char * cmnt, /* replaygain stuff by AliasMrJones */ void flacParseReplayGain(const FLAC__StreamMetadata *block, FlacData * data) { - int found; - float gain = 0.0; - float peak = 0.0; - int state = getReplayGainState(); + if(NULL == data->replayGainInfo) { + freeReplayGainInfo(data->replayGainInfo); + data->replayGainInfo = NULL; + } - if(state == REPLAYGAIN_OFF) return; + data->replayGainInfo = newReplayGainInfo(); - found = flacFindVorbisCommentFloat(block,"replaygain_album_gain",&gain); - if(found) { - flacFindVorbisCommentFloat(block,"replaygain_album_peak", - &peak); - } + int found = 0; - if(!found || state == REPLAYGAIN_TRACK) { - found = flacFindVorbisCommentFloat(block, - "replaygain_track_gain", &gain); - if(found) { - peak = 0.0; - flacFindVorbisCommentFloat(block, - "replaygain_track_peak",&peak); - } - } + found &= flacFindVorbisCommentFloat(block,"replaygain_album_gain", + &data->replayGainInfo->albumGain); + found &= flacFindVorbisCommentFloat(block,"replaygain_album_peak", + &data->replayGainInfo->albumPeak); + found &= flacFindVorbisCommentFloat(block,"replaygain_track_gain", + &data->replayGainInfo->trackGain); + found &= flacFindVorbisCommentFloat(block,"replaygain_track_peak", + &data->replayGainInfo->trackPeak); - if(found) data->replayGainScale = computeReplayGainScale(gain,peak); + if(!found) { + freeReplayGainInfo(data->replayGainInfo); + data->replayGainInfo = NULL; + } } void flacMetadata(const FLAC__SeekableStreamDecoder *dec, @@ -391,11 +391,9 @@ void flacMetadata(const FLAC__SeekableStreamDecoder *dec, } int flacSendChunk(FlacData * data) { - doReplayGain(data->chunk,data->chunk_length,&(data->dc->audioFormat), - data->replayGainScale); - switch(sendDataToOutputBuffer(data->cb, NULL, data->dc, 1, data->chunk, - data->chunk_length, data->time, data->bitRate)) + data->chunk_length, data->time, data->bitRate, + data->replayGainInfo)) { case OUTPUT_BUFFER_DC_STOP: return -1; diff --git a/src/inputPlugins/mod_plugin.c b/src/inputPlugins/mod_plugin.c index 766c38658..2a03cc404 100644 --- a/src/inputPlugins/mod_plugin.c +++ b/src/inputPlugins/mod_plugin.c @@ -191,7 +191,7 @@ int mod_decode(OutputBuffer * cb, DecoderControl * dc, char * path) { time += ret*secPerByte; sendDataToOutputBuffer(cb, NULL, dc, 0, (char *)data->audio_buffer, ret, time, - 0); + 0, NULL); } flushOutputBuffer(cb); diff --git a/src/inputPlugins/mp3_plugin.c b/src/inputPlugins/mp3_plugin.c index db5756b95..ab204ffa9 100644 --- a/src/inputPlugins/mp3_plugin.c +++ b/src/inputPlugins/mp3_plugin.c @@ -585,7 +585,8 @@ int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc) { data->outputPtr- data->outputBuffer, data->elapsedTime, - data->bitRate/1000); + data->bitRate/1000, + NULL); if(ret == OUTPUT_BUFFER_DC_STOP) { data->flush = 0; return DECODE_BREAK; @@ -710,7 +711,8 @@ int mp3_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) { data.inStream->seekable, data.outputBuffer, data.outputPtr-data.outputBuffer, - data.elapsedTime,data.bitRate/1000); + data.elapsedTime,data.bitRate/1000, + NULL); } closeInputStream(inStream); diff --git a/src/inputPlugins/mp4_plugin.c b/src/inputPlugins/mp4_plugin.c index 982ea3ea2..66d5600b4 100644 --- a/src/inputPlugins/mp4_plugin.c +++ b/src/inputPlugins/mp4_plugin.c @@ -284,7 +284,7 @@ int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char * path) { sampleBuffer+=offset*channels*2; sendDataToOutputBuffer(cb, NULL, dc, 1, sampleBuffer, - sampleBufferLen, time, bitRate); + sampleBufferLen, time, bitRate, NULL); if(dc->stop) { eof = 1; break; diff --git a/src/inputPlugins/ogg_plugin.c b/src/inputPlugins/ogg_plugin.c index 5d461586e..da08cb2e2 100644 --- a/src/inputPlugins/ogg_plugin.c +++ b/src/inputPlugins/ogg_plugin.c @@ -114,62 +114,45 @@ char * ogg_parseComment(char * comment, char * needle) { return NULL; } -float ogg_getReplayGainScale(char ** comments) { - int trackGainFound = 0; - int albumGainFound = 0; - float trackGain = 1.0; - float albumGain = 1.0; - float trackPeak = 0.0; - float albumPeak = 0.0; +void ogg_getReplayGainInfo(char ** comments, ReplayGainInfo ** infoPtr) { char * temp; - int replayGainState = getReplayGainState(); + int found = 0; - if(replayGainState == REPLAYGAIN_OFF) return 1.0; + if(*infoPtr) freeReplayGainInfo(*infoPtr); + *infoPtr = newReplayGainInfo(); while(*comments) { if((temp = ogg_parseComment(*comments,"replaygain_track_gain"))) { - trackGain = atof(temp); - trackGainFound = 1; + (*infoPtr)->trackGain = atof(temp); + found = 1; } else if((temp = ogg_parseComment(*comments, "replaygain_album_gain"))) { - albumGain = atof(temp); - albumGainFound = 1; + (*infoPtr)->albumGain = atof(temp); + found = 1; } else if((temp = ogg_parseComment(*comments, "replaygain_track_peak"))) { - trackPeak = atof(temp); + (*infoPtr)->trackPeak = atof(temp); + found = 1; } else if((temp = ogg_parseComment(*comments, "replaygain_album_peak"))) { - albumPeak = atof(temp); + (*infoPtr)->albumPeak = atof(temp); + found = 1; } comments++; } - switch(replayGainState) { - case REPLAYGAIN_ALBUM: - if(albumGainFound) { - return computeReplayGainScale(albumGain,albumPeak); - } - else if(trackGainFound) { - return computeReplayGainScale(trackGain,trackPeak); - } - case REPLAYGAIN_TRACK: - if(trackGainFound) { - return computeReplayGainScale(trackGain,trackPeak); - } - else if(albumGainFound) { - return computeReplayGainScale(albumGain,albumPeak); - } - } - - return 1.0; + if(!found) { + freeReplayGainInfo(*infoPtr); + *infoPtr = NULL; + } } MpdTag * oggCommentsParse(char ** comments) { @@ -248,7 +231,7 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) int chunkpos = 0; long bitRate = 0; long test; - float replayGainScale = 1.0; + ReplayGainInfo * replayGainInfo = NULL; char ** comments; data.inStream = inStream; @@ -304,7 +287,7 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) comments = ov_comment(&vf, -1)->user_comments; putOggCommentsIntoOutputBuffer(cb, inStream->metaName, comments); - replayGainScale = ogg_getReplayGainScale(comments); + ogg_getReplayGainInfo(comments, &replayGainInfo); } prev_section = current_section; @@ -321,14 +304,13 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) if((test = ov_bitrate_instant(&vf))>0) { bitRate = test/1000; } - doReplayGain(chunk,chunkpos,&(dc->audioFormat), - replayGainScale); sendDataToOutputBuffer(cb, inStream, dc, inStream->seekable, chunk, chunkpos, ov_pcm_tell(&vf)/ dc->audioFormat.sampleRate, - bitRate); + bitRate, + replayGainInfo); chunkpos = 0; if(dc->stop) break; } @@ -337,9 +319,11 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) if(!dc->stop && chunkpos > 0) { sendDataToOutputBuffer(cb, NULL, dc, inStream->seekable, chunk, chunkpos, - ov_time_tell(&vf), bitRate); + ov_time_tell(&vf), bitRate, replayGainInfo); } + if(replayGainInfo) freeReplayGainInfo(replayGainInfo); + ov_clear(&vf); flushOutputBuffer(cb); diff --git a/src/outputBuffer.c b/src/outputBuffer.c index cd7336a8b..463eeef79 100644 --- a/src/outputBuffer.c +++ b/src/outputBuffer.c @@ -64,7 +64,8 @@ void flushOutputBuffer(OutputBuffer * cb) { int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream, DecoderControl * dc, int seekable, char * dataIn, - long dataInLen, float time, mpd_uint16 bitRate) + long dataInLen, float time, mpd_uint16 bitRate, + ReplayGainInfo * replayGainInfo) { mpd_uint16 dataToSend; mpd_uint16 chunkLeft; @@ -91,6 +92,8 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream, &(cb->audioFormat),data); } + doReplayGain(replayGainInfo, data, datalen, &cb->audioFormat); + while(datalen) { if(currentChunk != cb->end) { int next = cb->end+1; diff --git a/src/outputBuffer.h b/src/outputBuffer.h index cec077542..23b49ef5b 100644 --- a/src/outputBuffer.h +++ b/src/outputBuffer.h @@ -24,6 +24,7 @@ #include "audio.h" #include "inputStream.h" #include "metadataChunk.h" +#include "replayGain.h" #define OUTPUT_BUFFER_DC_STOP -1 #define OUTPUT_BUFFER_DC_SEEK -2 @@ -50,9 +51,16 @@ void flushOutputBuffer(OutputBuffer * cb); /* we send inStream for buffering the inputStream while waiting to send the next chunk */ -int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream, - DecoderControl * dc, int seekable, char * data, long datalen, - float time, mpd_uint16 bitRate); +int sendDataToOutputBuffer( + OutputBuffer * cb, + InputStream * inStream, + DecoderControl * dc, + int seekable, + char * data, + long datalen, + float time, + mpd_uint16 bitRate, + ReplayGainInfo * replayGainInfo); int copyMpdTagToOutputBuffer(OutputBuffer * cb, MpdTag * tag); diff --git a/src/replayGain.c b/src/replayGain.c index 4788d7d95..138d3a68b 100644 --- a/src/replayGain.c +++ b/src/replayGain.c @@ -71,11 +71,7 @@ void initReplayGainState() { } } -int getReplayGainState() { - return replayGainState; -} - -float computeReplayGainScale(float gain, float peak) { +static float computeReplayGainScale(float gain, float peak) { float scale; if(gain == 0.0) return(1); @@ -89,14 +85,55 @@ float computeReplayGainScale(float gain, float peak) { return(scale); } -void doReplayGain(char * buffer, int bufferSize, AudioFormat * format, - float scale) -{ - mpd_sint16 * buffer16 = (mpd_sint16 *)buffer; - mpd_sint8 * buffer8 = (mpd_sint8 *)buffer; - mpd_sint32 temp32; +ReplayGainInfo * newReplayGainInfo() { + ReplayGainInfo * ret = malloc(sizeof(ReplayGainInfo)); + + ret->albumGain = 0.0; + ret->albumPeak = 1.0; + + ret->trackGain = 0.0; + ret->trackPeak = 1.0; + + /* set to -1 so that we know in doReplayGain to compute the scale */ + ret->scale = -1.0; + + return ret; +} + +void freeReplayGainInfo(ReplayGainInfo * info) { + free(info); +} + +void doReplayGain(ReplayGainInfo * info, char * buffer, int bufferSize, + AudioFormat * format) +{ + mpd_sint16 * buffer16; + mpd_sint8 * buffer8; + mpd_sint32 temp32; + float scale; + + if(replayGainState == REPLAYGAIN_OFF || !info) return; + + if(info->scale < 0) { + switch(replayGainState) { + case REPLAYGAIN_TRACK: + info->scale = computeReplayGainScale(info->trackGain, + info->trackPeak); + break; + default: + info->scale = computeReplayGainScale(info->albumGain, + info->albumPeak); + break; + } + } + + if(info->scale <= 1.01 && info->scale >= 0.99) return; + + buffer16 = (mpd_sint16 *)buffer; + buffer8 = (mpd_sint8 *)buffer; + + scale = info->scale; - if(scale == 1.0) return; switch(format->bits) { case 16: while(bufferSize > 0){ @@ -122,4 +159,3 @@ void doReplayGain(char * buffer, int bufferSize, AudioFormat * format, ERROR("%i bits not supported by doReplaygain!\n", format->bits); } } -/* End of added code */ diff --git a/src/replayGain.h b/src/replayGain.h index 5d8ee7b24..112034fbe 100644 --- a/src/replayGain.h +++ b/src/replayGain.h @@ -26,13 +26,23 @@ #define REPLAYGAIN_TRACK 1 #define REPLAYGAIN_ALBUM 2 +typedef struct _ReplayGainInfo { + float albumGain; + float albumPeak; + float trackGain; + float trackPeak; + + /* used internally by mpd, to mess with it*/ + float scale; +} ReplayGainInfo; + +ReplayGainInfo * newReplayGainInfo(); + +void freeReplayGainInfo(ReplayGainInfo * info); + void initReplayGainState(); -int getReplayGainState(); - -float computeReplayGainScale(float gain, float peak); - -void doReplayGain(char * buffer, int bufferSize, AudioFormat * format, - float scale); +void doReplayGain(ReplayGainInfo * info, char * buffer, int bufferSize, + AudioFormat * format); #endif