diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/filter/replay_gain_filter_plugin.c | 45 | ||||
-rw-r--r-- | src/filter/replay_gain_filter_plugin.h | 13 | ||||
-rw-r--r-- | src/output_init.c | 33 | ||||
-rw-r--r-- | src/output_thread.c | 3 |
4 files changed, 88 insertions, 6 deletions
diff --git a/src/filter/replay_gain_filter_plugin.c b/src/filter/replay_gain_filter_plugin.c index 248690d17..c8e74c7fe 100644 --- a/src/filter/replay_gain_filter_plugin.c +++ b/src/filter/replay_gain_filter_plugin.c @@ -27,7 +27,9 @@ #include "pcm_volume.h" #include "replay_gain_info.h" #include "replay_gain_config.h" +#include "mixer_control.h" +#include <assert.h> #include <string.h> #undef G_LOG_DOMAIN @@ -36,6 +38,18 @@ struct replay_gain_filter { struct filter filter; + /** + * If set, then this hardware mixer is used for applying + * replay gain, instead of the software volume library. + */ + struct mixer *mixer; + + /** + * The base volume level for scale=1.0, between 1 and 100 + * (including). + */ + unsigned base; + enum replay_gain_mode mode; struct replay_gain_info info; @@ -74,6 +88,21 @@ replay_gain_filter_update(struct replay_gain_filter *filter) filter->volume = pcm_float_to_volume(scale); } else filter->volume = PCM_VOLUME_1; + + if (filter->mixer != NULL) { + /* update the hardware mixer volume */ + + unsigned volume = (filter->volume * filter->base) / PCM_VOLUME_1; + if (volume > 100) + volume = 100; + + GError *error = NULL; + if (!mixer_set_volume(filter->mixer, volume, &error)) { + g_warning("Failed to update hardware mixer: %s", + error->message); + g_error_free(error); + } + } } static struct filter * @@ -83,6 +112,7 @@ replay_gain_filter_init(G_GNUC_UNUSED const struct config_param *param, struct replay_gain_filter *filter = g_new(struct replay_gain_filter, 1); filter_init(&filter->filter, &replay_gain_filter_plugin); + filter->mixer = NULL; filter->mode = replay_gain_mode; replay_gain_info_init(&filter->info); @@ -178,6 +208,21 @@ const struct filter_plugin replay_gain_filter_plugin = { }; void +replay_gain_filter_set_mixer(struct filter *_filter, struct mixer *mixer, + unsigned base) +{ + struct replay_gain_filter *filter = + (struct replay_gain_filter *)_filter; + + assert(mixer == NULL || (base > 0 && base <= 100)); + + filter->mixer = mixer; + filter->base = base; + + replay_gain_filter_update(filter); +} + +void replay_gain_filter_set_info(struct filter *_filter, const struct replay_gain_info *info) { diff --git a/src/filter/replay_gain_filter_plugin.h b/src/filter/replay_gain_filter_plugin.h index 4ab9f42a6..348b4f50c 100644 --- a/src/filter/replay_gain_filter_plugin.h +++ b/src/filter/replay_gain_filter_plugin.h @@ -23,6 +23,19 @@ #include "replay_gain_info.h" struct filter; +struct mixer; + +/** + * Enables or disables the hardware mixer for applying replay gain. + * + * @param mixer the hardware mixer, or NULL to fall back to software + * volume + * @param base the base volume level for scale=1.0, between 1 and 100 + * (including). + */ +void +replay_gain_filter_set_mixer(struct filter *_filter, struct mixer *mixer, + unsigned base); /** * Sets a new #replay_gain_info at the beginning of a new song. diff --git a/src/output_init.c b/src/output_init.c index 387915ddc..f3d22ace1 100644 --- a/src/output_init.c +++ b/src/output_init.c @@ -32,6 +32,7 @@ #include "filter_config.h" #include "filter/chain_filter_plugin.h" #include "filter/autoconvert_filter_plugin.h" +#include "filter/replay_gain_filter_plugin.h" #include <glib.h> @@ -196,12 +197,19 @@ audio_output_init(struct audio_output *ao, const struct config_param *param, /* create the replay_gain filter */ - ao->replay_gain_filter = filter_new(&replay_gain_filter_plugin, - param, NULL); - assert(ao->replay_gain_filter != NULL); + const char *replay_gain_handler = + config_get_block_string(param, "replay_gain_handler", + "software"); - filter_chain_append(ao->filter, ao->replay_gain_filter); - ao->replay_gain_serial = 0; + if (strcmp(replay_gain_handler, "none") != 0) { + ao->replay_gain_filter = filter_new(&replay_gain_filter_plugin, + param, NULL); + assert(ao->replay_gain_filter != NULL); + + filter_chain_append(ao->filter, ao->replay_gain_filter); + ao->replay_gain_serial = 0; + } else + ao->replay_gain_filter = NULL; /* create the normalization filter (if configured) */ @@ -247,6 +255,21 @@ audio_output_init(struct audio_output *ao, const struct config_param *param, g_error_free(error); } + /* use the hardware mixer for replay gain? */ + + if (strcmp(replay_gain_handler, "mixer") == 0) { + if (ao->mixer != NULL) + replay_gain_filter_set_mixer(ao->replay_gain_filter, + ao->mixer, 100); + else + g_warning("No such mixer for output '%s'", ao->name); + } else if (strcmp(replay_gain_handler, "software") != 0 && + ao->replay_gain_filter != NULL) { + g_set_error(error_r, audio_output_quark(), 0, + "Invalid \"replay_gain_handler\" value"); + return false; + } + /* the "convert" filter must be the last one in the chain */ ao->convert_filter = filter_new(&convert_filter_plugin, NULL, NULL); diff --git a/src/output_thread.c b/src/output_thread.c index 0e34c64b7..4bf0827f6 100644 --- a/src/output_thread.c +++ b/src/output_thread.c @@ -264,7 +264,8 @@ ao_play_chunk(struct audio_output *ao, const struct music_chunk *chunk) /* update replay gain */ - if (chunk->replay_gain_serial != ao->replay_gain_serial) { + if (ao->replay_gain_filter != NULL && + chunk->replay_gain_serial != ao->replay_gain_serial) { replay_gain_filter_set_info(ao->replay_gain_filter, chunk->replay_gain_serial != 0 ? &chunk->replay_gain_info |