From 5c3a8a0139813644799136d05e2ed4675cde530a Mon Sep 17 00:00:00 2001
From: Ludovic Pouzenc <ludovic@pouzenc.fr>
Date: Wed, 30 May 2012 20:47:15 +0000
Subject: Version qui marche des GtkVuMeter, youpie !!!

git-svn-id: file:///var/svn/2012-violon-leds/trunk@7 6be1fa4d-33ac-4c33-becc-79fcb3794bb6
---
 tests/test4/compute.c            |   2 +-
 tests/test4/gtkvumeter.c         | 501 ++++++++++++++-------------------------
 tests/test4/gtkvumeter.h         |  93 ++------
 tests/test4/no-perf/compute.c    |  42 ++++
 tests/test4/no-perf/compute.h    |  10 +
 tests/test4/no-perf/gtkvumeter.c | 408 +++++++++++++++++++++++++++++++
 tests/test4/no-perf/gtkvumeter.h |  80 +++++++
 tests/test4/no-perf/test4.c      |  56 +++++
 tests/test4/test4.c              |   8 +-
 tests/test4/win_main.c           |  42 ++--
 10 files changed, 825 insertions(+), 417 deletions(-)
 create mode 100644 tests/test4/no-perf/compute.c
 create mode 100644 tests/test4/no-perf/compute.h
 create mode 100644 tests/test4/no-perf/gtkvumeter.c
 create mode 100644 tests/test4/no-perf/gtkvumeter.h
 create mode 100644 tests/test4/no-perf/test4.c

(limited to 'tests/test4')

diff --git a/tests/test4/compute.c b/tests/test4/compute.c
index 91a5455..11a7f81 100644
--- a/tests/test4/compute.c
+++ b/tests/test4/compute.c
@@ -1,6 +1,6 @@
 #include "compute.h"
 
