[banshee/gapless-ng: 826/836] [libbanshee] Fix ReplayGain support.



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]