[gnome-media] implement LFE



commit e360b34ed5b9d5aa699bb172ecf1a2429969477a
Author: Lennart Poettering <lennart poettering net>
Date:   Fri May 15 02:01:03 2009 +0200

    implement LFE
    
    This is mostly Bastien's work.
    
    I added some code to break a feedbock loop between the LFE and the
    Volume slider and also made sure we don't store the volume twice, once
    in GvcChannelMap and in GvcMixerStream. After this change we'll always
    go to GvcChannelMap.
---
 gnome-volume-control/src/gvc-balance-bar.c         |  192 ++++++++++++++-----
 gnome-volume-control/src/gvc-balance-bar.h         |    3 +
 gnome-volume-control/src/gvc-channel-bar.c         |    2 +
 gnome-volume-control/src/gvc-channel-map.c         |   67 ++++++-
 gnome-volume-control/src/gvc-channel-map.h         |    7 +-
 gnome-volume-control/src/gvc-mixer-dialog.c        |   27 +++-
 gnome-volume-control/src/gvc-mixer-event-role.c    |   15 +-
 gnome-volume-control/src/gvc-mixer-sink-input.c    |    8 +-
 gnome-volume-control/src/gvc-mixer-sink.c          |   12 +-
 gnome-volume-control/src/gvc-mixer-source-output.c |    5 +-
 gnome-volume-control/src/gvc-mixer-source.c        |    8 +-
 gnome-volume-control/src/gvc-mixer-stream.c        |   52 ++++--
 gnome-volume-control/src/gvc-mixer-stream.h        |    8 +-
 gnome-volume-control/src/gvc-stream-status-icon.c  |    5 +-
 14 files changed, 292 insertions(+), 119 deletions(-)

diff --git a/gnome-volume-control/src/gvc-balance-bar.c b/gnome-volume-control/src/gvc-balance-bar.c
index f51a93a..7ea0fea 100644
--- a/gnome-volume-control/src/gvc-balance-bar.c
+++ b/gnome-volume-control/src/gvc-balance-bar.c
@@ -32,6 +32,7 @@
 #include "gvc-balance-bar.h"
 
 #define SCALE_SIZE 128
+#define ADJUSTMENT_MAX_NORMAL 65536.0 /* PA_VOLUME_NORM */
 
 #define GVC_BALANCE_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_BALANCE_BAR, GvcBalanceBarPrivate))
 
@@ -83,7 +84,7 @@ _scale_box_new (GvcBalanceBar *bar)
         GtkWidget            *sbox;
         GtkWidget            *ebox;
         GtkAdjustment        *adjustment = bar->priv->adjustment;
-        char                 *str;
+        char                 *str_lower, *str_upper;
 
         bar->priv->scale_box = box = gtk_hbox_new (FALSE, 6);
         priv->scale = gtk_hscale_new (priv->adjustment);
@@ -102,30 +103,35 @@ _scale_box_new (GvcBalanceBar *bar)
 
         gtk_box_pack_start (GTK_BOX (box), priv->scale, TRUE, TRUE, 0);
 
-        if (bar->priv->btype == BALANCE_TYPE_RL) {
-                str = g_strdup_printf ("<small>%s</small>", C_("balance", "Left"));
-                gtk_scale_add_mark (GTK_SCALE (priv->scale), adjustment->lower,
-                                    GTK_POS_BOTTOM, str);
-                g_free (str);
-
-                str = g_strdup_printf ("<small>%s</small>", C_("balance", "Right"));
-                gtk_scale_add_mark (GTK_SCALE (priv->scale),  adjustment->upper,
-                                    GTK_POS_BOTTOM, str);
-                g_free (str);
-        } else {
-                str = g_strdup_printf ("<small>%s</small>", C_("balance", "Front"));
-                gtk_scale_add_mark (GTK_SCALE (priv->scale), adjustment->lower,
-                                    GTK_POS_BOTTOM, str);
-                g_free (str);
-
-                str = g_strdup_printf ("<small>%s</small>", C_("balance", "Rear"));
-                gtk_scale_add_mark (GTK_SCALE (priv->scale),  adjustment->upper,
-                                    GTK_POS_BOTTOM, str);
-                g_free (str);
+        switch (bar->priv->btype) {
+        case BALANCE_TYPE_RL:
+                str_lower = g_strdup_printf ("<small>%s</small>", C_("balance", "Left"));
+                str_upper = g_strdup_printf ("<small>%s</small>", C_("balance", "Right"));
+                break;
+        case BALANCE_TYPE_FR:
+                str_lower = g_strdup_printf ("<small>%s</small>", C_("balance", "Front"));
+                str_upper = g_strdup_printf ("<small>%s</small>", C_("balance", "Rear"));
+                break;
+        case BALANCE_TYPE_LFE:
+                str_lower = g_strdup_printf ("<small>%s</small>", C_("balance", "Minimum"));
+                str_upper = g_strdup_printf ("<small>%s</small>", C_("balance", "Maximum"));
+                break;
+        default:
+                g_assert_not_reached ();
         }
 
-        gtk_scale_add_mark (GTK_SCALE (priv->scale), (adjustment->upper - adjustment->lower)/2 + adjustment->lower, 
-                            GTK_POS_BOTTOM, NULL);
+        gtk_scale_add_mark (GTK_SCALE (priv->scale), adjustment->lower,
+                            GTK_POS_BOTTOM, str_lower);
+        g_free (str_lower);
+        gtk_scale_add_mark (GTK_SCALE (priv->scale),  adjustment->upper,
+                            GTK_POS_BOTTOM, str_upper);
+        g_free (str_upper);
+
+        if (bar->priv->btype != BALANCE_TYPE_LFE) {
+                gtk_scale_add_mark (GTK_SCALE (priv->scale),
+                                    (adjustment->upper - adjustment->lower)/2 + adjustment->lower,
+                                    GTK_POS_BOTTOM, NULL);
+        }
 
         bar->priv->end_box = ebox = gtk_hbox_new (FALSE, 6);
         gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, FALSE, 0);
