Index: gsr-window.c
===================================================================
--- gsr-window.c	(revision 4071)
+++ gsr-window.c	(working copy)
@@ -48,6 +48,7 @@
 #include <profiles/gnome-media-profiles.h>
 
 #include "gsr-window.h"
+#include "gtkvumeter.h"
 
 GST_DEBUG_CATEGORY_STATIC (gsr_debug);
 #define GST_CAT_DEFAULT gsr_debug
@@ -65,6 +66,9 @@ extern void gsr_add_recent (gchar *filen
 #define KEY_LAST_PROFILE_ID GCONF_DIR "last-profile-id"
 #define EBUSY_TRY_AGAIN     3000    /* Empirical data */
 
+#define LOW_VUMETER_VAL -40.0
+#define HIGH_VUMETER_VAL +0.0
+
 typedef struct _GSRWindowPipeline {
 	GstElement *pipeline;
 	GstState    state;     /* last seen (async) pipeline state */
@@ -1298,7 +1302,8 @@ stop_cb (GtkAction *action,
 		set_pipeline_state_to_null (priv->record->pipeline);
 		gtk_widget_set_sensitive (window->priv->level, FALSE);
 		gtk_widget_set_sensitive (window->priv->volume_label, FALSE);
-		gtk_progress_set_percentage (GTK_PROGRESS (window->priv->level), 0);
+		gtk_vumeter_set_levels (GTK_VUMETER (window->priv->level),
+				LOW_VUMETER_VAL, LOW_VUMETER_VAL);
 	}
 }
 
@@ -1934,27 +1939,34 @@ level_message_handler_cb (GstBus * bus, 
 
     if (g_str_equal (name, "level")) {
       gint channels;
-      gdouble peak_dB;
-      gdouble myind;
-      const GValue *list;
-      const GValue *value;
+      const GValue *l_cur;
+      const GValue *l_peak;
+      gdouble cur=0.0, peak=0.0;
 
       gint i;
       /* we can get the number of channels as the length of any of the value
        * lists */
 
-      list = gst_structure_get_value (s, "rms");
-      channels = gst_value_list_get_size (list);
+      l_cur = (GValue *)gst_structure_get_value (s, "rms");
+      l_peak = (GValue *)gst_structure_get_value (s, "peak");
+
+      channels = gst_value_list_get_size (l_cur);
 
       for (i = 0; i < channels; ++i) {
-	list = gst_structure_get_value (s, "peak");
-        value = gst_value_list_get_value (list, i);
-        peak_dB = g_value_get_double (value);
-	myind = exp (peak_dB / 20);
-	if (myind > 1.0)
-		myind = 1.0;
-	gtk_progress_set_percentage (GTK_PROGRESS (priv->level), myind);
+	cur += g_value_get_double (gst_value_list_get_value (l_cur,i));
+	peak += g_value_get_double (gst_value_list_get_value (l_peak,i));
+      }
+      if (isinf (cur) || isnan (cur)) {
+	cur = LOW_VUMETER_VAL;
+      } else {
+	cur /= channels;
       }
+      if (isinf (peak) || isnan (peak)) {
+	peak = LOW_VUMETER_VAL;
+      } else {
+	peak /= channels;
+      }
+      gtk_vumeter_set_levels (GTK_VUMETER (priv->level), (gint)cur, (gint)cur);
     }
   }
   /* we handled the message we want, and ignored the ones we didn't want.
@@ -2444,6 +2456,9 @@ gsr_window_init (GSRWindow *window)
 	priv->statusbar = gtk_statusbar_new ();
 	GTK_WIDGET_SET_FLAGS (priv->statusbar, GTK_CAN_FOCUS);
 	gtk_box_pack_end (GTK_BOX (main_vbox), priv->statusbar, FALSE, FALSE, 0);
+        /* the resize grip makes the inner level widget to reduce its size when
+         * unsensitivised */
+        gtk_statusbar_set_has_resize_grip ( GTK_STATUSBAR (priv->statusbar), FALSE);
 	gtk_widget_show (priv->statusbar);
 
 	/* hack to get the same shadow as the status bar.. */
@@ -2463,13 +2478,15 @@ gsr_window_init (GSRWindow *window)
 	gtk_box_pack_start (GTK_BOX (hbox), priv->volume_label, FALSE, TRUE, 0);
 
 	/* initialize priv->level */
-	align = gtk_aspect_frame_new ("", 0.0, 0.0, 20, FALSE);
-	gtk_frame_set_shadow_type (GTK_FRAME (align), GTK_SHADOW_NONE);
-	gtk_widget_show (align);
-	gtk_box_pack_start (GTK_BOX (hbox), align, FALSE, FALSE, 0);
-
-	priv->level = gtk_progress_bar_new ();
-	gtk_container_add (GTK_CONTAINER (align), priv->level);
+	priv->level = gtk_vumeter_new (FALSE);
+	gtk_vumeter_set_min_max (GTK_VUMETER (priv->level), LOW_VUMETER_VAL, HIGH_VUMETER_VAL);
+	gtk_vumeter_set_peaks_falloff (GTK_VUMETER (priv->level),
+			GTK_VUMETER_PEAKS_FALLOFF_MEDIUM);
+	gtk_vumeter_set_scale (GTK_VUMETER (priv->level),
+			GTK_VUMETER_SCALE_LINEAR);
+	gtk_vumeter_set_levels (GTK_VUMETER (priv->level),
+			LOW_VUMETER_VAL, LOW_VUMETER_VAL);
+	gtk_box_pack_start (GTK_BOX (hbox), priv->level, TRUE, TRUE, 0);
 
 	gtk_widget_set_sensitive (window->priv->volume_label, FALSE);
 	gtk_widget_set_sensitive (window->priv->level, FALSE);
Index: gtkvumeter.h
===================================================================
--- gtkvumeter.h	(revision 0)
+++ gtkvumeter.h	(revision 0)
@@ -0,0 +1,82 @@
+/* $Id: gtkvumeter.h 1954 2008-09-01 19:16:32Z ensonic $
+ *
+ * GtkVumeter
+ * Copyright (C) 2003 Todd Goyen <wettoad@knighthoodofbuh.org>
+ *               2006 Stefan Kost <ensonic@users.sf.net>
+ *
+ * This widget has been release as freeware.
+ */
+
+#ifndef __GTKVUMETER_H__
+#define __GTKVUMETER_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_VUMETER                (gtk_vumeter_get_type ())
+#define GTK_VUMETER(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_VUMETER, GtkVUMeter))
+#define GTK_VUMETER_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_VUMETER GtkVUMeterClass))
+#define GTK_IS_VUMETER(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_VUMETER))
+#define GTK_IS_VUMETER_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_VUMETER))
+#define GTK_VUMETER_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_VUMETER, GtkVUMeterClass))
+
+typedef struct _GtkVUMeter      GtkVUMeter;
+typedef struct _GtkVUMeterClass GtkVUMeterClass;
+
+/**
+ * GtkVUMeter:
+ *
+ * a volume meter widget
+ */
+struct _GtkVUMeter {
+    GtkWidget   widget;
+
+    GdkColormap *colormap;
+    gint        colors;
+
+    GdkGC       **f_gc;
+    GdkGC       **b_gc;
+    GdkColor    *f_colors;
+    GdkColor    *b_colors;
+
+    gboolean    vertical;
+    gint        rms_level;
+    gint        min;
+    gint        max;
+
+    gint        peaks_falloff;
+    gint        delay_peak_level;
+    gint        peak_level;
+
+    gint        scale;
+};
+
+struct _GtkVUMeterClass {
+    GtkWidgetClass  parent_class;
+};
+
+/* this is not yet implemented */
+enum {
+    GTK_VUMETER_PEAKS_FALLOFF_SLOW,
+    GTK_VUMETER_PEAKS_FALLOFF_MEDIUM,
+    GTK_VUMETER_PEAKS_FALLOFF_FAST,
+    GTK_VUMETER_PEAKS_FALLOFF_LAST
+};
+
+enum {
+    GTK_VUMETER_SCALE_LINEAR,
+    GTK_VUMETER_SCALE_LOG,
+    GTK_VUMETER_SCALE_LAST
+};
+
+GType    gtk_vumeter_get_type (void) G_GNUC_CONST;
+GtkWidget *gtk_vumeter_new (gboolean vertical);
+void gtk_vumeter_set_min_max (GtkVUMeter *vumeter, gint min, gint max);
+void gtk_vumeter_set_levels (GtkVUMeter *vumeter, gint rms, gint peak);
+void gtk_vumeter_set_peaks_falloff (GtkVUMeter *vumeter, gint peaks_falloff);
+void gtk_vumeter_set_scale (GtkVUMeter *vumeter, gint scale);
+
+G_END_DECLS
+
+#endif /* __GTKVUMETER_H__ */
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 4071)
+++ Makefile.am	(working copy)
@@ -14,7 +14,9 @@ bin_PROGRAMS = gnome-sound-recorder
 gnome_sound_recorder_SOURCES =	\
 	gnome-recorder.c	\
 	gsr-window.c		\
