Merged with trunk R1283.
[ardour.git] / gtk2_ardour / canvas-waveview.c
index 3198c933b826ee1192c6e8273004f3b18eac35f4..747761ea9ae887e6fb1dfb5425580f5aa535ce3d 100644 (file)
@@ -1,21 +1,21 @@
 /*
-    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
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
+     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
+     the Free Software Foundation; either version 2 of the License, or
+     (at your option) any later version.
 
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
+     This program is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+     GNU General Public License for more details.
 
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+     You should have received a copy of the GNU General Public License
+     along with this program; if not, write to the Free Software
+     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id$
+     $Id$
 */
 
 #include <stdio.h>
 
 #include <ardour/dB.h>
 
+#include "logmeter.h"
 #include "canvas-waveview.h"
 #include "rgb_macros.h"
 
+extern void c_stacktrace();
+
 enum {
-       ARG_0,
-       ARG_DATA_SRC,
-       ARG_CHANNEL,
-       ARG_LENGTH_FUNCTION,
-       ARG_PEAK_FUNCTION,
-       ARG_GAIN_FUNCTION,
-       ARG_GAIN_SRC,
-       ARG_CACHE,
-       ARG_CACHE_UPDATER,
-       ARG_SAMPLES_PER_PIXEL,
-       ARG_AMPLITUDE_ABOVE_AXIS,
-       ARG_X,
-       ARG_Y,
-       ARG_HEIGHT,
-       ARG_WAVE_COLOR,
-       ARG_RECTIFIED,
-       ARG_SOURCEFILE_LENGTH_FUNCTION,
-       ARG_REGION_START
+        PROP_0,
+        PROP_DATA_SRC,
+        PROP_CHANNEL,
+        PROP_LENGTH_FUNCTION,
+        PROP_SOURCEFILE_LENGTH_FUNCTION,
+        PROP_PEAK_FUNCTION,
+        PROP_GAIN_FUNCTION,
+        PROP_GAIN_SRC,
+        PROP_CACHE,
+        PROP_CACHE_UPDATER,
+        PROP_SAMPLES_PER_UNIT,
+        PROP_AMPLITUDE_ABOVE_AXIS,
+        PROP_X,
+        PROP_Y,
+        PROP_HEIGHT,
+        PROP_WAVE_COLOR,
+        PROP_RECTIFIED,
+        PROP_REGION_START,
+        PROP_LOGSCALED,
 };
 
-static void gnome_canvas_waveview_class_init (GnomeCanvasWaveViewClass *class);
-static void gnome_canvas_waveview_init       (GnomeCanvasWaveView      *waveview);
-static void gnome_canvas_waveview_set_arg    (GtkObject              *object,
-                                             GtkArg                 *arg,
-                                             guint                   arg_id);
-static void gnome_canvas_waveview_get_arg    (GtkObject              *object,
-                                             GtkArg                 *arg,
-                                             guint                   arg_id);
+static void gnome_canvas_waveview_class_init     (GnomeCanvasWaveViewClass *class);
+
+static void gnome_canvas_waveview_init           (GnomeCanvasWaveView      *waveview);
+
+static void gnome_canvas_waveview_destroy        (GtkObject            *object);
+
+static void gnome_canvas_waveview_set_property   (GObject        *object,
+                                                  guint           prop_id,
+                                                  const GValue   *value,
+                                                  GParamSpec     *pspec);
+static void gnome_canvas_waveview_get_property   (GObject        *object,
+                                                  guint           prop_id,
+                                                  GValue         *value,
+                                                  GParamSpec     *pspec);
+
+static void   gnome_canvas_waveview_update       (GnomeCanvasItem *item,
+                                                  double          *affine,
+                                                  ArtSVP          *clip_path,
+                                                  int              flags);
+
+static void   gnome_canvas_waveview_bounds       (GnomeCanvasItem *item,
+                                                  double          *x1,
+                                                  double          *y1,
+                                                  double          *x2,
+                                                  double          *y2);
+
+static double gnome_canvas_waveview_point        (GnomeCanvasItem  *item,
+                                                  double            x,
+                                                  double            y,
+                                                  int               cx,
+                                                  int               cy,
+                                                  GnomeCanvasItem **actual_item);
+
+static void gnome_canvas_waveview_render         (GnomeCanvasItem *item,
+                                                  GnomeCanvasBuf  *buf);
 