@@ -176,6 +182,23 @@ gvc_balance_bar_set_size_group (GvcBalanceBar *bar,
         gtk_widget_queue_draw (GTK_WIDGET (bar));
 }
 
+static const char *
+btype_to_string (guint btype)
+{
+        switch (btype) {
+        case BALANCE_TYPE_RL:
+                return "Balance";
+        case BALANCE_TYPE_FR:
+                return "Fade";
+                break;
+        case BALANCE_TYPE_LFE:
+                return "LFE";
+        default:
+                g_assert_not_reached ();
+        }
+        return NULL;
+}
+
 static void
 update_level_from_map (GvcBalanceBar *bar,
                        GvcChannelMap *map)
@@ -183,14 +206,22 @@ update_level_from_map (GvcBalanceBar *bar,
         const gdouble *volumes;
         gdouble val;
 
-        g_debug ("Volume changed (for %s bar)",
-                 bar->priv->btype == BALANCE_TYPE_RL ? "Balance" : "Fade");
+        g_debug ("Volume changed (for %s bar)", btype_to_string (bar->priv->btype));
 
         volumes = gvc_channel_map_get_volume (map);
-        if (bar->priv->btype == BALANCE_TYPE_RL)
+        switch (bar->priv->btype) {
+        case BALANCE_TYPE_RL:
                 val = volumes[BALANCE];
-        else
+                break;
+        case BALANCE_TYPE_FR:
                 val = volumes[FADE];
+                break;
+        case BALANCE_TYPE_LFE:
+                val = volumes[LFE];
+                break;
+        default:
+                g_assert_not_reached ();
+        }
 
         gtk_adjustment_set_value (bar->priv->adjustment, val);
 }
@@ -230,22 +261,40 @@ gvc_balance_bar_set_balance_type (GvcBalanceBar *bar,
         g_return_if_fail (GVC_BALANCE_BAR (bar));
 
         bar->priv->btype = btype;
-        bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
-                                                                    -1.0,
-                                                                    1.0,
-                                                                    0.5,
-                                                                    0.5,
-                                                                    0.0));
+        if (bar->priv->btype != BALANCE_TYPE_LFE) {
+                bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
+                                                                            -1.0,
+                                                                            1.0,
+                                                                            0.5,
+                                                                            0.5,
+                                                                            0.0));
+        } else {
+                bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
+                                                                            0.0,
+                                                                            ADJUSTMENT_MAX_NORMAL,
+                                                                            ADJUSTMENT_MAX_NORMAL/100.0,
+                                                                            ADJUSTMENT_MAX_NORMAL/10.0,
+                                                                            0.0));
+        }
+
         g_object_ref_sink (bar->priv->adjustment);
         g_signal_connect (bar->priv->adjustment,
                           "value-changed",
                           G_CALLBACK (on_adjustment_value_changed),
                           bar);
 
