2 Copyright (C) 2000-2002 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <libgnomecanvas/libgnomecanvas.h>
27 #include <ardour/dB.h>
30 #include "canvas-waveview.h"
31 #include "rgb_macros.h"
33 extern void c_stacktrace();
40 PROP_SOURCEFILE_LENGTH_FUNCTION,
46 PROP_SAMPLES_PER_UNIT,
47 PROP_AMPLITUDE_ABOVE_AXIS,
57 static void gnome_canvas_waveview_class_init (GnomeCanvasWaveViewClass *class);
59 static void gnome_canvas_waveview_init (GnomeCanvasWaveView *waveview);
61 static void gnome_canvas_waveview_destroy (GtkObject *object);
63 static void gnome_canvas_waveview_set_property (GObject *object,
67 static void gnome_canvas_waveview_get_property (GObject *object,
72 static void gnome_canvas_waveview_update (GnomeCanvasItem *item,
77 static void gnome_canvas_waveview_bounds (GnomeCanvasItem *item,
83 static double gnome_canvas_waveview_point (GnomeCanvasItem *item,
88 GnomeCanvasItem **actual_item);
90 static void gnome_canvas_waveview_render (GnomeCanvasItem *item,
93 static void gnome_canvas_waveview_draw (GnomeCanvasItem *item,
94 GdkDrawable *drawable,
100 static void gnome_canvas_waveview_set_data_src (GnomeCanvasWaveView *,
103 static void gnome_canvas_waveview_set_channel (GnomeCanvasWaveView *,
106 static gint32 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview,
110 static GnomeCanvasItemClass *parent_class;
113 gnome_canvas_waveview_get_type (void)
115 static GType waveview_type;
117 if (!waveview_type) {
118 static const GTypeInfo object_info = {
119 sizeof (GnomeCanvasWaveViewClass),
120 (GBaseInitFunc) NULL,
121 (GBaseFinalizeFunc) NULL,
122 (GClassInitFunc) gnome_canvas_waveview_class_init,
123 (GClassFinalizeFunc) NULL,
124 NULL, /* class_data */
125 sizeof (GnomeCanvasWaveView),
127 (GInstanceInitFunc) gnome_canvas_waveview_init,
128 NULL /* value_table */
131 waveview_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasWaveView",
135 return waveview_type;
139 gnome_canvas_waveview_class_init (GnomeCanvasWaveViewClass *class)
141 GObjectClass *gobject_class;
142 GtkObjectClass *object_class;
143 GnomeCanvasItemClass *item_class;
145 gobject_class = (GObjectClass *) class;
146 object_class = (GtkObjectClass *) class;
147 item_class = (GnomeCanvasItemClass *) class;
149 parent_class = g_type_class_peek_parent (class);
151 gobject_class->set_property = gnome_canvas_waveview_set_property;
152 gobject_class->get_property = gnome_canvas_waveview_get_property;
154 g_object_class_install_property
157 g_param_spec_pointer ("data_src", NULL, NULL,
158 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
160 g_object_class_install_property
163 g_param_spec_uint ("channel", NULL, NULL,
165 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
167 g_object_class_install_property
169 PROP_LENGTH_FUNCTION,
170 g_param_spec_pointer ("length_function", NULL, NULL,
171 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
173 g_object_class_install_property
175 PROP_SOURCEFILE_LENGTH_FUNCTION,
176 g_param_spec_pointer ("sourcefile_length_function", NULL, NULL,
177 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
179 g_object_class_install_property
182 g_param_spec_pointer ("peak_function", NULL, NULL,
183 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
185 g_object_class_install_property
188 g_param_spec_pointer ("gain_function", NULL, NULL,
189 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
191 g_object_class_install_property
194 g_param_spec_pointer ("gain_src", NULL, NULL,
195 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
197 g_object_class_install_property
200 g_param_spec_pointer ("cache", NULL, NULL,
201 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
203 g_object_class_install_property
206 g_param_spec_boolean ("cache_updater", NULL, NULL,
208 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
210 g_object_class_install_property
212 PROP_SAMPLES_PER_UNIT,
213 g_param_spec_double ("samples_per_unit", NULL, NULL,
214 0.0, G_MAXDOUBLE, 0.0,
215 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
217 g_object_class_install_property
219 PROP_AMPLITUDE_ABOVE_AXIS,
220 g_param_spec_double ("amplitude_above_axis", NULL, NULL,
221 0.0, G_MAXDOUBLE, 0.0,
222 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
224 g_object_class_install_property
227 g_param_spec_double ("x", NULL, NULL,
228 0.0, G_MAXDOUBLE, 0.0,
229 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
231 g_object_class_install_property
234 g_param_spec_double ("y", NULL, NULL,
235 0.0, G_MAXDOUBLE, 0.0,
236 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
238 g_object_class_install_property
241 g_param_spec_double ("height", NULL, NULL,
242 0.0, G_MAXDOUBLE, 0.0,
243 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
245 g_object_class_install_property
248 g_param_spec_uint ("wave_color", NULL, NULL,
250 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
252 g_object_class_install_property
255 g_param_spec_boolean ("rectified", NULL, NULL,
257 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
259 g_object_class_install_property
262 g_param_spec_boolean ("logscaled", NULL, NULL,
264 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
266 g_object_class_install_property
269 g_param_spec_uint ("region_start", NULL, NULL,
271 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
273 object_class->destroy = gnome_canvas_waveview_destroy;
275 item_class->update = gnome_canvas_waveview_update;
276 item_class->bounds = gnome_canvas_waveview_bounds;
277 item_class->point = gnome_canvas_waveview_point;
278 item_class->render = gnome_canvas_waveview_render;
279 item_class->draw = gnome_canvas_waveview_draw;
282 GnomeCanvasWaveViewCache*
283 gnome_canvas_waveview_cache_new ()
285 GnomeCanvasWaveViewCache *c;
287 c = g_malloc (sizeof (GnomeCanvasWaveViewCache));
290 c->data = g_malloc (sizeof (GnomeCanvasWaveViewCacheEntry) * c->allocated);
299 gnome_canvas_waveview_cache_destroy (GnomeCanvasWaveViewCache* cache)
301 g_free (cache->data);
306 gnome_canvas_waveview_init (GnomeCanvasWaveView *waveview)
311 waveview->cache_updater = FALSE;
312 waveview->data_src = NULL;
313 waveview->channel = 0;
314 waveview->peak_function = NULL;
315 waveview->length_function = NULL;
316 waveview->sourcefile_length_function = NULL;
317 waveview->gain_curve_function = NULL;
318 waveview->gain_src = NULL;
319 waveview->rectified = FALSE;
320 waveview->logscaled = FALSE;
321 waveview->region_start = 0;
322 waveview->samples_per_unit = 1.0;
323 waveview->amplitude_above_axis = 1.0;
324 waveview->height = 100.0;
325 waveview->screen_width = gdk_screen_width ();
326 waveview->reload_cache_in_render = FALSE;
328 waveview->wave_color = RGBA_TO_UINT(44,35,126,255);
332 gnome_canvas_waveview_destroy (GtkObject *object)
334 GnomeCanvasWaveView *waveview;
336 g_return_if_fail (object != NULL);
337 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
339 waveview = GNOME_CANVAS_WAVEVIEW (object);
341 if (GTK_OBJECT_CLASS (parent_class)->destroy)
342 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
345 #define DEBUG_CACHE 0
346 #undef CACHE_MEMMOVE_OPTIMIZATION
349 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_sample, gulong end_sample)
351 gulong required_cache_entries;
352 gulong rf1, rf2,rf3, required_frames;
353 gulong new_cache_start, new_cache_end;
359 GnomeCanvasWaveViewCache *cache;
361 #ifdef CACHE_MEMMOVE_OPTIMIZATION
362 gulong present_frames;
363 gulong present_entries;
366 cache = waveview->cache;
368 start_sample = start_sample + waveview->region_start;
369 end_sample = end_sample + waveview->region_start;
371 // printf("waveview->region_start == %lu\n",waveview->region_start);
373 printf ("\n\n=> 0x%x cache @ 0x%x range: %lu - %lu request: %lu - %lu (%lu frames)\n",
375 cache->start, cache->end,
376 start_sample, end_sample, end_sample - start_sample);
379 if (cache->start <= start_sample && cache->end >= end_sample) {
381 // printf ("0x%x: cache hit for %lu-%lu (cache holds: %lu-%lu\n",
382 // waveview, start_sample, end_sample, cache->start, cache->end);
387 /* make sure the cache is at least twice as wide as the screen width, and put the start sample
388 in the middle, ensuring that we cover the end_sample.
391 /* Note the assumption that we have a 1:1 units:pixel ratio for the canvas. Its everywhere ... */
393 half_width = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit)/2.0 + 0.5);
395 if (start_sample < half_width) {
398 new_cache_start = start_sample - half_width;
401 /* figure out how many frames we want */
403 rf1 = end_sample - start_sample + 1;
404 rf2 = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit * 2.0f));
405 required_frames = MAX(rf1,rf2);
407 /* but make sure it doesn't extend beyond the end of the source material */
409 rf3 = (gulong) (waveview->sourcefile_length_function (waveview->data_src, waveview->samples_per_unit)) + 1;
410 if (rf3 < new_cache_start) {
413 rf3 -= new_cache_start;
417 fprintf (stderr, "AVAILABLE FRAMES = %lu of %lu, start = %lu, sstart = %lu, cstart = %lu\n",
418 rf3, waveview->sourcefile_length_function (waveview->data_src, waveview->samples_per_unit),
419 waveview->region_start, start_sample, new_cache_start);
422 required_frames = MIN(required_frames,rf3);
424 new_cache_end = new_cache_start + required_frames - 1;
426 required_cache_entries = (gulong) floor (required_frames / waveview->samples_per_unit );
429 fprintf (stderr, "new cache = %lu - %lu\n", new_cache_start, new_cache_end);
430 fprintf(stderr,"required_cach_entries = %lu, samples_per_unit = %f req frames = %lu\n",
431 required_cache_entries,waveview->samples_per_unit, required_frames);
434 if (required_cache_entries > cache->allocated) {
435 cache->data = g_realloc (cache->data, sizeof (GnomeCanvasWaveViewCacheEntry) * required_cache_entries);
436 cache->allocated = required_cache_entries;
441 ostart = new_cache_start;
443 #ifdef CACHE_MEMMOVE_OPTIMIZATION
445 /* data is not entirely in the cache, so go fetch it, making sure to fill the cache */
447 /* some of the required cache entries are in the cache, but in the wrong
448 locations. use memmove to fix this.
451 if (cache->start < new_cache_start && new_cache_start < cache->end) {
453 /* case one: the common area is at the end of the existing cache. move it
454 to the beginning of the cache, and set up to refill whatever remains.
457 wv->cache_start wv->cache_end
458 |-------------------------------------------------------| cache
459 |--------------------------------| requested
460 <------------------->
462 new_cache_start new_cache_end
466 present_frames = cache->end - new_cache_start;
467 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
470 fprintf (stderr, "existing material at end of current cache, move to start of new cache\n"
471 "\tcopy from %lu to start\n", cache->data_size - present_entries);
474 memmove (&cache->data[0],
475 &cache->data[cache->data_size - present_entries],
476 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
479 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
480 present_frames, required_frames, present_entries, new_cache_start + present_entries,
481 cache->data + present_entries);
484 copied = present_entries;
485 offset = present_entries;
486 new_cache_start += present_frames;
487 required_frames -= present_frames;
489 } else if (new_cache_end > cache->start && new_cache_end < cache->end) {
491 /* case two: the common area lives at the beginning of the existing cache.
493 wv->cache_start wv->cache_end
494 |-----------------------------------------------------|
495 |--------------------------------|
499 new_cache_start new_cache_end
502 present_frames = new_cache_end - cache->start;
503 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
505 memmove (&cache->data[cache->data_size - present_entries],
507 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
510 fprintf (stderr, "existing material at start of current cache, move to start of end cache\n");
514 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
515 present_entries, required_frames, present_entries, new_cache_start + present_entries,
516 cache->data + present_entries);
519 copied = present_entries;
521 required_frames -= present_frames;
534 #endif /* CACHE_MEMMOVE_OPTIMIZATION */
536 // fprintf(stderr,"length == %lu\n",waveview->length_function (waveview->data_src));
537 // required_frames = MIN (waveview->length_function (waveview->data_src) - new_cache_start, required_frames);
539 npeaks = (gulong) floor (required_frames / waveview->samples_per_unit);
540 required_frames = npeaks * waveview->samples_per_unit;
545 printf ("requesting %lu/%f to cover %lu-%lu at %f spu (request was %lu-%lu) into cache + %lu\n",
546 required_frames, required_frames/waveview->samples_per_unit, new_cache_start, new_cache_end,
547 waveview->samples_per_unit, start_sample, end_sample, offset);
551 // printf ("cache holds %lu entries, requesting %lu to cover %lu-%lu (request was %lu-%lu)\n",
552 // cache->data_size, npeaks, new_cache_start, new_cache_end,
553 // start_sample, end_sample);
556 if (required_frames) {
557 waveview->peak_function (waveview->data_src, npeaks, new_cache_start, required_frames, cache->data + offset, waveview->channel,waveview->samples_per_unit);
559 /* take into account any copied peaks */
566 if (npeaks < cache->allocated) {
568 fprintf (stderr, "zero fill cache for %lu at %lu\n", cache->allocated - npeaks, npeaks);
570 memset (&cache->data[npeaks], 0, sizeof (GnomeCanvasWaveViewCacheEntry) * (cache->allocated - npeaks));
571 cache->data_size = npeaks;
573 cache->data_size = cache->allocated;
576 if (waveview->gain_curve_function) {
579 gain = (float*) malloc (sizeof (float) * cache->data_size);
581 waveview->gain_curve_function (waveview->gain_src, new_cache_start, new_cache_end, gain, cache->data_size);
583 for (n = 0; n < cache->data_size; ++n) {
584 cache->data[n].min *= gain[n];
585 cache->data[n].max *= gain[n];
592 /* do optional log scaling. this implementation is not particularly efficient */
594 if (waveview->logscaled) {
596 GnomeCanvasWaveViewCacheEntry* buf = cache->data;
598 for (n = 0; n < cache->data_size; ++n) {
600 if (buf[n].max > 0.0f) {
601 buf[n].max = alt_log_meter(coefficient_to_dB(buf[n].max));
602 } else if (buf[n].max < 0.0f) {
603 buf[n].max = -alt_log_meter(coefficient_to_dB(-buf[n].max));
606 if (buf[n].min > 0.0f) {
607 buf[n].min = alt_log_meter(coefficient_to_dB(buf[n].min));
608 } else if (buf[n].min < 0.0f) {
609 buf[n].min = -alt_log_meter(coefficient_to_dB(-buf[n].min));
614 cache->start = ostart;
615 cache->end = new_cache_end;
619 fprintf (stderr, "return cache index = %d\n",
620 (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5));
622 return (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5);
627 gnome_canvas_waveview_set_data_src (GnomeCanvasWaveView *waveview, void *data_src)
630 if (waveview->cache_updater) {
631 if (waveview->data_src == data_src) {
632 waveview->reload_cache_in_render = TRUE;
636 waveview->cache->start = 0;
637 waveview->cache->end = 0;
640 waveview->data_src = data_src;
644 gnome_canvas_waveview_set_channel (GnomeCanvasWaveView *waveview, guint32 chan)
646 if (waveview->channel == chan) {
650 waveview->channel = chan;
654 gnome_canvas_waveview_reset_bounds (GnomeCanvasItem *item)
657 double x1, x2, y1, y2;
660 int Ix1, Ix2, Iy1, Iy2;
663 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
670 gnome_canvas_item_i2w_affine (item, i2w);
671 art_affine_point (&w1, &i1, i2w);
672 art_affine_point (&w2, &i2, i2w);
674 Ix1 = (int) rint(w1.x);
675 Ix2 = (int) rint(w2.x);
676 Iy1 = (int) rint(w1.y);
677 Iy2 = (int) rint(w2.y);
679 gnome_canvas_update_bbox (item, Ix1, Iy1, Ix2, Iy2);
687 gnome_canvas_waveview_set_property (GObject *object,
693 GnomeCanvasItem *item;
694 GnomeCanvasWaveView *waveview;
696 int calc_bounds = FALSE;
698 g_return_if_fail (object != NULL);
699 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
701 item = GNOME_CANVAS_ITEM (object);
702 waveview = GNOME_CANVAS_WAVEVIEW (object);
706 gnome_canvas_waveview_set_data_src (waveview, g_value_get_pointer(value));
711 gnome_canvas_waveview_set_channel (waveview, g_value_get_uint(value));
715 case PROP_LENGTH_FUNCTION:
716 waveview->length_function = g_value_get_pointer(value);
719 case PROP_SOURCEFILE_LENGTH_FUNCTION:
720 waveview->sourcefile_length_function = g_value_get_pointer(value);
724 case PROP_PEAK_FUNCTION:
725 waveview->peak_function = g_value_get_pointer(value);
729 case PROP_GAIN_FUNCTION:
730 waveview->gain_curve_function = g_value_get_pointer(value);
735 waveview->gain_src = g_value_get_pointer(value);
736 if (waveview->cache_updater) {
737 waveview->cache->start = 0;
738 waveview->cache->end = 0;
745 waveview->cache = g_value_get_pointer(value);
750 case PROP_CACHE_UPDATER:
751 waveview->cache_updater = g_value_get_boolean(value);
755 case PROP_SAMPLES_PER_UNIT:
756 if ((waveview->samples_per_unit = g_value_get_double(value)) < 1.0) {
757 waveview->samples_per_unit = 1.0;
759 if (waveview->cache_updater) {
760 waveview->cache->start = 0;
761 waveview->cache->end = 0;
767 case PROP_AMPLITUDE_ABOVE_AXIS:
768 waveview->amplitude_above_axis = g_value_get_double(value);
773 if (waveview->x != g_value_get_double (value)) {
774 waveview->x = g_value_get_double (value);
780 if (waveview->y != g_value_get_double (value)) {
781 waveview->y = g_value_get_double (value);
787 if (waveview->height != fabs (g_value_get_double (value))) {
788 waveview->height = fabs (g_value_get_double (value));
793 case PROP_WAVE_COLOR:
794 if (waveview->wave_color != g_value_get_uint(value)) {
795 waveview->wave_color = g_value_get_uint(value);
801 if (waveview->rectified != g_value_get_boolean(value)) {
802 waveview->rectified = g_value_get_boolean(value);
807 if (waveview->logscaled != g_value_get_boolean(value)) {
808 waveview->logscaled = g_value_get_boolean(value);
809 if (waveview->cache_updater) {
810 waveview->cache->start = 0;
811 waveview->cache->end = 0;
817 case PROP_REGION_START:
818 waveview->region_start = g_value_get_uint(value);
829 gnome_canvas_waveview_reset_bounds (item);
833 gnome_canvas_item_request_update (item);
839 gnome_canvas_waveview_get_property (GObject *object,
846 g_return_if_fail (object != NULL);
847 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
849 GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (object);
853 g_value_set_pointer(value, waveview->data_src);
857 g_value_set_uint(value, waveview->channel);
860 case PROP_LENGTH_FUNCTION:
861 g_value_set_pointer(value, waveview->length_function);
864 case PROP_SOURCEFILE_LENGTH_FUNCTION:
865 g_value_set_pointer(value, waveview->sourcefile_length_function);
868 case PROP_PEAK_FUNCTION:
869 g_value_set_pointer(value, waveview->peak_function);
872 case PROP_GAIN_FUNCTION:
873 g_value_set_pointer(value, waveview->gain_curve_function);
877 g_value_set_pointer(value, waveview->gain_src);
881 g_value_set_pointer(value, waveview->cache);
884 case PROP_CACHE_UPDATER:
885 g_value_set_boolean(value, waveview->cache_updater);
888 case PROP_SAMPLES_PER_UNIT:
889 g_value_set_double(value, waveview->samples_per_unit);
892 case PROP_AMPLITUDE_ABOVE_AXIS:
893 g_value_set_double(value, waveview->amplitude_above_axis);
897 g_value_set_double (value, waveview->x);
901 g_value_set_double (value, waveview->y);
905 g_value_set_double (value, waveview->height);
908 case PROP_WAVE_COLOR:
909 g_value_set_uint (value, waveview->wave_color);
913 g_value_set_boolean (value, waveview->rectified);
917 g_value_set_boolean (value, waveview->logscaled);
920 case PROP_REGION_START:
921 g_value_set_uint (value, waveview->region_start);
925 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
931 gnome_canvas_waveview_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
933 GnomeCanvasWaveView *waveview;
936 waveview = GNOME_CANVAS_WAVEVIEW (item);
938 // check_cache (waveview, "start of update");
940 if (parent_class->update)
941 (* parent_class->update) (item, affine, clip_path, flags);
943 gnome_canvas_waveview_reset_bounds (item);
945 /* get the canvas coordinates of the view. Do NOT use affines
946 for this, because they do not round to the integer units used
947 by the canvas, resulting in subtle pixel-level errors later.
953 gnome_canvas_item_i2w (item, &x, &y);
954 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_ulx, &waveview->bbox_uly);
956 waveview->samples = waveview->length_function (waveview->data_src);
958 x = waveview->x + (waveview->samples / waveview->samples_per_unit);
959 y = waveview->y + waveview->height;
961 gnome_canvas_item_i2w (item, &x, &y);
962 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_lrx, &waveview->bbox_lry);
964 /* cache the half-height and the end point in canvas units */
966 waveview->half_height = waveview->height / 2.0;
968 /* parse the color */
970 UINT_TO_RGBA (waveview->wave_color, &waveview->wave_r, &waveview->wave_g, &waveview->wave_b,
973 // check_cache (waveview, "end of update");
977 gnome_canvas_waveview_render (GnomeCanvasItem *item,
980 GnomeCanvasWaveView *waveview;
988 waveview = GNOME_CANVAS_WAVEVIEW (item);
990 // check_cache (waveview, "start of render");
992 if (parent_class->render) {
993 (*parent_class->render) (item, buf);
997 gnome_canvas_buf_ensure_buf (buf);
1001 begin = MAX(waveview->bbox_ulx,buf->rect.x0);
1003 if (waveview->bbox_lrx >= 0) {
1004 end = MIN(waveview->bbox_lrx,buf->rect.x1);
1013 s1 = floor ((begin - waveview->bbox_ulx) * waveview->samples_per_unit) ;
1015 // fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit);
1017 if (end == waveview->bbox_lrx) {
1018 /* This avoids minor rounding errors when we have the
1019 entire region visible.
1021 s2 = waveview->samples;
1023 s2 = s1 + floor ((end - begin) * waveview->samples_per_unit);
1027 printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)"
1028 " b/e %d..%d s= %lu..%lu @ %f\n",
1039 waveview->samples_per_unit);
1042 /* now ensure that the cache is full and properly
1046 // check_cache (waveview, "pre-ensure");
1048 if (waveview->cache_updater && waveview->reload_cache_in_render) {
1049 waveview->cache->start = 0;
1050 waveview->cache->end = 0;
1051 waveview->reload_cache_in_render = FALSE;
1054 cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
1056 // check_cache (waveview, "post-ensure");
1059 Now draw each line, clipping it appropriately. The clipping
1060 is done by the macros PAINT_FOO().
1063 half_height = waveview->half_height;
1065 /* this makes it slightly easier to comprehend whats going on */
1067 #define origin half_height
1069 for (x = begin; x < end; x++) {
1072 int clip_max, clip_min;
1077 max = waveview->cache->data[cache_index].max;
1078 min = waveview->cache->data[cache_index].min;
1090 /* don't rectify at single-sample zoom */
1092 if (waveview->rectified && waveview->samples_per_unit > 1) {
1094 if (fabs (min) > fabs (max)) {
1098 max = max * waveview->height;
1100 pymax = (int) rint ((item->y1 + waveview->height - max) * item->canvas->pixels_per_unit);
1101 pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
1105 max = max * half_height;
1106 min = min * half_height;
1108 pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
1109 pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
1112 /* OK, now fill the RGB buffer at x=i with a line between pymin and pymax,
1113 or, if samples_per_unit == 1, then a dot at each location.
1116 if (pymax == pymin) {
1117 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
1119 PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, pymin);
1122 /* show clipped waveforms with small red lines */
1124 if (clip_max || clip_min) {
1125 clip_length = MIN(5,(waveview->height/4));
1129 PAINT_VERT(buf, 255, 0, 0, x, pymax, pymax+clip_length);
1133 PAINT_VERT(buf, 255, 0, 0, x, pymin-clip_length, pymin);
1136 /* presto, we're done */
1146 gnome_canvas_waveview_draw (GnomeCanvasItem *item,
1147 GdkDrawable *drawable,
1149 int width, int height)
1151 GnomeCanvasWaveView *waveview;
1153 waveview = GNOME_CANVAS_WAVEVIEW (item);
1155 if (parent_class->draw) {
1156 (* parent_class->draw) (item, drawable, x, y, width, height);
1159 fprintf (stderr, "please don't use the CanvasWaveView item in a non-aa Canvas\n");
1164 gnome_canvas_waveview_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
1166 GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (item);
1171 *x2 = ceil (*x1 + (waveview->length_function (waveview->data_src) / waveview->samples_per_unit));
1172 *y2 = *y1 + waveview->height;
1176 gnome_canvas_item_i2w (item, &x, &y);
1177 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &a, &b);
1180 gnome_canvas_item_i2w (item, &x, &y);
1181 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &c, &d);
1182 printf ("item bounds now (%g,%g),(%g,%g)\n", a, b, c, d);
1188 gnome_canvas_waveview_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item)
1190 /* XXX for now, point is never inside the wave
1191 GnomeCanvasWaveView *waveview;
1192 double x1, y1, x2, y2;
1199 waveview = GNOME_CANVAS_WAVEVIEW (item);
1201 *actual_item = item;
1203 /* Find the bounds for the rectangle plus its outline width */
1205 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
1207 /* Is point inside rectangle */
1209 if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
1213 /* Point is outside rectangle */
1229 return sqrt (dx * dx + dy * dy);