[banshee/gapless-ng: 826/836] [libbanshee] Fix ReplayGain support.
- From: Christopher James Halse Rogers <chrishr src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [banshee/gapless-ng: 826/836] [libbanshee] Fix ReplayGain support.
- Date: Thu, 25 Feb 2010 22:45:18 +0000 (UTC)
commit 01079472bcc3e99cece8e7a049ff85f44ebf6e5c
Author: Christopher James Halse Rogers <raof ubuntu com>
Date: Wed Feb 24 19:01:26 2010 +1100
[libbanshee] Fix ReplayGain support.
This is a slight reworking of the patch by Christian Taedcke on BGO# 600072.
It does not add an extra volume element; playbin2 fixes the volume change
latency on its own.
Using the rgvolume element is substantially simpler with gapless, where it's
no longer as easy to identify the start/end of a track. This drops the custom
â??use the average of the last 10 volumes as RG scaling if no RG tagsâ?? logic
Banshee currently has.
libbanshee/banshee-player-pipeline.c | 66 ++++++++++++++++-
libbanshee/banshee-player-pipeline.h | 1 +
libbanshee/banshee-player-private.h | 7 ++
libbanshee/banshee-player-replaygain.c | 124 ++++++--------------------------
libbanshee/banshee-player-replaygain.h | 15 +----
libbanshee/banshee-player.c | 7 +-
6 files changed, 98 insertions(+), 122 deletions(-)
---
diff --git a/libbanshee/banshee-player-pipeline.c b/libbanshee/banshee-player-pipeline.c
index 568a49d..c640bbe 100644
--- a/libbanshee/banshee-player-pipeline.c
+++ b/libbanshee/banshee-player-pipeline.c
@@ -54,7 +54,6 @@ bp_pipeline_process_tag (const GstTagList *tag_list, const gchar *tag_name, Bans
value = gst_tag_list_get_value_index (tag_list, tag_name, 0);
if (value != NULL) {
- _bp_replaygain_process_tag (player, tag_name, value);
if (player->tag_found_cb != NULL) {
player->tag_found_cb (player, tag_name, value);
@@ -95,7 +94,6 @@ bp_pipeline_bus_callback (GstBus *bus, GstMessage *message, gpointer userdata)
gst_message_parse_state_changed (message, &old, &new, &pending);
_bp_missing_elements_handle_state_changed (player, old, new);
- _bp_replaygain_handle_state_changed (player, old, new, pending);
if (player->state_changed_cb != NULL && GST_MESSAGE_SRC (message) == GST_OBJECT (player->playbin)) {
player->state_changed_cb (player, old, new, pending);
@@ -293,11 +291,16 @@ _bp_pipeline_construct (BansheePlayer *player)
// link in equalizer, preamp and audioconvert.
gst_element_link_many (audiosinkqueue, eq_audioconvert, player->preamp,
player->equalizer, eq_audioconvert2, audiosink, NULL);
+ player->before_rgvolume = eq_audioconvert;
+ player->after_rgvolume = player->preamp;
} else {
// link the queue with the real audio sink
gst_element_link (audiosinkqueue, audiosink);
+ player->before_rgvolume = audiosinkqueue;
+ player->after_rgvolume = audiosink;
}
-
+ player->rgvolume_in_pipeline = FALSE;
+
_bp_vis_pipeline_setup (player);
// Now that our internal audio sink is constructed, tell playbin to use it
@@ -349,3 +352,60 @@ _bp_pipeline_destroy (BansheePlayer *player)
player->playbin = NULL;
}
+
+static void
+pad_block_cb (GstPad *srcPad, gboolean blocked, gpointer user_data) {
+
+ if (blocked == FALSE) {
+ return;
+ }
+
+ BansheePlayer* player = (BansheePlayer*) user_data;
+ g_return_if_fail (IS_BANSHEE_PLAYER (player));
+
+ if (player->rgvolume_in_pipeline == TRUE) {
+ g_return_if_fail (player->rgvolume != NULL);
+ gst_element_unlink(player->before_rgvolume, player->rgvolume);
+ gst_element_unlink(player->rgvolume, player->after_rgvolume);
+ } else {
+ gst_element_unlink(player->before_rgvolume, player->after_rgvolume);
+ }
+
+ if (player->rgvolume == NULL && player->replaygain_enabled == TRUE) {
+ player->rgvolume = gst_element_factory_make ("rgvolume", NULL);
+ gst_bin_add (GST_BIN (player->audiobin), player->rgvolume);
+ }
+
+ if (player->replaygain_enabled == TRUE) {
+ gst_element_sync_state_with_parent(player->rgvolume);
+
+ // link in rgvolume and connect to the real audio sink.
+ gst_element_link (player->before_rgvolume, player->rgvolume);
+ gst_element_link (player->rgvolume, player->after_rgvolume);
+ player->rgvolume_in_pipeline = TRUE;
+ } else {
+ // link the queue with the real audio sink
+ gst_element_link (player->before_rgvolume, player->after_rgvolume);
+ player->rgvolume_in_pipeline = FALSE;
+ }
+
+ if (gst_pad_is_blocked (srcPad) == TRUE) {
+ gst_pad_set_blocked_async(srcPad, FALSE, &pad_block_cb, player);
+ }
+
+ _bp_rgvolume_print_volume(player);
+}
+
+void _bp_pipeline_rebuild (BansheePlayer* player)
+{
+ g_return_if_fail (IS_BANSHEE_PLAYER (player));
+ g_return_if_fail (GST_IS_ELEMENT (player->before_rgvolume));
+
+ GstPad* srcPad = gst_element_get_static_pad(player->before_rgvolume, "src");
+
+ if (gst_pad_is_active(srcPad) == TRUE && gst_pad_is_blocked (srcPad) == FALSE) {
+ gst_pad_set_blocked_async(srcPad, TRUE, &pad_block_cb, player);
+ } else if (srcPad->block_callback == NULL) {
+ pad_block_cb(srcPad, TRUE, player);
+ }
+}
diff --git a/libbanshee/banshee-player-pipeline.h b/libbanshee/banshee-player-pipeline.h
index 6a0b9aa..7f5c00f 100644
--- a/libbanshee/banshee-player-pipeline.h
+++ b/libbanshee/banshee-player-pipeline.h
@@ -33,5 +33,6 @@
gboolean _bp_pipeline_construct (BansheePlayer *player);
void _bp_pipeline_destroy (BansheePlayer *player);
+void _bp_pipeline_rebuild (BansheePlayer* player);
#endif /* _BANSHEE_PLAYER_PIPELINE_H */
diff --git a/libbanshee/banshee-player-private.h b/libbanshee/banshee-player-private.h
index 6df0884..3c7a3d9 100644
--- a/libbanshee/banshee-player-private.h
+++ b/libbanshee/banshee-player-private.h
@@ -105,6 +105,13 @@ struct BansheePlayer {
GstElement *audiobin;
GstElement *equalizer;
GstElement *preamp;
+ GstElement *volume;
+ GstElement *rgvolume;
+
+ GstElement *before_rgvolume;
+ GstElement *after_rgvolume;
+ gboolean rgvolume_in_pipeline;
+
gint equalizer_status;
gdouble current_volume;
diff --git a/libbanshee/banshee-player-replaygain.c b/libbanshee/banshee-player-replaygain.c
index 78fe083..acfe737 100644
--- a/libbanshee/banshee-player-replaygain.c
+++ b/libbanshee/banshee-player-replaygain.c
@@ -28,128 +28,46 @@
#include <math.h>
#include "banshee-player-replaygain.h"
+#include "banshee-player-pipeline.h"
// ---------------------------------------------------------------------------
// Private Functions
// ---------------------------------------------------------------------------
-static inline void
-bp_replaygain_debug (BansheePlayer *player)
+static gdouble
+bp_replaygain_db_to_linear(gdouble value)
{
- gint i;
- for (i = 0; i < 11; i++) {
- printf ("%g ", player->volume_scale_history[i]);
- }
- printf ("\n");
-}
-
-static void
-bp_replaygain_update_pipeline (BansheePlayer *player,
- gdouble album_gain, gdouble album_peak,
- gdouble track_gain, gdouble track_peak)
-{
- gdouble gain = album_gain == 0.0 ? album_gain : track_gain;
- gdouble peak = album_peak == 0.0 ? album_peak : track_peak;
- gdouble scale = 0.0;
-
- g_return_if_fail (IS_BANSHEE_PLAYER (player));
-
- if (gain == 0.0) {
- gint i;
- player->current_scale_from_history = TRUE;
- // Compute the average scale from history
- for (i = 1; i <= 10; i++) {
- scale += player->volume_scale_history[i] / 10.0;
- }
- } else {
- player->current_scale_from_history = FALSE;
- scale = pow (10.0, gain / 20.0);
-
- if (peak != 0.0 && scale * peak > 1.0) {
- scale = 1.0 / peak;
- }
-
- if (scale > 15.0) {
- scale = 15.0;
- }
- }
-
- player->volume_scale_history[0] = scale;
- _bp_replaygain_update_volume (player);
+ return pow(10, value / 20.0);
}
// ---------------------------------------------------------------------------
// Internal Functions
// ---------------------------------------------------------------------------
-void
-_bp_replaygain_process_tag (BansheePlayer *player, const gchar *tag_name, const GValue *value)
-{
- if (strcmp (tag_name, GST_TAG_ALBUM_GAIN) == 0) {
- player->album_gain = g_value_get_double (value);
- } else if (strcmp (tag_name, GST_TAG_ALBUM_PEAK) == 0) {
- player->album_peak = g_value_get_double (value);
- } else if (strcmp (tag_name, GST_TAG_TRACK_GAIN) == 0) {
- player->track_gain = g_value_get_double (value);
- } else if (strcmp (tag_name, GST_TAG_TRACK_PEAK) == 0) {
- player->track_peak = g_value_get_double (value);
- }
-}
-void
-_bp_replaygain_handle_state_changed (BansheePlayer *player, GstState old, GstState new, GstState pending)
+GstElement* _bp_rgvolume_new (BansheePlayer *player)
{
- if (old == GST_STATE_READY && new == GST_STATE_NULL &&
- pending == GST_STATE_VOID_PENDING && player->volume_scale_history_shift) {
-
- memmove (player->volume_scale_history + 1,
- player->volume_scale_history, sizeof (gdouble) * 10);
-
- if (player->current_scale_from_history) {
- player->volume_scale_history[1] = 1.0;
- }
-
- player->volume_scale_history[0] = 1.0;
- player->volume_scale_history_shift = FALSE;
-
- player->album_gain = player->album_peak = 0.0;
- player->track_gain = player->track_peak = 0.0;
- } else if (old == GST_STATE_READY && new == GST_STATE_PAUSED &&
- pending == GST_STATE_PLAYING && !player->volume_scale_history_shift) {
-
- player->volume_scale_history_shift = TRUE;
-
- bp_replaygain_update_pipeline (player,
- player->album_gain, player->album_peak,
- player->track_gain, player->track_peak);
+ GstElement *rgvolume = gst_element_factory_make ("rgvolume", NULL);
+
+ if (rgvolume == NULL) {
+ bp_debug ("Loading ReplayGain plugin failed.");
}
+
+ return rgvolume;
}
-void
-_bp_replaygain_update_volume (BansheePlayer *player)
+void _bp_rgvolume_print_volume(BansheePlayer *player)
{
- GParamSpec *volume_spec;
- GValue value = { 0, };
+ g_return_if_fail (IS_BANSHEE_PLAYER (player));
+ if ((player->replaygain_enabled == TRUE) && (player->rgvolume != NULL)) {
gdouble scale;
-
- if (player == NULL || player->playbin == NULL) {
- return;
- }
-
- scale = player->replaygain_enabled ? player->volume_scale_history[0] : 1.0;
-
- volume_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (player->playbin), "volume");
- g_value_init (&value, G_TYPE_DOUBLE);
- g_value_set_double (&value, player->current_volume * scale);
- g_param_value_validate (volume_spec, &value);
-
- if (player->replaygain_enabled) {
- bp_debug ("scaled volume: %f (ReplayGain) * %f (User) = %f", scale, player->current_volume,
- g_value_get_double (&value));
+
+ g_object_get (G_OBJECT (player->rgvolume), "result-gain", &scale, NULL);
+
+ bp_debug ("scaled volume: %.2f (ReplayGain) * %.2f (User) = %.2f",
+ bp_replaygain_db_to_linear(scale), player->current_volume,
+ bp_replaygain_db_to_linear(scale) * player->current_volume);
}
-
- g_object_set_property (G_OBJECT (player->playbin), "volume", &value);
- g_value_unset (&value);
}
// ---------------------------------------------------------------------------
@@ -162,7 +80,7 @@ bp_replaygain_set_enabled (BansheePlayer *player, gboolean enabled)
g_return_if_fail (IS_BANSHEE_PLAYER (player));
player->replaygain_enabled = enabled;
bp_debug ("%s ReplayGain", enabled ? "Enabled" : "Disabled");
- _bp_replaygain_update_volume (player);
+ _bp_pipeline_rebuild(player);
}
P_INVOKE gboolean
diff --git a/libbanshee/banshee-player-replaygain.h b/libbanshee/banshee-player-replaygain.h
index b552c2d..8c38148 100644
--- a/libbanshee/banshee-player-replaygain.h
+++ b/libbanshee/banshee-player-replaygain.h
@@ -31,18 +31,7 @@
#include "banshee-player-private.h"
-void _bp_replaygain_process_tag (BansheePlayer *player, const gchar *tag_name, const GValue *value);
-void _bp_replaygain_handle_state_changed (BansheePlayer *player, GstState old, GstState new, GstState pending);
-void _bp_replaygain_update_volume (BansheePlayer *player);
-
-static inline void
-_bp_replaygain_init (BansheePlayer *player)
-{
- gint i;
- for (i = 0; i < 11; i++) {
- player->volume_scale_history[i] = 1.0;
- }
-
-}
+GstElement* _bp_rgvolume_new (BansheePlayer *player);
+void _bp_rgvolume_print_volume (BansheePlayer *player);
#endif /* _BANSHEE_PLAYER_REPLAYGAIN_H */
diff --git a/libbanshee/banshee-player.c b/libbanshee/banshee-player.c
index 47c19f2..157494d 100644
--- a/libbanshee/banshee-player.c
+++ b/libbanshee/banshee-player.c
@@ -124,8 +124,6 @@ bp_new ()
player->mutex = g_mutex_new ();
- _bp_replaygain_init (player);
-
return player;
}
@@ -285,8 +283,11 @@ P_INVOKE void
bp_set_volume (BansheePlayer *player, gdouble volume)
{
g_return_if_fail (IS_BANSHEE_PLAYER (player));
+ g_return_if_fail (GST_IS_ELEMENT (player->playbin));
+
player->current_volume = CLAMP (volume, 0.0, 1.0);
- _bp_replaygain_update_volume (player);
+ g_object_set (player->playbin, "volume", player->current_volume, NULL);
+ _bp_rgvolume_print_volume (player);
}
P_INVOKE gdouble
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]