diff --git a/gnome-volume-control/src/gvc-balance-bar.c b/gnome-volume-control/src/gvc-balance-bar.c
index f51a93a..74d05ab 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))
 
@@ -112,7 +113,7 @@ _scale_box_new (GvcBalanceBar *bar)
                 gtk_scale_add_mark (GTK_SCALE (priv->scale),  adjustment->upper,
                                     GTK_POS_BOTTOM, str);
                 g_free (str);
-        } else {
+        } else if (bar->priv->btype == BALANCE_TYPE_FR) {
                 str = g_strdup_printf ("<small>%s</small>", C_("balance", "Front"));
                 gtk_scale_add_mark (GTK_SCALE (priv->scale), adjustment->lower,
                                     GTK_POS_BOTTOM, str);
@@ -124,8 +125,11 @@ _scale_box_new (GvcBalanceBar *bar)
                 g_free (str);
         }
 
-        gtk_scale_add_mark (GTK_SCALE (priv->scale), (adjustment->upper - adjustment->lower)/2 + adjustment->lower, 
-                            GTK_POS_BOTTOM, NULL);
+	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 +180,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 +204,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 +259,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 (_("_Sub-woofer:"));
+                break;
+	default:
+		g_assert_not_reached ();
         }
         gtk_misc_set_alignment (GTK_MISC (bar->priv->label),
                                 0.0,
@@ -343,7 +390,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,6 +426,8 @@ on_scale_scroll_event (GtkWidget      *widget,
 
         value = gtk_adjustment_get_value (bar->priv->adjustment);
 
+        //FIXME fix for the LFE case
+
         if (event->direction == GDK_SCROLL_UP) {
                 if (value + 0.01 > 1.0)
                         value = 1.0;
@@ -396,6 +445,27 @@ on_scale_scroll_event (GtkWidget      *widget,
         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)
@@ -412,10 +482,17 @@ on_adjustment_value_changed (GtkAdjustment *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-map.c b/gnome-volume-control/src/gvc-channel-map.c
index 66a8ecf..d67a32e 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;
 }
@@ -97,6 +142,14 @@ gvc_channel_map_can_fade (GvcChannelMap  *map)
         return map->priv->can_fade;
 }
 
+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)
 {
@@ -196,6 +249,7 @@ 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;
diff --git a/gnome-volume-control/src/gvc-channel-map.h b/gnome-volume-control/src/gvc-channel-map.h
index b00895a..7d90e5e 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,6 +64,7 @@ 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);
diff --git a/gnome-volume-control/src/gvc-mixer-dialog.c b/gnome-volume-control/src/gvc-mixer-dialog.c
index 036fe87..68c41ec 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;
@@ -144,6 +145,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) {
@@ -156,6 +158,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) {
@@ -179,6 +186,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);
@@ -191,9 +199,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));
 }
 