-static void   gnome_canvas_waveview_update      (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
-static void   gnome_canvas_waveview_bounds      (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2);
-static double gnome_canvas_waveview_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item);
+static void gnome_canvas_waveview_draw           (GnomeCanvasItem *item,
+                                                  GdkDrawable     *drawable,
+                                                  int              x,
+                                                  int              y,
+                                                  int              w,
+                                                  int              h);
 
-static void gnome_canvas_waveview_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf);
-static void gnome_canvas_waveview_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int w, int h);
+static void gnome_canvas_waveview_set_data_src   (GnomeCanvasWaveView *,
+                                                  void *);
 
-static void gnome_canvas_waveview_set_data_src      (GnomeCanvasWaveView *, void *);
-static void gnome_canvas_waveview_set_channel      (GnomeCanvasWaveView *, guint32);
+static void gnome_canvas_waveview_set_channel    (GnomeCanvasWaveView *,
+                                                  guint32);
 
-static gint32 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_sample, gulong end_sample);
+static gint32 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview,
+                                                  gulong               start_sample,
+                                                  gulong               end_sample);
 
 static GnomeCanvasItemClass *parent_class;
 
-GtkType
+GType
 gnome_canvas_waveview_get_type (void)
 {
-       static GtkType waveview_type = 0;
-
-       if (!waveview_type) {
-               GtkTypeInfo waveview_info = {
-                       "GnomeCanvasWaveView",
-                       sizeof (GnomeCanvasWaveView),
-                       sizeof (GnomeCanvasWaveViewClass),
-                       (GtkClassInitFunc) gnome_canvas_waveview_class_init,
-                       (GtkObjectInitFunc) gnome_canvas_waveview_init,
-                       NULL, /* reserved_1 */
-                       NULL, /* reserved_2 */
-                       (GtkClassInitFunc) NULL
-               };
-
-               waveview_type = gtk_type_unique (gnome_canvas_item_get_type (), &waveview_info);
-       }
-
-       return waveview_type;
-}
+        static GType waveview_type;
+
+        if (!waveview_type) {
+                static const GTypeInfo object_info = {
+                        sizeof (GnomeCanvasWaveViewClass),
+                        (GBaseInitFunc) NULL,
+                        (GBaseFinalizeFunc) NULL,
+                        (GClassInitFunc) gnome_canvas_waveview_class_init,
+                        (GClassFinalizeFunc) NULL,
+                        NULL,                  /* class_data */
+                        sizeof (GnomeCanvasWaveView),
+                        0,                     /* n_preallocs */
+                        (GInstanceInitFunc) gnome_canvas_waveview_init,
+                        NULL                   /* value_table */
+                };
+
+                waveview_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasWaveView",
+                                                        &object_info, 0);
+        }
+
+        return waveview_type;
+ }
 
 static void
 gnome_canvas_waveview_class_init (GnomeCanvasWaveViewClass *class)
 {
-       GtkObjectClass *object_class;
-       GnomeCanvasItemClass *item_class;
-
-       object_class = (GtkObjectClass *) class;
-       item_class = (GnomeCanvasItemClass *) class;
-
-       parent_class = gtk_type_class (gnome_canvas_item_get_type ());
-
-       gtk_object_add_arg_type ("GnomeCanvasWaveView::data_src", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_DATA_SRC);
-       gtk_object_add_arg_type ("GnomeCanvasWaveView::channel", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_CHANNEL);
-       gtk_object_add_arg_type ("GnomeCanvasWaveView::length_function", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_LENGTH_FUNCTION);
-       gtk_object_add_arg_type ("GnomeCanvasWaveView::sourcefile_length_function", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_SOURCEFILE_LENGTH_FUNCTION);
-       gtk_object_add_arg_type ("GnomeCanvasWaveView::peak_function", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_PEAK_FUNCTION);
-       gtk_object_add_arg_type ("GnomeCanvasWaveView::gain_function", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_GAIN_FUNCTION);
-       gtk_object_add_arg_type ("GnomeCanvasWaveView::gain_src", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_GAIN_SRC);
-       gtk_object_add_arg_type ("GnomeCanvasWaveView::cache", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_CACHE);
-       gtk_object_add_arg_type ("GnomeCanvasWaveView::cache_updater", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_CACHE_UPDATER);
-       gtk_object_add_arg_type ("GnomeCanvasWaveView::samples_per_unit", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_SAMPLES_PER_PIXEL);
-       gtk_object_add_arg_type ("GnomeCanvasWaveView::amplitude_above_axis", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_AMPLITUDE_ABOVE_AXIS);
-       gtk_object_add_arg_type ("GnomeCanvasWaveView::x", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X);
-       gtk_object_add_arg_type ("GnomeCanvasWaveView::y", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y);
-       gtk_object_add_arg_type ("GnomeCanvasWaveView::height", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_HEIGHT);
-       gtk_object_add_arg_type ("GnomeCanvasWaveView::wave_color", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_WAVE_COLOR);
-       gtk_object_add_arg_type ("GnomeCanvasWaveView::rectified", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_RECTIFIED);
-       gtk_object_add_arg_type ("GnomeCanvasWaveView::region_start", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_REGION_START);
-
-       object_class->set_arg = gnome_canvas_waveview_set_arg;
-       object_class->get_arg = gnome_canvas_waveview_get_arg;
-
-       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;
+        GObjectClass *gobject_class;
+        GtkObjectClass *object_class;
+        GnomeCanvasItemClass *item_class;
+
+        gobject_class = (GObjectClass *) class;
+        object_class = (GtkObjectClass *) class;
+        item_class = (GnomeCanvasItemClass *) class;
+
+        parent_class = g_type_class_peek_parent (class);
+
+        gobject_class->set_property = gnome_canvas_waveview_set_property;
+        gobject_class->get_property = gnome_canvas_waveview_get_property;
+
+        g_object_class_install_property
+                (gobject_class,
+                 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_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_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_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_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_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_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_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_RECTIFIED,
+                 g_param_spec_boolean ("rectified", 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)));
+        
+        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;
 }
 
 GnomeCanvasWaveViewCache*