-	gsr-window.h
+	gsr-window.h		\
+	gtkvumeter.c		\
+	gtkvumeter.h
 
 uidir = $(datadir)/gnome-sound-recorder/ui
 ui_DATA = ui.xml
Index: gtkvumeter.c
===================================================================
--- gtkvumeter.c	(revision 0)
+++ gtkvumeter.c	(revision 0)
@@ -0,0 +1,509 @@
+/* $Id: gtkvumeter.c 2060 2008-11-11 09:06:32Z ensonic $
+ *
+ * GtkVumeter
+ * Copyright (C) 2003 Todd Goyen <wettoad@knighthoodofbuh.org>
+ *               2006 Stefan Kost <ensonic@users.sf.net>
+ *
+ * This widget has been release as freeware.
+ */
+/* @todo:
+ * - make it use cairo
+ * - shade lines (100%, 50% brightness)
+ * - add properties:
+ *   - vertical : gboolean, readonly
+ *   - min,max,rms,peak : gint, read/write
+ *   - peaks_falloff,scale_type : enum, read/write
+ */
+/**
+ * SECTION:gtkvumeter
+ * @short_description: vu meter widget
+ *
+ * Shows a vertical or horizontal gauge with a colorized bar to signal volume
+ * level.
+ */
+
+#include <math.h>
+#include <gtk/gtk.h>
+#include "gtkvumeter.h"
+
+#define MIN_HORIZONTAL_VUMETER_WIDTH   150
+#define HORIZONTAL_VUMETER_HEIGHT  6
+#define VERTICAL_VUMETER_WIDTH     6
+#define MIN_VERTICAL_VUMETER_HEIGHT    400
+
+static void gtk_vumeter_init (GtkVUMeter *vumeter);
+static void gtk_vumeter_class_init (GtkVUMeterClass *class);
+static void gtk_vumeter_destroy (GtkObject *object);
+static void gtk_vumeter_realize (GtkWidget *widget);
+static void gtk_vumeter_size_request (GtkWidget *widget, GtkRequisition *requisition);
+static void gtk_vumeter_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
+static gint gtk_vumeter_expose (GtkWidget *widget, GdkEventExpose *event);
+static void gtk_vumeter_free_colors (GtkVUMeter *vumeter);
+static void gtk_vumeter_setup_colors (GtkVUMeter *vumeter);
+static gint gtk_vumeter_sound_level_to_draw_level (GtkVUMeter *vumeter, gint level);
+
+static GtkWidgetClass *parent_class = NULL;
+
+GType gtk_vumeter_get_type (void)
+{
+    static GType vumeter_type = 0;
+
+    if (G_UNLIKELY(!vumeter_type)) {
+        const GTypeInfo vumeter_info = {
+            sizeof (GtkVUMeterClass),
+            NULL, NULL,
+            (GClassInitFunc) gtk_vumeter_class_init,
+            NULL, NULL, sizeof (GtkVUMeter), 0,
+            (GInstanceInitFunc) gtk_vumeter_init,
+        };
+        vumeter_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkVUMeter", &vumeter_info, 0);
+    }
+
+    return vumeter_type;
+}
+
+/**
+ * gtk_vumeter_new:
+ * @vertical: %TRUE for a vertical VUMeter, %FALSE for horizontal VUMeter.
+ *
+ * Creates a new VUMeter widget.
+ *
+ * Returns: the new #GtkWidget
+ */
+GtkWidget* gtk_vumeter_new (gboolean vertical)
+{
+    GtkVUMeter *vumeter;
+    vumeter = GTK_VUMETER( g_object_new (GTK_TYPE_VUMETER,NULL));
+    vumeter->vertical = vertical;
+    return GTK_WIDGET (vumeter);
+}
+
+static void gtk_vumeter_init (GtkVUMeter *vumeter)
+{
+    vumeter->colormap = NULL;
+    vumeter->colors = 0;
+    vumeter->f_gc = NULL;
+    vumeter->b_gc = NULL;
+    vumeter->f_colors = NULL;
+    vumeter->b_colors = NULL;
+
+    vumeter->rms_level = 0;
+    vumeter->min = 0;
+    vumeter->max = 32767;
+    vumeter->peaks_falloff = GTK_VUMETER_PEAKS_FALLOFF_MEDIUM;
+    vumeter->peak_level = 0;
+    vumeter->delay_peak_level = 0;
+
+    vumeter->scale = GTK_VUMETER_SCALE_LINEAR;
+}
+
+static void gtk_vumeter_class_init (GtkVUMeterClass *klass)
+{
+    GtkObjectClass *object_class = (GtkObjectClass*) klass;
+    GtkWidgetClass *widget_class = (GtkWidgetClass*) klass;
+
+    parent_class = g_type_class_peek_parent (klass);
+
+    object_class->destroy = gtk_vumeter_destroy;
+
+    widget_class->realize = gtk_vumeter_realize;
+    widget_class->expose_event = gtk_vumeter_expose;
+    widget_class->size_request = gtk_vumeter_size_request;
+    widget_class->size_allocate = gtk_vumeter_size_allocate;
+}
+
+static void gtk_vumeter_destroy (GtkObject *object)
+{
+    GtkVUMeter *vumeter = GTK_VUMETER (object);
+
+    gtk_vumeter_free_colors (vumeter);
+
+    GTK_OBJECT_CLASS (parent_class)->destroy (object);
+}
+
+static void gtk_vumeter_realize (GtkWidget *widget)
+{
+    GtkVUMeter *vumeter;
+    GdkWindowAttr attributes;
+    gint attributes_mask;
+
+    g_return_if_fail (widget != NULL);
+    g_return_if_fail (GTK_IS_VUMETER (widget));
+
+    GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+    vumeter = GTK_VUMETER (widget);
+
+    attributes.x = widget->allocation.x;
+    attributes.y = widget->allocation.y;
+    attributes.width = widget->allocation.width;
+    attributes.height = widget->allocation.height;
+    attributes.wclass = GDK_INPUT_OUTPUT;
+    attributes.window_type = GDK_WINDOW_CHILD;
+    attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
+    attributes.visual = gtk_widget_get_visual (widget);
+    attributes.colormap = gtk_widget_get_colormap (widget);
+    attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+    widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
+
+    widget->style = gtk_style_attach (widget->style, widget->window);
+
+    gdk_window_set_user_data (widget->window, widget);
+    gtk_style_set_background (widget->style, widget->window,  GTK_STATE_NORMAL);
+
+    /* colors */
+    vumeter->colormap = gdk_colormap_get_system ();
+    gtk_vumeter_setup_colors (vumeter);
+}
+
+static void gtk_vumeter_size_request (GtkWidget *widget, GtkRequisition *requisition)
+{
+    GtkVUMeter *vumeter;
+
+    g_return_if_fail (GTK_IS_VUMETER (widget));
+    g_return_if_fail (requisition != NULL);
+
+    vumeter = GTK_VUMETER (widget);
+
+    if (vumeter->vertical == TRUE) {
+        requisition->width = VERTICAL_VUMETER_WIDTH;
+        requisition->height = MIN_VERTICAL_VUMETER_HEIGHT;
+    } else {
+        requisition->width = MIN_HORIZONTAL_VUMETER_WIDTH;
+        requisition->height = HORIZONTAL_VUMETER_HEIGHT;
+    }
+}
+
+static void gtk_vumeter_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
+{
+    GtkVUMeter *vumeter;
+
+    g_return_if_fail (widget != NULL);
+    g_return_if_fail (GTK_IS_VUMETER (widget));
+    g_return_if_fail (allocation != NULL);
+
+    GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
+
+    widget->allocation = *allocation;
+    vumeter = GTK_VUMETER (widget);
+
+    if (GTK_WIDGET_REALIZED (widget)) {
+        if (vumeter->vertical == TRUE) {
+            /* veritcal */
+            gdk_window_move_resize (widget->window, allocation->x, allocation->y,
+                MAX(allocation->width,VERTICAL_VUMETER_WIDTH),
+                MIN(allocation->height, MIN_VERTICAL_VUMETER_HEIGHT));
+        } else {
+            /* horizontal */
+            gdk_window_move_resize (widget->window, allocation->x, allocation->y,
+                MIN(allocation->width, MIN_HORIZONTAL_VUMETER_WIDTH),
+                MAX(allocation->height,HORIZONTAL_VUMETER_HEIGHT));
+        }
+        /* Fix the colours */
+        gtk_vumeter_setup_colors (vumeter);
+    }
+}
+
+static gint gtk_vumeter_expose (GtkWidget *widget, GdkEventExpose *event)
+{
+    GtkVUMeter *vumeter;
+    gint index, rms_level, peak_level;
+    gint width, height;
+    /* detail for part of progressbar
+    const gchar detail[]="trough";
+    */
+
+    g_return_val_if_fail (widget != NULL, FALSE);
+    g_return_val_if_fail (GTK_IS_VUMETER (widget), FALSE);
+    g_return_val_if_fail (event != NULL, FALSE);
+
+    if (event->count > 0)
+        return FALSE;
+
+    vumeter = GTK_VUMETER (widget);
+    rms_level = gtk_vumeter_sound_level_to_draw_level (vumeter,
+                   vumeter->rms_level);
+    peak_level = gtk_vumeter_sound_level_to_draw_level (vumeter,
+                   vumeter->peak_level);
+    if (vumeter->vertical == TRUE) {
+        width = widget->allocation.width - 2;
+        height = widget->allocation.height;
+
+        /* draw border */
+        gtk_paint_box (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
+            NULL, widget, NULL/*detail*/, 0, 0, widget->allocation.width, height);
+        /* draw background gradient */
+        for (index = rms_level; index < peak_level; index++) {
+            gdk_draw_line (widget->window, vumeter->f_gc[index], 1, index + 1, width, index + 1);
+        }
+        /* draw foreground gradient */
+        for (index = 0; index < rms_level; index++) {
+            gdk_draw_line (widget->window, vumeter->b_gc[index], 1, index + 1, width, index + 1);
+        }
+    } else { /* Horizontal */
+        width = widget->allocation.width;
+        height = widget->allocation.height - 2;
+
+        /* draw border */
+        gtk_paint_box (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
+            NULL, widget, NULL/*detail*/, 0, 0, width, widget->allocation.height);
+        /* draw background gradient */
+        for (index = rms_level; index < peak_level; index++) {
+            gdk_draw_line (widget->window, vumeter->b_gc[index], width - index - 1, 1, width - index - 1, height);
+        }
+        /* draw foreground gradient */
+        for (index = peak_level; index < width - 2; index++) {
+            gdk_draw_line (widget->window, vumeter->f_gc[index], width - index - 1, 1, width - index - 1, height);
+        }
+    }
+
+    //GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
+    //return(TRUE);
+    return(FALSE);
+}
+
+static void gtk_vumeter_free_colors (GtkVUMeter *vumeter)
+{
+    gint index;
+
+    /* Free old gc's */
+    if (vumeter->f_gc && vumeter->b_gc) {
+        for (index = 0; index < vumeter->colors; index++) {
+            if (vumeter->f_gc[index]) {
+                g_object_unref (G_OBJECT(vumeter->f_gc[index]));
+            }
+            if (vumeter->b_gc[index]) {
+                g_object_unref (G_OBJECT(vumeter->b_gc[index]));
+            }
+        }
+        g_free(vumeter->f_gc);
+        g_free(vumeter->b_gc);
+        vumeter->f_gc = NULL;
+        vumeter->b_gc = NULL;
+    }
+
+    /* Free old Colors */
+    if (vumeter->f_colors) {
+        gdk_colormap_free_colors (vumeter->colormap, vumeter->f_colors, vumeter->colors);
+        g_free (vumeter->f_colors);
+        vumeter->f_colors = NULL;
+    }
+    if (vumeter->b_colors) {
+        gdk_colormap_free_colors (vumeter->colormap, vumeter->b_colors, vumeter->colors);
+        g_free (vumeter->b_colors);
+        vumeter->b_colors = NULL;
+    }
+}
+
+static void gtk_vumeter_setup_colors (GtkVUMeter *vumeter)
+{
+    gint index;
+    gint f_step, b_step;
+    gint first, second;
+    gint max = 0, min = 0, log_max = 0;
+
+    g_return_if_fail (vumeter->colormap != NULL);
+
+    gtk_vumeter_free_colors (vumeter);
+
+    /* Set new size */
+    if (vumeter->vertical == TRUE) {
+        vumeter->colors = MAX(GTK_WIDGET(vumeter)->allocation.height - 2, 0);
+    } else {
+        vumeter->colors = MAX(GTK_WIDGET(vumeter)->allocation.width - 2, 0);
+    }
+
+    if (vumeter->colors == 0)
+      return;
+    /* allocate new memory */
+    vumeter->f_colors = g_malloc (vumeter->colors * sizeof(GdkColor));
+    vumeter->b_colors = g_malloc (vumeter->colors * sizeof(GdkColor));
+    vumeter->f_gc = g_malloc (vumeter->colors * sizeof(GdkGC *));
+    vumeter->b_gc = g_malloc (vumeter->colors * sizeof(GdkGC *));
+
+    /* Initialize stuff */
+    if (vumeter->scale == GTK_VUMETER_SCALE_LINEAR) {
+        first = vumeter->colors / 2;
+        second = vumeter->colors;
+    } else {
+        max = (gdouble)vumeter->max;
+        min = (gdouble)vumeter->min;
+        log_max = - 20.0 * log10(1.0/(max - min + 1.0));
+        first = (gint)((gdouble)vumeter->colors * 6.0 / log_max);
+        second = (gint)((gdouble)vumeter->colors * 18.0 / log_max);
+    }
+
+    vumeter->f_colors[0].red = 65535;
+    vumeter->f_colors[0].green = 0;
+    vumeter->f_colors[0].blue = 0;
+
+    vumeter->b_colors[0].red = 49151;
+    //vumeter->b_colors[0].red = 32767;
+    vumeter->b_colors[0].green = 0;
+    vumeter->b_colors[0].blue = 0;
+
+    /* Allocate from Red to Yellow */
+    f_step = 65535 / (first - 1);
+    b_step = 49151 / (first - 1);
+    //b_step = 32767  / (first - 1);
+    for (index = 1; index < first; index++) {
+        /* foreground */
+        vumeter->f_colors[index].red = 65535;
+        vumeter->f_colors[index].green = vumeter->f_colors[index - 1].green + f_step;
+        vumeter->f_colors[index].blue = 0;
+        /* background */
+        vumeter->b_colors[index].red = 49151;
+        //vumeter->b_colors[index].red = 32767;
+        vumeter->b_colors[index].green = vumeter->b_colors[index - 1].green + b_step;
+        vumeter->b_colors[index].blue = 0;
+    }
+    /* Allocate from Yellow to Green */
+    f_step = 65535 / (second - first);
+    b_step = 49151 / (second - first);
+    //b_step = 32767 / (second - first);
+    for (index = first; index < second; index++) {
+        /* foreground */
+        vumeter->f_colors[index].red = vumeter->f_colors[index - 1].red - f_step;
+        vumeter->f_colors[index].green = vumeter->f_colors[index - 1].green;
+        vumeter->f_colors[index].blue = 0;
+        /* background */
+        vumeter->b_colors[index].red = vumeter->b_colors[index - 1].red - b_step;
+        vumeter->b_colors[index].green = vumeter->b_colors[index - 1].green;
+        vumeter->b_colors[index].blue = 0;
+    }
+    if (vumeter->scale == GTK_VUMETER_SCALE_LOG) {
+        /* Allocate from Green to Dark Green */
+        f_step = 32767 / (vumeter->colors - second);
+        b_step = 32767 / (vumeter->colors - second);
+        for (index = second; index < vumeter->colors; index++) {
+            /* foreground */
+            vumeter->f_colors[index].red = 0;
+            vumeter->f_colors[index].green = vumeter->f_colors[index - 1].green - f_step;
+            vumeter->f_colors[index].blue = 0;
+            /* background */
+            vumeter->b_colors[index].red = 0;
+            vumeter->b_colors[index].green = vumeter->b_colors[index - 1].green - b_step;
+            vumeter->b_colors[index].blue = 0;
+        }
+    }
+    /* Allocate the Colours */
+    for (index = 0; index < vumeter->colors; index++) {
+        /* foreground */
+        gdk_colormap_alloc_color (vumeter->colormap, &vumeter->f_colors[index], FALSE, TRUE);
+        vumeter->f_gc[index] = gdk_gc_new(GTK_WIDGET(vumeter)->window);
+        gdk_gc_set_foreground(vumeter->f_gc[index], &vumeter->f_colors[index]);
+        /* background */
+        gdk_colormap_alloc_color (vumeter->colormap, &vumeter->b_colors[index], FALSE, TRUE);
+        vumeter->b_gc[index] = gdk_gc_new(GTK_WIDGET(vumeter)->window);
+        gdk_gc_set_foreground(vumeter->b_gc[index], &vumeter->b_colors[index]);
+    }
+}
+
+static gint gtk_vumeter_sound_level_to_draw_level (GtkVUMeter *vumeter,
+               gint sound_level)
+{
+    gdouble draw_level;
+    gdouble level, min, max, height;
+    gdouble log_level, log_max;
+
+    level = (gdouble)sound_level;
+    min = (gdouble)vumeter->min;
+    max = (gdouble)vumeter->max;
+    height = (gdouble)vumeter->colors;
+
+    if (vumeter->scale == GTK_VUMETER_SCALE_LINEAR) {
+        draw_level = (1.0 - (level - min)/(max - min)) * height;
+    } else {
+        log_level = log10((level - min + 1)/(max - min + 1));
+        log_max = log10(1/(max - min + 1));
+        draw_level = log_level/log_max * height;
+    }
+
+    return ((gint)draw_level);
+}
+
+/**
+ * gtk_vumeter_set_min_max:
+ * @vumeter: the vumeter widget to change the level bounds
+ * @min: the new minimum level shown (level that is 0%)
+ * @max: the new maximum level shown (level that is 100%)
+ *
+ * Sets the minimum and maximum of the VU Meters scale.
+ * The positions are irrelevant as the widget will rearrange them.
+ * It will also increment max by one if min == max.
+ * And finally it will clamp the current level into the min,max range.
+ */
+void gtk_vumeter_set_min_max (GtkVUMeter *vumeter, gint min, gint max)
+{
+    g_return_if_fail (GTK_IS_VUMETER (vumeter));
+
+    vumeter->max = MAX(max, min);
+    vumeter->min = MIN(min, max);
+    if (vumeter->max == vumeter->min) {
+        vumeter->max++;
+    }
+    vumeter->rms_level = CLAMP (vumeter->rms_level, vumeter->min, vumeter->max);
+    vumeter->peak_level = CLAMP (vumeter->peak_level, vumeter->min, vumeter->max);
+    gtk_widget_queue_draw (GTK_WIDGET(vumeter));
+}
+
+/**
+ * gtk_vumeter_set_levels:
+ * @vumeter: the vumeter widget to change the current level
+ * @rms: the new rms level shown
+ * @peak: the new peak level shown
+ *
+ * Sets new level values for the level display.
+ * They are clamped to the min max range.
+ */
+void gtk_vumeter_set_levels (GtkVUMeter *vumeter, gint rms, gint peak)
+{
+    g_return_if_fail (GTK_IS_VUMETER (vumeter));
+
+    vumeter->rms_level = CLAMP (rms, vumeter->min, vumeter->max);
+    vumeter->peak_level = CLAMP (peak, vumeter->min, vumeter->max);
+
+    gtk_widget_queue_draw (GTK_WIDGET(vumeter));
+}
+
+/**
+ * gtk_vumeter_set_peaks_falloff:
+ * @vumeter: the vumeter widget to change the current level
+ * @peaks_falloff: controls the speed to the peak decay
+ *
+ * Sets the speed for the peaks to decay.
+ *
+ * PLEASE NOTE: the falloff is not yet implemented
+ */
+void gtk_vumeter_set_peaks_falloff (GtkVUMeter *vumeter, gint peaks_falloff)
+{
+    g_return_if_fail (GTK_IS_VUMETER (vumeter));
+
+    if (peaks_falloff > GTK_VUMETER_PEAKS_FALLOFF_FAST) {
+        peaks_falloff = GTK_VUMETER_PEAKS_FALLOFF_FAST;
+    }
+    vumeter->peaks_falloff=peaks_falloff;
+}
+
+/**
+ * gtk_vumeter_set_scale:
+ * @vumeter: the vumeter widget to change the scaling type
+ * @scale: the scale type, either GTK_VUMETER_SCALE_LINEAR or GTK_VUMETER_SCALE_LOG
+ *
+ * Sets the scale of the VU Meter.
+ * It is either log or linear and defaults to linear.
+ * No matter which scale you set the input should always be linear, #GtkVUMeter
+ * does the log calculation. 0db is red. -6db is yellow. -18db is green.
+ * Whatever min turns into is dark green.
+ */
+void gtk_vumeter_set_scale (GtkVUMeter *vumeter, gint scale)
+{
+    g_return_if_fail (GTK_IS_VUMETER (vumeter));
+
+    if (scale != vumeter->scale) {
+        vumeter->scale = CLAMP(scale, GTK_VUMETER_SCALE_LINEAR, GTK_VUMETER_SCALE_LAST - 1);
+        if (GTK_WIDGET_REALIZED(vumeter)) {
+            gtk_vumeter_setup_colors (vumeter);
+            gtk_widget_queue_draw (GTK_WIDGET(vumeter));
+        }
+    }
+}
