add replayGain stuff for flac from AliasMrJones

git-svn-id: https://svn.musicpd.org/mpd/trunk@943 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
Warren Dukes 2004-05-07 22:42:54 +00:00
parent ff3323334a
commit 04fdc209d9
7 changed files with 222 additions and 98 deletions

View File

@ -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 \
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 \
outputBuffer.h
outputBuffer.h replayGain.h
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 \
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 \
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 \
$(mpd_headers)
replayGain.c $(mpd_headers)
mpd_CFLAGS = $(MPD_CFLAGS)
mpd_LDADD = $(MPD_LIBS) $(ID3_LIB) $(MAD_LIB) $(MP4FF_LIB)

View File

@ -37,7 +37,7 @@
#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_REQUIRED 5
#define CONF_NUMBER_OF_ALLOW_CATS 1
@ -123,7 +123,8 @@ char ** readConf(char * file) {
"filesystem_charset",
"password",
"default_permissions",
"buffer_size"
"buffer_size",
"replaygain"
};
int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = {

View File

@ -48,6 +48,7 @@
#define CONF_PASSWORD 24
#define CONF_DEFAULT_PERMISSIONS 25
#define CONF_BUFFER_SIZE 26
#define CONF_REPLAYGAIN 27
#define CONF_CAT_CHAR "\n"

View File

@ -25,6 +25,7 @@
#include "pcm_utils.h"
#include "inputStream.h"
#include "outputBuffer.h"
#include "replayGain.h"
#include <stdio.h>
#include <string.h>
@ -41,8 +42,8 @@ typedef struct {
OutputBuffer * cb;
AudioFormat * af;
DecoderControl * dc;
char * file;
InputStream inStream;
float replayGainScale;
} FlacData;
/* this code is based on flac123, from flac-tools */
@ -66,9 +67,7 @@ FLAC__SeekableStreamDecoderLengthStatus flacLength(
const FLAC__SeekableStreamDecoder *, FLAC__uint64 *, void *);
FLAC__bool flacEOF(const FLAC__SeekableStreamDecoder *, void *);
void flacPlayFile(char *file, OutputBuffer * cb, AudioFormat * af,
DecoderControl *dc)
{
int flac_decode(OutputBuffer * cb, AudioFormat * af, DecoderControl *dc) {
FLAC__SeekableStreamDecoder * flacDec;
FlacData data;
int status = 1;
@ -80,14 +79,14 @@ void flacPlayFile(char *file, OutputBuffer * cb, AudioFormat * af,
data.cb = cb;
data.af = af;
data.dc = dc;
data.file = file;
data.replayGainScale = 1.0;
if(openInputStreamFromFile(&(data.inStream),file)<0) {
ERROR("unable to open flac: %s\n",file);
return;
if(openInputStreamFromFile(&(data.inStream),dc->file)<0) {
ERROR("unable to open flac: %s\n",dc->file);
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__seekable_stream_decoder_set_read_callback(flacDec,
flacRead);
@ -107,28 +106,37 @@ void flacPlayFile(char *file, OutputBuffer * cb, AudioFormat * af,
status&=FLAC__seekable_stream_decoder_set_client_data(flacDec,
(void *)&data);
if(!status) {
ERROR("flac problem before init(): %s\n",file);
ERROR("flac problem before init(): %s\n",dc->file);
flacPrintErroredState(
FLAC__seekable_stream_decoder_get_state(flacDec),file);
FLAC__seekable_stream_decoder_get_state(flacDec),
dc->file);
FLAC__seekable_stream_decoder_delete(flacDec);
return;
return -1;
}
if(FLAC__seekable_stream_decoder_init(flacDec)!=
FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
{
ERROR("flac problem doing init(): %s\n",file);
ERROR("flac problem doing init(): %s\n",dc->file);
flacPrintErroredState(
FLAC__seekable_stream_decoder_get_state(flacDec),file);
FLAC__seekable_stream_decoder_get_state(flacDec),
dc->file);
FLAC__seekable_stream_decoder_delete(flacDec);
return;
return -1;
}
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(
FLAC__seekable_stream_decoder_get_state(flacDec),file);
FLAC__seekable_stream_decoder_get_state(flacDec),
dc->file);
FLAC__seekable_stream_decoder_delete(flacDec);
return;
return -1;
}
dc->state = DECODE_STATE_DECODE;
dc->start = 0;
while(1) {
FLAC__seekable_stream_decoder_process_single(flacDec);
if(FLAC__seekable_stream_decoder_get_state(flacDec)!=
@ -155,7 +163,8 @@ void flacPlayFile(char *file, OutputBuffer * cb, AudioFormat * af,
/*FLAC__file_decoder_process_until_end_of_file(flacDec);*/
if(!dc->stop) {
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_delete(flacDec);
@ -164,6 +173,16 @@ void flacPlayFile(char *file, OutputBuffer * cb, AudioFormat * af,
flacSendChunk(&data);
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(
@ -232,16 +251,16 @@ void flacError(const FLAC__SeekableStreamDecoder *dec,
switch(status) {
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;
case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
ERROR("bad header %s\n",data->file);
ERROR("bad header %s\n",data->dc->file);
break;
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;
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,
}
}
void flacMetadata(const FLAC__SeekableStreamDecoder *dec,
const FLAC__StreamMetadata *meta, void *data)
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,
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) {
doReplayGain(data->chunk,data->chunk_length,data->af,
data->replayGainScale);
switch(sendDataToOutputBuffer(data->cb,data->dc,data->chunk,
data->chunk_length,data->time,data->bitRate))
{
@ -341,70 +431,5 @@ FLAC__StreamDecoderWriteStatus flacWrite(const FLAC__SeekableStreamDecoder *dec,
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
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
/* vim:set shiftwidth=8 tabstop=8 expandtab: */

View File

@ -27,7 +27,5 @@
int flac_decode(OutputBuffer * cb, AudioFormat * af, DecoderControl * dc);
int getFlacTotalTime(char * file);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
/* vim:set shiftwidth=8 tabstop=8 expandtab: */

80
src/replayGain.c Normal file
View File

@ -0,0 +1,80 @@
#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 */

19
src/replayGain.h Normal file
View File

@ -0,0 +1,19 @@
#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