-        if (bar->priv->btype == BALANCE_TYPE_RL) {
+        switch (btype) {
+        case BALANCE_TYPE_RL:
                 bar->priv->label = gtk_label_new_with_mnemonic (_("_Balance:"));
-        } else {
+                break;
+        case BALANCE_TYPE_FR:
                 bar->priv->label = gtk_label_new_with_mnemonic (_("_Fade:"));
+                break;
+        case BALANCE_TYPE_LFE:
+                bar->priv->label = gtk_label_new_with_mnemonic (_("_Subwoofer:"));
+                break;
+        default:
+                g_assert_not_reached ();
         }
         gtk_misc_set_alignment (GTK_MISC (bar->priv->label),
                                 0.0,
@@ -343,7 +392,7 @@ gvc_balance_bar_class_init (GvcBalanceBarClass *klass)
                                          g_param_spec_int ("balance-type",
                                                            "balance type",
                                                            "Whether the balance is right-left or front-rear",
-                                                           BALANCE_TYPE_RL, BALANCE_TYPE_FR, BALANCE_TYPE_RL,
+                                                           BALANCE_TYPE_RL, NUM_BALANCE_TYPES - 1, BALANCE_TYPE_RL,
                                                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
 
         g_type_class_add_private (klass, sizeof (GvcBalanceBarPrivate));
@@ -379,23 +428,57 @@ on_scale_scroll_event (GtkWidget      *widget,
 
         value = gtk_adjustment_get_value (bar->priv->adjustment);
 
-        if (event->direction == GDK_SCROLL_UP) {
-                if (value + 0.01 > 1.0)
-                        value = 1.0;
-                else
-                        value = value + 0.01;
-                gtk_adjustment_set_value (bar->priv->adjustment, value);
-        } else if (event->direction == GDK_SCROLL_DOWN) {
-                if (value - 0.01 < 0)
-                        value = 0.0;
-                else
-                        value = value - 0.01;
-                gtk_adjustment_set_value (bar->priv->adjustment, value);
+        if (bar->priv->btype == BALANCE_TYPE_LFE) {
+                if (event->direction == GDK_SCROLL_UP) {
+                        if (value + ADJUSTMENT_MAX_NORMAL/100.0 > ADJUSTMENT_MAX_NORMAL)
+                                value = ADJUSTMENT_MAX_NORMAL;
+                        else
+                                value = value + ADJUSTMENT_MAX_NORMAL/100.0;
+                } else if (event->direction == GDK_SCROLL_DOWN) {
+                        if (value - ADJUSTMENT_MAX_NORMAL/100.0 < 0)
+                                value = 0.0;
+                        else
+                                value = value - ADJUSTMENT_MAX_NORMAL/100.0;
+                }
+        } else {
+                if (event->direction == GDK_SCROLL_UP) {
+                        if (value + 0.01 > 1.0)
+                                value = 1.0;
+                        else
+                                value = value + 0.01;
+                } else if (event->direction == GDK_SCROLL_DOWN) {
+                        if (value - 0.01 < 0)
+                                value = 0.0;
+                        else
+                                value = value - 0.01;
+                }
         }
+        gtk_adjustment_set_value (bar->priv->adjustment, value);
 
         return TRUE;
 }
 
+/* FIXME remove when we depend on a newer PA */
+static pa_cvolume *
+gvc_pa_cvolume_set_position (pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t, pa_volume_t v) {
+        unsigned c;
+        gboolean good = FALSE;
+
+        g_assert(cv);
+        g_assert(map);
+
+        g_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), NULL);
+        g_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, NULL);
+
+        for (c = 0; c < map->channels; c++)
+                if (map->map[c] == t) {
+                        cv->values[c] = v;
+                        good = TRUE;
+                }
+
+        return good ? cv : NULL;
+}
+
 static void
 on_adjustment_value_changed (GtkAdjustment *adjustment,
                              GvcBalanceBar *bar)
@@ -407,15 +490,22 @@ on_adjustment_value_changed (GtkAdjustment *adjustment,
         if (bar->priv->channel_map == NULL)
                 return;
 
-        cv = *gvc_channel_map_get_cvolume_for_volumes (bar->priv->channel_map, -1);
+        cv = *gvc_channel_map_get_cvolume (bar->priv->channel_map);
         val = gtk_adjustment_get_value (adjustment);
 
         pa_map = gvc_channel_map_get_pa_channel_map (bar->priv->channel_map);
 
-        if (bar->priv->btype == BALANCE_TYPE_RL)
+        switch (bar->priv->btype) {
+        case BALANCE_TYPE_RL:
                 pa_cvolume_set_balance (&cv, pa_map, val);
-        else
+                break;
+        case BALANCE_TYPE_FR:
                 pa_cvolume_set_fade (&cv, pa_map, val);
+                break;
+        case BALANCE_TYPE_LFE:
+                gvc_pa_cvolume_set_position (&cv, pa_map, PA_CHANNEL_POSITION_LFE, val);
+                break;
+        }
 
         gvc_channel_map_volume_changed (bar->priv->channel_map, &cv);
 }
diff --git a/gnome-volume-control/src/gvc-balance-bar.h b/gnome-volume-control/src/gvc-balance-bar.h
index 01b2f13..5122552 100644
--- a/gnome-volume-control/src/gvc-balance-bar.h
+++ b/gnome-volume-control/src/gvc-balance-bar.h
@@ -37,8 +37,11 @@ G_BEGIN_DECLS
 typedef enum {
         BALANCE_TYPE_RL,
         BALANCE_TYPE_FR,
+        BALANCE_TYPE_LFE,
 } GvcBalanceType;
 
+#define NUM_BALANCE_TYPES BALANCE_TYPE_LFE + 1
+
 typedef struct GvcBalanceBarPrivate GvcBalanceBarPrivate;
 
 typedef struct
diff --git a/gnome-volume-control/src/gvc-channel-bar.c b/gnome-volume-control/src/gvc-channel-bar.c
index dfe5027..39aa656 100644
--- a/gnome-volume-control/src/gvc-channel-bar.c
+++ b/gnome-volume-control/src/gvc-channel-bar.c
@@ -24,6 +24,8 @@
 #include <stdio.h>
 #include <unistd.h>
 
+#include <pulse/pulseaudio.h>
+
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
diff --git a/gnome-volume-control/src/gvc-channel-map.c b/gnome-volume-control/src/gvc-channel-map.c
index e508e80..99ededc 100644
--- a/gnome-volume-control/src/gvc-channel-map.c
+++ b/gnome-volume-control/src/gvc-channel-map.c
@@ -37,9 +37,10 @@ struct GvcChannelMapPrivate
 {
         pa_channel_map        pa_map;
         pa_cvolume            pa_volume;
-        gdouble               extern_volume[3]; /* volume, balance, fade */
+        gdouble               extern_volume[NUM_TYPES]; /* volume, balance, fade, lfe */
         gboolean              can_balance;
         gboolean              can_fade;
+        gboolean              has_lfe;
 };
 
 enum {
@@ -55,6 +56,40 @@ static void     gvc_channel_map_finalize   (GObject            *object);
 
 G_DEFINE_TYPE (GvcChannelMap, gvc_channel_map, G_TYPE_OBJECT)
 
+/* FIXME remove when we depend on a newer PA */
+static int
+gvc_pa_channel_map_has_position (const pa_channel_map *map, pa_channel_position_t p) {
+        unsigned c;
+
+        g_return_val_if_fail(pa_channel_map_valid(map), 0);
+        g_return_val_if_fail(p < PA_CHANNEL_POSITION_MAX, 0);
+
+        for (c = 0; c < map->channels; c++)
+                if (map->map[c] == p)
+                        return 1;
+
+        return 0;
+}
+
+static pa_volume_t
+pa_cvolume_get_position (pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t) {
+        unsigned c;
+        pa_volume_t v = PA_VOLUME_MUTED;
+
+        g_assert(cv);
+        g_assert(map);
+
+        g_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), PA_VOLUME_MUTED);
+        g_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, PA_VOLUME_MUTED);
+
+        for (c = 0; c < map->channels; c++)
+                if (map->map[c] == t)
+                        if (cv->values[c] > v)
+                                v = cv->values[c];
+
+        return v;
+}
+
 guint
 gvc_channel_map_get_num_channels (GvcChannelMap *map)
 {
@@ -75,8 +110,18 @@ gvc_channel_map_get_volume (GvcChannelMap *map)
                 return NULL;
 
         map->priv->extern_volume[VOLUME] = (gdouble) pa_cvolume_max (&map->priv->pa_volume);
-        map->priv->extern_volume[BALANCE] = (gdouble) pa_cvolume_get_balance (&map->priv->pa_volume, &map->priv->pa_map);
-        map->priv->extern_volume[FADE] = (gdouble) pa_cvolume_get_fade (&map->priv->pa_volume, &map->priv->pa_map);
+        if (gvc_channel_map_can_balance (map))
+                map->priv->extern_volume[BALANCE] = (gdouble) pa_cvolume_get_balance (&map->priv->pa_volume, &map->priv->pa_map);
+        else
+                map->priv->extern_volume[BALANCE] = 0;
+        if (gvc_channel_map_can_fade (map))
+                map->priv->extern_volume[FADE] = (gdouble) pa_cvolume_get_fade (&map->priv->pa_volume, &map->priv->pa_map);
+        else
+                map->priv->extern_volume[FADE] = 0;
+        if (gvc_channel_map_has_lfe (map))
+                map->priv->extern_volume[LFE] = (gdouble) pa_cvolume_get_position (&map->priv->pa_volume, &map->priv->pa_map, PA_CHANNEL_POSITION_LFE);
+        else
+                map->priv->extern_volume[LFE] = 0;
 
         return map->priv->extern_volume;
 }
