Commit 04fdc209 authored by Warren Dukes's avatar Warren Dukes

add replayGain stuff for flac from AliasMrJones

git-svn-id: https://svn.musicpd.org/mpd/trunk@943 09075e82-0dd4-0310-85a5-a0d7c8717e4f
parent ff332333
...@@ -6,14 +6,14 @@ mpd_headers = buffer2array.h interface.h command.h playlist.h ls.h \ ...@@ -6,14 +6,14 @@ mpd_headers = buffer2array.h interface.h command.h playlist.h ls.h \
audio.h playerData.h stats.h myfprintf.h sig_handlers.h decode.h log.h \ audio.h playerData.h stats.h myfprintf.h sig_handlers.h decode.h log.h \
audiofile_decode.h charConv.h permission.h mpd_types.h pcm_utils.h \ audiofile_decode.h charConv.h permission.h mpd_types.h pcm_utils.h \
mp4_decode.h aac_decode.h signal_check.h utf8.h inputStream.h \ mp4_decode.h aac_decode.h signal_check.h utf8.h inputStream.h \
outputBuffer.h outputBuffer.h replayGain.h
mpd_SOURCES = main.c buffer2array.c interface.c command.c playlist.c ls.c \ mpd_SOURCES = main.c buffer2array.c interface.c command.c playlist.c ls.c \
song.c list.c directory.c tables.c utils.c path.c mp3_decode.c \ song.c list.c directory.c tables.c utils.c path.c mp3_decode.c \
tag.c player.c listen.c conf.c ogg_decode.c volume.c flac_decode.c \ tag.c player.c listen.c conf.c ogg_decode.c volume.c flac_decode.c \
audio.c playerData.c stats.c myfprintf.c sig_handlers.c decode.c log.c \ audio.c playerData.c stats.c myfprintf.c sig_handlers.c decode.c log.c \
audiofile_decode.c charConv.c permission.c pcm_utils.c mp4_decode.c \ audiofile_decode.c charConv.c permission.c pcm_utils.c mp4_decode.c \
aac_decode.c signal_check.c utf8.c inputStream.c outputBuffer.c \ aac_decode.c signal_check.c utf8.c inputStream.c outputBuffer.c \
$(mpd_headers) replayGain.c $(mpd_headers)
mpd_CFLAGS = $(MPD_CFLAGS) mpd_CFLAGS = $(MPD_CFLAGS)
mpd_LDADD = $(MPD_LIBS) $(ID3_LIB) $(MAD_LIB) $(MP4FF_LIB) mpd_LDADD = $(MPD_LIBS) $(ID3_LIB) $(MAD_LIB) $(MP4FF_LIB)
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
#define CONF_COMMENT '#' #define CONF_COMMENT '#'
#define CONF_NUMBER_OF_PARAMS 27 #define CONF_NUMBER_OF_PARAMS 28
#define CONF_NUMBER_OF_PATHS 6 #define CONF_NUMBER_OF_PATHS 6
#define CONF_NUMBER_OF_REQUIRED 5 #define CONF_NUMBER_OF_REQUIRED 5
#define CONF_NUMBER_OF_ALLOW_CATS 1 #define CONF_NUMBER_OF_ALLOW_CATS 1
...@@ -123,7 +123,8 @@ char ** readConf(char * file) { ...@@ -123,7 +123,8 @@ char ** readConf(char * file) {
"filesystem_charset", "filesystem_charset",
"password", "password",
"default_permissions", "default_permissions",
"buffer_size" "buffer_size",
"replaygain"
}; };
int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = { int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = {
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#define CONF_PASSWORD 24 #define CONF_PASSWORD 24
#define CONF_DEFAULT_PERMISSIONS 25 #define CONF_DEFAULT_PERMISSIONS 25
#define CONF_BUFFER_SIZE 26 #define CONF_BUFFER_SIZE 26
#define CONF_REPLAYGAIN 27
#define CONF_CAT_CHAR "\n" #define CONF_CAT_CHAR "\n"
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "pcm_utils.h" #include "pcm_utils.h"
#include "inputStream.h" #include "inputStream.h"
#include "outputBuffer.h" #include "outputBuffer.h"
#include "replayGain.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
...@@ -41,8 +42,8 @@ typedef struct { ...@@ -41,8 +42,8 @@ typedef struct {
OutputBuffer * cb; OutputBuffer * cb;
AudioFormat * af; AudioFormat * af;
DecoderControl * dc; DecoderControl * dc;
char * file;
InputStream inStream; InputStream inStream;
float replayGainScale;
} FlacData; } FlacData;
/* this code is based on flac123, from flac-tools */ /* this code is based on flac123, from flac-tools */
...@@ -66,9 +67,7 @@ FLAC__SeekableStreamDecoderLengthStatus flacLength( ...@@ -66,9 +67,7 @@ FLAC__SeekableStreamDecoderLengthStatus flacLength(
const FLAC__SeekableStreamDecoder *, FLAC__uint64 *, void *); const FLAC__SeekableStreamDecoder *, FLAC__uint64 *, void *);
FLAC__bool flacEOF(const FLAC__SeekableStreamDecoder *, void *); FLAC__bool flacEOF(const FLAC__SeekableStreamDecoder *, void *);
void flacPlayFile(char *file, OutputBuffer * cb, AudioFormat * af, int flac_decode(OutputBuffer * cb, AudioFormat * af, DecoderControl *dc) {
DecoderControl *dc)
{
FLAC__SeekableStreamDecoder * flacDec; FLAC__SeekableStreamDecoder * flacDec;
FlacData data; FlacData data;
int status = 1; int status = 1;
...@@ -80,14 +79,14 @@ void flacPlayFile(char *file, OutputBuffer * cb, AudioFormat * af, ...@@ -80,14 +79,14 @@ void flacPlayFile(char *file, OutputBuffer * cb, AudioFormat * af,
data.cb = cb; data.cb = cb;
data.af = af; data.af = af;
data.dc = dc; data.dc = dc;
data.file = file; data.replayGainScale = 1.0;
if(openInputStreamFromFile(&(data.inStream),file)<0) { if(openInputStreamFromFile(&(data.inStream),dc->file)<0) {
ERROR("unable to open flac: %s\n",file); ERROR("unable to open flac: %s\n",dc->file);
return; return -1;
} }
if(!(flacDec = FLAC__seekable_stream_decoder_new())) return; if(!(flacDec = FLAC__seekable_stream_decoder_new())) return -1;
/*status&=FLAC__file_decoder_set_md5_checking(flacDec,1);*/ /*status&=FLAC__file_decoder_set_md5_checking(flacDec,1);*/
status&=FLAC__seekable_stream_decoder_set_read_callback(flacDec, status&=FLAC__seekable_stream_decoder_set_read_callback(flacDec,
flacRead); flacRead);
...@@ -107,28 +106,37 @@ void flacPlayFile(char *file, OutputBuffer * cb, AudioFormat * af, ...@@ -107,28 +106,37 @@ void flacPlayFile(char *file, OutputBuffer * cb, AudioFormat * af,
status&=FLAC__seekable_stream_decoder_set_client_data(flacDec, status&=FLAC__seekable_stream_decoder_set_client_data(flacDec,
(void *)&data); (void *)&data);
if(!status) { if(!status) {
ERROR("flac problem before init(): %s\n",file); ERROR("flac problem before init(): %s\n",dc->file);
flacPrintErroredState( flacPrintErroredState(
FLAC__seekable_stream_decoder_get_state(flacDec),file); FLAC__seekable_stream_decoder_get_state(flacDec),
dc->file);
FLAC__seekable_stream_decoder_delete(flacDec); FLAC__seekable_stream_decoder_delete(flacDec);
return; return -1;
} }
if(FLAC__seekable_stream_decoder_init(flacDec)!= if(FLAC__seekable_stream_decoder_init(flacDec)!=
FLAC__STREAM_DECODER_SEARCH_FOR_METADATA) FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
{ {
ERROR("flac problem doing init(): %s\n",file); ERROR("flac problem doing init(): %s\n",dc->file);
flacPrintErroredState( flacPrintErroredState(
FLAC__seekable_stream_decoder_get_state(flacDec),file); FLAC__seekable_stream_decoder_get_state(flacDec),
dc->file);
FLAC__seekable_stream_decoder_delete(flacDec); FLAC__seekable_stream_decoder_delete(flacDec);
return; return -1;
} }
if(!FLAC__seekable_stream_decoder_process_until_end_of_metadata(flacDec)) { if(!FLAC__seekable_stream_decoder_process_until_end_of_metadata(flacDec)) {
ERROR("flac problem reading metadata: %s\n",file); ERROR("flac problem reading metadata: %s\n", dc->file);
flacPrintErroredState( flacPrintErroredState(
FLAC__seekable_stream_decoder_get_state(flacDec),file); FLAC__seekable_stream_decoder_get_state(flacDec),
dc->file);
FLAC__seekable_stream_decoder_delete(flacDec); FLAC__seekable_stream_decoder_delete(flacDec);
return; return -1;
} }
dc->state = DECODE_STATE_DECODE;
dc->start = 0;
while(1) { while(1) {
FLAC__seekable_stream_decoder_process_single(flacDec); FLAC__seekable_stream_decoder_process_single(flacDec);
if(FLAC__seekable_stream_decoder_get_state(flacDec)!= if(FLAC__seekable_stream_decoder_get_state(flacDec)!=
...@@ -155,7 +163,8 @@ void flacPlayFile(char *file, OutputBuffer * cb, AudioFormat * af, ...@@ -155,7 +163,8 @@ void flacPlayFile(char *file, OutputBuffer * cb, AudioFormat * af,
/*FLAC__file_decoder_process_until_end_of_file(flacDec);*/ /*FLAC__file_decoder_process_until_end_of_file(flacDec);*/
if(!dc->stop) { if(!dc->stop) {
flacPrintErroredState( flacPrintErroredState(
FLAC__seekable_stream_decoder_get_state(flacDec),file); FLAC__seekable_stream_decoder_get_state(flacDec),
dc->file);
FLAC__seekable_stream_decoder_finish(flacDec); FLAC__seekable_stream_decoder_finish(flacDec);
} }
FLAC__seekable_stream_decoder_delete(flacDec); FLAC__seekable_stream_decoder_delete(flacDec);
...@@ -164,6 +173,16 @@ void flacPlayFile(char *file, OutputBuffer * cb, AudioFormat * af, ...@@ -164,6 +173,16 @@ void flacPlayFile(char *file, OutputBuffer * cb, AudioFormat * af,
flacSendChunk(&data); flacSendChunk(&data);
flushOutputBuffer(data.cb); flushOutputBuffer(data.cb);
} }
if(dc->seek) dc->seek = 0;
if(dc->stop) {
dc->state = DECODE_STATE_STOP;
dc->stop = 0;
}
else dc->state = DECODE_STATE_STOP;
return 0;
} }
FLAC__SeekableStreamDecoderReadStatus flacRead( FLAC__SeekableStreamDecoderReadStatus flacRead(
...@@ -232,16 +251,16 @@ void flacError(const FLAC__SeekableStreamDecoder *dec, ...@@ -232,16 +251,16 @@ void flacError(const FLAC__SeekableStreamDecoder *dec,
switch(status) { switch(status) {
case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC: case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
ERROR("flac lost sync: %s\n",data->file); ERROR("flac lost sync: %s\n",data->dc->file);
break; break;
case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER: case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
ERROR("bad header %s\n",data->file); ERROR("bad header %s\n",data->dc->file);
break; break;
case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH: case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
ERROR("crc mismatch %s\n",data->file); ERROR("crc mismatch %s\n",data->dc->file);
break; break;
default: default:
ERROR("unknow flac error %s\n",data->file); ERROR("unknow flac error %s\n",data->dc->file);
} }
} }
...@@ -277,12 +296,83 @@ void flacPrintErroredState(FLAC__SeekableStreamDecoderState state, ...@@ -277,12 +296,83 @@ void flacPrintErroredState(FLAC__SeekableStreamDecoderState state,
} }
} }
int flacFindVorbisCommentFloat(const FLAC__StreamMetadata * block, char * cmnt,
float * fl)
{
int offset = FLAC__metadata_object_vorbiscomment_find_entry_from(
block,0,cmnt);
if(offset >= 0) {
int pos = strlen(cmnt)+1; /* 1 is for '=' */
int len = block->data.vorbis_comment.comments[offset].length
-pos;
if(len > 0) {
char * dup = malloc(len+1);
memcpy(dup,&(block->data.vorbis_comment.comments[offset].entry[pos]),len);
dup[len] = '\0';
*fl = atof(dup);
free(dup);
return 1;
}
}
return 0;
}
/* 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(state == REPLAYGAIN_OFF) return;
found = flacFindVorbisCommentFloat(block,"replaygain_album_gain",&gain);
if(found) {
flacFindVorbisCommentFloat(block,"replaygain_album_peak",
&peak);
}
if(!found || state == REPLAYGAIN_TRACK) {
if(flacFindVorbisCommentFloat(block,"replaygain_track_gain",
&gain))
{
peak = 0.0;
flacFindVorbisCommentFloat(block,
"replaygain_track_peak",&peak);
}
}
data->replayGainScale = computeReplayGainScale(gain,peak);
}
void flacMetadata(const FLAC__SeekableStreamDecoder *dec, void flacMetadata(const FLAC__SeekableStreamDecoder *dec,
const FLAC__StreamMetadata *meta, void *data) const FLAC__StreamMetadata *block, void *vdata)
{ {
FlacData * data = (FlacData *)vdata;
switch(block->type) {
case FLAC__METADATA_TYPE_STREAMINFO:
data->af->bits = block->data.stream_info.bits_per_sample;
data->af->bits = 16;
data->af->sampleRate = block->data.stream_info.sample_rate;
data->af->channels = block->data.stream_info.channels;
data->cb->totalTime =
((float)block->data.stream_info.total_samples)/
data->af->sampleRate;
break;
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
flacParseReplayGain(block,data);
default:
break;
}
} }
int flacSendChunk(FlacData * data) { int flacSendChunk(FlacData * data) {
doReplayGain(data->chunk,data->chunk_length,data->af,
data->replayGainScale);
switch(sendDataToOutputBuffer(data->cb,data->dc,data->chunk, switch(sendDataToOutputBuffer(data->cb,data->dc,data->chunk,
data->chunk_length,data->time,data->bitRate)) data->chunk_length,data->time,data->bitRate))
{ {
...@@ -341,70 +431,5 @@ FLAC__StreamDecoderWriteStatus flacWrite(const FLAC__SeekableStreamDecoder *dec, ...@@ -341,70 +431,5 @@ FLAC__StreamDecoderWriteStatus flacWrite(const FLAC__SeekableStreamDecoder *dec,
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
} }
int flac_getAudioFormatAndTime(char * file, AudioFormat * format, float * time) {
FLAC__Metadata_SimpleIterator * it;
FLAC__StreamMetadata * block = NULL;
int found = 0;
int ret = -1;
if(!(it = FLAC__metadata_simple_iterator_new())) return -1;
if(!FLAC__metadata_simple_iterator_init(it,file,1,0)) {
FLAC__metadata_simple_iterator_delete(it);
return -1;
}
do {
if(block) FLAC__metadata_object_delete(block);
block = FLAC__metadata_simple_iterator_get_block(it);
if(block->type == FLAC__METADATA_TYPE_STREAMINFO) found=1;
} while(!found && FLAC__metadata_simple_iterator_next(it));
if(found) {
format->bits = block->data.stream_info.bits_per_sample;
format->bits = 16;
format->sampleRate = block->data.stream_info.sample_rate;
format->channels = block->data.stream_info.channels;
*time = ((float)block->data.stream_info.total_samples)/
format->sampleRate;
ret = 0;
}
if(block) FLAC__metadata_object_delete(block);
FLAC__metadata_simple_iterator_delete(it);
return ret;
}
int getFlacTotalTime(char * file) {
float totalTime;
AudioFormat af;
if(flac_getAudioFormatAndTime(file,&af,&totalTime)<0) return -1;
return (int)(totalTime+0.5);
}
int flac_decode(OutputBuffer * cb, AudioFormat * af, DecoderControl * dc) {
if(flac_getAudioFormatAndTime(dc->file,af,&(cb->totalTime))<0) {
ERROR("\"%s\" doesn't seem to be a flac\n",dc->file);
return -1;
}
dc->state = DECODE_STATE_DECODE;
dc->start = 0;
flacPlayFile(dc->file,cb,af,dc);
if(dc->seek) dc->seek = 0;
if(dc->stop) {
dc->state = DECODE_STATE_STOP;
dc->stop = 0;
}
else dc->state = DECODE_STATE_STOP;
return 0;
}
#endif #endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */ /* vim:set shiftwidth=8 tabstop=8 expandtab: */
...@@ -27,7 +27,5 @@ ...@@ -27,7 +27,5 @@
int flac_decode(OutputBuffer * cb, AudioFormat * af, DecoderControl * dc); int flac_decode(OutputBuffer * cb, AudioFormat * af, DecoderControl * dc);
int getFlacTotalTime(char * file);
#endif #endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */ /* vim:set shiftwidth=8 tabstop=8 expandtab: */
#include "replayGain.h"
#include "log.h"
#include "conf.h"
#include <string.h>
#include <math.h>
#include <stdlib.h>
/* Added 4/14/2004 by AliasMrJones */
static int replayGainState = REPLAYGAIN_OFF;
void initReplayGainState() {
if(!getConf()[CONF_REPLAYGAIN]) return;
if(strcmp(getConf()[CONF_REPLAYGAIN],"track")==0) {
replayGainState = REPLAYGAIN_TRACK;
}
else if(strcmp(getConf()[CONF_REPLAYGAIN],"album")==0) {
replayGainState = REPLAYGAIN_ALBUM;
}
else {
ERROR("replaygain value \"%s\" is invalid\n",
getConf()[CONF_REPLAYGAIN]);
exit(EXIT_FAILURE);
}
}
int getReplayGainState() {
return replayGainState;
}
float computeReplayGainScale(float gain, float peak){
float scale;
if(gain == 0.0) return(1);
scale = pow(10.0, gain/20.0);
if(scale > 15.0) scale = 15.0;
if (scale * peak > 1.0) {
scale = 1.0 / 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;
if(scale == 1.0) return;
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--;
}
break;
default:
ERROR("%i bits not supported by doReplaygain!\n", format->bits);
}
}
/* End of added code */
#ifndef REPLAYGAIN_H
#define REPLAYGAIN_H
#include "audio.h"
#define REPLAYGAIN_OFF 0
#define REPLAYGAIN_TRACK 1
#define REPLAYGAIN_ALBUM 2
void initReplayGainState();
int getReplayGainState();
float computeReplayGainScale(float gain, float peak);
void doReplayGain(char * buffer, int bufferSize, AudioFormat * format,
float scale);
#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