aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/filter/replay_gain_filter_plugin.c45
-rw-r--r--src/filter/replay_gain_filter_plugin.h13
-rw-r--r--src/output_init.c33
-rw-r--r--src/output_thread.c3
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