-void function audio2hsv_1(gint audio_level, gint *light_h, gint *light_s, gint *light_v) {
+void audio2hsv_1(gint audio_level, gint *light_h, gint *light_s, gint *light_v) {
 	// Dummy code
 	*light_h=-audio_level;
 	*light_s=audio_level;
diff --git a/tests/test4/gtkvumeter.c b/tests/test4/gtkvumeter.c
index 2cc1b61..cb0f9d7 100644
--- a/tests/test4/gtkvumeter.c
+++ b/tests/test4/gtkvumeter.c
@@ -1,13 +1,4 @@
-/***************************************************************************
- *            gtkvumeter.c
- *
- *  Fri Jan 10 20:06:23 2003
- *  Copyright  2003  Todd Goyen
- *  wettoad@knighthoodofbuh.org
- ****************************************************************************/
-
-#include <math.h>
-#include <gtk/gtk.h>
+#include <string.h>
 #include "gtkvumeter.h"
 
 #define MIN_HORIZONTAL_VUMETER_WIDTH   40
@@ -15,138 +6,142 @@
 #define VERTICAL_VUMETER_WIDTH     20
 #define MIN_VERTICAL_VUMETER_HEIGHT    40
 
-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);
+G_DEFINE_TYPE (GtkVuMeter, gtk_vu_meter, GTK_TYPE_DRAWING_AREA);
 
 static GdkColor default_f_gradient_keys[3] = {{0,65535,0,0},{0,65535,65535,0},{0,0,65535,0}};
 static GdkColor default_b_gradient_keys[3] = {{0,49151,0,0},{0,49151,49151,0},{0,0,49151,0}};
-static GtkWidgetClass *parent_class = NULL;
 
-
-
-GtkType gtk_vumeter_get_type (void)
-{
-    static GType vumeter_type = 0;
-    
-    if (!vumeter_type) {
-        static 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;
+static gboolean gtk_vu_meter_expose (GtkWidget *vumeter, GdkEventExpose *event);
+static void gtk_vu_meter_setup_colors (GtkVuMeter *vumeter);
+static void gtk_vu_meter_free_colors (GtkVuMeter *vumeter);
+static void free_drawbuf(guchar *pixels, gpointer data);
+static void gtk_vu_meter_size_request (GtkWidget *widget, GtkRequisition *requisition);
+static void gtk_vu_meter_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
+static gint gtk_vu_meter_sound_level_to_draw_level (GtkVuMeter *vumeter);
+
+static void gtk_vu_meter_class_init (GtkVuMeterClass *class) {
+	GtkWidgetClass *widget_class;
+	widget_class = GTK_WIDGET_CLASS (class);
+	widget_class->expose_event = gtk_vu_meter_expose;
+	widget_class->size_request = gtk_vu_meter_size_request;
+	widget_class->size_allocate = gtk_vu_meter_size_allocate;    
 }
 
-GtkWidget* gtk_vumeter_new (gboolean vertical)
-{
-    GtkVUMeter *vumeter;
-    vumeter = gtk_type_new (GTK_TYPE_VUMETER);
-    vumeter->vertical = vertical;
-    return GTK_WIDGET (vumeter);
+static void  gtk_vu_meter_init (GtkVuMeter *vumeter) {
+	vumeter->vertical=TRUE;
+    	gtk_vu_meter_set_gradient(vumeter, 3, default_f_gradient_keys, 3, default_b_gradient_keys);
+        gtk_vu_meter_setup_colors(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->level = 0;
-    vumeter->min = 0;
-    vumeter->max = 32767;
-    vumeter->peaks_falloff = GTK_VUMETER_PEAKS_FALLOFF_MEDIUM;
-    vumeter->peak_level = 0;
-    
-    vumeter->scale = GTK_VUMETER_SCALE_LINEAR;
+void gtk_vu_meter_set_gradient (GtkVuMeter *vumeter, gint f_gradient_key_count, GdkColor *f_gradient_keys, gint b_gradient_key_count, GdkColor *b_gradient_keys) {
+    //XXX : memdup is a bad idea ?
+    GdkColor *fgk = g_memdup(f_gradient_keys, f_gradient_key_count*sizeof(GdkColor));
+    GdkColor *bgk = g_memdup(b_gradient_keys, b_gradient_key_count*sizeof(GdkColor));
+    g_return_if_fail (fgk != NULL);
+    g_return_if_fail (bgk != NULL);
 
-    //XXX A bit heavy...
-    gtk_vumeter_set_gradient(vumeter, 3, default_f_gradient_keys, 3, default_b_gradient_keys);
+    vumeter->f_gradient_keys = fgk;
+    vumeter->f_gradient_key_count=f_gradient_key_count;
+    vumeter->b_gradient_keys = bgk;
+    vumeter->b_gradient_key_count=b_gradient_key_count;	
 }
-
-static void gtk_vumeter_class_init (GtkVUMeterClass *class)
-{
-    GtkObjectClass *object_class;
-    GtkWidgetClass *widget_class;
-
-    object_class = (GtkObjectClass*) class;
-    widget_class = (GtkWidgetClass*) class;
-    parent_class = gtk_type_class(gtk_widget_get_type());
-
-    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_vu_meter_free_colors (GtkVuMeter *vumeter) {
+	// TODO : free pixmaps	
 }
 
-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_vu_meter_setup_colors (GtkVuMeter *vumeter) {
+
+	gint i,j;
+	guchar *f_drawbuf, *b_drawbuf, f_r, f_g, f_b, b_r, b_g, b_b;
+	gint f_key_len, b_key_len;
+	gint f_key_i, b_key_i;
+	gdouble f_key_pos, b_key_pos;
+	GdkColor *fgk, *bgk;
+
+	gint h=GTK_WIDGET(vumeter)->allocation.height;
+	gint w=GTK_WIDGET(vumeter)->allocation.width;
+
+	// Clean every previous colors and buffers
+	gtk_vu_meter_free_colors (vumeter);
+
+	if (vumeter->vertical == TRUE) {
+		vumeter->colors = MAX(h, 0);
+	} else {
+		vumeter->colors = MAX(w, 0);
+	}
+
+	// Allocate a memory buffers to hold the gradients
+	f_drawbuf=g_malloc(h*w*3);
+	b_drawbuf=g_malloc(h*w*3);
+	g_return_if_fail (f_drawbuf != NULL);
+	g_return_if_fail (b_drawbuf != NULL);
+
+	// Compute some values before looping for gradient generation
+	f_key_len = vumeter->colors / (vumeter->f_gradient_key_count-1) + 1;
+	b_key_len = vumeter->colors / (vumeter->b_gradient_key_count-1) + 1;
+	fgk=vumeter->f_gradient_keys;
+	bgk=vumeter->b_gradient_keys;
+
+	for (i=0; i<vumeter->colors; i++) {
+		// Compute the current position in the gradient keys
+		f_key_i=i/f_key_len;
+		f_key_pos=((gdouble) (i%f_key_len)/f_key_len);
+		b_key_i=i/f_key_len;
+		b_key_pos=((gdouble) (i%b_key_len)/b_key_len);
+
+		/* Generate the Colours */
+		/* foreground */
+		f_r = ( fgk[f_key_i].red*(1.0-f_key_pos) + fgk[f_key_i+1].red*f_key_pos ) / 256;
+		f_g = ( fgk[f_key_i].green*(1.0-f_key_pos) + fgk[f_key_i+1].green*f_key_pos ) / 256;
+		f_b = ( fgk[f_key_i].blue*(1.0-f_key_pos) + fgk[f_key_i+1].blue*f_key_pos ) / 256;
+		/* background */
+		b_r = ( bgk[b_key_i].red*(1.0-b_key_pos) + bgk[b_key_i+1].red*b_key_pos ) / 256;
+		b_g = ( bgk[b_key_i].green*(1.0-b_key_pos) + bgk[b_key_i+1].green*b_key_pos ) / 256;
+		b_b = ( bgk[b_key_i].blue*(1.0-b_key_pos) + bgk[b_key_i+1].blue*b_key_pos ) / 256;
+
+		/* Apply the color in the drawbufs */
+		if (vumeter->vertical == TRUE) {
+			// Vertical mode : draw directly the whole line of identical color
+			for (j=3*w*i; j<3*w*(i+1); ) {
+				f_drawbuf[j++]=f_r;
+				f_drawbuf[j++]=f_g;
+				f_drawbuf[j++]=f_b;
+			}
+			for (j=3*w*i; j<3*w*(i+1); ) {
+				b_drawbuf[j++]=b_r;
+				b_drawbuf[j++]=b_g;
+				b_drawbuf[j++]=b_b;
+			}
+		} else {
+			// Horiziontal mode : draw only the first line (color change at each pixel)
+			// Others line will be duplicated at the end
+			f_drawbuf[i]=f_r;
+			f_drawbuf[i+1]=f_g;
+			f_drawbuf[i+2]=f_b;
+			b_drawbuf[i]=b_r;
+			b_drawbuf[i+1]=b_g;
+			b_drawbuf[i+2]=b_b;
+		}
+	}
+	if (vumeter->vertical != TRUE) {
+		// Duplicate the first line over the others
+		for (j=1; j<h; j++) {
+			memcpy(f_drawbuf, f_drawbuf+3*w*j, w);
+		}
+	}
+	
+	vumeter->f_pixbuf = gdk_pixbuf_new_from_data(f_drawbuf, GDK_COLORSPACE_RGB, FALSE, 8, w, h, w*3, free_drawbuf, NULL);
+	vumeter->b_pixbuf = gdk_pixbuf_new_from_data(b_drawbuf, GDK_COLORSPACE_RGB, FALSE, 8, w, h, w*3, free_drawbuf, NULL);
 }
 
-static void gtk_vumeter_size_request (GtkWidget *widget, GtkRequisition *requisition)
+static void gtk_vu_meter_size_request (GtkWidget *widget, GtkRequisition *requisition)
 {
-    GtkVUMeter *vumeter;
+    GtkVuMeter *vumeter;
 
-    g_return_if_fail (GTK_IS_VUMETER (widget));
+    g_return_if_fail (GTK_IS_VU_METER (widget));
     g_return_if_fail (requisition != NULL);
 
-    vumeter = GTK_VUMETER (widget);
+    vumeter = GTK_VU_METER (widget);
 
     if (vumeter->vertical == TRUE) {
         requisition->width = VERTICAL_VUMETER_WIDTH;
@@ -157,16 +152,16 @@ static void gtk_vumeter_size_request (GtkWidget *widget, GtkRequisition *requisi
     }
 }
 
-static void gtk_vumeter_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
+static void gtk_vu_meter_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
 {
-    GtkVUMeter *vumeter;
+    GtkVuMeter *vumeter;
     
     g_return_if_fail (widget != NULL);
-    g_return_if_fail (GTK_IS_VUMETER (widget));
+    g_return_if_fail (GTK_IS_VU_METER (widget));
     g_return_if_fail (allocation != NULL);
 
     widget->allocation = *allocation;
-    vumeter = GTK_VUMETER (widget);
+    vumeter = GTK_VU_METER (widget);
 
     if (GTK_WIDGET_REALIZED (widget)) {
         if (vumeter->vertical == TRUE) { /* veritcal */
@@ -177,183 +172,75 @@ static void gtk_vumeter_size_allocate (GtkWidget *widget, GtkAllocation *allocat
                 MAX(allocation->width, MIN_HORIZONTAL_VUMETER_WIDTH), HORIZONTAL_VUMETER_HEIGHT);
         }
         /* Fix the colours */
-        gtk_vumeter_setup_colors (vumeter);
+        gtk_vu_meter_setup_colors (vumeter);
     }
 }
 
-static gint gtk_vumeter_expose (GtkWidget *widget, GdkEventExpose *event)
-{
-    GtkVUMeter *vumeter;
-    gint index, level;
-    gint width, height;
-    
-    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);
+static void free_drawbuf(guchar *pixels, gpointer data) {
+	g_free(pixels);
+}
 
-    if (event->count > 0)
-        return FALSE;
+static gboolean gtk_vu_meter_expose (GtkWidget *vumeter, GdkEventExpose *event) {
+	//gdk_pixbuf_render_to_drawable(pixbuf, dbuf_pixmap, app->style->fg_gc[GTK_STATE_NORMAL], 0, 0, 0, 0, WIDTH, HEIGHT, GDK_RGB_DITHER_NORMAL, 0, 0);
+        cairo_t *cr;
+	gint draw_level = gtk_vu_meter_sound_level_to_draw_level(GTK_VU_METER(vumeter));
+	
+        cr = gdk_cairo_create (vumeter->window);
 
-    vumeter = GTK_VUMETER (widget);
-    level = gtk_vumeter_sound_level_to_draw_level (vumeter);
+        // set a clip region for the expose event
+        cairo_rectangle (cr,event->area.x, event->area.y, event->area.width, event->area.height);
+        cairo_clip(cr);
 
-    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, "trough", 0, 0, widget->allocation.width, height);
-        /* draw background gradient */
-        for (index = 0; index < level; index++) {
-            gdk_draw_line (widget->window, vumeter->b_gc[index], 1, index + 1, width, index + 1);   
-        }
-        /* draw foreground gradient */
-        for (index = level; index < height - 2; index++) {
-            gdk_draw_line (widget->window, vumeter->f_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, "trough", 0, 0, width, widget->allocation.height);
-        /* draw background gradient */
-        for (index = 0; index < level; index++) {
-            gdk_draw_line (widget->window, vumeter->b_gc[index], index + 1, 1, index + 1, height);   
-        }
-        /* draw foreground gradient */
-        for (index = level; index < height - 2; index++) {
-            gdk_draw_line (widget->window, vumeter->f_gc[index], index + 1, 1, index + 1, height);            
-        }        
-    }
+	// Paint from the stored gradient
+	gdk_cairo_set_source_pixbuf(cr, GTK_VU_METER(vumeter)->b_pixbuf,0,0);
+	cairo_paint(cr);
 
-    return FALSE;
-}
+        // set a clip region for the expose event
+	if (GTK_VU_METER(vumeter)->vertical==TRUE) {
+	        cairo_rectangle (cr,event->area.x, event->area.y+draw_level, event->area.width, event->area.height-draw_level);
+	} else {
+		//TODO
+	        cairo_rectangle (cr,event->area.x, event->area.y, event->area.width, 12/*event->area.height*/);
+	}
+        cairo_clip(cr);
 
-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;
-    }
+	// Paint from the stored gradient
+	gdk_cairo_set_source_pixbuf(cr, GTK_VU_METER(vumeter)->f_pixbuf,0,0);
+	cairo_paint(cr);
+
+        cairo_destroy(cr);
+
+	return FALSE;
 }
 
-static void gtk_vumeter_setup_colors (GtkVUMeter *vumeter)
-{
-    gint index;
-    gint max;
-    gint f_key_len, b_key_len;
-    gint f_key_index, b_key_index;
-    gdouble f_key_pos, b_key_pos;
-    GdkColor *fgk, *bgk;
-    
-    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);
-    }
-    
-    /* 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 */
-    
-    max=vumeter->colors;
-    f_key_len = max / (vumeter->f_gradient_key_count-1) + 1;
-    b_key_len = max / (vumeter->b_gradient_key_count-1) + 1;
-    fgk=vumeter->f_gradient_keys;
-    bgk=vumeter->b_gradient_keys;
-    
-    for (index = 0; index < max; index++) {
-	f_key_index=index/f_key_len;
-	f_key_pos=((gdouble) (index%f_key_len)/f_key_len);
-	b_key_index=index/f_key_len;
-	b_key_pos=((gdouble) (index%b_key_len)/b_key_len);
-	
-        /* Generate the Colours */
-        /* foreground */
-        vumeter->f_colors[index].red = fgk[f_key_index].red*(1.0-f_key_pos) + fgk[f_key_index+1].red*f_key_pos;
-        vumeter->f_colors[index].green = fgk[f_key_index].green*(1.0-f_key_pos) + fgk[f_key_index+1].green*f_key_pos;
-        vumeter->f_colors[index].blue = fgk[f_key_index].blue*(1.0-f_key_pos) + fgk[f_key_index+1].blue*f_key_pos;
-        /* background */
-        vumeter->b_colors[index].red = bgk[b_key_index].red*(1.0-b_key_pos) + bgk[b_key_index+1].red*b_key_pos;
-        vumeter->b_colors[index].green = bgk[b_key_index].green*(1.0-b_key_pos) + bgk[b_key_index+1].green*b_key_pos;
-        vumeter->b_colors[index].blue = bgk[b_key_index].blue*(1.0-b_key_pos) + bgk[b_key_index+1].blue*b_key_pos;
-
-        /* Allocate the Colours */
-        /* foreground */
-	//TODO : try to use gdk_colormap_alloc_colors or suppress f_colors array
-        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_vu_meter_sound_level_to_draw_level (GtkVuMeter *vumeter) {
+	gint draw_level;
+	gdouble level, min, max, height;
+
+	level = (gdouble)vumeter->level;
+	min = (gdouble)vumeter->min;
+	max = (gdouble)vumeter->max;
+	height = (gdouble)vumeter->colors;
+
+	draw_level = (1.0 - (level - min)/(max - min)) * height;
+
+	//printf("1.0 - (%lf - %lf)/(%lf - %lf)) * %lf => %i\n", level, min, max, min, height, draw_level);
+
+	return draw_level;
 }
 
-static gint gtk_vumeter_sound_level_to_draw_level (GtkVUMeter *vumeter)
-{
-    gdouble draw_level;
-    gdouble level, min, max, height;
-    gdouble log_level, log_max;
-    
-    level = (gdouble)vumeter->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);
+GtkWidget * gtk_vu_meter_new (gboolean vertical) {
+	GtkWidget *vumeter = g_object_new (GTK_TYPE_VU_METER, NULL);
+	GTK_VU_METER(vumeter)->vertical=vertical;
+	GTK_VU_METER(vumeter)->level=0;
+	GTK_VU_METER(vumeter)->min=-32767;
+	GTK_VU_METER(vumeter)->max=32767;
 }
 
-void gtk_vumeter_set_min_max (GtkVUMeter *vumeter, gint min, gint max)
+
+void gtk_vu_meter_set_min_max (GtkVuMeter *vumeter, gint min, gint max)
 {
     g_return_if_fail (vumeter != NULL);
-    g_return_if_fail (GTK_IS_VUMETER (vumeter));
 
     vumeter->max = MAX(max, min);
     vumeter->min = MIN(min, max);
@@ -364,45 +251,11 @@ void gtk_vumeter_set_min_max (GtkVUMeter *vumeter, gint min, gint max)
     gtk_widget_queue_draw (GTK_WIDGET(vumeter)); 
 }
 
-void gtk_vumeter_set_level (GtkVUMeter *vumeter, gint level)
+void gtk_vu_meter_set_level(GtkVuMeter *vumeter, gint level)
 {
     g_return_if_fail (vumeter != NULL);
-    g_return_if_fail (GTK_IS_VUMETER (vumeter));
 
     vumeter->level = CLAMP (level, vumeter->min, vumeter->max);
     gtk_widget_queue_draw (GTK_WIDGET(vumeter));    
 }
 
-void gtk_vumeter_set_peaks_falloff (GtkVUMeter *vumeter, gint peaks_falloff)
-{
-    g_return_if_fail (vumeter != NULL);
-    g_return_if_fail (GTK_IS_VUMETER (vumeter));  
-}
-
-void gtk_vumeter_set_scale (GtkVUMeter *vumeter, gint scale)
-{
-    g_return_if_fail (vumeter != NULL);
-    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));
-        }            
-    }
-}
-
-void gtk_vumeter_set_gradient (GtkVUMeter *vumeter, gint f_gradient_key_count, GdkColor *f_gradient_keys, gint b_gradient_key_count, GdkColor *b_gradient_keys) {
-    //XXX : memdup is a bad idea ?
-    GdkColor *fgk = g_memdup(f_gradient_keys, f_gradient_key_count*sizeof(GdkColor));
-    GdkColor *bgk = g_memdup(b_gradient_keys, b_gradient_key_count*sizeof(GdkColor));
-    g_return_if_fail (fgk != NULL);
-    g_return_if_fail (bgk != NULL);
-
-    vumeter->f_gradient_keys = fgk;
-    vumeter->f_gradient_key_count=f_gradient_key_count;
-    vumeter->b_gradient_keys = bgk;
-    vumeter->b_gradient_key_count=b_gradient_key_count;	
-}
-
diff --git a/tests/test4/gtkvumeter.h b/tests/test4/gtkvumeter.h
index ea64dcb..ec7ee67 100644
--- a/tests/test4/gtkvumeter.h
+++ b/tests/test4/gtkvumeter.h
@@ -1,80 +1,39 @@
-/***************************************************************************
- *            gtkvumeter.h
- *
- *  Fri Jan 10 20:06:41 2003
- *  Copyright  2003  Todd Goyen
- *  wettoad@knighthoodofbuh.org
- ****************************************************************************/
-
-#ifndef __GTKVUMETER_H__
-#define __GTKVUMETER_H__
-
+#ifndef GTKVUMETER_H
+#define GTKVUMETER_H
 #include <gtk/gtk.h>
 
-G_BEGIN_DECLS
+#define GTK_TYPE_VU_METER             (gtk_vu_meter_get_type ())
+#define GTK_VU_METER(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_VU_METER, GtkVuMeter))
+#define GTK_VU_METER_CLASS(obj)       (G_TYPE_CHECK_CLASS_CAST ((obj), GTK_VU_METER,  GtkVuMeterClass))
+#define GTK_IS_VU_METER(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_VU_METER))
+#define GTK_IS_VU_METER_CLASS(obj)    (G_TYPE_CHECK_CLASS_TYPE ((obj), GTK_TYPE_VU_METER))
+#define GTK_VU_METER_GET_CLASS        (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_VU_METER, GtkVuMeterClass))
 
-#define GTK_TYPE_VUMETER                (gtk_vumeter_get_type ())
-#define GTK_VUMETER(obj)                (GTK_CHECK_CAST ((obj), GTK_TYPE_VUMETER, GtkVUMeter))
-#define GTK_VUMETER_CLASS(klass)        (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_VUMETER GtkVUMeterClass))
-#define GTK_IS_VUMETER(obj)             (GTK_CHECK_TYPE ((obj), GTK_TYPE_VUMETER))
-#define GTK_IS_VUMETER_CLASS(klass)     (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_VUMETER))
-#define GTK_VUMETER_GET_CLASS(obj)      (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_VUMETER, GtkVUMeterClass))
+typedef struct _GtkVuMeter            GtkVuMeter;
+typedef struct _GtkVuMeterClass       GtkVuMeterClass;
 
-typedef struct _GtkVUMeter      GtkVUMeter;
-typedef struct _GtkVUMeterClass GtkVUMeterClass;
-    
-struct _GtkVUMeter {
-    GtkWidget   widget;
-    
-    gint	f_gradient_key_count;
-    GdkColor	*f_gradient_keys;
-    gint	b_gradient_key_count;
-    GdkColor	*b_gradient_keys;
+struct _GtkVuMeter {
+	GtkDrawingArea parent;
 
-    GdkColormap *colormap;
-    gint        colors;
-    
-    GdkGC       **f_gc;
-    GdkGC       **b_gc;
-    GdkColor    *f_colors;
-    GdkColor    *b_colors;
-    
-    gboolean    vertical;
-    gint        level;
-    gint        min;
-    gint        max;
+	/* private */
+	gboolean vertical;
+	gint level, min, max;
 
-    gint        peaks_falloff;
-    gint        peak_level;
-    
-    gint        scale;
-};
-
-struct _GtkVUMeterClass {
-    GtkWidgetClass  parent_class;
-};
+	gint f_gradient_key_count, b_gradient_key_count;
+	GdkColor *f_gradient_keys, *b_gradient_keys;
 
-enum {
-    GTK_VUMETER_PEAKS_FALLOFF_SLOW,
-    GTK_VUMETER_PEAKS_FALLOFF_MEDIUM,
-    GTK_VUMETER_PEAKS_FALLOFF_FAST,
-    GTK_VUMETER_PEAKS_FALLOFF_LAST    
+	gint colors;
+	GdkPixbuf *f_pixbuf, *b_pixbuf;
 };
 
-enum {
-    GTK_VUMETER_SCALE_LINEAR,
-    GTK_VUMETER_SCALE_LOG,
-    GTK_VUMETER_SCALE_LAST    
+struct _GtkVuMeterClass {
+	GtkDrawingAreaClass parent_class;
 };
 
-GtkType    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_level (GtkVUMeter *vumeter, gint level);
-void gtk_vumeter_set_peaks_falloff (GtkVUMeter *vumeter, gint peaks_falloff);
-void gtk_vumeter_set_scale (GtkVUMeter *vumeter, gint scale);
-void gtk_vumeter_set_gradient (GtkVUMeter *vumeter, gint f_gradient_key_count, GdkColor *f_gradient_keys, gint b_gradient_key_count, GdkColor *b_gradient_keys);
 
-G_END_DECLS
+GtkWidget * gtk_vu_meter_new (gboolean vertical);
+void gtk_vu_meter_set_gradient (GtkVuMeter *vumeter, gint f_gradient_key_count, GdkColor *f_gradient_keys, gint b_gradient_key_count, GdkColor *b_gradient_keys);
+void gtk_vu_meter_set_min_max (GtkVuMeter *vumeter, gint min, gint max);
+void gtk_vu_meter_set_level(GtkVuMeter *vumeter, gint level);
 
-#endif /* __GTKVUMETER_H__ */
+#endif /*GTKVUMETER_H*/
diff --git a/tests/test4/no-perf/compute.c b/tests/test4/no-perf/compute.c
new file mode 100644
index 0000000..91a5455
--- /dev/null
+++ b/tests/test4/no-perf/compute.c
@@ -0,0 +1,42 @@
+#include "compute.h"
+
+void function audio2hsv_1(gint audio_level, gint *light_h, gint *light_s, gint *light_v) {
+	// Dummy code
+	*light_h=-audio_level;
+	*light_s=audio_level;
+	*light_v=65535;
+}
+
+		
+void hsv2rgb(gint h, gint s, gint v, gint *r, gint *g, gint *b) {
+   /*
+    * Purpose:
+    * Convert HSV values to RGB values
+    * All values are in the range [0..65535]
+    */
+   float F, M, N, K;
+   int   I;
+   
+   if ( s == 0 ) {
+      /* 
+       * Achromatic case, set level of grey 
+       */
+      *r = v;
+      *g = v;
+      *b = v;
+   } else {
+      I = (int) h/(65535/6);	/* should be in the range 0..5 */
+      F = h - I;		/* fractional part */
+
+      M = v * (1 - s);
+      N = v * (1 - s * F);
+      K = v * (1 - s * (1 - F));
+
+      if (I == 0) { *r = v; *g = K; *b = M; }
+      if (I == 1) { *r = N; *g = v; *b = M; }
+      if (I == 2) { *r = M; *g = v; *b = K; }
+      if (I == 3) { *r = M; *g = N; *b = v; }
+      if (I == 4) { *r = K; *g = M; *b = v; }
+      if (I == 5) { *r = v; *g = M; *b = N; }
+   }
+}
diff --git a/tests/test4/no-perf/compute.h b/tests/test4/no-perf/compute.h
new file mode 100644
index 0000000..2454e56
--- /dev/null
+++ b/tests/test4/no-perf/compute.h
@@ -0,0 +1,10 @@
+#ifndef COMPUTE_H
+#define COMPUTE_H
+
+#include <gtk/gtk.h>
+
+void audio2hsv_1(gint audio_level, gint *light_h, gint *light_s, gint *light_v);
+void hsv2rgb(gint h, gint s, gint v, gint *r, gint *g, gint *b);
+
+#endif
+
diff --git a/tests/test4/no-perf/gtkvumeter.c b/tests/test4/no-perf/gtkvumeter.c
new file mode 100644
index 0000000..2cc1b61
--- /dev/null
+++ b/tests/test4/no-perf/gtkvumeter.c
@@ -0,0 +1,408 @@
+/***************************************************************************
+ *            gtkvumeter.c
+ *
+ *  Fri Jan 10 20:06:23 2003
+ *  Copyright  2003  Todd Goyen
+ *  wettoad@knighthoodofbuh.org
+ ****************************************************************************/
+
+#include <math.h>
+#include <gtk/gtk.h>
+#include "gtkvumeter.h"
+
+#define MIN_HORIZONTAL_VUMETER_WIDTH   40
+#define HORIZONTAL_VUMETER_HEIGHT  20
+#define VERTICAL_VUMETER_WIDTH     20
+#define MIN_VERTICAL_VUMETER_HEIGHT    40
+
+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);
+
+static GdkColor default_f_gradient_keys[3] = {{0,65535,0,0},{0,65535,65535,0},{0,0,65535,0}};
+static GdkColor default_b_gradient_keys[3] = {{0,49151,0,0},{0,49151,49151,0},{0,0,49151,0}};
+static GtkWidgetClass *parent_class = NULL;
+
+
+
+GtkType gtk_vumeter_get_type (void)
+{
+    static GType vumeter_type = 0;
+    
+    if (!vumeter_type) {
+        static 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;
+}
+
+GtkWidget* gtk_vumeter_new (gboolean vertical)
+{
+    GtkVUMeter *vumeter;
+    vumeter = gtk_type_new (GTK_TYPE_VUMETER);
+    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->level = 0;
+    vumeter->min = 0;
+    vumeter->max = 32767;
+    vumeter->peaks_falloff = GTK_VUMETER_PEAKS_FALLOFF_MEDIUM;
+    vumeter->peak_level = 0;
+    
+    vumeter->scale = GTK_VUMETER_SCALE_LINEAR;
+
+    //XXX A bit heavy...
+    gtk_vumeter_set_gradient(vumeter, 3, default_f_gradient_keys, 3, default_b_gradient_keys);
+}
+
+static void gtk_vumeter_class_init (GtkVUMeterClass *class)
+{
+    GtkObjectClass *object_class;
+    GtkWidgetClass *widget_class;
+
+    object_class = (GtkObjectClass*) class;
+    widget_class = (GtkWidgetClass*) class;
+    parent_class = gtk_type_class(gtk_widget_get_type());
+
+    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);
+
+    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,
+                VERTICAL_VUMETER_WIDTH, MAX(allocation->height, MIN_VERTICAL_VUMETER_HEIGHT));
+        } else { /* horizontal */
+            gdk_window_move_resize (widget->window, allocation->x, allocation->y,
+                MAX(allocation->width, MIN_HORIZONTAL_VUMETER_WIDTH), HORIZONTAL_VUMETER_HEIGHT);
+        }
+        /* Fix the colours */
+        gtk_vumeter_setup_colors (vumeter);
+    }
+}
+
+static gint gtk_vumeter_expose (GtkWidget *widget, GdkEventExpose *event)
+{
+    GtkVUMeter *vumeter;
+    gint index, level;
+    gint width, height;
+    
+    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);
+    level = gtk_vumeter_sound_level_to_draw_level (vumeter);
+
+    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, "trough", 0, 0, widget->allocation.width, height);
+        /* draw background gradient */
+        for (index = 0; index < level; index++) {
+            gdk_draw_line (widget->window, vumeter->b_gc[index], 1, index + 1, width, index + 1);   
+        }
+        /* draw foreground gradient */
+        for (index = level; index < height - 2; index++) {
+            gdk_draw_line (widget->window, vumeter->f_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, "trough", 0, 0, width, widget->allocation.height);
+        /* draw background gradient */
+        for (index = 0; index < level; index++) {
+            gdk_draw_line (widget->window, vumeter->b_gc[index], index + 1, 1, index + 1, height);   
+        }
+        /* draw foreground gradient */
+        for (index = level; index < height - 2; index++) {
+            gdk_draw_line (widget->window, vumeter->f_gc[index], index + 1, 1, index + 1, height);            
+        }        
+    }
+
+    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 max;
+    gint f_key_len, b_key_len;
+    gint f_key_index, b_key_index;
+    gdouble f_key_pos, b_key_pos;
+    GdkColor *fgk, *bgk;
+    
+    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);
+    }
+    
+    /* 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 */
+    
+    max=vumeter->colors;
+    f_key_len = max / (vumeter->f_gradient_key_count-1) + 1;
+    b_key_len = max / (vumeter->b_gradient_key_count-1) + 1;
+    fgk=vumeter->f_gradient_keys;
+    bgk=vumeter->b_gradient_keys;
+    
+    for (index = 0; index < max; index++) {
+	f_key_index=index/f_key_len;
+	f_key_pos=((gdouble) (index%f_key_len)/f_key_len);
+	b_key_index=index/f_key_len;
+	b_key_pos=((gdouble) (index%b_key_len)/b_key_len);
+	
+        /* Generate the Colours */
+        /* foreground */
+        vumeter->f_colors[index].red = fgk[f_key_index].red*(1.0-f_key_pos) + fgk[f_key_index+1].red*f_key_pos;
+        vumeter->f_colors[index].green = fgk[f_key_index].green*(1.0-f_key_pos) + fgk[f_key_index+1].green*f_key_pos;
+        vumeter->f_colors[index].blue = fgk[f_key_index].blue*(1.0-f_key_pos) + fgk[f_key_index+1].blue*f_key_pos;
+        /* background */
+        vumeter->b_colors[index].red = bgk[b_key_index].red*(1.0-b_key_pos) + bgk[b_key_index+1].red*b_key_pos;
+        vumeter->b_colors[index].green = bgk[b_key_index].green*(1.0-b_key_pos) + bgk[b_key_index+1].green*b_key_pos;
+        vumeter->b_colors[index].blue = bgk[b_key_index].blue*(1.0-b_key_pos) + bgk[b_key_index+1].blue*b_key_pos;
+
+        /* Allocate the Colours */
+        /* foreground */
+	//TODO : try to use gdk_colormap_alloc_colors or suppress f_colors array
+        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)
+{
+    gdouble draw_level;
+    gdouble level, min, max, height;
+    gdouble log_level, log_max;
+    
+    level = (gdouble)vumeter->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);
+}
+
+void gtk_vumeter_set_min_max (GtkVUMeter *vumeter, gint min, gint max)
+{
+    g_return_if_fail (vumeter != NULL);
+    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->level = CLAMP (vumeter->level, vumeter->min, vumeter->max);
+    gtk_widget_queue_draw (GTK_WIDGET(vumeter)); 
+}
+
+void gtk_vumeter_set_level (GtkVUMeter *vumeter, gint level)
+{
+    g_return_if_fail (vumeter != NULL);
+    g_return_if_fail (GTK_IS_VUMETER (vumeter));
+
+    vumeter->level = CLAMP (level, vumeter->min, vumeter->max);
+    gtk_widget_queue_draw (GTK_WIDGET(vumeter));    
+}
+
+void gtk_vumeter_set_peaks_falloff (GtkVUMeter *vumeter, gint peaks_falloff)
+{
+    g_return_if_fail (vumeter != NULL);
+    g_return_if_fail (GTK_IS_VUMETER (vumeter));  
+}
+
+void gtk_vumeter_set_scale (GtkVUMeter *vumeter, gint scale)
+{
+    g_return_if_fail (vumeter != NULL);
+    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));
+        }            
+    }
+}
+
+void gtk_vumeter_set_gradient (GtkVUMeter *vumeter, gint f_gradient_key_count, GdkColor *f_gradient_keys, gint b_gradient_key_count, GdkColor *b_gradient_keys) {
+    //XXX : memdup is a bad idea ?
+    GdkColor *fgk = g_memdup(f_gradient_keys, f_gradient_key_count*sizeof(GdkColor));
+    GdkColor *bgk = g_memdup(b_gradient_keys, b_gradient_key_count*sizeof(GdkColor));
+    g_return_if_fail (fgk != NULL);
+    g_return_if_fail (bgk != NULL);
+
+    vumeter->f_gradient_keys = fgk;
+    vumeter->f_gradient_key_count=f_gradient_key_count;
+    vumeter->b_gradient_keys = bgk;
+    vumeter->b_gradient_key_count=b_gradient_key_count;	
+}
+
diff --git a/tests/test4/no-perf/gtkvumeter.h b/tests/test4/no-perf/gtkvumeter.h
new file mode 100644
index 0000000..ea64dcb
--- /dev/null
+++ b/tests/test4/no-perf/gtkvumeter.h
@@ -0,0 +1,80 @@
+/***************************************************************************
+ *            gtkvumeter.h
+ *
+ *  Fri Jan 10 20:06:41 2003
+ *  Copyright  2003  Todd Goyen
+ *  wettoad@knighthoodofbuh.org
+ ****************************************************************************/
+
+#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)                (GTK_CHECK_CAST ((obj), GTK_TYPE_VUMETER, GtkVUMeter))
+#define GTK_VUMETER_CLASS(klass)        (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_VUMETER GtkVUMeterClass))
+#define GTK_IS_VUMETER(obj)             (GTK_CHECK_TYPE ((obj), GTK_TYPE_VUMETER))
+#define GTK_IS_VUMETER_CLASS(klass)     (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_VUMETER))
+#define GTK_VUMETER_GET_CLASS(obj)      (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_VUMETER, GtkVUMeterClass))
+
+typedef struct _GtkVUMeter      GtkVUMeter;
+typedef struct _GtkVUMeterClass GtkVUMeterClass;
+    
+struct _GtkVUMeter {
+    GtkWidget   widget;
+    
+    gint	f_gradient_key_count;
+    GdkColor	*f_gradient_keys;
+    gint	b_gradient_key_count;
+    GdkColor	*b_gradient_keys;
+
+    GdkColormap *colormap;
+    gint        colors;
+    
+    GdkGC       **f_gc;
+    GdkGC       **b_gc;
+    GdkColor    *f_colors;
+    GdkColor    *b_colors;
+    
+    gboolean    vertical;
+    gint        level;
+    gint        min;
+    gint        max;
+
+    gint        peaks_falloff;
+    gint        peak_level;
+    
+    gint        scale;
+};
+
+struct _GtkVUMeterClass {
+    GtkWidgetClass  parent_class;
+};
+
+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    
+};
+
+GtkType    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_level (GtkVUMeter *vumeter, gint level);
+void gtk_vumeter_set_peaks_falloff (GtkVUMeter *vumeter, gint peaks_falloff);
+void gtk_vumeter_set_scale (GtkVUMeter *vumeter, gint scale);
+void gtk_vumeter_set_gradient (GtkVUMeter *vumeter, gint f_gradient_key_count, GdkColor *f_gradient_keys, gint b_gradient_key_count, GdkColor *b_gradient_keys);
+
+G_END_DECLS
+
+#endif /* __GTKVUMETER_H__ */
diff --git a/tests/test4/no-perf/test4.c b/tests/test4/no-perf/test4.c
new file mode 100644
index 0000000..787f7c2
--- /dev/null
+++ b/tests/test4/no-perf/test4.c
@@ -0,0 +1,56 @@
+#include <gtk/gtk.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "gtkvumeter.h"
+#include "win_main.h"
+#include "compute.h"
+
+void audio_thread(void *args) {
+	gint min=-32767, max=32767;
+	gint *audio_vumeter_val=((gint*)args)+0;
+	gint *light_h=((gint*)args)+1;
+	gint *light_s=((gint*)args)+2;
+	gint *light_v=((gint*)args)+3;
+	gint *light_r=((gint*)args)+4;
+	gint *light_g=((gint*)args)+5;
+	gint *light_b=((gint*)args)+6;
+
+	while(1) {
+		// Dummy code for audio capture
+		*audio_vumeter_val=min+rand()/(float)RAND_MAX*(max-min);
+		usleep(10);
+
+		// Transfert Function
+		audio2hsv_1(*audio_vumeter_val,*light_h,*light_s,*light_v);
+
+		// Conversion
+		hsv2rgb(*light_h,*light_s,*light_v,light_r,light_g,light_b);
+		
+		// Send to DMX
+		//TODO
+	}
+}
+
+int main (int argc, char **argv)
+{
+	GtkWidget *mainwin;
+	gint vals_for_vumeters[7]={0,0,0,0,0,0}; //sound,h,s,v,r,g,b
+
+	pthread_t audio_analyzer;
+
+	g_thread_init(NULL);
+	gdk_threads_init();
+	gdk_threads_enter();
+	gtk_init (&argc, &argv);
+
+	mainwin=win_main_build();
+	gtk_widget_show_all (mainwin);
+
+	pthread_create (&audio_analyzer, (void *)NULL, (void *)audio_thread, (void *)vals_for_vumeters);
+	g_timeout_add (33, win_main_update_vumeters, (gpointer)vals_for_vumeters);
+
+	gtk_main ();
+	gdk_threads_leave();
+
+	return 0;
+}
diff --git a/tests/test4/test4.c b/tests/test4/test4.c
index 787f7c2..df38794 100644
--- a/tests/test4/test4.c
+++ b/tests/test4/test4.c
@@ -18,10 +18,10 @@ void audio_thread(void *args) {
 	while(1) {
 		// Dummy code for audio capture
 		*audio_vumeter_val=min+rand()/(float)RAND_MAX*(max-min);
-		usleep(10);
+		usleep(10000);
 
 		// Transfert Function
-		audio2hsv_1(*audio_vumeter_val,*light_h,*light_s,*light_v);
+		audio2hsv_1(*audio_vumeter_val,light_h,light_s,light_v);
 
 		// Conversion
 		hsv2rgb(*light_h,*light_s,*light_v,light_r,light_g,light_b);
@@ -34,7 +34,7 @@ void audio_thread(void *args) {
 int main (int argc, char **argv)
 {
 	GtkWidget *mainwin;
-	gint vals_for_vumeters[7]={0,0,0,0,0,0}; //sound,h,s,v,r,g,b
+	gint vals_for_vumeters[7]={0,0,0,0,0,0,0}; //sound,h,s,v,r,g,b
 
 	pthread_t audio_analyzer;
 
@@ -47,7 +47,7 @@ int main (int argc, char **argv)
 	gtk_widget_show_all (mainwin);
 
 	pthread_create (&audio_analyzer, (void *)NULL, (void *)audio_thread, (void *)vals_for_vumeters);
-	g_timeout_add (33, win_main_update_vumeters, (gpointer)vals_for_vumeters);
+	g_timeout_add (10, win_main_update_vumeters, (gpointer)vals_for_vumeters);
 
 	gtk_main ();
 	gdk_threads_leave();
diff --git a/tests/test4/win_main.c b/tests/test4/win_main.c
index c0249cf..4229c40 100644
--- a/tests/test4/win_main.c
+++ b/tests/test4/win_main.c
@@ -21,45 +21,45 @@ GtkWidget *win_main_build() {
 	gtk_container_add(GTK_CONTAINER(win), hbox1);
 	gtk_container_set_border_width(GTK_CONTAINER(hbox1), 5);
 
-//TODO : gtk_vumeter_set_min_max (GTK_VUMETER(vumeter), min, max);
-	vumeter_sound = gtk_vumeter_new (TRUE);
+//TODO : gtk_vumeter_set_min_max (GTK_VU_METER(vumeter), min, max);
+	vumeter_sound = gtk_vu_meter_new (TRUE);
 	gtk_box_pack_start(GTK_BOX(hbox1), vumeter_sound, FALSE, FALSE, 0);
 
-	vumeter_h = gtk_vumeter_new (TRUE);
-	gtk_vumeter_set_gradient(GTK_VUMETER(vumeter_h), 7, f_gradient_hue, 7, b_gradient_hue);
+	vumeter_h = gtk_vu_meter_new (TRUE);
+	gtk_vu_meter_set_gradient(GTK_VU_METER(vumeter_h), 7, f_gradient_hue, 7, b_gradient_hue);
 	gtk_box_pack_start(GTK_BOX(hbox1), vumeter_h, FALSE, FALSE, 0);
 
-	vumeter_s = gtk_vumeter_new (TRUE);
-	gtk_vumeter_set_gradient(GTK_VUMETER(vumeter_s), 2, f_gradient_red, 2, b_gradient_red);
+	vumeter_s = gtk_vu_meter_new (TRUE);
+	gtk_vu_meter_set_gradient(GTK_VU_METER(vumeter_s), 2, f_gradient_red, 2, b_gradient_red);
 	gtk_box_pack_start(GTK_BOX(hbox1), vumeter_s, FALSE, FALSE, 0);
 
-	vumeter_v = gtk_vumeter_new (TRUE);
-	gtk_vumeter_set_gradient(GTK_VUMETER(vumeter_v), 2, f_gradient_red, 2, b_gradient_red);
+	vumeter_v = gtk_vu_meter_new (TRUE);
+	gtk_vu_meter_set_gradient(GTK_VU_METER(vumeter_v), 2, f_gradient_red, 2, b_gradient_red);
 	gtk_box_pack_start(GTK_BOX(hbox1), vumeter_v, FALSE, FALSE, 0);
 
 
-	vumeter_r = gtk_vumeter_new (TRUE);
-	gtk_vumeter_set_gradient(GTK_VUMETER(vumeter_r), 2, f_gradient_red, 2, b_gradient_red);
+	vumeter_r = gtk_vu_meter_new (TRUE);
+	gtk_vu_meter_set_gradient(GTK_VU_METER(vumeter_r), 2, f_gradient_red, 2, b_gradient_red);
 	gtk_box_pack_start(GTK_BOX(hbox1), vumeter_r, FALSE, FALSE, 0);
 
-	vumeter_g = gtk_vumeter_new (TRUE);
-	gtk_vumeter_set_gradient(GTK_VUMETER(vumeter_g), 2, f_gradient_green, 2, b_gradient_green);
+	vumeter_g = gtk_vu_meter_new (TRUE);
+	gtk_vu_meter_set_gradient(GTK_VU_METER(vumeter_g), 2, f_gradient_green, 2, b_gradient_green);
 	gtk_box_pack_start(GTK_BOX(hbox1), vumeter_g, FALSE, FALSE, 0);
 
-	vumeter_b = gtk_vumeter_new (TRUE);
-	gtk_vumeter_set_gradient(GTK_VUMETER(vumeter_b), 2, f_gradient_blue, 2, b_gradient_blue);
+	vumeter_b = gtk_vu_meter_new (TRUE);
+	gtk_vu_meter_set_gradient(GTK_VU_METER(vumeter_b), 2, f_gradient_blue, 2, b_gradient_blue);
 	gtk_box_pack_start(GTK_BOX(hbox1), vumeter_b, FALSE, FALSE, 0);
 
 	return win;
 }
 
 void win_main_update_vumeters(void *vals) {
-	gtk_vumeter_set_level(GTK_VUMETER(vumeter_sound), ((gint*)vals)[0]);
-	gtk_vumeter_set_level(GTK_VUMETER(vumeter_h), ((gint*)vals)[1]);
-	gtk_vumeter_set_level(GTK_VUMETER(vumeter_s), ((gint*)vals)[2]);
-	gtk_vumeter_set_level(GTK_VUMETER(vumeter_v), ((gint*)vals)[3]);
-	gtk_vumeter_set_level(GTK_VUMETER(vumeter_r), ((gint*)vals)[4]);
-	gtk_vumeter_set_level(GTK_VUMETER(vumeter_g), ((gint*)vals)[5]);
-	gtk_vumeter_set_level(GTK_VUMETER(vumeter_b), ((gint*)vals)[6]);
+	gtk_vu_meter_set_level(GTK_VU_METER(vumeter_sound), ((gint*)vals)[0]);
+	gtk_vu_meter_set_level(GTK_VU_METER(vumeter_h), ((gint*)vals)[1]);
+	gtk_vu_meter_set_level(GTK_VU_METER(vumeter_s), ((gint*)vals)[2]);
+	gtk_vu_meter_set_level(GTK_VU_METER(vumeter_v), ((gint*)vals)[3]);
+	gtk_vu_meter_set_level(GTK_VU_METER(vumeter_r), ((gint*)vals)[4]);
+	gtk_vu_meter_set_level(GTK_VU_METER(vumeter_g), ((gint*)vals)[5]);
+	gtk_vu_meter_set_level(GTK_VU_METER(vumeter_b), ((gint*)vals)[6]);
 }
 
-- 
cgit v1.2.3