slimming diet for the narrow-mixer strip
[ardour.git] / gtk2_ardour / canvas-waveview.c
index 34b64770a6b770293b997bdaf1361d03fb29a035..2080b208d8a2eb6f839cc0657bf3c72e58d6a98c 100644 (file)
@@ -1,5 +1,5 @@
- /*
-     Copyright (C) 2000-2002 Paul Davis 
+/*
+     Copyright (C) 2000-2002 Paul Davis
 
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
 
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
      $Id$
      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
      $Id$
- */
+*/
+
+#include <stdio.h>
+#include <math.h>
+#include <libgnomecanvas/libgnomecanvas.h>
+#include <cairo.h>
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
 
 
- #include <stdio.h>
- #include <math.h>
- #include <libgnomecanvas/libgnomecanvas.h>
- #include <string.h>
- #include <limits.h>
+#include "ardour/dB.h"
 
 
- #include <ardour/dB.h>
+#include "logmeter.h"
+#include "canvas-waveview.h"
+#include "rgb_macros.h"
+
+/* POSIX guarantees casting between void* and function pointers, ISO C doesn't
+ * We can work around warnings by going one step deeper in our casts
+ */
+#ifdef _POSIX_VERSION
+#define POSIX_FUNC_PTR_CAST(type, object) *((type*) &(object))
+#endif // _POSIX_VERSION
 
 
- #include "canvas-waveview.h"
- #include "rgb_macros.h"
+extern void c_stacktrace(void);
 
 
- enum {
+enum {
         PROP_0,
         PROP_DATA_SRC,
         PROP_CHANNEL,
         PROP_0,
         PROP_DATA_SRC,
         PROP_CHANNEL,
         PROP_Y,
         PROP_HEIGHT,
         PROP_WAVE_COLOR,
         PROP_Y,
         PROP_HEIGHT,
         PROP_WAVE_COLOR,
+        PROP_CLIP_COLOR,
+        PROP_ZERO_COLOR,
+        PROP_FILL_COLOR,
+        PROP_FILLED,
         PROP_RECTIFIED,
         PROP_RECTIFIED,
-        PROP_REGION_START
- };
+        PROP_ZERO_LINE,
+        PROP_REGION_START,
+        PROP_LOGSCALED,
+};
 
 
- static void gnome_canvas_waveview_class_init     (GnomeCanvasWaveViewClass *class);
+static void gnome_canvas_waveview_class_init     (GnomeCanvasWaveViewClass *class);
 
 
- static void gnome_canvas_waveview_init           (GnomeCanvasWaveView      *waveview);
+static void gnome_canvas_waveview_init           (GnomeCanvasWaveView      *waveview);
 
 
- static void gnome_canvas_waveview_destroy        (GtkObject            *object);
+static void gnome_canvas_waveview_destroy        (GtkObject            *object);
 
 
- static void gnome_canvas_waveview_set_property   (GObject        *object,
+static void gnome_canvas_waveview_set_property   (GObject        *object,
                                                   guint           prop_id,
                                                   const GValue   *value,
                                                   GParamSpec     *pspec);
                                                   guint           prop_id,
                                                   const GValue   *value,
                                                   GParamSpec     *pspec);
- static void gnome_canvas_waveview_get_property   (GObject        *object,
+static void gnome_canvas_waveview_get_property   (GObject        *object,
                                                   guint           prop_id,
                                                   GValue         *value,
                                                   GParamSpec     *pspec);
 
                                                   guint           prop_id,
                                                   GValue         *value,
                                                   GParamSpec     *pspec);
 
- static void   gnome_canvas_waveview_update       (GnomeCanvasItem *item,
+static void   gnome_canvas_waveview_update       (GnomeCanvasItem *item,
                                                   double          *affine,
                                                   ArtSVP          *clip_path,
                                                   int              flags);
 
                                                   double          *affine,
                                                   ArtSVP          *clip_path,
                                                   int              flags);
 
- static void   gnome_canvas_waveview_bounds       (GnomeCanvasItem *item,
+static void   gnome_canvas_waveview_bounds       (GnomeCanvasItem *item,
                                                   double          *x1,
                                                   double          *y1,
                                                   double          *x2,
                                                   double          *y2);
 
                                                   double          *x1,
                                                   double          *y1,
                                                   double          *x2,
                                                   double          *y2);
 
- static double gnome_canvas_waveview_point        (GnomeCanvasItem  *item,
+static double gnome_canvas_waveview_point        (GnomeCanvasItem  *item,
                                                   double            x,
                                                   double            y,
                                                   int               cx,
                                                   int               cy,
                                                   GnomeCanvasItem **actual_item);
 
                                                   double            x,
                                                   double            y,
                                                   int               cx,
                                                   int               cy,
                                                   GnomeCanvasItem **actual_item);
 
- static void gnome_canvas_waveview_render         (GnomeCanvasItem *item,
+static void gnome_canvas_waveview_render         (GnomeCanvasItem *item,
                                                   GnomeCanvasBuf  *buf);
 
                                                   GnomeCanvasBuf  *buf);
 
- static void gnome_canvas_waveview_draw           (GnomeCanvasItem *item,
+static void gnome_canvas_waveview_draw           (GnomeCanvasItem *item,
                                                   GdkDrawable     *drawable,
                                                   int              x,
                                                   int              y,
                                                   int              w,
                                                   int              h);
 
                                                   GdkDrawable     *drawable,
                                                   int              x,
                                                   int              y,
                                                   int              w,
                                                   int              h);
 
- static void gnome_canvas_waveview_set_data_src   (GnomeCanvasWaveView *,
+static void gnome_canvas_waveview_set_data_src   (GnomeCanvasWaveView *,
                                                   void *);
 
                                                   void *);
 
- static void gnome_canvas_waveview_set_channel    (GnomeCanvasWaveView *,
+static void gnome_canvas_waveview_set_channel    (GnomeCanvasWaveView *,
                                                   guint32);
 
                                                   guint32);
 
- static gint32 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview,
+static guint32 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview,
                                                   gulong               start_sample,
                                                   gulong               end_sample);
 
                                                   gulong               start_sample,
                                                   gulong               end_sample);
 
- static GnomeCanvasItemClass *parent_class;
 
 
- GType
- gnome_canvas_waveview_get_type (void)
- {
+static int _gradient_rendering = 0;
+
+static GnomeCanvasItemClass *parent_class;
+
+GType
+gnome_canvas_waveview_get_type (void)
+{
         static GType waveview_type;
 
         if (!waveview_type) {
         static GType waveview_type;
 
         if (!waveview_type) {
         return waveview_type;
  }
 
         return waveview_type;
  }
 
- static void
- gnome_canvas_waveview_class_init (GnomeCanvasWaveViewClass *class)
- {
+static void
+gnome_canvas_waveview_class_init (GnomeCanvasWaveViewClass *class)
+{
         GObjectClass *gobject_class;
         GtkObjectClass *object_class;
         GnomeCanvasItemClass *item_class;
         GObjectClass *gobject_class;
         GtkObjectClass *object_class;
         GnomeCanvasItemClass *item_class;
                  PROP_DATA_SRC,
                  g_param_spec_pointer ("data_src", NULL, NULL,
                                        (G_PARAM_READABLE | G_PARAM_WRITABLE)));
                  PROP_DATA_SRC,
                  g_param_spec_pointer ("data_src", NULL, NULL,
                                        (G_PARAM_READABLE | G_PARAM_WRITABLE)));
-        
+
         g_object_class_install_property
                 (gobject_class,
                  PROP_CHANNEL,
                  g_param_spec_uint ("channel", NULL, NULL,
                                     0, G_MAXUINT, 0,
                                     (G_PARAM_READABLE | G_PARAM_WRITABLE)));
         g_object_class_install_property
                 (gobject_class,
                  PROP_CHANNEL,
                  g_param_spec_uint ("channel", NULL, NULL,
                                     0, G_MAXUINT, 0,
                                     (G_PARAM_READABLE | G_PARAM_WRITABLE)));
-        
+
         g_object_class_install_property
                 (gobject_class,
                  PROP_LENGTH_FUNCTION,
                  g_param_spec_pointer ("length_function", NULL, NULL,
                                        (G_PARAM_READABLE | G_PARAM_WRITABLE)));
         g_object_class_install_property
                 (gobject_class,
                  PROP_LENGTH_FUNCTION,
                  g_param_spec_pointer ("length_function", NULL, NULL,
                                        (G_PARAM_READABLE | G_PARAM_WRITABLE)));
-        
+
         g_object_class_install_property
                 (gobject_class,
                  PROP_SOURCEFILE_LENGTH_FUNCTION,
                  g_param_spec_pointer ("sourcefile_length_function", NULL, NULL,
                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
         g_object_class_install_property
                 (gobject_class,
                  PROP_SOURCEFILE_LENGTH_FUNCTION,
                  g_param_spec_pointer ("sourcefile_length_function", NULL, NULL,
                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
-        
+
         g_object_class_install_property
                 (gobject_class,
                  PROP_PEAK_FUNCTION,
                  g_param_spec_pointer ("peak_function", NULL, NULL,
                                        (G_PARAM_READABLE | G_PARAM_WRITABLE)));
         g_object_class_install_property
                 (gobject_class,
                  PROP_PEAK_FUNCTION,
                  g_param_spec_pointer ("peak_function", NULL, NULL,
                                        (G_PARAM_READABLE | G_PARAM_WRITABLE)));
-        
+
         g_object_class_install_property
                 (gobject_class,
                  PROP_GAIN_FUNCTION,
                  g_param_spec_pointer ("gain_function", NULL, NULL,
                                        (G_PARAM_READABLE | G_PARAM_WRITABLE)));
         g_object_class_install_property
                 (gobject_class,
                  PROP_GAIN_FUNCTION,
                  g_param_spec_pointer ("gain_function", NULL, NULL,
                                        (G_PARAM_READABLE | G_PARAM_WRITABLE)));
-        
+
         g_object_class_install_property
                 (gobject_class,
                  PROP_GAIN_SRC,
                  g_param_spec_pointer ("gain_src", NULL, NULL,
                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
         g_object_class_install_property
                 (gobject_class,
                  PROP_GAIN_SRC,
                  g_param_spec_pointer ("gain_src", NULL, NULL,
                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
-       
+
         g_object_class_install_property
                 (gobject_class,
                  PROP_CACHE,
                  g_param_spec_pointer ("cache", NULL, NULL,
                                        (G_PARAM_READABLE | G_PARAM_WRITABLE)));
         g_object_class_install_property
                 (gobject_class,
                  PROP_CACHE,
                  g_param_spec_pointer ("cache", NULL, NULL,
                                        (G_PARAM_READABLE | G_PARAM_WRITABLE)));
-        
+
         g_object_class_install_property
                 (gobject_class,
                  PROP_CACHE_UPDATER,
                  g_param_spec_boolean ("cache_updater", NULL, NULL,
                                       FALSE,
                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
         g_object_class_install_property
                 (gobject_class,
                  PROP_CACHE_UPDATER,
                  g_param_spec_boolean ("cache_updater", NULL, NULL,
                                       FALSE,
                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
-        
+
         g_object_class_install_property
                 (gobject_class,
                  PROP_SAMPLES_PER_UNIT,
                  g_param_spec_double ("samples_per_unit", NULL, NULL,
                                       0.0, G_MAXDOUBLE, 0.0,
                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
         g_object_class_install_property
                 (gobject_class,
                  PROP_SAMPLES_PER_UNIT,
                  g_param_spec_double ("samples_per_unit", NULL, NULL,
                                       0.0, G_MAXDOUBLE, 0.0,
                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
-        
+
         g_object_class_install_property
                 (gobject_class,
                  PROP_AMPLITUDE_ABOVE_AXIS,
                  g_param_spec_double ("amplitude_above_axis", NULL, NULL,
                                       0.0, G_MAXDOUBLE, 0.0,
                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
         g_object_class_install_property
                 (gobject_class,
                  PROP_AMPLITUDE_ABOVE_AXIS,
                  g_param_spec_double ("amplitude_above_axis", NULL, NULL,
                                       0.0, G_MAXDOUBLE, 0.0,
                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
-        
+
         g_object_class_install_property
                 (gobject_class,
                  PROP_X,
                  g_param_spec_double ("x", NULL, NULL,
                                       0.0, G_MAXDOUBLE, 0.0,
                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
         g_object_class_install_property
                 (gobject_class,
                  PROP_X,
                  g_param_spec_double ("x", NULL, NULL,
                                       0.0, G_MAXDOUBLE, 0.0,
                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
-        
+
         g_object_class_install_property
                 (gobject_class,
                  PROP_Y,
                  g_param_spec_double ("y", NULL, NULL,
                                       0.0, G_MAXDOUBLE, 0.0,
                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
         g_object_class_install_property
                 (gobject_class,
                  PROP_Y,
                  g_param_spec_double ("y", NULL, NULL,
                                       0.0, G_MAXDOUBLE, 0.0,
                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
-        
+
         g_object_class_install_property
                 (gobject_class,
                  PROP_HEIGHT,
                  g_param_spec_double ("height", NULL, NULL,
                                       0.0, G_MAXDOUBLE, 0.0,
                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
         g_object_class_install_property
                 (gobject_class,
                  PROP_HEIGHT,
                  g_param_spec_double ("height", NULL, NULL,
                                       0.0, G_MAXDOUBLE, 0.0,
                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
-        
+
         g_object_class_install_property
                 (gobject_class,
                  PROP_WAVE_COLOR,
                  g_param_spec_uint ("wave_color", NULL, NULL,
                                     0, G_MAXUINT, 0,
                                     (G_PARAM_READABLE | G_PARAM_WRITABLE)));
         g_object_class_install_property
                 (gobject_class,
                  PROP_WAVE_COLOR,
                  g_param_spec_uint ("wave_color", NULL, NULL,
                                     0, G_MAXUINT, 0,
                                     (G_PARAM_READABLE | G_PARAM_WRITABLE)));
-        
+
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_CLIP_COLOR,
+                 g_param_spec_uint ("clip_color", NULL, NULL,
+                                    0, G_MAXUINT, 0,
+                                    (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_ZERO_COLOR,
+                 g_param_spec_uint ("zero_color", NULL, NULL,
+                                    0, G_MAXUINT, 0,
+                                    (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_FILL_COLOR,
+                 g_param_spec_uint ("fill_color", NULL, NULL,
+                                    0, G_MAXUINT, 0,
+                                    (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_FILLED,
+                 g_param_spec_boolean ("filled", NULL, NULL,
+                                       FALSE,
+                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
         g_object_class_install_property
                 (gobject_class,
                  PROP_RECTIFIED,
                  g_param_spec_boolean ("rectified", NULL, NULL,
                                        FALSE,
                                        (G_PARAM_READABLE | G_PARAM_WRITABLE)));
         g_object_class_install_property
                 (gobject_class,
                  PROP_RECTIFIED,
                  g_param_spec_boolean ("rectified", NULL, NULL,
                                        FALSE,
                                        (G_PARAM_READABLE | G_PARAM_WRITABLE)));
-        
+
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_ZERO_LINE,
+                 g_param_spec_boolean ("zero_line", NULL, NULL,
+                                       FALSE,
+                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_LOGSCALED,
+                 g_param_spec_boolean ("logscaled", NULL, NULL,
+                                       FALSE,
+                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
         g_object_class_install_property
                 (gobject_class,
                  PROP_REGION_START,
                  g_param_spec_uint ("region_start", NULL, NULL,
                                     0, G_MAXUINT, 0,
                                     (G_PARAM_READABLE | G_PARAM_WRITABLE)));
         g_object_class_install_property
                 (gobject_class,
                  PROP_REGION_START,
                  g_param_spec_uint ("region_start", NULL, NULL,
                                     0, G_MAXUINT, 0,
                                     (G_PARAM_READABLE | G_PARAM_WRITABLE)));
-        
+
         object_class->destroy = gnome_canvas_waveview_destroy;
         object_class->destroy = gnome_canvas_waveview_destroy;
-        
+
         item_class->update = gnome_canvas_waveview_update;
         item_class->bounds = gnome_canvas_waveview_bounds;
         item_class->point = gnome_canvas_waveview_point;
         item_class->render = gnome_canvas_waveview_render;
         item_class->draw = gnome_canvas_waveview_draw;
         item_class->update = gnome_canvas_waveview_update;
         item_class->bounds = gnome_canvas_waveview_bounds;
         item_class->point = gnome_canvas_waveview_point;
         item_class->render = gnome_canvas_waveview_render;
         item_class->draw = gnome_canvas_waveview_draw;
- }
+}
+
+void 
+gnome_canvas_waveview_set_gradient_waveforms (int yn)
+{
+       _gradient_rendering = yn;
+}
 
 GnomeCanvasWaveViewCache*
 
 GnomeCanvasWaveViewCache*
-gnome_canvas_waveview_cache_new ()
+gnome_canvas_waveview_cache_new (void)
 {
        GnomeCanvasWaveViewCache *c;
 
 {
        GnomeCanvasWaveViewCache *c;
 
@@ -306,6 +375,9 @@ gnome_canvas_waveview_init (GnomeCanvasWaveView *waveview)
        waveview->gain_curve_function = NULL;
        waveview->gain_src = NULL;
        waveview->rectified = FALSE;
        waveview->gain_curve_function = NULL;
        waveview->gain_src = NULL;
        waveview->rectified = FALSE;
+       waveview->logscaled = FALSE;
+       waveview->filled = TRUE;
+       waveview->zero_line = FALSE;
        waveview->region_start = 0;
        waveview->samples_per_unit = 1.0;
        waveview->amplitude_above_axis = 1.0;
        waveview->region_start = 0;
        waveview->samples_per_unit = 1.0;
        waveview->amplitude_above_axis = 1.0;
@@ -313,26 +385,27 @@ gnome_canvas_waveview_init (GnomeCanvasWaveView *waveview)
        waveview->screen_width = gdk_screen_width ();
        waveview->reload_cache_in_render = FALSE;
 
        waveview->screen_width = gdk_screen_width ();
        waveview->reload_cache_in_render = FALSE;
 
-       waveview->wave_color = RGBA_TO_UINT(44,35,126,255);
+       waveview->wave_color = 0;
+       waveview->clip_color = 0;
+       waveview->zero_color = 0;
+       waveview->fill_color = 0;
 }
 
 static void
 gnome_canvas_waveview_destroy (GtkObject *object)
 {
 }
 
 static void
 gnome_canvas_waveview_destroy (GtkObject *object)
 {
-       GnomeCanvasWaveView *waveview;
-
        g_return_if_fail (object != NULL);
        g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
 
        g_return_if_fail (object != NULL);
        g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
 
-       waveview = GNOME_CANVAS_WAVEVIEW (object);
-
        if (GTK_OBJECT_CLASS (parent_class)->destroy)
                (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
 }
 
 #define DEBUG_CACHE 0
        if (GTK_OBJECT_CLASS (parent_class)->destroy)
                (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
 }
 
 #define DEBUG_CACHE 0
+#undef CACHE_MEMMOVE_OPTIMIZATION
 
 
-static gint32
+/** @return cache index of start_sample within the cache */
+static guint32
 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_sample, gulong end_sample)
 {
        gulong required_cache_entries;
 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_sample, gulong end_sample)
 {
        gulong required_cache_entries;
@@ -345,6 +418,10 @@ gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_
        gulong copied;
        GnomeCanvasWaveViewCache *cache;
        float* gain;
        gulong copied;
        GnomeCanvasWaveViewCache *cache;
        float* gain;
+#ifdef CACHE_MEMMOVE_OPTIMIZATION
+       gulong present_frames;
+       gulong present_entries;
+#endif
 
        cache = waveview->cache;
 
 
        cache = waveview->cache;
 
@@ -352,12 +429,13 @@ gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_
        end_sample = end_sample + waveview->region_start;
 #if DEBUG_CACHE
        // printf("waveview->region_start == %lu\n",waveview->region_start);
        end_sample = end_sample + waveview->region_start;
 #if DEBUG_CACHE
        // printf("waveview->region_start == %lu\n",waveview->region_start);
-       printf ("=> 0x%x cache @ 0x%x range: %lu - %lu request: %lu - %lu (%lu frames)\n", 
+       // c_stacktrace ();
+       printf ("\n\n=> 0x%x cache @ 0x%x range: %lu - %lu request: %lu - %lu (%lu frames)\n",
                waveview, cache,
                cache->start, cache->end,
                start_sample, end_sample, end_sample - start_sample);
 #endif
                waveview, cache,
                cache->start, cache->end,
                start_sample, end_sample, end_sample - start_sample);
 #endif
-               
+
        if (cache->start <= start_sample && cache->end >= end_sample) {
 #if DEBUG_CACHE
                // printf ("0x%x: cache hit for %lu-%lu (cache holds: %lu-%lu\n",
        if (cache->start <= start_sample && cache->end >= end_sample) {
 #if DEBUG_CACHE
                // printf ("0x%x: cache hit for %lu-%lu (cache holds: %lu-%lu\n",
@@ -367,13 +445,13 @@ gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_
        }
 
        /* make sure the cache is at least twice as wide as the screen width, and put the start sample
        }
 
        /* make sure the cache is at least twice as wide as the screen width, and put the start sample
-          in the middle, ensuring that we cover the end_sample. 
+          in the middle, ensuring that we cover the end_sample.
        */
 
        /* Note the assumption that we have a 1:1 units:pixel ratio for the canvas. Its everywhere ... */
        */
 
        /* Note the assumption that we have a 1:1 units:pixel ratio for the canvas. Its everywhere ... */
-       
+
        half_width = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit)/2.0 + 0.5);
        half_width = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit)/2.0 + 0.5);
-       
+
        if (start_sample < half_width) {
                new_cache_start = 0;
        } else {
        if (start_sample < half_width) {
                new_cache_start = 0;
        } else {
@@ -389,10 +467,14 @@ gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_
        /* but make sure it doesn't extend beyond the end of the source material */
 
        rf3 = (gulong) (waveview->sourcefile_length_function (waveview->data_src, waveview->samples_per_unit)) + 1;
        /* but make sure it doesn't extend beyond the end of the source material */
 
        rf3 = (gulong) (waveview->sourcefile_length_function (waveview->data_src, waveview->samples_per_unit)) + 1;
-       rf3 -= new_cache_start;
+       if (rf3 < new_cache_start) {
+               rf3 = 0;
+       } else {
+               rf3 -= new_cache_start;
+       }
 
 #if DEBUG_CACHE
 
 #if DEBUG_CACHE
-       fprintf (stderr, "\n\nAVAILABLE FRAMES = %lu of %lu, start = %lu, sstart = %lu, cstart = %lu\n", 
+       fprintf (stderr, "AVAILABLE FRAMES = %lu of %lu, start = %lu, sstart = %lu, cstart = %lu\n",
                 rf3, waveview->sourcefile_length_function (waveview->data_src, waveview->samples_per_unit),
                 waveview->region_start, start_sample, new_cache_start);
 #endif
                 rf3, waveview->sourcefile_length_function (waveview->data_src, waveview->samples_per_unit),
                 waveview->region_start, start_sample, new_cache_start);
 #endif
@@ -405,8 +487,8 @@ gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_
 
 #if DEBUG_CACHE
        fprintf (stderr, "new cache = %lu - %lu\n", new_cache_start, new_cache_end);
 
 #if DEBUG_CACHE
        fprintf (stderr, "new cache = %lu - %lu\n", new_cache_start, new_cache_end);
-       fprintf(stderr,"required_cach_entries = %lu, samples_per_unit = %f\n",
-               required_cache_entries,waveview->samples_per_unit);
+       fprintf(stderr,"required_cach_entries = %lu, samples_per_unit = %f req frames = %lu\n",
+               required_cache_entries,waveview->samples_per_unit, required_frames);
 #endif
 
        if (required_cache_entries > cache->allocated) {
 #endif
 
        if (required_cache_entries > cache->allocated) {
@@ -418,9 +500,8 @@ gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_
 
        ostart = new_cache_start;
 
 
        ostart = new_cache_start;
 
-#undef CACHE_MEMMOVE_OPTIMIZATION
 #ifdef CACHE_MEMMOVE_OPTIMIZATION
 #ifdef CACHE_MEMMOVE_OPTIMIZATION
-       
+
        /* data is not entirely in the cache, so go fetch it, making sure to fill the cache */
 
        /* some of the required cache entries are in the cache, but in the wrong
        /* data is not entirely in the cache, so go fetch it, making sure to fill the cache */
 
        /* some of the required cache entries are in the cache, but in the wrong
@@ -428,24 +509,24 @@ gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_
        */
 
        if (cache->start < new_cache_start && new_cache_start < cache->end) {
        */
 
        if (cache->start < new_cache_start && new_cache_start < cache->end) {
-               
-               /* case one: the common area is at the end of the existing cache. move it 
+
+               /* case one: the common area is at the end of the existing cache. move it
                   to the beginning of the cache, and set up to refill whatever remains.
                   to the beginning of the cache, and set up to refill whatever remains.
-                  
-                  
+
+
                           wv->cache_start                                        wv->cache_end
                           |-------------------------------------------------------| cache
                                                               |--------------------------------| requested
                                                               <------------------->
                                                                     "present"
                           wv->cache_start                                        wv->cache_end
                           |-------------------------------------------------------| cache
                                                               |--------------------------------| requested
                                                               <------------------->
                                                                     "present"
-                                                           new_cache_start                      new_cache_end       
+                                                           new_cache_start                      new_cache_end
                */
                */
-                               
+
 
                present_frames = cache->end - new_cache_start;
                present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
 
 
                present_frames = cache->end - new_cache_start;
                present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
 
-#if DEBUG_CACHE                
+#if DEBUG_CACHE
                fprintf (stderr, "existing material at end of current cache, move to start of new cache\n"
                         "\tcopy from %lu to start\n", cache->data_size - present_entries);
 #endif
                fprintf (stderr, "existing material at end of current cache, move to start of new cache\n"
                         "\tcopy from %lu to start\n", cache->data_size - present_entries);
 #endif
@@ -453,7 +534,7 @@ gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_
                memmove (&cache->data[0],
                         &cache->data[cache->data_size - present_entries],
                         present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
                memmove (&cache->data[0],
                         &cache->data[cache->data_size - present_entries],
                         present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
-               
+
 #if DEBUG_CACHE
                fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
                         present_frames, required_frames, present_entries, new_cache_start + present_entries,
 #if DEBUG_CACHE
                fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
                         present_frames, required_frames, present_entries, new_cache_start + present_entries,
@@ -467,8 +548,8 @@ gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_
 
        } else if (new_cache_end > cache->start && new_cache_end < cache->end) {
 
 
        } else if (new_cache_end > cache->start && new_cache_end < cache->end) {
 
-               /* case two: the common area lives at the beginning of the existing cache. 
-                  
+               /* case two: the common area lives at the beginning of the existing cache.
+
                                             wv->cache_start                                      wv->cache_end
                                             |-----------------------------------------------------|
                               |--------------------------------|
                                             wv->cache_start                                      wv->cache_end
                                             |-----------------------------------------------------|
                               |--------------------------------|
@@ -477,15 +558,15 @@ gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_
 
                              new_cache_start                      new_cache_end
                */
 
                              new_cache_start                      new_cache_end
                */
-               
+
                present_frames = new_cache_end - cache->start;
                present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
 
                memmove (&cache->data[cache->data_size - present_entries],
                         &cache->data[0],
                         present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
                present_frames = new_cache_end - cache->start;
                present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
 
                memmove (&cache->data[cache->data_size - present_entries],
                         &cache->data[0],
                         present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
-               
-#if DEBUG_CACHE                
+
+#if DEBUG_CACHE
                fprintf (stderr, "existing material at start of current cache, move to start of end cache\n");
 #endif
 
                fprintf (stderr, "existing material at start of current cache, move to start of end cache\n");
 #endif
 
@@ -499,7 +580,7 @@ gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_
                offset = 0;
                required_frames -= present_frames;
 
                offset = 0;
                required_frames -= present_frames;
 
-               
+
        } else {
                copied = 0;
                offset = 0;
        } else {
                copied = 0;
                offset = 0;
@@ -514,8 +595,8 @@ gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_
 
 //     fprintf(stderr,"length == %lu\n",waveview->length_function (waveview->data_src));
 //     required_frames = MIN (waveview->length_function (waveview->data_src) - new_cache_start, required_frames);
 
 //     fprintf(stderr,"length == %lu\n",waveview->length_function (waveview->data_src));
 //     required_frames = MIN (waveview->length_function (waveview->data_src) - new_cache_start, required_frames);
+
        npeaks = (gulong) floor (required_frames / waveview->samples_per_unit);
        npeaks = (gulong) floor (required_frames / waveview->samples_per_unit);
-       npeaks = MAX (1, npeaks);
        required_frames = npeaks * waveview->samples_per_unit;
 
 #if DEBUG_CACHE
        required_frames = npeaks * waveview->samples_per_unit;
 
 #if DEBUG_CACHE
@@ -532,11 +613,15 @@ gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_
 //             start_sample, end_sample);
 #endif
 
 //             start_sample, end_sample);
 #endif
 
-       waveview->peak_function (waveview->data_src, npeaks, new_cache_start, required_frames, cache->data + offset, waveview->channel,waveview->samples_per_unit);
+       if (required_frames) {
+               waveview->peak_function (waveview->data_src, npeaks, new_cache_start, required_frames, cache->data + offset, waveview->channel,waveview->samples_per_unit);
 
 
-       /* take into account any copied peaks */
+               /* take into account any copied peaks */
 
 
-       npeaks += copied;
+               npeaks += copied;
+       } else {
+               npeaks = copied;
+       }
 
        if (npeaks < cache->allocated) {
 #if DEBUG_CACHE
 
        if (npeaks < cache->allocated) {
 #if DEBUG_CACHE
@@ -561,18 +646,40 @@ gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_
                }
 
                free (gain);
                }
 
                free (gain);
-       
+
+       }
+
+       /* do optional log scaling.  this implementation is not particularly efficient */
+
+       if (waveview->logscaled) {
+               guint32 n;
+               GnomeCanvasWaveViewCacheEntry* buf = cache->data;
+
+               for (n = 0; n < cache->data_size; ++n) {
+
+                       if (buf[n].max > 0.0f) {
+                               buf[n].max = alt_log_meter(fast_coefficient_to_dB(buf[n].max));
+                       } else if (buf[n].max < 0.0f) {
+                               buf[n].max = -alt_log_meter(fast_coefficient_to_dB(-buf[n].max));
+                       }
+
+                       if (buf[n].min > 0.0f) {
+                               buf[n].min = alt_log_meter(fast_coefficient_to_dB(buf[n].min));
+                       } else if (buf[n].min < 0.0f) {
+                               buf[n].min = -alt_log_meter(fast_coefficient_to_dB(-buf[n].min));
+                       }
+               }
        }
        }
-       
+
        cache->start = ostart;
        cache->end = new_cache_end;
 
   out:
 #if DEBUG_CACHE
        cache->start = ostart;
        cache->end = new_cache_end;
 
   out:
 #if DEBUG_CACHE
-       fprintf (stderr, "return cache index = %d\n", 
-                (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5));
+       fprintf (stderr, "return cache index = %d\n",
+                (guint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5));
 #endif
 #endif
-       return (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5);
+       return (guint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5);
 
 }
 
 
 }
 
@@ -585,7 +692,7 @@ gnome_canvas_waveview_set_data_src (GnomeCanvasWaveView *waveview, void *data_sr
                        waveview->reload_cache_in_render = TRUE;
                        return;
                }
                        waveview->reload_cache_in_render = TRUE;
                        return;
                }
-       
+
                waveview->cache->start  = 0;
                waveview->cache->end = 0;
        }
                waveview->cache->start  = 0;
                waveview->cache->end = 0;
        }
@@ -599,11 +706,11 @@ gnome_canvas_waveview_set_channel (GnomeCanvasWaveView *waveview, guint32 chan)
        if (waveview->channel == chan) {
                return;
        }
        if (waveview->channel == chan) {
                return;
        }
-       
+
        waveview->channel = chan;
 }
 
        waveview->channel = chan;
 }
 
-static void 
+static void
 gnome_canvas_waveview_reset_bounds (GnomeCanvasItem *item)
 
 {
 gnome_canvas_waveview_reset_bounds (GnomeCanvasItem *item)
 
 {
@@ -632,8 +739,8 @@ gnome_canvas_waveview_reset_bounds (GnomeCanvasItem *item)
        gnome_canvas_update_bbox (item, Ix1, Iy1, Ix2, Iy2);
 }
 
        gnome_canvas_update_bbox (item, Ix1, Iy1, Ix2, Iy2);
 }
 
-/* 
- * CANVAS CALLBACKS 
+/*
+ * CANVAS CALLBACKS
  */
 
 static void
  */
 
 static void
@@ -643,6 +750,8 @@ gnome_canvas_waveview_set_property (GObject      *object,
                                    GParamSpec   *pspec)
 
 {
                                    GParamSpec   *pspec)
 
 {
+       (void) pspec;
+
        GnomeCanvasItem *item;
        GnomeCanvasWaveView *waveview;
        int redraw = FALSE;
        GnomeCanvasItem *item;
        GnomeCanvasWaveView *waveview;
        int redraw = FALSE;
@@ -654,6 +763,7 @@ gnome_canvas_waveview_set_property (GObject      *object,
        item = GNOME_CANVAS_ITEM (object);
        waveview = GNOME_CANVAS_WAVEVIEW (object);
 
        item = GNOME_CANVAS_ITEM (object);
        waveview = GNOME_CANVAS_WAVEVIEW (object);
 
+       void * ptr;
        switch (prop_id) {
        case PROP_DATA_SRC:
                gnome_canvas_waveview_set_data_src (waveview, g_value_get_pointer(value));
        switch (prop_id) {
        case PROP_DATA_SRC:
                gnome_canvas_waveview_set_data_src (waveview, g_value_get_pointer(value));
@@ -666,22 +776,27 @@ gnome_canvas_waveview_set_property (GObject      *object,
                break;
 
        case PROP_LENGTH_FUNCTION:
                break;
 
        case PROP_LENGTH_FUNCTION:
-               waveview->length_function = g_value_get_pointer(value);
+               ptr = g_value_get_pointer(value);
+               waveview->length_function = POSIX_FUNC_PTR_CAST(waveview_length_function_t, ptr);
                redraw = TRUE;
                break;
                redraw = TRUE;
                break;
+
        case PROP_SOURCEFILE_LENGTH_FUNCTION:
        case PROP_SOURCEFILE_LENGTH_FUNCTION:
-               waveview->sourcefile_length_function = g_value_get_pointer(value);
+               ptr = g_value_get_pointer(value);
+               waveview->sourcefile_length_function = POSIX_FUNC_PTR_CAST(waveview_sourcefile_length_function_t, ptr);
                redraw = TRUE;
                break;
 
        case PROP_PEAK_FUNCTION:
                redraw = TRUE;
                break;
 
        case PROP_PEAK_FUNCTION:
-               waveview->peak_function = g_value_get_pointer(value);
+               ptr = g_value_get_pointer(value);
+               waveview->peak_function = POSIX_FUNC_PTR_CAST(waveview_peak_function_t, ptr);
                redraw = TRUE;
                break;
 
        case PROP_GAIN_FUNCTION:
                redraw = TRUE;
                break;
 
        case PROP_GAIN_FUNCTION:
-               waveview->gain_curve_function = g_value_get_pointer(value);
-               redraw = TRUE;
+               ptr = g_value_get_pointer(value);
+               waveview->gain_curve_function = POSIX_FUNC_PTR_CAST(waveview_gain_curve_function_t, ptr);
+                        redraw = TRUE;
                break;
 
        case PROP_GAIN_SRC:
                break;
 
        case PROP_GAIN_SRC:
@@ -750,12 +865,59 @@ gnome_canvas_waveview_set_property (GObject      *object,
                }
                break;
 
                }
                break;
 
+       case PROP_CLIP_COLOR:
+               if (waveview->clip_color != g_value_get_uint(value)) {
+                       waveview->clip_color = g_value_get_uint(value);
+                       redraw = TRUE;
+               }
+               break;
+
+       case PROP_ZERO_COLOR:
+               if (waveview->zero_color != g_value_get_uint(value)) {
+                       waveview->zero_color = g_value_get_uint(value);
+                       redraw = TRUE;
+               }
+               break;
+
+       case PROP_FILL_COLOR:
+               if (waveview->fill_color != g_value_get_uint(value)) {
+                       waveview->fill_color = g_value_get_uint(value);
+                       redraw = TRUE;
+               }
+               break;
+
+       case PROP_FILLED:
+               if (waveview->filled != g_value_get_boolean(value)) {
+                       waveview->filled = g_value_get_boolean(value);
+                       redraw = TRUE;
+               }
+               break;
+
        case PROP_RECTIFIED:
                if (waveview->rectified != g_value_get_boolean(value)) {
                        waveview->rectified = g_value_get_boolean(value);
                        redraw = TRUE;
                }
                break;
        case PROP_RECTIFIED:
                if (waveview->rectified != g_value_get_boolean(value)) {
                        waveview->rectified = g_value_get_boolean(value);
                        redraw = TRUE;
                }
                break;
+
+       case PROP_ZERO_LINE:
+               if (waveview->zero_line != g_value_get_boolean(value)) {
+                       waveview->zero_line = g_value_get_boolean(value);
+                       redraw = TRUE;
+               }
+               break;
+
+       case PROP_LOGSCALED:
+               if (waveview->logscaled != g_value_get_boolean(value)) {
+                       waveview->logscaled = g_value_get_boolean(value);
+                       if (waveview->cache_updater) {
+                               waveview->cache->start = 0;
+                               waveview->cache->end = 0;
+                       }
+                       redraw = TRUE;
+                       calc_bounds = TRUE;
+               }
+               break;
        case PROP_REGION_START:
                waveview->region_start = g_value_get_uint(value);
                redraw = TRUE;
        case PROP_REGION_START:
                waveview->region_start = g_value_get_uint(value);
                redraw = TRUE;
@@ -778,61 +940,62 @@ gnome_canvas_waveview_set_property (GObject      *object,
 }
 
 static void
 }
 
 static void
-gnome_canvas_waveview_get_property (GObject      *object,
-                                   guint         prop_id,
-                                   GValue       *value,
-                                   GParamSpec   *pspec)
+gnome_canvas_waveview_get_property (
+               GObject      *object,
+               guint         prop_id,
+               GValue       *value,
+               GParamSpec   *pspec)
 {
 {
-       
-   
+
+
        g_return_if_fail (object != NULL);
        g_return_if_fail (object != NULL);
-        g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
+       g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
 
        GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (object);
 
        switch (prop_id) {
        case PROP_DATA_SRC:
 
        GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (object);
 
        switch (prop_id) {
        case PROP_DATA_SRC:
-               g_value_set_pointer(value, waveview->data_src);
+               g_value_set_pointer(value, waveview->data_src);
                break;
 
        case PROP_CHANNEL:
                break;
 
        case PROP_CHANNEL:
-               g_value_set_uint(value, waveview->channel);
+               g_value_set_uint(value, waveview->channel);
                break;
 
        case PROP_LENGTH_FUNCTION:
                break;
 
        case PROP_LENGTH_FUNCTION:
-               g_value_set_pointer(value, waveview->length_function);
+               g_value_set_pointer(value, POSIX_FUNC_PTR_CAST(void*, waveview->length_function));
                break;
 
        case PROP_SOURCEFILE_LENGTH_FUNCTION:
                break;
 
        case PROP_SOURCEFILE_LENGTH_FUNCTION:
-               g_value_set_pointer(value, waveview->sourcefile_length_function);
+               g_value_set_pointer(value, POSIX_FUNC_PTR_CAST(void*, waveview->sourcefile_length_function));
                break;
 
        case PROP_PEAK_FUNCTION:
                break;
 
        case PROP_PEAK_FUNCTION:
-               g_value_set_pointer(value, waveview->peak_function);
+               g_value_set_pointer(value, POSIX_FUNC_PTR_CAST(void*, waveview->peak_function));
                break;
 
        case PROP_GAIN_FUNCTION:
                break;
 
        case PROP_GAIN_FUNCTION:
-               g_value_set_pointer(value, waveview->gain_curve_function);
+               g_value_set_pointer(value, POSIX_FUNC_PTR_CAST(void*, waveview->gain_curve_function));
                break;
 
        case PROP_GAIN_SRC:
                break;
 
        case PROP_GAIN_SRC:
-               g_value_set_pointer(value, waveview->gain_src);
+               g_value_set_pointer(value, waveview->gain_src);
                break;
 
        case PROP_CACHE:
                break;
 
        case PROP_CACHE:
-               g_value_set_pointer(value, waveview->cache);
+               g_value_set_pointer(value, waveview->cache);
                break;
 
        case PROP_CACHE_UPDATER:
                break;
 
        case PROP_CACHE_UPDATER:
-               g_value_set_boolean(value, waveview->cache_updater);
+               g_value_set_boolean(value, waveview->cache_updater);
                break;
 
        case PROP_SAMPLES_PER_UNIT:
                break;
 
        case PROP_SAMPLES_PER_UNIT:
-               g_value_set_double(value, waveview->samples_per_unit);
+               g_value_set_double(value, waveview->samples_per_unit);
                break;
 
        case PROP_AMPLITUDE_ABOVE_AXIS:
                break;
 
        case PROP_AMPLITUDE_ABOVE_AXIS:
-               g_value_set_double(value, waveview->amplitude_above_axis);
+               g_value_set_double(value, waveview->amplitude_above_axis);
                break;
 
        case PROP_X:
                break;
 
        case PROP_X:
@@ -851,11 +1014,38 @@ gnome_canvas_waveview_get_property (GObject      *object,
                g_value_set_uint (value, waveview->wave_color);
                break;
 
                g_value_set_uint (value, waveview->wave_color);
                break;
 
+       case PROP_CLIP_COLOR:
+               g_value_set_uint (value, waveview->clip_color);
+               break;
+
+       case PROP_ZERO_COLOR:
+               g_value_set_uint (value, waveview->zero_color);
+               break;
+
+       case PROP_FILL_COLOR:
+               g_value_set_uint (value, waveview->fill_color);
+               break;
+
+       case PROP_FILLED:
+               g_value_set_boolean (value, waveview->filled);
+               break;
+
        case PROP_RECTIFIED:
                g_value_set_boolean (value, waveview->rectified);
        case PROP_RECTIFIED:
                g_value_set_boolean (value, waveview->rectified);
+               break;
+
+       case PROP_ZERO_LINE:
+               g_value_set_boolean (value, waveview->zero_line);
+               break;
+
+       case PROP_LOGSCALED:
+               g_value_set_boolean (value, waveview->logscaled);
+               break;
 
        case PROP_REGION_START:
                g_value_set_uint (value, waveview->region_start);
 
        case PROP_REGION_START:
                g_value_set_uint (value, waveview->region_start);
+               break;
+
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
@@ -904,21 +1094,26 @@ gnome_canvas_waveview_update (GnomeCanvasItem *item, double *affine, ArtSVP *cli
 
        UINT_TO_RGBA (waveview->wave_color, &waveview->wave_r, &waveview->wave_g, &waveview->wave_b,
                      &waveview->wave_a);
 
        UINT_TO_RGBA (waveview->wave_color, &waveview->wave_r, &waveview->wave_g, &waveview->wave_b,
                      &waveview->wave_a);
+       UINT_TO_RGBA (waveview->clip_color, &waveview->clip_r, &waveview->clip_g, &waveview->clip_b,
+                     &waveview->clip_a);
+       UINT_TO_RGBA (waveview->fill_color, &waveview->fill_r, &waveview->fill_g, &waveview->fill_b,
+                     &waveview->fill_a);
 
 //     check_cache (waveview, "end of update");
 }
 
 static void
 
 //     check_cache (waveview, "end of update");
 }
 
 static void
-gnome_canvas_waveview_render (GnomeCanvasItem *item,
-                           GnomeCanvasBuf *buf)
+gnome_canvas_waveview_gradient_render (GnomeCanvasItem *item,
+                                      GnomeCanvasBuf *buf)
 {
        GnomeCanvasWaveView *waveview;
        gulong s1, s2;
        int clip_length = 0;
        int pymin, pymax;
 {
        GnomeCanvasWaveView *waveview;
        gulong s1, s2;
        int clip_length = 0;
        int pymin, pymax;
-       int cache_index;
+       guint cache_index;
        double half_height;
        double half_height;
-       int x, end, begin;
+       int x;
+       char rectify;
 
        waveview = GNOME_CANVAS_WAVEVIEW (item);
 
 
        waveview = GNOME_CANVAS_WAVEVIEW (item);
 
@@ -933,19 +1128,29 @@ gnome_canvas_waveview_render (GnomeCanvasItem *item,
                buf->is_bg = FALSE;
        }
 
                buf->is_bg = FALSE;
        }
 
-       begin = MAX(waveview->bbox_ulx,buf->rect.x0);
+       /* a "unit" means a pixel */
 
 
-       if (waveview->bbox_lrx >= 0) {
-               end = MIN(waveview->bbox_lrx,buf->rect.x1);
-       } else {
-               end = buf->rect.x1;
-       }
+       /* begin: render start x (units) */
+       int const begin = MAX (waveview->bbox_ulx, buf->rect.x0);
+
+        /* zbegin: start x for zero line (units) */
+       int const zbegin = (begin == waveview->bbox_ulx) ? (begin + 1) : begin;
+
+       /* end: render end x (units) */
+       int const end = (waveview->bbox_lrx >= 0) ? MIN (waveview->bbox_lrx,buf->rect.x1) : buf->rect.x1;
+
+       /* zend: end x for zero-line (units) */
+       int const zend = (end == waveview->bbox_lrx) ? (end - 1) : end;
 
        if (begin == end) {
                return;
        }
 
 
        if (begin == end) {
                return;
        }
 
-       s1 = floor ((begin - waveview->bbox_ulx) * waveview->samples_per_unit) ;
+       /* s1: start sample
+          s2: end sample
+       */
+
+       s1 = floor ((begin - waveview->bbox_ulx) * waveview->samples_per_unit);
 
        // fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit);
 
 
        // fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit);
 
@@ -960,7 +1165,7 @@ gnome_canvas_waveview_render (GnomeCanvasItem *item,
 
 #if 0
        printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)"
 
 #if 0
        printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)"
-               " b/e %d..%d s= %lu..%lu\n",
+               " b/e %d..%d s= %lu..%lu @ %f\n",
                waveview,
                buf->rect.x0,
                buf->rect.x1,
                waveview,
                buf->rect.x0,
                buf->rect.x1,
@@ -970,7 +1175,8 @@ gnome_canvas_waveview_render (GnomeCanvasItem *item,
                waveview->bbox_lrx,
                waveview->bbox_uly,
                waveview->bbox_lry,
                waveview->bbox_lrx,
                waveview->bbox_uly,
                waveview->bbox_lry,
-               begin, end, s1, s2);
+               begin, end, s1, s2,
+               waveview->samples_per_unit);
 #endif
 
        /* now ensure that the cache is full and properly
 #endif
 
        /* now ensure that the cache is full and properly
@@ -985,11 +1191,19 @@ gnome_canvas_waveview_render (GnomeCanvasItem *item,
                waveview->reload_cache_in_render = FALSE;
        }
 
                waveview->reload_cache_in_render = FALSE;
        }
 
-       cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
-
 //     check_cache (waveview, "post-ensure");
 
 //     check_cache (waveview, "post-ensure");
 
-       /* 
+       /* don't rectify at single-sample zoom */
+       if (waveview->rectified && waveview->samples_per_unit > 1) {
+               rectify = TRUE;
+       }
+       else {
+               rectify = FALSE;
+       }
+
+       clip_length = MIN(5,(waveview->height/4));
+
+       /*
           Now draw each line, clipping it appropriately. The clipping
           is done by the macros PAINT_FOO().
        */
           Now draw each line, clipping it appropriately. The clipping
           is done by the macros PAINT_FOO().
        */
@@ -997,149 +1211,1255 @@ gnome_canvas_waveview_render (GnomeCanvasItem *item,
        half_height = waveview->half_height;
 
 /* this makes it slightly easier to comprehend whats going on */
        half_height = waveview->half_height;
 
 /* this makes it slightly easier to comprehend whats going on */
-
 #define origin half_height
 
 #define origin half_height
 
-       for (x = begin; x < end; x++) {
-
+       if (waveview->filled && !rectify) {
+               int prev_pymin = 1;
+               int prev_pymax = 0;
+               int last_pymin = 1;
+               int last_pymax = 0;
+               int next_pymin, next_pymax;
                double max, min;
                double max, min;
-               int clip_max, clip_min;
-               
-               clip_max = 0;
-               clip_min = 0;
+               int next_clip_max = 0;
+               int next_clip_min = 0;
+
+               int wave_middle = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
+               int wave_top = (int) rint ((item->y1) * item->canvas->pixels_per_unit);
+
+               if (s1 < waveview->samples_per_unit) {
+                       /* we haven't got a prev vars to compare with, so outline the whole line here */
+                       prev_pymax = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
+                       prev_pymin = prev_pymax;
+               }
+               else {
+                       s1 -= waveview->samples_per_unit;
+               }
+
+               if(end == waveview->bbox_lrx) {
+                       /* we don't have the NEXT vars for the last sample */
+                       last_pymax = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
+                       last_pymin = last_pymax;
+               }
+               else {
+                       s2 += waveview->samples_per_unit;
+               }
+
+               cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
 
 
+               /*
+                * Compute the variables outside the rendering rect
+                */
+               if(prev_pymax != prev_pymin) {
+
+                       prev_pymax = (int) rint ((item->y1 + origin - MIN(waveview->cache->data[cache_index].max, 1.0) * half_height) * item->canvas->pixels_per_unit);
+                       prev_pymin = (int) rint ((item->y1 + origin - MAX(waveview->cache->data[cache_index].min, -1.0) * half_height) * item->canvas->pixels_per_unit);
+                       ++cache_index;
+               }
+               if(last_pymax != last_pymin) {
+                       /* take the index of one sample right of what we render */
+                       guint index = cache_index + (end - begin);
+
+                       if (index >= waveview->cache->data_size) {
+
+                               /* the data we want is off the end of the cache, which must mean its beyond
+                                  the end of the region's source; hence the peak values are 0 */
+                               last_pymax = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
+                               last_pymin = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
+
+                       } else {
+
+                               last_pymax = (int) rint ((item->y1 + origin - MIN(waveview->cache->data[index].max, 1.0) * half_height) * item->canvas->pixels_per_unit);
+                               last_pymin = (int) rint ((item->y1 + origin - MAX(waveview->cache->data[index].min, -1.0) * half_height) * item->canvas->pixels_per_unit);
+
+                       }
+
+               }
+
+               /*
+                * initialize NEXT* variables for the first run, duplicated in the loop for speed
+                */
                max = waveview->cache->data[cache_index].max;
                min = waveview->cache->data[cache_index].min;
                max = waveview->cache->data[cache_index].max;
                min = waveview->cache->data[cache_index].min;
-               
+
                if (max >= 1.0) {
                        max = 1.0;
                if (max >= 1.0) {
                        max = 1.0;
-                       clip_max = 1;
+                       next_clip_max = 1;
                }
 
                if (min <= -1.0) {
                        min = -1.0;
                }
 
                if (min <= -1.0) {
                        min = -1.0;
-                       clip_min = 1;
+                       next_clip_min = 1;
+               }
+
+               max *= half_height;
+               min *= half_height;
+
+               next_pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
+               next_pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
+
+               /*
+                * And now the loop
+                */
+               for(x = begin; x < end; ++x) {
+                       int clip_max = next_clip_max;
+                       int clip_min = next_clip_min;
+                       int fill_max, fill_min;
+
+                       pymax = next_pymax;
+                       pymin = next_pymin;
+
+                       /* compute next */
+                       if(x == end - 1) {
+                               /*next is now the last column, which is outside the rendering rect, and possibly outside the region*/
+                               next_pymax = last_pymax;
+                               next_pymin = last_pymin;
+                       }
+                       else {
+                               ++cache_index;
+
+                               if (cache_index < waveview->cache->data_size) {
+                                       max = waveview->cache->data[cache_index].max;
+                                       min = waveview->cache->data[cache_index].min;
+                               } else {
+                                       max = min = 0;
+                               }
+
+                               next_clip_max = 0;
+                               next_clip_min = 0;
+
+                               if (max >= 1.0) {
+                                       max = 1.0;
+                                       next_clip_max = 1;
+                               }
+
+                               if (min <= -1.0) {
+                                       min = -1.0;
+                                       next_clip_min = 1;
+                               }
+
+                               max *= half_height;
+                               min *= half_height;
+
+                               next_pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
+                               next_pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
+                       }
+
+                       /* render */
+                       if (pymax == pymin) {
+                               PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
+                       } else {
+                               if((prev_pymax < pymax && next_pymax < pymax) ||
+                                  (prev_pymax == pymax && next_pymax == pymax)) {
+                                       fill_max = pymax + 1;
+                                       PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
+                               }
+                               else {
+                                       fill_max = MAX(prev_pymax, next_pymax);
+                                       if(pymax == fill_max) {
+                                               PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
+                                               ++fill_max;
+                                       } else {
+                                               PAINT_VERTA_GR(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max, wave_middle, wave_top);
+                                       }
+                                       
+                               }
+
+                               if((prev_pymin > pymin && next_pymin > pymin) ||
+                                  (prev_pymin == pymin && next_pymin == pymin)) {
+                                       fill_min = pymin - 1;
+                                       PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin-1);
+                               }
+                               else {
+                                       fill_min = MIN(prev_pymin, next_pymin);
+                                       if(pymin == fill_min) {
+                                               PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
+                                       }
+                                       else {
+                                               PAINT_VERTA_GR(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, fill_min, pymin, wave_middle, wave_top);
+                                       }
+                               }
+
+                               if(fill_max < fill_min) {
+                                       PAINT_VERTA_GR(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max, fill_min, wave_middle, wave_top);
+                               }
+                               else if(fill_max == fill_min) {
+                                       PAINT_DOTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max);
+                               }
+                       }
+
+                       if (clip_max) {
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax + clip_length);
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x + 1, pymax, pymax + (clip_length -1));
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x - 1, pymax, pymax + (clip_length - 1));
+
+                       }
+
+                       if (clip_min) {
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a , x, pymin - clip_length, pymin);
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x + 1, pymin - (clip_length - 1), pymin);
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x - 1, pymin - (clip_length - 1), pymin);
+                       }
+
+                       prev_pymax = pymax;
+                       prev_pymin = pymin;
+               }
+
+       } else if (waveview->filled && rectify) {
+
+               int prev_pymax = -1;
+               int last_pymax = -1;
+               int next_pymax;
+               double max, min;
+               int next_clip_max = 0;
+               int next_clip_min = 0;
+
+               int wave_middle = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
+               int wave_top = (int) rint ((item->y1) * item->canvas->pixels_per_unit);
+
+               // for rectified, this stays constant throughout the loop
+               pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
+
+               if(s1 < waveview->samples_per_unit) {
+                       /* we haven't got a prev vars to compare with, so outline the whole line here */
+                       prev_pymax = pymin;
+               }
+               else {
+                       s1 -= waveview->samples_per_unit;
+               }
+
+               if(end == waveview->bbox_lrx) {
+                       /* we don't have the NEXT vars for the last sample */
+                       last_pymax = pymin;
+               }
+               else {
+                       s2 += waveview->samples_per_unit;
                }
 
                }
 
-               /* don't rectify at single-sample zoom */
+               cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
 
 
-               if (waveview->rectified && waveview->samples_per_unit > 1) {
+               /*
+                * Compute the variables outside the rendering rect
+                */
+               if(prev_pymax < 0) {
+                       max = MIN(waveview->cache->data[cache_index].max, 1.0);
+                       min = MAX(waveview->cache->data[cache_index].min, -1.0);
 
                        if (fabs (min) > fabs (max)) {
                                max = fabs (min);
 
                        if (fabs (min) > fabs (max)) {
                                max = fabs (min);
-                       } 
+                       }
 
 
-                       max = max * waveview->height;
+                       prev_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
+                       ++cache_index;
+               }
+               if(last_pymax < 0) {
+                       /* take the index of one sample right of what we render */
+                       int index = cache_index + (end - begin);
 
 
-                       pymax = (int) rint ((item->y1 + waveview->height - max) * item->canvas->pixels_per_unit);
-                       pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
+                       max = MIN(waveview->cache->data[index].max, 1.0);
+                       min = MAX(waveview->cache->data[index].min, -1.0);
 
 
-               } else {
-                       
-                       max = max * half_height;
-                       min = min * half_height;
-                       
-                       pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
-                       pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
+                       if (fabs (min) > fabs (max)) {
+                               max = fabs (min);
+                       }
+
+                       last_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
                }
 
                }
 
-               /* OK, now fill the RGB buffer at x=i with a line between pymin and pymax,
-                  or, if samples_per_unit == 1, then a dot at each location.
-               */
+               /*
+                * initialize NEXT* variables for the first run, duplicated in the loop for speed
+                */
+               max = waveview->cache->data[cache_index].max;
+               min = waveview->cache->data[cache_index].min;
 
 
-               if (pymax == pymin) {
-                       PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
-               } else {
-                       PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, pymin);
+               if (max >= 1.0) {
+                       max = 1.0;
+                       next_clip_max = 1;
                }
                }
-               
-               /* show clipped waveforms with small red lines */
 
 
-               if (clip_max || clip_min) {
-                       clip_length = MIN(5,(waveview->height/4));
+               if (min <= -1.0) {
+                       min = -1.0;
+                       next_clip_min = 1;
                }
 
                }
 
-               if (clip_max) {
-                       PAINT_VERT(buf, 255, 0, 0, x, pymax, pymax+clip_length);
+               if (fabs (min) > fabs (max)) {
+                       max = fabs (min);
                }
 
                }
 
-               if (clip_min) {
-                       PAINT_VERT(buf, 255, 0, 0, x, pymin-clip_length, pymin);
+               next_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
+
+               /*
+                * And now the loop
+                */
+               for(x = begin; x < end; ++x) {
+                       int clip_max = next_clip_max;
+                       int clip_min = next_clip_min;
+                       int fill_max;
+
+                       pymax = next_pymax;
+
+                       /* compute next */
+                       if(x == end - 1) {
+                               /*next is now the last column, which is outside the rendering rect, and possibly outside the region*/
+                               next_pymax = last_pymax;
+                       }
+                       else {
+                               ++cache_index;
+
+                               max = waveview->cache->data[cache_index].max;
+                               min = waveview->cache->data[cache_index].min;
+
+                               if (max >= 1.0) {
+                                       max = 1.0;
+                                       next_clip_max = 1;
+                               }
+
+                               if (min <= -1.0) {
+                                       min = -1.0;
+                                       next_clip_min = 1;
+                               }
+
+                               if (fabs (min) > fabs (max)) {
+                                       max = fabs (min);
+                               }
+
+                               next_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
+                       }
+
+                       /* render */
+                       if (pymax == pymin) {
+                               PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
+                       } else {
+                               if((prev_pymax < pymax && next_pymax < pymax) ||
+                                  (prev_pymax == pymax && next_pymax == pymax)) {
+                                       fill_max = pymax + 1;
+                                       PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
+                               }
+                               else {
+                                       fill_max = MAX(prev_pymax, next_pymax);
+                                       if(pymax == fill_max) {
+                                               PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
+                                               ++fill_max;
+                                       }
+                                       else {
+                                               PAINT_VERTA_GR(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max, wave_middle, wave_top);
+                                       }
+                               }
+
+                               if(fill_max < pymin) {
+                                       PAINT_VERTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max, pymin);
+                               }
+                               else if(fill_max == pymin) {
+                                       PAINT_DOTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, pymin);
+                               }
+                       }
+
+                       if (clip_max) {
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax + clip_length);
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x + 1, pymax, pymax + (clip_length -1));
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x - 1, pymax, pymax + (clip_length - 1));
+                       }
+
+                       if (clip_min) { 
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a , x, pymin - clip_length, pymin);
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x + 1, pymin - (clip_length - 1), pymin);
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x - 1, pymin - (clip_length - 1), pymin);
+                       }
+
+                       prev_pymax = pymax;
                }
                }
-
-               /* presto, we're done */
-               
-               cache_index++;
        }
        }
+       else {
+               cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
 
 
-#undef origin
+               for (x = begin; x < end; x++) {
 
 
-}
+                       double max, min;
+                       int clip_max, clip_min;
 
 
-static void
-gnome_canvas_waveview_draw (GnomeCanvasItem *item,
-                         GdkDrawable *drawable,
-                         int x, int y,
-                         int width, int height)
-{
-       GnomeCanvasWaveView *waveview;
+                       clip_max = 0;
+                       clip_min = 0;
 
 
-       waveview = GNOME_CANVAS_WAVEVIEW (item);
+                       max = waveview->cache->data[cache_index].max;
+                       min = waveview->cache->data[cache_index].min;
 
 
-       if (parent_class->draw) {
-               (* parent_class->draw) (item, drawable, x, y, width, height);
-       }
+                       if (max >= 1.0) {
+                               max = 1.0;
+                               clip_max = 1;
+                       }
 
 
-       fprintf (stderr, "please don't use the CanvasWaveView item in a non-aa Canvas\n");
-       abort ();
-}
+                       if (min <= -1.0) {
+                               min = -1.0;
+                               clip_min = 1;
+                       }
 
 
-static void
-gnome_canvas_waveview_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
-{
-       GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (item);
+                       if (rectify) {
 
 
-       *x1 = waveview->x;
-       *y1 = waveview->y;
+                               if (fabs (min) > fabs (max)) {
+                                       max = fabs (min);
+                               }
 
 
-       *x2 = ceil (*x1 + (waveview->length_function (waveview->data_src) / waveview->samples_per_unit));
-       *y2 = *y1 + waveview->height;
+                               max = max * waveview->height;
 
 
-#if 0
-       x = 0; y = 0;
-       gnome_canvas_item_i2w (item, &x, &y);
-       gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &a, &b);
-       x = *x2;
-       y = *y2;
-       gnome_canvas_item_i2w (item, &x, &y);
-       gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &c, &d);
-       printf ("item bounds now (%g,%g),(%g,%g)\n", a, b, c, d);
-#endif         
+                               pymax = (int) rint ((item->y1 + waveview->height - max) * item->canvas->pixels_per_unit);
+                               pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
 
 
-}
+                       } else {
 
 
-static double
-gnome_canvas_waveview_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item)
-{
-       /* XXX for now, point is never inside the wave 
-       GnomeCanvasWaveView *waveview;
-       double x1, y1, x2, y2;
-       double dx, dy;
-       */
+                               max = max * half_height;
+                               min = min * half_height;
 
 
-       return DBL_MAX;
+                               pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
+                               pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
+                       }
 
 
-#if 0
-       waveview = GNOME_CANVAS_WAVEVIEW (item);
+                       /* OK, now fill the RGB buffer at x=i with a line between pymin and pymax,
+                          or, if samples_per_unit == 1, then a dot at each location.
+                       */
 
 
-       *actual_item = item;
+                       if (pymax == pymin) {
+                               PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
+                       } else {
+                               PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, pymin);
+                       }
+
+                       /* show clipped waveforms with small red lines */
+
+                       if (clip_max) {
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length);
+                       }
+
+                       if (clip_min) {
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin);
+                       }
+
+                       /* presto, we're done */
+
+                       cache_index++;
+               }
+       }
+
+       if (!waveview->rectified && waveview->zero_line && waveview->height >= 100) {
+               // Paint zeroline.
+
+               unsigned char zero_r, zero_g, zero_b, zero_a;
+               UINT_TO_RGBA( waveview->zero_color, &zero_r, &zero_g, &zero_b, &zero_a);
+               int zeroline_y = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
+               PAINT_HORIZA(buf, zero_r, zero_g, zero_b, zero_a, zbegin, zend, zeroline_y);
+       }
+#undef origin
+
+}
+
+static void
+gnome_canvas_waveview_flat_render (GnomeCanvasItem *item,
+                                  GnomeCanvasBuf *buf)
+{
+       GnomeCanvasWaveView *waveview;
+       gulong s1, s2;
+       int clip_length = 0;
+       int pymin, pymax;
+       guint cache_index;
+       double half_height;
+       int x;
+       char rectify;
+
+       waveview = GNOME_CANVAS_WAVEVIEW (item);
+
+//     check_cache (waveview, "start of render");
+
+       if (parent_class->render) {
+               (*parent_class->render) (item, buf);
+       }
+
+       if (buf->is_bg) {
+               gnome_canvas_buf_ensure_buf (buf);
+               buf->is_bg = FALSE;
+       }
+
+       /* a "unit" means a pixel */
+
+       /* begin: render start x (units) */
+       int const begin = MAX (waveview->bbox_ulx, buf->rect.x0);
+
+        /* zbegin: start x for zero line (units) */
+       int const zbegin = (begin == waveview->bbox_ulx) ? (begin + 1) : begin;
+
+       /* end: render end x (units) */
+       int const end = (waveview->bbox_lrx >= 0) ? MIN (waveview->bbox_lrx,buf->rect.x1) : buf->rect.x1;
+
+       /* zend: end x for zero-line (units) */
+       int const zend = (end == waveview->bbox_lrx) ? (end - 1) : end;
+
+       if (begin == end) {
+               return;
+       }
+
+       /* s1: start sample
+          s2: end sample
+       */
+
+       s1 = floor ((begin - waveview->bbox_ulx) * waveview->samples_per_unit);
+
+       // fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit);
+
+       if (end == waveview->bbox_lrx) {
+               /* This avoids minor rounding errors when we have the
+                  entire region visible.
+               */
+               s2 = waveview->samples;
+       } else {
+               s2 = s1 + floor ((end - begin) * waveview->samples_per_unit);
+       }
+
+#if 0
+       printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)"
+               " b/e %d..%d s= %lu..%lu @ %f\n",
+               waveview,
+               buf->rect.x0,
+               buf->rect.x1,
+               buf->rect.y0,
+               buf->rect.y1,
+               waveview->bbox_ulx,
+               waveview->bbox_lrx,
+               waveview->bbox_uly,
+               waveview->bbox_lry,
+               begin, end, s1, s2,
+               waveview->samples_per_unit);
+#endif
+
+       /* now ensure that the cache is full and properly
+          positioned.
+       */
+
+//     check_cache (waveview, "pre-ensure");
+
+       if (waveview->cache_updater && waveview->reload_cache_in_render) {
+               waveview->cache->start = 0;
+               waveview->cache->end = 0;
+               waveview->reload_cache_in_render = FALSE;
+       }
+
+//     check_cache (waveview, "post-ensure");
+
+       /* don't rectify at single-sample zoom */
+       if (waveview->rectified && waveview->samples_per_unit > 1) {
+               rectify = TRUE;
+       }
+       else {
+               rectify = FALSE;
+       }
+
+       clip_length = MIN(5,(waveview->height/4));
+
+       /*
+          Now draw each line, clipping it appropriately. The clipping
+          is done by the macros PAINT_FOO().
+       */
+
+       half_height = waveview->half_height;
+
+/* this makes it slightly easier to comprehend whats going on */
+#define origin half_height
+
+       if (waveview->filled && !rectify) {
+               int prev_pymin = 1;
+               int prev_pymax = 0;
+               int last_pymin = 1;
+               int last_pymax = 0;
+               int next_pymin, next_pymax;
+               double max, min;
+               int next_clip_max = 0;
+               int next_clip_min = 0;
+
+               if (s1 < waveview->samples_per_unit) {
+                       /* we haven't got a prev vars to compare with, so outline the whole line here */
+                       prev_pymax = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
+                       prev_pymin = prev_pymax;
+               }
+               else {
+                       s1 -= waveview->samples_per_unit;
+               }
+
+               if(end == waveview->bbox_lrx) {
+                       /* we don't have the NEXT vars for the last sample */
+                       last_pymax = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
+                       last_pymin = last_pymax;
+               }
+               else {
+                       s2 += waveview->samples_per_unit;
+               }
+
+               cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
+
+               /*
+                * Compute the variables outside the rendering rect
+                */
+               if(prev_pymax != prev_pymin) {
+
+                       prev_pymax = (int) rint ((item->y1 + origin - MIN(waveview->cache->data[cache_index].max, 1.0) * half_height) * item->canvas->pixels_per_unit);
+                       prev_pymin = (int) rint ((item->y1 + origin - MAX(waveview->cache->data[cache_index].min, -1.0) * half_height) * item->canvas->pixels_per_unit);
+                       ++cache_index;
+               }
+               if(last_pymax != last_pymin) {
+                       /* take the index of one sample right of what we render */
+                       guint index = cache_index + (end - begin);
+
+                       if (index >= waveview->cache->data_size) {
+
+                               /* the data we want is off the end of the cache, which must mean its beyond
+                                  the end of the region's source; hence the peak values are 0 */
+                               last_pymax = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
+                               last_pymin = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
+
+                       } else {
+
+                               last_pymax = (int) rint ((item->y1 + origin - MIN(waveview->cache->data[index].max, 1.0) * half_height) * item->canvas->pixels_per_unit);
+                               last_pymin = (int) rint ((item->y1 + origin - MAX(waveview->cache->data[index].min, -1.0) * half_height) * item->canvas->pixels_per_unit);
+
+                       }
+
+               }
+
+               /*
+                * initialize NEXT* variables for the first run, duplicated in the loop for speed
+                */
+               max = waveview->cache->data[cache_index].max;
+               min = waveview->cache->data[cache_index].min;
+
+               if (max >= 1.0) {
+                       max = 1.0;
+                       next_clip_max = 1;
+               }
+
+               if (min <= -1.0) {
+                       min = -1.0;
+                       next_clip_min = 1;
+               }
+
+               max *= half_height;
+               min *= half_height;
+
+               next_pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
+               next_pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
+
+               /*
+                * And now the loop
+                */
+               for(x = begin; x < end; ++x) {
+                       int clip_max = next_clip_max;
+                       int clip_min = next_clip_min;
+                       int fill_max, fill_min;
+
+                       pymax = next_pymax;
+                       pymin = next_pymin;
+
+                       /* compute next */
+                       if(x == end - 1) {
+                               /*next is now the last column, which is outside the rendering rect, and possibly outside the region*/
+                               next_pymax = last_pymax;
+                               next_pymin = last_pymin;
+                       }
+                       else {
+                               ++cache_index;
+
+                               if (cache_index < waveview->cache->data_size) {
+                                       max = waveview->cache->data[cache_index].max;
+                                       min = waveview->cache->data[cache_index].min;
+                               } else {
+                                       max = min = 0;
+                               }
+
+                               next_clip_max = 0;
+                               next_clip_min = 0;
+
+                               if (max >= 1.0) {
+                                       max = 1.0;
+                                       next_clip_max = 1;
+                               }
+
+                               if (min <= -1.0) {
+                                       min = -1.0;
+                                       next_clip_min = 1;
+                               }
+
+                               max *= half_height;
+                               min *= half_height;
+
+                               next_pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
+                               next_pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
+                       }
+
+                       /* render */
+                       if (pymax == pymin) {
+                               PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
+                       } else {
+                               if((prev_pymax < pymax && next_pymax < pymax) ||
+                                  (prev_pymax == pymax && next_pymax == pymax)) {
+                                       fill_max = pymax + 1;
+                                       PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
+                               }
+                               else {
+                                       fill_max = MAX(prev_pymax, next_pymax);
+                                       if(pymax == fill_max) {
+                                               PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
+                                               ++fill_max;
+                                       }
+                                       else {
+                                               PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max);
+                                       }
+                               }
+
+                               if((prev_pymin > pymin && next_pymin > pymin) ||
+                                  (prev_pymin == pymin && next_pymin == pymin)) {
+                                       fill_min = pymin - 1;
+                                       PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin-1);
+                               }
+                               else {
+                                       fill_min = MIN(prev_pymin, next_pymin);
+                                       if(pymin == fill_min) {
+                                               PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
+                                       }
+                                       else {
+                                               PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, fill_min, pymin);
+                                       }
+                               }
+
+                               if(fill_max < fill_min) {
+                                       PAINT_VERTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max, fill_min);
+                               }
+                               else if(fill_max == fill_min) {
+                                       PAINT_DOTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max);
+                               }
+                       }
+
+                       if (clip_max) {
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length);
+                       }
+
+                       if (clip_min) {
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin);
+                       }
+
+                       prev_pymax = pymax;
+                       prev_pymin = pymin;
+               }
+
+       } else if (waveview->filled && rectify) {
+
+               int prev_pymax = -1;
+               int last_pymax = -1;
+               int next_pymax;
+               double max, min;
+               int next_clip_max = 0;
+               int next_clip_min = 0;
+
+               // for rectified, this stays constant throughout the loop
+               pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
+
+               if(s1 < waveview->samples_per_unit) {
+                       /* we haven't got a prev vars to compare with, so outline the whole line here */
+                       prev_pymax = pymin;
+               }
+               else {
+                       s1 -= waveview->samples_per_unit;
+               }
+
+               if(end == waveview->bbox_lrx) {
+                       /* we don't have the NEXT vars for the last sample */
+                       last_pymax = pymin;
+               }
+               else {
+                       s2 += waveview->samples_per_unit;
+               }
+
+               cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
+
+               /*
+                * Compute the variables outside the rendering rect
+                */
+               if(prev_pymax < 0) {
+                       max = MIN(waveview->cache->data[cache_index].max, 1.0);
+                       min = MAX(waveview->cache->data[cache_index].min, -1.0);
+
+                       if (fabs (min) > fabs (max)) {
+                               max = fabs (min);
+                       }
+
+                       prev_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
+                       ++cache_index;
+               }
+               if(last_pymax < 0) {
+                       /* take the index of one sample right of what we render */
+                       int index = cache_index + (end - begin);
+
+                       max = MIN(waveview->cache->data[index].max, 1.0);
+                       min = MAX(waveview->cache->data[index].min, -1.0);
+
+                       if (fabs (min) > fabs (max)) {
+                               max = fabs (min);
+                       }
+
+                       last_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
+               }
+
+               /*
+                * initialize NEXT* variables for the first run, duplicated in the loop for speed
+                */
+               max = waveview->cache->data[cache_index].max;
+               min = waveview->cache->data[cache_index].min;
+
+               if (max >= 1.0) {
+                       max = 1.0;
+                       next_clip_max = 1;
+               }
+
+               if (min <= -1.0) {
+                       min = -1.0;
+                       next_clip_min = 1;
+               }
+
+               if (fabs (min) > fabs (max)) {
+                       max = fabs (min);
+               }
+
+               next_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
+
+               /*
+                * And now the loop
+                */
+               for(x = begin; x < end; ++x) {
+                       int clip_max = next_clip_max;
+                       int clip_min = next_clip_min;
+                       int fill_max;
+
+                       pymax = next_pymax;
+
+                       /* compute next */
+                       if(x == end - 1) {
+                               /*next is now the last column, which is outside the rendering rect, and possibly outside the region*/
+                               next_pymax = last_pymax;
+                       }
+                       else {
+                               ++cache_index;
+
+                               max = waveview->cache->data[cache_index].max;
+                               min = waveview->cache->data[cache_index].min;
+
+                               if (max >= 1.0) {
+                                       max = 1.0;
+                                       next_clip_max = 1;
+                               }
+
+                               if (min <= -1.0) {
+                                       min = -1.0;
+                                       next_clip_min = 1;
+                               }
+
+                               if (fabs (min) > fabs (max)) {
+                                       max = fabs (min);
+                               }
+
+                               next_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
+                       }
+
+                       /* render */
+                       if (pymax == pymin) {
+                               PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
+                       } else {
+                               if((prev_pymax < pymax && next_pymax < pymax) ||
+                                  (prev_pymax == pymax && next_pymax == pymax)) {
+                                       fill_max = pymax + 1;
+                                       PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
+                               }
+                               else {
+                                       fill_max = MAX(prev_pymax, next_pymax);
+                                       if(pymax == fill_max) {
+                                               PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
+                                               ++fill_max;
+                                       }
+                                       else {
+                                               PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max);
+                                       }
+                               }
+
+                               if(fill_max < pymin) {
+                                       PAINT_VERTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max, pymin);
+                               }
+                               else if(fill_max == pymin) {
+                                       PAINT_DOTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, pymin);
+                               }
+                       }
+
+                       if (clip_max) {
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length);
+                       }
+
+                       if (clip_min) {
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin);
+                       }
+
+                       prev_pymax = pymax;
+               }
+       }
+       else {
+               cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
+
+               for (x = begin; x < end; x++) {
+
+                       double max, min;
+                       int clip_max, clip_min;
+
+                       clip_max = 0;
+                       clip_min = 0;
+
+                       max = waveview->cache->data[cache_index].max;
+                       min = waveview->cache->data[cache_index].min;
+
+                       if (max >= 1.0) {
+                               max = 1.0;
+                               clip_max = 1;
+                       }
+
+                       if (min <= -1.0) {
+                               min = -1.0;
+                               clip_min = 1;
+                       }
+
+                       if (rectify) {
+
+                               if (fabs (min) > fabs (max)) {
+                                       max = fabs (min);
+                               }
+
+                               max = max * waveview->height;
+
+                               pymax = (int) rint ((item->y1 + waveview->height - max) * item->canvas->pixels_per_unit);
+                               pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
+
+                       } else {
+
+                               max = max * half_height;
+                               min = min * half_height;
+
+                               pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
+                               pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
+                       }
+
+                       /* OK, now fill the RGB buffer at x=i with a line between pymin and pymax,
+                          or, if samples_per_unit == 1, then a dot at each location.
+                       */
+
+                       if (pymax == pymin) {
+                               PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
+                       } else {
+                               PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, pymin);
+                       }
+
+                       /* show clipped waveforms with small red lines */
+
+                       if (clip_max) {
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length);
+                       }
+
+                       if (clip_min) {
+                               PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin);
+                       }
+
+                       /* presto, we're done */
+
+                       cache_index++;
+               }
+       }
+
+       if (!waveview->rectified && waveview->zero_line && waveview->height >= 100) {
+               // Paint zeroline.
+
+               unsigned char zero_r, zero_g, zero_b, zero_a;
+               UINT_TO_RGBA( waveview->zero_color, &zero_r, &zero_g, &zero_b, &zero_a);
+               int zeroline_y = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
+               PAINT_HORIZA(buf, zero_r, zero_g, zero_b, zero_a, zbegin, zend, zeroline_y);
+       }
+#undef origin
+}
+
+static void
+gnome_canvas_waveview_render (GnomeCanvasItem *item,
+                             GnomeCanvasBuf *buf)
+{
+       if (_gradient_rendering) {
+               gnome_canvas_waveview_gradient_render (item, buf);
+       } else {
+               gnome_canvas_waveview_flat_render (item, buf);
+       }
+}
+
+static void
+gnome_canvas_waveview_draw (GnomeCanvasItem *item,
+                           GdkDrawable *drawable,
+                           int x, int y,
+                           int width, int height)
+{
+       GnomeCanvasWaveView *waveview;
+       cairo_t* cr;
+       gulong s1, s2;
+       int cache_index;
+       gboolean rectify;
+       double origin;
+       double xoff;
+       double yoff = 0.0;
+       double ulx;
+       double uly;
+       double lrx;
+       double lry;
+
+       waveview = GNOME_CANVAS_WAVEVIEW (item);
+
+       /* compute intersection of Drawable area and waveview,
+          in canvas coordinate space
+       */
+
+       if (x > waveview->bbox_ulx) {
+               ulx = x;
+       } else {
+               ulx = waveview->bbox_ulx;
+       }
+
+       if (y > waveview->bbox_uly) {
+               uly = y;
+       } else {
+               uly = waveview->bbox_uly;
+       }
+
+       if (x + width > waveview->bbox_lrx) {
+               lrx = waveview->bbox_lrx;
+       } else {
+               lrx = x + width;
+       }
+
+       if (y + height > waveview->bbox_lry) {
+               lry = waveview->bbox_lry;
+       } else {
+               lry = y + height;
+       }
+
+       /* figure out which samples we need for the resulting intersection */
+
+       s1 = floor ((ulx - waveview->bbox_ulx) * waveview->samples_per_unit) ;
+
+       if (lrx == waveview->bbox_lrx) {
+               /* This avoids minor rounding errors when we have the
+                  entire region visible.
+               */
+               s2 = waveview->samples;
+       } else {
+               s2 = s1 + floor ((lrx - ulx) * waveview->samples_per_unit);
+       }
+
+       /* translate back to buffer coordinate space */
+
+       ulx -= x;
+       uly -= y;
+       lrx -= x;
+       lry -= y;
+
+       /* don't rectify at single-sample zoom */
+       if(waveview->rectified && waveview->samples_per_unit > 1.0) {
+               rectify = TRUE;
+       } else {
+               rectify = FALSE;
+       }
+
+       cr = gdk_cairo_create (drawable);
+       cairo_set_line_width (cr, 0.5);
+
+       origin = waveview->bbox_uly - y + waveview->half_height;
+
+       cairo_rectangle (cr, ulx, uly, lrx - ulx, lry - uly);
+       cairo_clip (cr);
+
+       if (waveview->cache_updater && waveview->reload_cache_in_render) {
+               waveview->cache->start = 0;
+               waveview->cache->end = 0;
+               waveview->reload_cache_in_render = FALSE;
+       }
+
+       cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
+
+#if 0
+       printf ("%p r (%d,%d)(%d,%d)[%d x %d] bbox (%d,%d)(%d,%d)[%d x %d]"
+               " draw (%.1f,%.1f)(%.1f,%.1f)[%.1f x %.1f] s= %lu..%lu\n",
+               waveview,
+               x, y,
+               x + width,
+               y + height,
+               width,
+               height,
+               waveview->bbox_ulx,
+               waveview->bbox_uly,
+               waveview->bbox_lrx,
+               waveview->bbox_lry,
+               waveview->bbox_lrx - waveview->bbox_ulx,
+               waveview->bbox_lry - waveview->bbox_uly,
+               ulx, uly,
+               lrx, lry,
+               lrx - ulx,
+               lry - uly,
+               s1, s2);
+#endif
+
+       /* draw the top half */
+
+       for (xoff = ulx; xoff < lrx; xoff++) {
+               double max, min;
+
+               max = waveview->cache->data[cache_index].max;
+               min = waveview->cache->data[cache_index].min;
+
+               if (min <= -1.0) {
+                       min = -1.0;
+               }
+
+               if (max >= 1.0) {
+                       max = 1.0;
+               }
+
+               if (rectify) {
+                       if (fabs (min) > fabs (max)) {
+                               max = fabs (min);
+                       }
+               }
+
+               yoff = origin - (waveview->half_height * max) + 0.5;
+
+               if (xoff == ulx) {
+                       /* first point */
+                       cairo_move_to (cr, xoff+0.5, yoff);
+               } else {
+                       cairo_line_to (cr, xoff+0.5, yoff);
+               }
+
+               cache_index++;
+       }
+
+       /* from the final top point, move out of the clip zone */
+
+       cairo_line_to (cr, xoff + 10, yoff);
+
+       /* now draw the bottom half */
+
+       for (--xoff, --cache_index; xoff >= ulx; --xoff) {
+               double min;
+
+               min = waveview->cache->data[cache_index].min;
+
+               if (min <= -1.0) {
+                       min = -1.0;
+               }
+
+               yoff = origin - (waveview->half_height * min) + 0.5;
+
+               cairo_line_to (cr, xoff+0.5, yoff);
+               cache_index--;
+       }
+
+       /* from the final lower point, move out of the clip zone */
+
+       cairo_line_to (cr, xoff - 10, yoff);
+
+       /* close path to fill */
+
+       cairo_close_path (cr);
+
+       /* fill and stroke */
+
+       cairo_set_source_rgba (cr,
+                              (waveview->fill_r/255.0),
+                              (waveview->fill_g/255.0),
+                              (waveview->fill_b/255.0),
+                              (waveview->fill_a/255.0));
+       cairo_fill_preserve (cr);
+       cairo_set_source_rgba (cr,
+                              (waveview->wave_r/255.0),
+                              (waveview->wave_g/255.0),
+                              (waveview->wave_b/255.0),
+                              (waveview->wave_a/255.0));
+       cairo_stroke (cr);
+
+       cairo_destroy (cr);
+}
+
+#if 0
+               if (clip_max || clip_min) {
+                       cairo_set_source_rgba (cr, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a);
+               }
+
+               if (clip_max) {
+                       cairo_move_to (cr, xoff, yoff1);
+                       cairo_line_to (cr, xoff, yoff1 + clip_length);
+                       cairo_stroke (cr);
+               }
+
+               if (clip_min) {
+                       cairo_move_to (cr, xoff, yoff2);
+                       cairo_line_to (cr, xoff, yoff2 - clip_length);
+                       cairo_stroke (cr);
+               }
+
+#endif
+
+static void
+gnome_canvas_waveview_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
+{
+       GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (item);
+
+       *x1 = waveview->x;
+       *y1 = waveview->y;
+
+       *x2 = ceil (*x1 + (waveview->length_function (waveview->data_src) / waveview->samples_per_unit));
+       *y2 = *y1 + waveview->height;
+
+#if 0
+       x = 0; y = 0;
+       gnome_canvas_item_i2w (item, &x, &y);
+       gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &a, &b);
+       x = *x2;
+       y = *y2;
+       gnome_canvas_item_i2w (item, &x, &y);
+       gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &c, &d);
+       printf ("item bounds now (%g,%g),(%g,%g)\n", a, b, c, d);
+#endif
+
+}
+
+static double
+gnome_canvas_waveview_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item)
+{
+       (void) item;
+       (void) x;
+       (void) y;
+       (void) cx;
+       (void) cy;
+       (void) actual_item;
+
+       /* XXX for now, point is never inside the wave
+       GnomeCanvasWaveView *waveview;
+       double x1, y1, x2, y2;
+       double dx, dy;
+       */
+
+       return DBL_MAX;
+
+#if 0
+       waveview = GNOME_CANVAS_WAVEVIEW (item);
+
+       *actual_item = item;
 
        /* Find the bounds for the rectangle plus its outline width */
 
        gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
 
        /* Is point inside rectangle */
 
        /* Find the bounds for the rectangle plus its outline width */
 
        gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
 
        /* Is point inside rectangle */
-       
+
        if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
                return 0.0;
        }
        if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
                return 0.0;
        }