@@ -108,6 +153,14 @@ gvc_channel_map_get_mapping (GvcChannelMap  *map)
         return pa_channel_map_to_pretty_name (&map->priv->pa_map);
 }
 
+gboolean
+gvc_channel_map_has_lfe (GvcChannelMap  *map)
+{
+        g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE);
+
+        return map->priv->has_lfe;
+}
+
 const pa_channel_map *
 gvc_channel_map_get_pa_channel_map (GvcChannelMap  *map)
 {
@@ -120,17 +173,13 @@ gvc_channel_map_get_pa_channel_map (GvcChannelMap  *map)
 }
 
 const pa_cvolume *
-gvc_channel_map_get_cvolume_for_volumes (GvcChannelMap  *map,
-                                         gint            volume)
+gvc_channel_map_get_cvolume (GvcChannelMap  *map)
 {
         g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
 
         if (!pa_channel_map_valid(&map->priv->pa_map))
                 return NULL;
 
-        if (volume >= 0)
-                pa_cvolume_scale (&map->priv->pa_volume, (pa_volume_t) volume);
-
         return &map->priv->pa_volume;
 }
 
@@ -207,9 +256,11 @@ set_from_pa_map (GvcChannelMap        *map,
 #ifdef HAVE_NEW_PULSE
         map->priv->can_balance = pa_channel_map_can_balance (pa_map);
         map->priv->can_fade = pa_channel_map_can_fade (pa_map);
+        map->priv->has_lfe = gvc_pa_channel_map_has_position (pa_map, PA_CHANNEL_POSITION_LFE);
 #else
         map->priv->can_balance = TRUE;
         map->priv->can_fade = FALSE;
+        map->priv->has_lfe = FALSE;
 #endif
 
         map->priv->pa_map = *pa_map;
diff --git a/gnome-volume-control/src/gvc-channel-map.h b/gnome-volume-control/src/gvc-channel-map.h
index d1c85a2..b35c9cb 100644
--- a/gnome-volume-control/src/gvc-channel-map.h
+++ b/gnome-volume-control/src/gvc-channel-map.h
@@ -51,8 +51,11 @@ enum {
         VOLUME,
         BALANCE,
         FADE,
+        LFE,
 };
 
+#define NUM_TYPES LFE + 1
+
 GType                   gvc_channel_map_get_type                (void);
 
 GvcChannelMap *         gvc_channel_map_new                     (void);
@@ -61,14 +64,14 @@ guint                   gvc_channel_map_get_num_channels        (GvcChannelMap
 const gdouble *         gvc_channel_map_get_volume              (GvcChannelMap  *map);
 gboolean                gvc_channel_map_can_balance             (GvcChannelMap  *map);
 gboolean                gvc_channel_map_can_fade                (GvcChannelMap  *map);
+gboolean                gvc_channel_map_has_lfe                 (GvcChannelMap  *map);
 
 void                    gvc_channel_map_volume_changed          (GvcChannelMap    *map,
                                                                  const pa_cvolume *cv);
 const char *            gvc_channel_map_get_mapping             (GvcChannelMap  *map);
 
 /* private */
-const pa_cvolume *      gvc_channel_map_get_cvolume_for_volumes (GvcChannelMap  *map,
-                                                                 int             volume);
+const pa_cvolume *      gvc_channel_map_get_cvolume             (GvcChannelMap  *map);
 const pa_channel_map *  gvc_channel_map_get_pa_channel_map      (GvcChannelMap  *map);
 G_END_DECLS
 
diff --git a/gnome-volume-control/src/gvc-mixer-dialog.c b/gnome-volume-control/src/gvc-mixer-dialog.c
index d30bb28..a2a4a87 100644
--- a/gnome-volume-control/src/gvc-mixer-dialog.c
+++ b/gnome-volume-control/src/gvc-mixer-dialog.c
@@ -64,6 +64,7 @@ struct GvcMixerDialogPrivate
         GtkWidget       *output_settings_box;
         GtkWidget       *output_balance_bar;
         GtkWidget       *output_fade_bar;
+        GtkWidget       *output_lfe_bar;
         GtkWidget       *input_treeview;
         GtkWidget       *sound_theme_chooser;
         GtkWidget       *click_feedback_button;
@@ -145,6 +146,7 @@ update_output_settings (GvcMixerDialog *dialog)
 {
         GvcMixerStream *stream;
         GvcChannelMap  *map;
+        guint           num_settings;
 
         g_debug ("Updating output settings");
         if (dialog->priv->output_balance_bar != NULL) {
@@ -157,6 +159,11 @@ update_output_settings (GvcMixerDialog *dialog)
                                       dialog->priv->output_fade_bar);
                 dialog->priv->output_fade_bar = NULL;
         }
+        if (dialog->priv->output_lfe_bar != NULL) {
+                gtk_container_remove (GTK_CONTAINER (dialog->priv->output_settings_box),
+                                      dialog->priv->output_lfe_bar);
+                dialog->priv->output_lfe_bar = NULL;
+        }
 
         stream = gvc_mixer_control_get_default_sink (dialog->priv->mixer_control);
         if (stream == NULL) {
@@ -180,6 +187,7 @@ update_output_settings (GvcMixerDialog *dialog)
                             dialog->priv->output_balance_bar,
                             FALSE, FALSE, 12);
         gtk_widget_show (dialog->priv->output_balance_bar);
+        num_settings = 1;
 
         if (gvc_channel_map_can_fade (map)) {
                 dialog->priv->output_fade_bar = gvc_balance_bar_new (map, BALANCE_TYPE_FR);
@@ -192,9 +200,24 @@ update_output_settings (GvcMixerDialog *dialog)
                                     dialog->priv->output_fade_bar,
                                     FALSE, FALSE, 12);
                 gtk_widget_show (dialog->priv->output_fade_bar);
+                num_settings++;
+        }
+
+        if (gvc_channel_map_has_lfe (map)) {
+                dialog->priv->output_lfe_bar = gvc_balance_bar_new (map, BALANCE_TYPE_LFE);
+                if (dialog->priv->size_group != NULL) {
+                        gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (dialog->priv->output_lfe_bar),
+                                                        dialog->priv->size_group,
+                                                        TRUE);
+                }
+                gtk_box_pack_start (GTK_BOX (dialog->priv->output_settings_box),
+                                    dialog->priv->output_lfe_bar,
+                                    FALSE, FALSE, 12);
+                gtk_widget_show (dialog->priv->output_lfe_bar);
+                num_settings++;
         }
 