@@ -173,6 +317,7 @@ gnome_canvas_waveview_init (GnomeCanvasWaveView *waveview)
        waveview->gain_curve_function = NULL;
        waveview->gain_src = NULL;
        waveview->rectified = FALSE;
+       waveview->logscaled = FALSE;
        waveview->region_start = 0;
        waveview->samples_per_unit = 1.0;
        waveview->amplitude_above_axis = 1.0;
@@ -181,11 +326,24 @@ gnome_canvas_waveview_init (GnomeCanvasWaveView *waveview)
        waveview->reload_cache_in_render = FALSE;
 
        waveview->wave_color = RGBA_TO_UINT(44,35,126,255);
+}
+
+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));
+
+       waveview = GNOME_CANVAS_WAVEVIEW (object);
 
-       GNOME_CANVAS_ITEM(waveview)->object.flags |= GNOME_CANVAS_ITEM_NO_AUTO_REDRAW;
+       if (GTK_OBJECT_CLASS (parent_class)->destroy)
+               (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
 }
 
 #define DEBUG_CACHE 0
+#undef CACHE_MEMMOVE_OPTIMIZATION
 
 static gint32
 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_sample, gulong end_sample)
@@ -197,11 +355,13 @@ gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_
        gulong npeaks;
        gulong offset;
        gulong ostart;
-       gulong present_frames;
-       gulong present_entries;
        gulong copied;
        GnomeCanvasWaveViewCache *cache;
        float* gain;
+#ifdef CACHE_MEMMOVE_OPTIMIZATION
+       gulong present_frames;
+       gulong present_entries;
+#endif
 
        cache = waveview->cache;
 
@@ -245,12 +405,16 @@ 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)) + 1;
-       rf3 -= new_cache_start;
+       rf3 = (gulong) (waveview->sourcefile_length_function (waveview->data_src, waveview->samples_per_unit)) + 1;
+       if (rf3 < new_cache_start) {
+               rf3 = 0;
+       } else {
+               rf3 -= new_cache_start;
+       }
 
 #if DEBUG_CACHE
        fprintf (stderr, "\n\nAVAILABLE FRAMES = %lu of %lu, start = %lu, sstart = %lu, cstart = %lu\n", 
-                rf3, waveview->sourcefile_length_function (waveview->data_src),
+                rf3, waveview->sourcefile_length_function (waveview->data_src, waveview->samples_per_unit),
                 waveview->region_start, start_sample, new_cache_start);
 #endif
 
@@ -262,8 +426,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);
-       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) {
@@ -275,7 +439,6 @@ gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_
 
        ostart = new_cache_start;
 
-#undef CACHE_MEMMOVE_OPTIMIZATION
 #ifdef CACHE_MEMMOVE_OPTIMIZATION
        
        /* data is not entirely in the cache, so go fetch it, making sure to fill the cache */
@@ -371,8 +534,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);
+
        npeaks = (gulong) floor (required_frames / waveview->samples_per_unit);
-       npeaks = MAX (1, npeaks);
        required_frames = npeaks * waveview->samples_per_unit;
 
 #if DEBUG_CACHE
@@ -389,11 +552,15 @@ gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_
 //             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);
-
-       /* take into account any copied peaks */
+       if (required_frames) {
+               waveview->peak_function (waveview->data_src, npeaks, new_cache_start, required_frames, cache->data + offset, waveview->channel,waveview->samples_per_unit);
 
-       npeaks += copied;
+               /* take into account any copied peaks */
+               
+               npeaks += copied;
+       } else {
+               npeaks = copied;
+       }
 
        if (npeaks < cache->allocated) {
 #if DEBUG_CACHE
@@ -420,7 +587,29 @@ gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_
                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(coefficient_to_dB(buf[n].max));
+                       } else if (buf[n].max < 0.0f) {
+                               buf[n].max = -alt_log_meter(coefficient_to_dB(-buf[n].max));
+                       }
+                       
+                       if (buf[n].min > 0.0f) {
+                               buf[n].min = alt_log_meter(coefficient_to_dB(buf[n].min));
+                       } else if (buf[n].min < 0.0f) {
+                               buf[n].min = -alt_log_meter(coefficient_to_dB(-buf[n].min));
+                       }
+               }
+       }
+
        cache->start = ostart;
        cache->end = new_cache_end;
 
@@ -494,51 +683,55 @@ gnome_canvas_waveview_reset_bounds (GnomeCanvasItem *item)
  */
 
 static void
