Commit 54679d90 authored by Warren Dukes's avatar Warren Dukes

rewrite replaygain code, needs testing

git-svn-id: https://svn.musicpd.org/mpd/trunk@2482 09075e82-0dd4-0310-85a5-a0d7c8717e4f
parent 1d105d12
...@@ -7,10 +7,6 @@ ...@@ -7,10 +7,6 @@
*) Steal resampling code from ices (i think this code works only for 16-bit) *) Steal resampling code from ices (i think this code works only for 16-bit)
*) Rewrite replaygain stuff: *) 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 *) If replaygain tag info present, average the replaygain gain's
and peak's on the fly and peak's on the fly
*) If NULL replaygain struct, then use the average replaygain gains *) If NULL replaygain struct, then use the average replaygain gains
......
...@@ -362,7 +362,7 @@ int aac_decode(OutputBuffer * cb, DecoderControl * dc, char * path) { ...@@ -362,7 +362,7 @@ int aac_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
sampleBufferLen = sampleCount*2; sampleBufferLen = sampleCount*2;
sendDataToOutputBuffer(cb, NULL, dc, 0, sampleBuffer, sendDataToOutputBuffer(cb, NULL, dc, 0, sampleBuffer,
sampleBufferLen, time, bitRate); sampleBufferLen, time, bitRate, NULL);
if(dc->seek) { if(dc->seek) {
dc->seekError = 1; dc->seekError = 1;
dc->seek = 0; dc->seek = 0;
......
...@@ -116,7 +116,8 @@ int audiofile_decode(OutputBuffer * cb, DecoderControl * dc, char * path) { ...@@ -116,7 +116,8 @@ int audiofile_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
ret*fs, ret*fs,
(float)current / (float)current /
(float)dc->audioFormat.sampleRate, (float)dc->audioFormat.sampleRate,
bitRate); bitRate,
NULL);
if(dc->stop) break; if(dc->stop) break;
} }
} }
......
...@@ -44,8 +44,8 @@ typedef struct { ...@@ -44,8 +44,8 @@ typedef struct {
OutputBuffer * cb; OutputBuffer * cb;
DecoderControl * dc; DecoderControl * dc;
InputStream inStream; InputStream inStream;
float replayGainScale;
char * path; char * path;
ReplayGainInfo * replayGainInfo;
} FlacData; } FlacData;
/* this code is based on flac123, from flac-tools */ /* this code is based on flac123, from flac-tools */
...@@ -82,7 +82,7 @@ int flac_decode(OutputBuffer * cb, DecoderControl *dc, char * path) { ...@@ -82,7 +82,7 @@ int flac_decode(OutputBuffer * cb, DecoderControl *dc, char * path) {
data.bitRate = 0; data.bitRate = 0;
data.cb = cb; data.cb = cb;
data.dc = dc; data.dc = dc;
data.replayGainScale = 1.0; data.replayGainInfo = NULL;
data.path = path; data.path = path;
if(openInputStream(&(data.inStream), path)<0) { if(openInputStream(&(data.inStream), path)<0) {
...@@ -195,6 +195,8 @@ int flac_decode(OutputBuffer * cb, DecoderControl *dc, char * path) { ...@@ -195,6 +195,8 @@ int flac_decode(OutputBuffer * cb, DecoderControl *dc, char * path) {
else dc->state = DECODE_STATE_STOP; else dc->state = DECODE_STATE_STOP;
fail: fail:
if(data.replayGainInfo) freeReplayGainInfo(data.replayGainInfo);
if(streamOpen) closeInputStream(&(data.inStream)); if(streamOpen) closeInputStream(&(data.inStream));
if(flacDec) FLAC__seekable_stream_decoder_delete(flacDec); if(flacDec) FLAC__seekable_stream_decoder_delete(flacDec);
...@@ -338,30 +340,28 @@ int flacFindVorbisCommentFloat(const FLAC__StreamMetadata * block, char * cmnt, ...@@ -338,30 +340,28 @@ int flacFindVorbisCommentFloat(const FLAC__StreamMetadata * block, char * cmnt,
/* replaygain stuff by AliasMrJones */ /* replaygain stuff by AliasMrJones */
void flacParseReplayGain(const FLAC__StreamMetadata *block, FlacData * data) { void flacParseReplayGain(const FLAC__StreamMetadata *block, FlacData * data) {
int found; if(NULL == data->replayGainInfo) {
float gain = 0.0; freeReplayGainInfo(data->replayGainInfo);
float peak = 0.0; data->replayGainInfo = NULL;
int state = getReplayGainState(); }
if(state == REPLAYGAIN_OFF) return; data->replayGainInfo = newReplayGainInfo();
found = flacFindVorbisCommentFloat(block,"replaygain_album_gain",&gain); int found = 0;
if(found) {
flacFindVorbisCommentFloat(block,"replaygain_album_peak",
&peak);
}
if(!found || state == REPLAYGAIN_TRACK) { found &= flacFindVorbisCommentFloat(block,"replaygain_album_gain",
found = flacFindVorbisCommentFloat(block, &data->replayGainInfo->albumGain);
"replaygain_track_gain", &gain); found &= flacFindVorbisCommentFloat(block,"replaygain_album_peak",
if(found) { &data->replayGainInfo->albumPeak);
peak = 0.0; found &= flacFindVorbisCommentFloat(block,"replaygain_track_gain",
flacFindVorbisCommentFloat(block, &data->replayGainInfo->trackGain);
"replaygain_track_peak",&peak); 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, void flacMetadata(const FLAC__SeekableStreamDecoder *dec,
...@@ -391,11 +391,9 @@ void flacMetadata(const FLAC__SeekableStreamDecoder *dec, ...@@ -391,11 +391,9 @@ void flacMetadata(const FLAC__SeekableStreamDecoder *dec,
} }
int flacSendChunk(FlacData * data) { 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, 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: case OUTPUT_BUFFER_DC_STOP:
return -1; return -1;
......
...@@ -191,7 +191,7 @@ int mod_decode(OutputBuffer * cb, DecoderControl * dc, char * path) { ...@@ -191,7 +191,7 @@ int mod_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
time += ret*secPerByte; time += ret*secPerByte;
sendDataToOutputBuffer(cb, NULL, dc, 0, sendDataToOutputBuffer(cb, NULL, dc, 0,
(char *)data->audio_buffer, ret, time, (char *)data->audio_buffer, ret, time,
0); 0, NULL);
} }
flushOutputBuffer(cb); flushOutputBuffer(cb);
......
...@@ -585,7 +585,8 @@ int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc) { ...@@ -585,7 +585,8 @@ int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc) {
data->outputPtr- data->outputPtr-
data->outputBuffer, data->outputBuffer,
data->elapsedTime, data->elapsedTime,
data->bitRate/1000); data->bitRate/1000,
NULL);
if(ret == OUTPUT_BUFFER_DC_STOP) { if(ret == OUTPUT_BUFFER_DC_STOP) {
data->flush = 0; data->flush = 0;
return DECODE_BREAK; return DECODE_BREAK;
...@@ -710,7 +711,8 @@ int mp3_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) { ...@@ -710,7 +711,8 @@ int mp3_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) {
data.inStream->seekable, data.inStream->seekable,
data.outputBuffer, data.outputBuffer,
data.outputPtr-data.outputBuffer, data.outputPtr-data.outputBuffer,
data.elapsedTime,data.bitRate/1000); data.elapsedTime,data.bitRate/1000,
NULL);
} }
closeInputStream(inStream); closeInputStream(inStream);
......
...@@ -284,7 +284,7 @@ int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char * path) { ...@@ -284,7 +284,7 @@ int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
sampleBuffer+=offset*channels*2; sampleBuffer+=offset*channels*2;
sendDataToOutputBuffer(cb, NULL, dc, 1, sampleBuffer, sendDataToOutputBuffer(cb, NULL, dc, 1, sampleBuffer,
sampleBufferLen, time, bitRate); sampleBufferLen, time, bitRate, NULL);
if(dc->stop) { if(dc->stop) {
eof = 1; eof = 1;
break; break;
......
...@@ -114,62 +114,45 @@ char * ogg_parseComment(char * comment, char * needle) { ...@@ -114,62 +114,45 @@ char * ogg_parseComment(char * comment, char * needle) {
return NULL; return NULL;
} }
float ogg_getReplayGainScale(char ** comments) { void ogg_getReplayGainInfo(char ** comments, ReplayGainInfo ** infoPtr) {
int trackGainFound = 0;
int albumGainFound = 0;
float trackGain = 1.0;
float albumGain = 1.0;
float trackPeak = 0.0;
float albumPeak = 0.0;
char * temp; char * temp;
int replayGainState = getReplayGainState(); int found = 0;
if(replayGainState == REPLAYGAIN_OFF) return 1.0; if(*infoPtr) freeReplayGainInfo(*infoPtr);
*infoPtr = newReplayGainInfo();
while(*comments) { while(*comments) {
if((temp = ogg_parseComment(*comments,"replaygain_track_gain"))) if((temp = ogg_parseComment(*comments,"replaygain_track_gain")))
{ {
trackGain = atof(temp); (*infoPtr)->trackGain = atof(temp);
trackGainFound = 1; found = 1;
} }
else if((temp = ogg_parseComment(*comments, else if((temp = ogg_parseComment(*comments,
"replaygain_album_gain"))) "replaygain_album_gain")))
{ {
albumGain = atof(temp); (*infoPtr)->albumGain = atof(temp);
albumGainFound = 1; found = 1;
} }
else if((temp = ogg_parseComment(*comments, else if((temp = ogg_parseComment(*comments,
"replaygain_track_peak"))) "replaygain_track_peak")))
{ {
trackPeak = atof(temp); (*infoPtr)->trackPeak = atof(temp);
found = 1;
} }
else if((temp = ogg_parseComment(*comments, else if((temp = ogg_parseComment(*comments,
"replaygain_album_peak"))) "replaygain_album_peak")))
{ {
albumPeak = atof(temp); (*infoPtr)->albumPeak = atof(temp);
found = 1;
} }
comments++; comments++;
} }
switch(replayGainState) { if(!found) {
case REPLAYGAIN_ALBUM: freeReplayGainInfo(*infoPtr);
if(albumGainFound) { *infoPtr = NULL;
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;
} }
MpdTag * oggCommentsParse(char ** comments) { MpdTag * oggCommentsParse(char ** comments) {
...@@ -248,7 +231,7 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) ...@@ -248,7 +231,7 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
int chunkpos = 0; int chunkpos = 0;
long bitRate = 0; long bitRate = 0;
long test; long test;
float replayGainScale = 1.0; ReplayGainInfo * replayGainInfo = NULL;
char ** comments; char ** comments;
data.inStream = inStream; data.inStream = inStream;
...@@ -304,7 +287,7 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) ...@@ -304,7 +287,7 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
comments = ov_comment(&vf, -1)->user_comments; comments = ov_comment(&vf, -1)->user_comments;
putOggCommentsIntoOutputBuffer(cb, inStream->metaName, putOggCommentsIntoOutputBuffer(cb, inStream->metaName,
comments); comments);
replayGainScale = ogg_getReplayGainScale(comments); ogg_getReplayGainInfo(comments, &replayGainInfo);
} }
prev_section = current_section; prev_section = current_section;
...@@ -321,14 +304,13 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) ...@@ -321,14 +304,13 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
if((test = ov_bitrate_instant(&vf))>0) { if((test = ov_bitrate_instant(&vf))>0) {
bitRate = test/1000; bitRate = test/1000;
} }
doReplayGain(chunk,chunkpos,&(dc->audioFormat),
replayGainScale);
sendDataToOutputBuffer(cb, inStream, dc, sendDataToOutputBuffer(cb, inStream, dc,
inStream->seekable, inStream->seekable,
chunk, chunkpos, chunk, chunkpos,
ov_pcm_tell(&vf)/ ov_pcm_tell(&vf)/
dc->audioFormat.sampleRate, dc->audioFormat.sampleRate,
bitRate); bitRate,
replayGainInfo);
chunkpos = 0; chunkpos = 0;
if(dc->stop) break; if(dc->stop) break;
} }
...@@ -337,9 +319,11 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) ...@@ -337,9 +319,11 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
if(!dc->stop && chunkpos > 0) { if(!dc->stop && chunkpos > 0) {
sendDataToOutputBuffer(cb, NULL, dc, inStream->seekable, sendDataToOutputBuffer(cb, NULL, dc, inStream->seekable,
chunk, chunkpos, chunk, chunkpos,
ov_time_tell(&vf), bitRate); ov_time_tell(&vf), bitRate, replayGainInfo);
} }
if(replayGainInfo) freeReplayGainInfo(replayGainInfo);
ov_clear(&vf); ov_clear(&vf);
flushOutputBuffer(cb); flushOutputBuffer(cb);
......
...@@ -64,7 +64,8 @@ void flushOutputBuffer(OutputBuffer * cb) { ...@@ -64,7 +64,8 @@ void flushOutputBuffer(OutputBuffer * cb) {
int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream, int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
DecoderControl * dc, int seekable, char * dataIn, 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 dataToSend;
mpd_uint16 chunkLeft; mpd_uint16 chunkLeft;
...@@ -91,6 +92,8 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream, ...@@ -91,6 +92,8 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
&(cb->audioFormat),data); &(cb->audioFormat),data);
} }
doReplayGain(replayGainInfo, data, datalen, &cb->audioFormat);
while(datalen) { while(datalen) {
if(currentChunk != cb->end) { if(currentChunk != cb->end) {
int next = cb->end+1; int next = cb->end+1;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "audio.h" #include "audio.h"
#include "inputStream.h" #include "inputStream.h"
#include "metadataChunk.h" #include "metadataChunk.h"
#include "replayGain.h"
#define OUTPUT_BUFFER_DC_STOP -1 #define OUTPUT_BUFFER_DC_STOP -1
#define OUTPUT_BUFFER_DC_SEEK -2 #define OUTPUT_BUFFER_DC_SEEK -2
...@@ -50,9 +51,16 @@ void flushOutputBuffer(OutputBuffer * cb); ...@@ -50,9 +51,16 @@ void flushOutputBuffer(OutputBuffer * cb);
/* we send inStream for buffering the inputStream while waiting to /* we send inStream for buffering the inputStream while waiting to
send the next chunk */ send the next chunk */
int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream, int sendDataToOutputBuffer(
DecoderControl * dc, int seekable, char * data, long datalen, OutputBuffer * cb,
float time, mpd_uint16 bitRate); InputStream * inStream,
DecoderControl * dc,
int seekable,
char * data,
long datalen,
float time,
mpd_uint16 bitRate,
ReplayGainInfo * replayGainInfo);
int copyMpdTagToOutputBuffer(OutputBuffer * cb, MpdTag * tag); int copyMpdTagToOutputBuffer(OutputBuffer * cb, MpdTag * tag);
......
...@@ -71,11 +71,7 @@ void initReplayGainState() { ...@@ -71,11 +71,7 @@ void initReplayGainState() {
} }
} }
int getReplayGainState() { static float computeReplayGainScale(float gain, float peak) {
return replayGainState;
}
float computeReplayGainScale(float gain, float peak) {
float scale; float scale;
if(gain == 0.0) return(1); if(gain == 0.0) return(1);
...@@ -89,14 +85,55 @@ float computeReplayGainScale(float gain, float peak) { ...@@ -89,14 +85,55 @@ float computeReplayGainScale(float gain, float peak) {
return(scale); return(scale);
} }
void doReplayGain(char * buffer, int bufferSize, AudioFormat * format, ReplayGainInfo * newReplayGainInfo() {
float scale) 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_sint16 *)buffer; mpd_sint16 * buffer16;
mpd_sint8 * buffer8 = (mpd_sint8 *)buffer; mpd_sint8 * buffer8;
mpd_sint32 temp32; 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) { switch(format->bits) {
case 16: case 16:
while(bufferSize > 0){ while(bufferSize > 0){
...@@ -122,4 +159,3 @@ void doReplayGain(char * buffer, int bufferSize, AudioFormat * format, ...@@ -122,4 +159,3 @@ void doReplayGain(char * buffer, int bufferSize, AudioFormat * format,
ERROR("%i bits not supported by doReplaygain!\n", format->bits); ERROR("%i bits not supported by doReplaygain!\n", format->bits);
} }
} }
/* End of added code */
...@@ -26,13 +26,23 @@ ...@@ -26,13 +26,23 @@
#define REPLAYGAIN_TRACK 1 #define REPLAYGAIN_TRACK 1
#define REPLAYGAIN_ALBUM 2 #define REPLAYGAIN_ALBUM 2
void initReplayGainState(); typedef struct _ReplayGainInfo {
float albumGain;
float albumPeak;
float trackGain;
float trackPeak;
/* used internally by mpd, to mess with it*/
float scale;
} ReplayGainInfo;
int getReplayGainState(); ReplayGainInfo * newReplayGainInfo();
float computeReplayGainScale(float gain, float peak); void freeReplayGainInfo(ReplayGainInfo * info);
void initReplayGainState();
void doReplayGain(char * buffer, int bufferSize, AudioFormat * format, void doReplayGain(ReplayGainInfo * info, char * buffer, int bufferSize,
float scale); AudioFormat * format);
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment