diff options
Diffstat (limited to '')
-rw-r--r-- | src/decoder_api.c | 16 | ||||
-rw-r--r-- | src/decoder_internal.h | 2 | ||||
-rw-r--r-- | src/decoder_thread.c | 7 | ||||
-rw-r--r-- | src/replay_gain.c | 55 | ||||
-rw-r--r-- | src/replay_gain.h | 11 | ||||
-rw-r--r-- | src/replay_gain_state.c | 142 | ||||
-rw-r--r-- | src/replay_gain_state.h | 50 |
7 files changed, 207 insertions, 76 deletions
diff --git a/src/decoder_api.c b/src/decoder_api.c index 5106b564f..8e1e22f9d 100644 --- a/src/decoder_api.c +++ b/src/decoder_api.c @@ -27,6 +27,7 @@ #include "buffer.h" #include "pipe.h" #include "chunk.h" +#include "replay_gain_state.h" #include <glib.h> @@ -352,10 +353,10 @@ decoder_data(struct decoder *decoder, /* apply replay gain or normalization */ - if (replay_gain_mode != REPLAY_GAIN_OFF) - replay_gain_apply(decoder->replay_gain, - dest, nbytes, - &dc->out_audio_format); + replay_gain_state_set_mode(decoder->replay_gain, + replay_gain_mode); + replay_gain_state_apply(decoder->replay_gain, + dest, nbytes, &dc->out_audio_format); /* expand the music pipe chunk */ @@ -425,10 +426,5 @@ decoder_replay_gain(struct decoder *decoder, { assert(decoder != NULL); - if (decoder->replay_gain != NULL) - replay_gain_info_free(decoder->replay_gain); - - decoder->replay_gain = replay_gain_info != NULL - ? replay_gain_info_dup(replay_gain_info) - : NULL; + replay_gain_state_set_info(decoder->replay_gain, replay_gain_info); } diff --git a/src/decoder_internal.h b/src/decoder_internal.h index b15b06888..159b40b92 100644 --- a/src/decoder_internal.h +++ b/src/decoder_internal.h @@ -53,7 +53,7 @@ struct decoder { /** the chunk currently being written to */ struct music_chunk *chunk; - struct replay_gain_info *replay_gain; + struct replay_gain_state *replay_gain; }; /** diff --git a/src/decoder_thread.c b/src/decoder_thread.c index f793fd032..625ec46cc 100644 --- a/src/decoder_thread.c +++ b/src/decoder_thread.c @@ -31,7 +31,7 @@ #include "mapper.h" #include "path.h" #include "uri.h" -#include "replay_gain.h" +#include "replay_gain_state.h" #include <glib.h> @@ -303,7 +303,8 @@ decoder_run_song(struct decoder_control *dc, { struct decoder decoder = { .dc = dc, - .replay_gain = NULL, + .replay_gain = replay_gain_state_new(replay_gain_preamp, + replay_gain_missing_preamp), }; int ret; @@ -332,7 +333,7 @@ decoder_run_song(struct decoder_control *dc, /* flush the last chunk */ if (decoder.replay_gain != NULL) - replay_gain_info_free(decoder.replay_gain); + replay_gain_state_free(decoder.replay_gain); if (decoder.chunk != NULL) decoder_flush_chunk(&decoder); diff --git a/src/replay_gain.c b/src/replay_gain.c index 482cd4bd3..3537a96ed 100644 --- a/src/replay_gain.c +++ b/src/replay_gain.c @@ -23,8 +23,6 @@ #include "config.h" #include "replay_gain.h" #include "conf.h" -#include "audio_format.h" -#include "pcm_volume.h" #include "idle.h" #include <glib.h> @@ -41,8 +39,8 @@ static const char *const replay_gain_mode_names[] = { enum replay_gain_mode replay_gain_mode = REPLAY_GAIN_OFF; -static float replay_gain_preamp = 1.0; -static float replay_gain_missing_preamp = 1.0; +float replay_gain_preamp = 1.0; +float replay_gain_missing_preamp = 1.0; const char * replay_gain_get_mode_string(void) @@ -130,23 +128,6 @@ void replay_gain_global_init(void) } } -static float calc_replay_gain_scale(float gain, float peak) -{ - float scale; - - if (gain == 0.0) - return (1); - scale = pow(10.0, gain / 20.0); - scale *= replay_gain_preamp; - if (scale > 15.0) - scale = 15.0; - - if (scale * peak > 1.0) { - scale = 1.0 / peak; - } - return (scale); -} - struct replay_gain_info *replay_gain_info_new(void) { struct replay_gain_info *ret = g_new(struct replay_gain_info, 1); @@ -156,9 +137,6 @@ struct replay_gain_info *replay_gain_info_new(void) ret->tuples[i].peak = 0.0; } - /* set to -1 so that we know in replay_gain_apply to compute the scale */ - ret->scale = -1.0; - return ret; } @@ -172,32 +150,3 @@ void replay_gain_info_free(struct replay_gain_info *info) { g_free(info); } - -void -replay_gain_apply(struct replay_gain_info *info, char *buffer, int size, - const struct audio_format *format) -{ - float scale; - - if (replay_gain_mode == REPLAY_GAIN_OFF) - return; - - if (info) { - if (info->scale < 0) { - const struct replay_gain_tuple *tuple = - &info->tuples[replay_gain_mode]; - - g_debug("computing ReplayGain %s scale with gain %f, peak %f\n", - replay_gain_mode_names[replay_gain_mode], - tuple->gain, tuple->peak); - - info->scale = calc_replay_gain_scale(tuple->gain, tuple->peak); - } - scale = info->scale; - } - else { - scale = replay_gain_missing_preamp; - } - - pcm_volume(buffer, size, format, pcm_float_to_volume(scale)); -} diff --git a/src/replay_gain.h b/src/replay_gain.h index b26512975..c27e2be06 100644 --- a/src/replay_gain.h +++ b/src/replay_gain.h @@ -31,9 +31,9 @@ enum replay_gain_mode { REPLAY_GAIN_TRACK, }; -struct audio_format; - extern enum replay_gain_mode replay_gain_mode; +extern float replay_gain_preamp; +extern float replay_gain_missing_preamp; struct replay_gain_tuple { float gain; @@ -42,9 +42,6 @@ struct replay_gain_tuple { struct replay_gain_info { struct replay_gain_tuple tuples[2]; - - /* used internally by mpd, to mess with it */ - float scale; }; struct replay_gain_info * @@ -74,8 +71,4 @@ replay_gain_get_mode_string(void); bool replay_gain_set_mode_string(const char *p); -void -replay_gain_apply(struct replay_gain_info *info, char *buffer, int bufferSize, - const struct audio_format *format); - #endif diff --git a/src/replay_gain_state.c b/src/replay_gain_state.c new file mode 100644 index 000000000..c14ff6e10 --- /dev/null +++ b/src/replay_gain_state.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2003-2010 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "replay_gain_state.h" +#include "pcm_volume.h" + +#include <glib.h> + +#include <assert.h> +#include <math.h> + +struct replay_gain_state { + float preamp, missing_preamp; + + enum replay_gain_mode mode; + + struct replay_gain_info *info; + + float scale; +}; + +struct replay_gain_state * +replay_gain_state_new(float preamp, float missing_preamp) +{ + struct replay_gain_state *state = g_new(struct replay_gain_state, 1); + + state->preamp = preamp; + state->missing_preamp = missing_preamp; + state->mode = REPLAY_GAIN_OFF; + state->info = NULL; + + return state; +} + +void +replay_gain_state_free(struct replay_gain_state *state) +{ + assert(state != NULL); + + if (state->info != NULL) + replay_gain_info_free(state->info); + + g_free(state); +} + +static float +calc_replay_gain_scale(float gain, float peak, float preamp) +{ + float scale; + + if (gain == 0.0) + return (1); + scale = pow(10.0, gain / 20.0); + scale *= preamp; + if (scale > 15.0) + scale = 15.0; + + if (scale * peak > 1.0) { + scale = 1.0 / peak; + } + return (scale); +} + +static void +replay_gain_state_calc_scale(struct replay_gain_state *state) +{ + assert(state != NULL); + + if (state->mode == REPLAY_GAIN_OFF || state->info == NULL) + return; + + const struct replay_gain_tuple *tuple = + &state->info->tuples[state->mode]; + + g_debug("computing ReplayGain scale with gain %f, peak %f", + tuple->gain, tuple->peak); + + state->scale = calc_replay_gain_scale(tuple->gain, tuple->peak, + state->preamp); +} + +void +replay_gain_state_set_mode(struct replay_gain_state *state, + enum replay_gain_mode mode) +{ + assert(state != NULL); + + if (mode == state->mode) + return; + + state->mode = mode; + + replay_gain_state_calc_scale(state); +} + +void +replay_gain_state_set_info(struct replay_gain_state *state, + const struct replay_gain_info *info) +{ + assert(state != NULL); + + if (state->info != NULL) + replay_gain_info_free(state->info); + + state->info = info != NULL + ? replay_gain_info_dup(info) + : NULL; + + replay_gain_state_calc_scale(state); +} + +void +replay_gain_state_apply(const struct replay_gain_state *state, + void *buffer, size_t size, + const struct audio_format *format) +{ + assert(state != NULL); + + if (state->mode == REPLAY_GAIN_OFF) + return; + + float scale = state->info != NULL + ? state->scale : state->missing_preamp; + pcm_volume(buffer, size, format, pcm_float_to_volume(scale)); +} diff --git a/src/replay_gain_state.h b/src/replay_gain_state.h new file mode 100644 index 000000000..7fa476095 --- /dev/null +++ b/src/replay_gain_state.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2003-2010 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_REPLAY_GAIN_STATE_H +#define MPD_REPLAY_GAIN_STATE_H + +#include "check.h" +#include "replay_gain.h" + +#include <stddef.h> + +struct replay_gain_state; +struct audio_format; + +struct replay_gain_state * +replay_gain_state_new(float preamp, float missing_preamp); + +void +replay_gain_state_free(struct replay_gain_state *state); + +void +replay_gain_state_set_mode(struct replay_gain_state *state, + enum replay_gain_mode mode); + +void +replay_gain_state_set_info(struct replay_gain_state *state, + const struct replay_gain_info *info); + +void +replay_gain_state_apply(const struct replay_gain_state *state, + void *buffer, size_t size, + const struct audio_format *format); + +#endif |