-        /* We could make this into a "No settings" label instead */
+        /* FIXME: We could make this into a "No settings" label instead */
         gtk_widget_set_sensitive (dialog->priv->output_balance_bar, gvc_channel_map_can_balance (map));
 }
 
@@ -514,7 +537,7 @@ on_adjustment_value_changed (GtkAdjustment  *adjustment,
         stream = g_object_get_data (G_OBJECT (adjustment), "gvc-mixer-dialog-stream"),
         volume = gtk_adjustment_get_value (adjustment);
         if (stream != NULL) {
-                gvc_mixer_stream_change_volume (stream, (guint)volume);
+                gvc_mixer_stream_set_volume(stream, (pa_volume_t) volume );
         }
 }
 
diff --git a/gnome-volume-control/src/gvc-mixer-event-role.c b/gnome-volume-control/src/gvc-mixer-event-role.c
index b5469ca..51798e2 100644
--- a/gnome-volume-control/src/gvc-mixer-event-role.c
+++ b/gnome-volume-control/src/gvc-mixer-event-role.c
@@ -53,21 +53,21 @@ G_DEFINE_TYPE (GvcMixerEventRole, gvc_mixer_event_role, GVC_TYPE_MIXER_STREAM)
 
 static gboolean
 update_settings (GvcMixerEventRole *role,
-                 guint              volume,
                  gboolean           is_muted)
 {
         pa_operation              *o;
         guint                      index;
+        GvcChannelMap     *map;
         pa_context                *context;
         pa_ext_stream_restore_info info;
 
         index = gvc_mixer_stream_get_index (GVC_MIXER_STREAM (role));
 
-        pa_cvolume_set (&info.volume, 1, (pa_volume_t)volume);
+        map = gvc_mixer_stream_get_channel_map (GVC_MIXER_STREAM(role));
 
+        info.volume = *gvc_channel_map_get_cvolume(map);
         info.name = "sink-input-by-media-role:event";
-        info.channel_map.channels = 1;
-        info.channel_map.map[0] = PA_CHANNEL_POSITION_MONO;
+        info.channel_map = *gvc_channel_map_get_pa_channel_map(map);
         info.device = role->priv->device;
         info.mute = is_muted;
 
@@ -92,11 +92,9 @@ update_settings (GvcMixerEventRole *role,
 }
 
 static gboolean
-gvc_mixer_event_role_change_volume (GvcMixerStream *stream,
-                                    guint           volume)
+gvc_mixer_event_role_push_volume (GvcMixerStream *stream)
 {
         return update_settings (GVC_MIXER_EVENT_ROLE (stream),
-                                volume,
                                 gvc_mixer_stream_get_is_muted (stream));
 }
 
@@ -105,7 +103,6 @@ gvc_mixer_event_role_change_is_muted (GvcMixerStream *stream,
                                       gboolean        is_muted)
 {
         return update_settings (GVC_MIXER_EVENT_ROLE (stream),
-                                gvc_mixer_stream_get_volume (stream),
                                 is_muted);
 }
 
@@ -184,7 +181,7 @@ gvc_mixer_event_role_class_init (GvcMixerEventRoleClass *klass)
         object_class->set_property = gvc_mixer_event_role_set_property;
         object_class->get_property = gvc_mixer_event_role_get_property;
 
-        stream_class->change_volume = gvc_mixer_event_role_change_volume;
+        stream_class->push_volume = gvc_mixer_event_role_push_volume;
         stream_class->change_is_muted = gvc_mixer_event_role_change_is_muted;
 
         g_object_class_install_property (object_class,
diff --git a/gnome-volume-control/src/gvc-mixer-sink-input.c b/gnome-volume-control/src/gvc-mixer-sink-input.c
index 963229e..c000e18 100644
--- a/gnome-volume-control/src/gvc-mixer-sink-input.c
+++ b/gnome-volume-control/src/gvc-mixer-sink-input.c
@@ -45,8 +45,7 @@ static void     gvc_mixer_sink_input_finalize   (GObject            *object);
 G_DEFINE_TYPE (GvcMixerSinkInput, gvc_mixer_sink_input, GVC_TYPE_MIXER_STREAM)
 
 static gboolean
-gvc_mixer_sink_input_change_volume (GvcMixerStream *stream,
-                                    guint           volume)
+gvc_mixer_sink_input_push_volume (GvcMixerStream *stream)
 {
         pa_operation      *o;
         guint              index;
@@ -60,8 +59,7 @@ gvc_mixer_sink_input_change_volume (GvcMixerStream *stream,
         map = gvc_mixer_stream_get_channel_map (stream);
         num_channels = gvc_channel_map_get_num_channels (map);
 
-        /* set the volume */
-        cv = gvc_channel_map_get_cvolume_for_volumes (map, volume);
+        cv = gvc_channel_map_get_cvolume(map);
 
         context = gvc_mixer_stream_get_pa_context (stream);
 
@@ -132,7 +130,7 @@ gvc_mixer_sink_input_class_init (GvcMixerSinkInputClass *klass)
         object_class->constructor = gvc_mixer_sink_input_constructor;
         object_class->finalize = gvc_mixer_sink_input_finalize;
 
-        stream_class->change_volume = gvc_mixer_sink_input_change_volume;
+        stream_class->push_volume = gvc_mixer_sink_input_push_volume;
         stream_class->change_is_muted = gvc_mixer_sink_input_change_is_muted;
 
         g_type_class_add_private (klass, sizeof (GvcMixerSinkInputPrivate));
diff --git a/gnome-volume-control/src/gvc-mixer-sink.c b/gnome-volume-control/src/gvc-mixer-sink.c
index c242723..218f9cd 100644
--- a/gnome-volume-control/src/gvc-mixer-sink.c
+++ b/gnome-volume-control/src/gvc-mixer-sink.c
@@ -46,8 +46,7 @@ static void     gvc_mixer_sink_dispose    (GObject           *object);
 G_DEFINE_TYPE (GvcMixerSink, gvc_mixer_sink, GVC_TYPE_MIXER_STREAM)
 
 static gboolean
-gvc_mixer_sink_change_volume (GvcMixerStream *stream,
-                              guint           volume)
+gvc_mixer_sink_push_volume (GvcMixerStream *stream)
 {
         pa_operation      *o;
         guint              index;
@@ -60,10 +59,8 @@ gvc_mixer_sink_change_volume (GvcMixerStream *stream,
 
         map = gvc_mixer_stream_get_channel_map (stream);
 
-        g_debug ("Changing volume for sink: vol=%u", (guint)volume);
-
         /* set the volume */
-        cv = gvc_channel_map_get_cvolume_for_volumes (map, volume);
+        cv = gvc_channel_map_get_cvolume(map);
 
         context = gvc_mixer_stream_get_pa_context (stream);
 
@@ -135,7 +132,7 @@ gvc_mixer_sink_constructor (GType                  type,
                             guint                  n_construct_properties,
                             GObjectConstructParam *construct_params)
 {
-        GObject       *object;
+        GObject      *object;
         GvcMixerSink *self;
 
         object = G_OBJECT_CLASS (gvc_mixer_sink_parent_class)->constructor (type, n_construct_properties, construct_params);
@@ -155,7 +152,7 @@ gvc_mixer_sink_class_init (GvcMixerSinkClass *klass)
         object_class->dispose = gvc_mixer_sink_dispose;
         object_class->finalize = gvc_mixer_sink_finalize;
 
-        stream_class->change_volume = gvc_mixer_sink_change_volume;
+        stream_class->push_volume = gvc_mixer_sink_push_volume;
         stream_class->change_is_muted = gvc_mixer_sink_change_is_muted;
         stream_class->is_running = gvc_mixer_sink_is_running;
 
@@ -166,7 +163,6 @@ static void
 gvc_mixer_sink_init (GvcMixerSink *sink)
 {
         sink->priv = GVC_MIXER_SINK_GET_PRIVATE (sink);
-
 }
 
 static void
diff --git a/gnome-volume-control/src/gvc-mixer-source-output.c b/gnome-volume-control/src/gvc-mixer-source-output.c
index b71ad23..a9cf120 100644
--- a/gnome-volume-control/src/gvc-mixer-source-output.c
+++ b/gnome-volume-control/src/gvc-mixer-source-output.c
@@ -45,8 +45,7 @@ static void     gvc_mixer_source_output_finalize   (GObject            *object);
 G_DEFINE_TYPE (GvcMixerSourceOutput, gvc_mixer_source_output, GVC_TYPE_MIXER_STREAM)
 
 static gboolean
-gvc_mixer_source_output_change_volume (GvcMixerStream *stream,
-                                       guint           volume)
+gvc_mixer_source_output_push_volume (GvcMixerStream *stream)
 {
         /* FIXME: */
         return TRUE;
@@ -84,7 +83,7 @@ gvc_mixer_source_output_class_init (GvcMixerSourceOutputClass *klass)
         object_class->constructor = gvc_mixer_source_output_constructor;
         object_class->finalize = gvc_mixer_source_output_finalize;
 
-        stream_class->change_volume = gvc_mixer_source_output_change_volume;
+        stream_class->push_volume = gvc_mixer_source_output_push_volume;
         stream_class->change_is_muted = gvc_mixer_source_output_change_is_muted;
 
         g_type_class_add_private (klass, sizeof (GvcMixerSourceOutputPrivate));
diff --git a/gnome-volume-control/src/gvc-mixer-source.c b/gnome-volume-control/src/gvc-mixer-source.c
index 6eeb107..2c2e833 100644
--- a/gnome-volume-control/src/gvc-mixer-source.c
+++ b/gnome-volume-control/src/gvc-mixer-source.c
@@ -45,21 +45,21 @@ static void     gvc_mixer_source_finalize   (GObject            *object);
 G_DEFINE_TYPE (GvcMixerSource, gvc_mixer_source, GVC_TYPE_MIXER_STREAM)
 
 static gboolean
-gvc_mixer_source_change_volume (GvcMixerStream *stream,
-                              guint           volume)
+gvc_mixer_source_push_volume (GvcMixerStream *stream)
 {
         pa_operation      *o;
         guint              index;
         GvcChannelMap     *map;
         pa_context        *context;
         const pa_cvolume  *cv;
+        GvcMixerSource    *source = GVC_MIXER_SOURCE (stream);
 
         index = gvc_mixer_stream_get_index (stream);
 
         map = gvc_mixer_stream_get_channel_map (stream);
 
         /* set the volume */
-        cv = gvc_channel_map_get_cvolume_for_volumes (map, volume);
+        cv = gvc_channel_map_get_cvolume (map);
 
         context = gvc_mixer_stream_get_pa_context (stream);
 
@@ -130,7 +130,7 @@ gvc_mixer_source_class_init (GvcMixerSourceClass *klass)
         object_class->constructor = gvc_mixer_source_constructor;
         object_class->finalize = gvc_mixer_source_finalize;
 
-        stream_class->change_volume = gvc_mixer_source_change_volume;
+        stream_class->push_volume = gvc_mixer_source_push_volume;
         stream_class->change_is_muted = gvc_mixer_source_change_is_muted;
 
         g_type_class_add_private (klass, sizeof (GvcMixerSourcePrivate));
diff --git a/gnome-volume-control/src/gvc-mixer-stream.c b/gnome-volume-control/src/gvc-mixer-stream.c
index 60464e7..c1d4679 100644
--- a/gnome-volume-control/src/gvc-mixer-stream.c
+++ b/gnome-volume-control/src/gvc-mixer-stream.c
@@ -41,8 +41,6 @@ struct GvcMixerStreamPrivate
         guint          id;
         guint          index;
         GvcChannelMap *channel_map;
-        guint          volume;
-        gdouble        decibel;
         char          *name;
         char          *description;
         char          *application_id;
@@ -123,24 +121,32 @@ guint
 gvc_mixer_stream_get_volume (GvcMixerStream *stream)
 {
         g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
-        return stream->priv->volume;
+
+        return (pa_volume_t) gvc_channel_map_get_volume(stream->priv->channel_map)[VOLUME];
 }
 
 gdouble
 gvc_mixer_stream_get_decibel (GvcMixerStream *stream)
 {
         g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
-        return stream->priv->decibel;
+
+        return pa_sw_volume_to_dB(
+                        (pa_volume_t) gvc_channel_map_get_volume(stream->priv->channel_map)[VOLUME]);
 }
 
 gboolean
 gvc_mixer_stream_set_volume (GvcMixerStream *stream,
-                             pa_volume_t     volume)
+                              pa_volume_t     volume)
 {
+        pa_cvolume cv;
+
         g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
 
-        if (volume != stream->priv->volume) {
-                stream->priv->volume = volume;
+        cv = *gvc_channel_map_get_cvolume(stream->priv->channel_map);
+        pa_cvolume_scale(&cv, volume);
+
+        if (!pa_cvolume_equal(gvc_channel_map_get_cvolume(stream->priv->channel_map), &cv)) {
+                gvc_channel_map_volume_changed(stream->priv->channel_map, &cv);
                 g_object_notify (G_OBJECT (stream), "volume");
         }
 
@@ -151,11 +157,16 @@ gboolean
 gvc_mixer_stream_set_decibel (GvcMixerStream *stream,
                               gdouble         db)
 {
+        pa_cvolume cv;
+
         g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
 
-        if (db != stream->priv->decibel) {
-                stream->priv->decibel = db;
-                g_object_notify (G_OBJECT (stream), "decibel");
+        cv = *gvc_channel_map_get_cvolume(stream->priv->channel_map);
+        pa_cvolume_scale(&cv, pa_sw_volume_from_dB(db));
+
+        if (!pa_cvolume_equal(gvc_channel_map_get_cvolume(stream->priv->channel_map), &cv)) {
+                gvc_channel_map_volume_changed(stream->priv->channel_map, &cv);
+                g_object_notify (G_OBJECT (stream), "volume");
         }
 
         return TRUE;
@@ -287,8 +298,9 @@ static void
 on_channel_map_volume_changed (GvcChannelMap  *channel_map,
                                GvcMixerStream *stream)
 {
-        g_debug ("Volume changed");
-        gvc_mixer_stream_change_volume (stream, stream->priv->volume);
+        gvc_mixer_stream_push_volume (stream);
+
+        g_object_notify (G_OBJECT (stream), "volume");
 }
 
 static gboolean
@@ -449,10 +461,12 @@ gvc_mixer_stream_get_property (GObject     *object,
                 g_value_set_string (value, self->priv->icon_name);
                 break;
         case PROP_VOLUME:
-                g_value_set_ulong (value, self->priv->volume);
+                g_value_set_ulong (value,
+                                   pa_cvolume_max(gvc_channel_map_get_cvolume(self->priv->channel_map)));
                 break;
         case PROP_DECIBEL:
-                g_value_set_double (value, self->priv->decibel);
+                g_value_set_double (value,
+                                    pa_sw_volume_to_dB(pa_cvolume_max(gvc_channel_map_get_cvolume(self->priv->channel_map))));
                 break;
         case PROP_IS_MUTED:
                 g_value_set_boolean (value, self->priv->is_muted);
@@ -487,8 +501,7 @@ gvc_mixer_stream_constructor (GType                  type,
 }
 
 static gboolean
-gvc_mixer_stream_real_change_volume (GvcMixerStream *stream,
-                                     guint           volume)
+gvc_mixer_stream_real_push_volume (GvcMixerStream *stream)
 {
         return FALSE;
 }
@@ -501,12 +514,11 @@ gvc_mixer_stream_real_change_is_muted (GvcMixerStream *stream,
 }
 
 gboolean
-gvc_mixer_stream_change_volume (GvcMixerStream *stream,
-                                guint           volume)
+gvc_mixer_stream_push_volume (GvcMixerStream *stream)
 {
         gboolean ret;
         g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
-        ret = GVC_MIXER_STREAM_GET_CLASS (stream)->change_volume (stream, volume);
+        ret = GVC_MIXER_STREAM_GET_CLASS (stream)->push_volume (stream);
         return ret;
 }
 
@@ -538,7 +550,7 @@ gvc_mixer_stream_class_init (GvcMixerStreamClass *klass)
         gobject_class->set_property = gvc_mixer_stream_set_property;
         gobject_class->get_property = gvc_mixer_stream_get_property;
 
-        klass->change_volume = gvc_mixer_stream_real_change_volume;
+        klass->push_volume = gvc_mixer_stream_real_push_volume;
         klass->change_is_muted = gvc_mixer_stream_real_change_is_muted;
 
         g_object_class_install_property (gobject_class,
diff --git a/gnome-volume-control/src/gvc-mixer-stream.h b/gnome-volume-control/src/gvc-mixer-stream.h
index 1c28cd0..58e4865 100644
--- a/gnome-volume-control/src/gvc-mixer-stream.h
+++ b/gnome-volume-control/src/gvc-mixer-stream.h
@@ -48,8 +48,7 @@ typedef struct
         GObjectClass           parent_class;
 
         /* vtable */
-        gboolean (*change_volume)   (GvcMixerStream *stream,
-                                     guint           volume);
+        gboolean (*push_volume)   (GvcMixerStream *stream);
         gboolean (*change_is_muted) (GvcMixerStream *stream,
                                      gboolean        is_muted);
         gboolean (*is_running)      (GvcMixerStream *stream);
@@ -64,9 +63,8 @@ GvcChannelMap *     gvc_mixer_stream_get_channel_map (GvcMixerStream *stream);
 
 guint               gvc_mixer_stream_get_volume      (GvcMixerStream *stream);
 gdouble             gvc_mixer_stream_get_decibel     (GvcMixerStream *stream);
-gboolean            gvc_mixer_stream_change_volume   (GvcMixerStream *stream,
-                                                      guint           volume);
-guint32             gvc_mixer_stream_get_base_volume (GvcMixerStream *stream);
+gboolean            gvc_mixer_stream_push_volume     (GvcMixerStream *stream);
+pa_volume_t         gvc_mixer_stream_get_base_volume (GvcMixerStream *stream);
 
 gboolean            gvc_mixer_stream_get_is_muted    (GvcMixerStream *stream);
 gboolean            gvc_mixer_stream_get_can_decibel (GvcMixerStream *stream);
diff --git a/gnome-volume-control/src/gvc-stream-status-icon.c b/gnome-volume-control/src/gvc-stream-status-icon.c
index ef302bc..5696661 100644
--- a/gnome-volume-control/src/gvc-stream-status-icon.c
+++ b/gnome-volume-control/src/gvc-stream-status-icon.c
@@ -67,8 +67,9 @@ on_adjustment_value_changed (GtkAdjustment *adjustment,
         gdouble volume;
 
         volume = gtk_adjustment_get_value (adjustment);
-        gvc_mixer_stream_change_volume (icon->priv->mixer_stream,
-                                        (guint)volume);
+
+        gvc_mixer_stream_set_volume(icon->priv->mixer_stream,
+                                    (pa_volume_t) volume );
 }
 
 static gboolean



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]