-gnome_canvas_waveview_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
+gnome_canvas_waveview_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+
 {
        GnomeCanvasItem *item;
        GnomeCanvasWaveView *waveview;
-       int redraw;
-       int calc_bounds;
+       int redraw = FALSE;
+       int calc_bounds = FALSE;
+
+       g_return_if_fail (object != NULL);
+       g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
 
        item = GNOME_CANVAS_ITEM (object);
        waveview = GNOME_CANVAS_WAVEVIEW (object);
 
-       redraw = FALSE;
-       calc_bounds = FALSE;
-
-       switch (arg_id) {
-       case ARG_DATA_SRC:
-               gnome_canvas_waveview_set_data_src (waveview, GTK_VALUE_POINTER(*arg));
+       switch (prop_id) {
+       case PROP_DATA_SRC:
+               gnome_canvas_waveview_set_data_src (waveview, g_value_get_pointer(value));
                redraw = TRUE;
                break;
 
-       case ARG_CHANNEL:
-               gnome_canvas_waveview_set_channel (waveview, GTK_VALUE_UINT(*arg));
+       case PROP_CHANNEL:
+               gnome_canvas_waveview_set_channel (waveview, g_value_get_uint(value));
                redraw = TRUE;
                break;
 
-       case ARG_LENGTH_FUNCTION:
-               waveview->length_function = GTK_VALUE_POINTER(*arg);
+       case PROP_LENGTH_FUNCTION:
+               waveview->length_function = g_value_get_pointer(value);
                redraw = TRUE;
                break;
-       case ARG_SOURCEFILE_LENGTH_FUNCTION:
-               waveview->sourcefile_length_function = GTK_VALUE_POINTER(*arg);
+       case PROP_SOURCEFILE_LENGTH_FUNCTION:
+               waveview->sourcefile_length_function = g_value_get_pointer(value);
                redraw = TRUE;
                break;
 
-       case ARG_PEAK_FUNCTION:
-               waveview->peak_function = GTK_VALUE_POINTER(*arg);
+       case PROP_PEAK_FUNCTION:
+               waveview->peak_function = g_value_get_pointer(value);
                redraw = TRUE;
                break;
 
-       case ARG_GAIN_FUNCTION:
-               waveview->gain_curve_function = GTK_VALUE_POINTER(*arg);
+       case PROP_GAIN_FUNCTION:
+               waveview->gain_curve_function = g_value_get_pointer(value);
                redraw = TRUE;
                break;
 
-       case ARG_GAIN_SRC:
-               waveview->gain_src = GTK_VALUE_POINTER(*arg);
+       case PROP_GAIN_SRC:
+               waveview->gain_src = g_value_get_pointer(value);
                if (waveview->cache_updater) {
                        waveview->cache->start = 0;
                        waveview->cache->end = 0;
@@ -547,19 +740,19 @@ gnome_canvas_waveview_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
                calc_bounds = TRUE;
                break;
 
-       case ARG_CACHE:
-               waveview->cache = GTK_VALUE_POINTER(*arg);
+       case PROP_CACHE:
+               waveview->cache = g_value_get_pointer(value);
                redraw = TRUE;
                break;
 
 
-       case ARG_CACHE_UPDATER:
-               waveview->cache_updater = GTK_VALUE_BOOL(*arg);
+       case PROP_CACHE_UPDATER:
+               waveview->cache_updater = g_value_get_boolean(value);
                redraw = TRUE;
                break;
 
-       case ARG_SAMPLES_PER_PIXEL:
-               if ((waveview->samples_per_unit = GTK_VALUE_DOUBLE(*arg)) < 1.0) {
+       case PROP_SAMPLES_PER_UNIT:
+               if ((waveview->samples_per_unit = g_value_get_double(value)) < 1.0) {
                        waveview->samples_per_unit = 1.0;
                }
                if (waveview->cache_updater) {
@@ -570,47 +763,58 @@ gnome_canvas_waveview_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
                calc_bounds = TRUE;
                break;
 
-       case ARG_AMPLITUDE_ABOVE_AXIS:
-               waveview->amplitude_above_axis = GTK_VALUE_DOUBLE(*arg);
+       case PROP_AMPLITUDE_ABOVE_AXIS:
+               waveview->amplitude_above_axis = g_value_get_double(value);
                redraw = TRUE;
                break;
 
-       case ARG_X:
-               if (waveview->x != GTK_VALUE_DOUBLE (*arg)) {
-                       waveview->x = GTK_VALUE_DOUBLE (*arg);
+       case PROP_X:
+               if (waveview->x != g_value_get_double (value)) {
+                       waveview->x = g_value_get_double (value);
                        calc_bounds = TRUE;
                }
                break;
 
-       case ARG_Y:
-               if (waveview->y != GTK_VALUE_DOUBLE (*arg)) {
-                       waveview->y = GTK_VALUE_DOUBLE (*arg);
+       case PROP_Y:
+               if (waveview->y != g_value_get_double (value)) {
+                       waveview->y = g_value_get_double (value);
                        calc_bounds = TRUE;
                }
                break;
 
-       case ARG_HEIGHT:
-               if (waveview->height != fabs (GTK_VALUE_DOUBLE (*arg))) {
-                       waveview->height = fabs (GTK_VALUE_DOUBLE (*arg));
+       case PROP_HEIGHT:
+               if (waveview->height != fabs (g_value_get_double (value))) {
+                       waveview->height = fabs (g_value_get_double (value));
                        redraw = TRUE;
                }
                break;
 
-       case ARG_WAVE_COLOR:
-               if (waveview->wave_color != GTK_VALUE_INT(*arg)) {
-                       waveview->wave_color = GTK_VALUE_INT(*arg);
+       case PROP_WAVE_COLOR:
+               if (waveview->wave_color != g_value_get_uint(value)) {
+                       waveview->wave_color = g_value_get_uint(value);
                        redraw = TRUE;
                }
                break;
 
-       case ARG_RECTIFIED:
-               if (waveview->rectified != GTK_VALUE_BOOL(*arg)) {
-                       waveview->rectified = GTK_VALUE_BOOL(*arg);
+       case PROP_RECTIFIED:
+               if (waveview->rectified != g_value_get_boolean(value)) {
+                       waveview->rectified = g_value_get_boolean(value);
                        redraw = TRUE;
                }
                break;
-       case ARG_REGION_START:
-               waveview->region_start = GTK_VALUE_UINT(*arg);
+       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;
                calc_bounds = TRUE;
                break;
@@ -631,80 +835,93 @@ gnome_canvas_waveview_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
 }
 
 static void
-gnome_canvas_waveview_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
+gnome_canvas_waveview_get_property (GObject      *object,
+                                   guint         prop_id,
+                                   GValue       *value,
+                                   GParamSpec   *pspec)
 {
-       GnomeCanvasWaveView *waveview;
+       
+   
+       g_return_if_fail (object != NULL);
+        g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
 
-       waveview = GNOME_CANVAS_WAVEVIEW (object);
+       GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (object);
+
+       switch (prop_id) {
+       case PROP_DATA_SRC:
+               g_value_set_pointer(value, waveview->data_src);
+               break;
 
-       switch (arg_id) {
-       case ARG_DATA_SRC:
-               GTK_VALUE_POINTER(*arg) = waveview->data_src;
+       case PROP_CHANNEL:
+               g_value_set_uint(value, waveview->channel);
                break;
 
-       case ARG_CHANNEL:
-               GTK_VALUE_UINT(*arg) = waveview->channel;
+       case PROP_LENGTH_FUNCTION:
+               g_value_set_pointer(value, waveview->length_function);
                break;
 
-       case ARG_LENGTH_FUNCTION:
-               GTK_VALUE_POINTER(*arg) = waveview->length_function;
+       case PROP_SOURCEFILE_LENGTH_FUNCTION:
+               g_value_set_pointer(value, waveview->sourcefile_length_function);
                break;
 
-       case ARG_SOURCEFILE_LENGTH_FUNCTION:
-               GTK_VALUE_POINTER(*arg) = waveview->sourcefile_length_function;
+       case PROP_PEAK_FUNCTION:
+               g_value_set_pointer(value, waveview->peak_function);
                break;
 
-       case ARG_PEAK_FUNCTION:
-               GTK_VALUE_POINTER(*arg) = waveview->peak_function;
+       case PROP_GAIN_FUNCTION:
+               g_value_set_pointer(value, waveview->gain_curve_function);
                break;
 
-       case ARG_GAIN_FUNCTION:
-               GTK_VALUE_POINTER(*arg) = waveview->gain_curve_function;
+       case PROP_GAIN_SRC:
+               g_value_set_pointer(value, waveview->gain_src);
                break;
 
-       case ARG_GAIN_SRC:
-               GTK_VALUE_POINTER(*arg) = waveview->gain_src;
+       case PROP_CACHE:
+               g_value_set_pointer(value, waveview->cache);
                break;
 
-       case ARG_CACHE:
-               GTK_VALUE_POINTER(*arg) = waveview->cache;
+       case PROP_CACHE_UPDATER:
+               g_value_set_boolean(value, waveview->cache_updater);
                break;
 
-       case ARG_CACHE_UPDATER:
-               GTK_VALUE_BOOL(*arg) = waveview->cache_updater;
+       case PROP_SAMPLES_PER_UNIT:
+               g_value_set_double(value, waveview->samples_per_unit);
                break;
 
-       case ARG_SAMPLES_PER_PIXEL:
-               GTK_VALUE_DOUBLE(*arg) = waveview->samples_per_unit;
+       case PROP_AMPLITUDE_ABOVE_AXIS:
+               g_value_set_double(value, waveview->amplitude_above_axis);
                break;
 
-       case ARG_AMPLITUDE_ABOVE_AXIS:
-               GTK_VALUE_DOUBLE(*arg) = waveview->amplitude_above_axis;
+       case PROP_X:
+               g_value_set_double (value, waveview->x);
                break;
 
-       case ARG_X:
-               GTK_VALUE_DOUBLE (*arg) = waveview->x;
+       case PROP_Y:
+               g_value_set_double (value, waveview->y);
                break;
 
-       case ARG_Y:
-               GTK_VALUE_DOUBLE (*arg) = waveview->y;
+       case PROP_HEIGHT:
+               g_value_set_double (value, waveview->height);
                break;
 
-       case ARG_HEIGHT:
-               GTK_VALUE_DOUBLE (*arg) = waveview->height;
+       case PROP_WAVE_COLOR:
+               g_value_set_uint (value, waveview->wave_color);
                break;
 
-       case ARG_WAVE_COLOR:
-               GTK_VALUE_INT (*arg) = waveview->wave_color;
+       case PROP_RECTIFIED:
+               g_value_set_boolean (value, waveview->rectified);
                break;
 
-       case ARG_RECTIFIED:
-               GTK_VALUE_BOOL (*arg) = waveview->rectified;
+       case PROP_LOGSCALED:
+               g_value_set_boolean (value, waveview->logscaled);
+               break;
+
+       case PROP_REGION_START:
+               g_value_set_uint (value, waveview->region_start);
+               break;
 
-       case ARG_REGION_START:
-               GTK_VALUE_UINT (*arg) = waveview->region_start;
        default:
-               arg->type = GTK_TYPE_INVALID;
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
        }
 }
@@ -807,7 +1024,7 @@ gnome_canvas_waveview_render (GnomeCanvasItem *item,
 
 #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,
@@ -817,7 +1034,8 @@ gnome_canvas_waveview_render (GnomeCanvasItem *item,
                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