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>
29 #include "canvas-waveview.h"
30 #include "rgb_macros.h"
37 PROP_SOURCEFILE_LENGTH_FUNCTION,
43 PROP_SAMPLES_PER_UNIT,
44 PROP_AMPLITUDE_ABOVE_AXIS,
53 static void gnome_canvas_waveview_class_init (GnomeCanvasWaveViewClass *class);
55 static void gnome_canvas_waveview_init (GnomeCanvasWaveView *waveview);
57 static void gnome_canvas_waveview_destroy (GtkObject *object);
59 static void gnome_canvas_waveview_set_property (GObject *object,
63 static void gnome_canvas_waveview_get_property (GObject *object,
68 static void gnome_canvas_waveview_update (GnomeCanvasItem *item,
73 static void gnome_canvas_waveview_bounds (GnomeCanvasItem *item,
79 static double gnome_canvas_waveview_point (GnomeCanvasItem *item,
84 GnomeCanvasItem **actual_item);
86 static void gnome_canvas_waveview_render (GnomeCanvasItem *item,
89 static void gnome_canvas_waveview_draw (GnomeCanvasItem *item,
90 GdkDrawable *drawable,
96 static void gnome_canvas_waveview_set_data_src (GnomeCanvasWaveView *,
99 static void gnome_canvas_waveview_set_channel (GnomeCanvasWaveView *,
102 static gint32 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview,
106 static GnomeCanvasItemClass *parent_class;
109 gnome_canvas_waveview_get_type (void)
111 static GType waveview_type;
113 if (!waveview_type) {
114 static const GTypeInfo object_info = {
115 sizeof (GnomeCanvasWaveViewClass),
116 (GBaseInitFunc) NULL,
117 (GBaseFinalizeFunc) NULL,
118 (GClassInitFunc) gnome_canvas_waveview_class_init,
119 (GClassFinalizeFunc) NULL,
120 NULL, /* class_data */
121 sizeof (GnomeCanvasWaveView),
123 (GInstanceInitFunc) gnome_canvas_waveview_init,
124 NULL /* value_table */
127 waveview_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasWaveView",
131 return waveview_type;
135 gnome_canvas_waveview_class_init (GnomeCanvasWaveViewClass *class)
137 GObjectClass *gobject_class;
138 GtkObjectClass *object_class;
139 GnomeCanvasItemClass *item_class;
141 gobject_class = (GObjectClass *) class;
142 object_class = (GtkObjectClass *) class;
143 item_class = (GnomeCanvasItemClass *) class;
145 parent_class = g_type_class_peek_parent (class);
147 gobject_class->set_property = gnome_canvas_waveview_set_property;
148 gobject_class->get_property = gnome_canvas_waveview_get_property;
150 g_object_class_install_property
153 g_param_spec_pointer ("data_src", NULL, NULL,
154 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
156 g_object_class_install_property
159 g_param_spec_uint ("channel", NULL, NULL,
161 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
163 g_object_class_install_property
165 PROP_LENGTH_FUNCTION,
166 g_param_spec_pointer ("length_function", NULL, NULL,
167 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
169 g_object_class_install_property
171 PROP_SOURCEFILE_LENGTH_FUNCTION,
172 g_param_spec_pointer ("sourcefile_length_function", NULL, NULL,
173 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
175 g_object_class_install_property
178 g_param_spec_pointer ("peak_function", NULL, NULL,
179 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
181 g_object_class_install_property
184 g_param_spec_pointer ("gain_function", NULL, NULL,
185 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
187 g_object_class_install_property
190 g_param_spec_pointer ("gain_src", NULL, NULL,
191 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
193 g_object_class_install_property
196 g_param_spec_pointer ("cache", NULL, NULL,
197 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
199 g_object_class_install_property
202 g_param_spec_boolean ("cache_updater", NULL, NULL,
204 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
206 g_object_class_install_property
208 PROP_SAMPLES_PER_UNIT,
209 g_param_spec_double ("samples_per_unit", NULL, NULL,
210 0.0, G_MAXDOUBLE, 0.0,
211 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
213 g_object_class_install_property
215 PROP_AMPLITUDE_ABOVE_AXIS,
216 g_param_spec_double ("amplitude_above_axis", NULL, NULL,
217 0.0, G_MAXDOUBLE, 0.0,
218 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
220 g_object_class_install_property
223 g_param_spec_double ("x", NULL, NULL,
224 0.0, G_MAXDOUBLE, 0.0,
225 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
227 g_object_class_install_property
230 g_param_spec_double ("y", NULL, NULL,
231 0.0, G_MAXDOUBLE, 0.0,
232 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
234 g_object_class_install_property
237 g_param_spec_double ("height", NULL, NULL,
238 0.0, G_MAXDOUBLE, 0.0,
239 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
241 g_object_class_install_property
244 g_param_spec_uint ("wave_color", NULL, NULL,
246 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
248 g_object_class_install_property
251 g_param_spec_boolean ("rectified", NULL, NULL,
253 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
255 g_object_class_install_property
258 g_param_spec_uint ("region_start", NULL, NULL,
260 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
262 object_class->destroy = gnome_canvas_waveview_destroy;
264 item_class->update = gnome_canvas_waveview_update;
265 item_class->bounds = gnome_canvas_waveview_bounds;
266 item_class->point = gnome_canvas_waveview_point;
267 item_class->render = gnome_canvas_waveview_render;
268 item_class->draw = gnome_canvas_waveview_draw;
271 GnomeCanvasWaveViewCache*
272 gnome_canvas_waveview_cache_new ()
274 GnomeCanvasWaveViewCache *c;
276 c = g_malloc (sizeof (GnomeCanvasWaveViewCache));
279 c->data = g_malloc (sizeof (GnomeCanvasWaveViewCacheEntry) * c->allocated);
288 gnome_canvas_waveview_cache_destroy (GnomeCanvasWaveViewCache* cache)
290 g_free (cache->data);
295 gnome_canvas_waveview_init (GnomeCanvasWaveView *waveview)
300 waveview->cache_updater = FALSE;
301 waveview->data_src = NULL;
302 waveview->channel = 0;
303 waveview->peak_function = NULL;
304 waveview->length_function = NULL;
305 waveview->sourcefile_length_function = NULL;
306 waveview->gain_curve_function = NULL;
307 waveview->gain_src = NULL;
308 waveview->rectified = FALSE;
309 waveview->region_start = 0;
310 waveview->samples_per_unit = 1.0;
311 waveview->amplitude_above_axis = 1.0;
312 waveview->height = 100.0;
313 waveview->screen_width = gdk_screen_width ();
314 waveview->reload_cache_in_render = FALSE;
316 waveview->wave_color = RGBA_TO_UINT(44,35,126,255);
319 // GNOME_CANVAS_ITEM(waveview)->object.flags |= GNOME_CANVAS_ITEM_NO_AUTO_REDRAW;
323 gnome_canvas_waveview_destroy (GtkObject *object)
325 GnomeCanvasWaveView *waveview;
327 g_return_if_fail (object != NULL);
328 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
330 waveview = GNOME_CANVAS_WAVEVIEW (object);
332 gnome_canvas_waveview_cache_destroy (waveview->cache);
334 if (GTK_OBJECT_CLASS (parent_class)->destroy)
335 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
338 #define DEBUG_CACHE 0
341 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_sample, gulong end_sample)
343 gulong required_cache_entries;
344 gulong rf1, rf2,rf3, required_frames;
345 gulong new_cache_start, new_cache_end;
351 GnomeCanvasWaveViewCache *cache;
354 cache = waveview->cache;
356 start_sample = start_sample + waveview->region_start;
357 end_sample = end_sample + waveview->region_start;
359 // printf("waveview->region_start == %lu\n",waveview->region_start);
360 printf ("=> 0x%x cache @ 0x%x range: %lu - %lu request: %lu - %lu (%lu frames)\n",
362 cache->start, cache->end,
363 start_sample, end_sample, end_sample - start_sample);
366 if (cache->start <= start_sample && cache->end >= end_sample) {
368 // printf ("0x%x: cache hit for %lu-%lu (cache holds: %lu-%lu\n",
369 // waveview, start_sample, end_sample, cache->start, cache->end);
374 /* make sure the cache is at least twice as wide as the screen width, and put the start sample
375 in the middle, ensuring that we cover the end_sample.
378 /* Note the assumption that we have a 1:1 units:pixel ratio for the canvas. Its everywhere ... */
380 half_width = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit)/2.0 + 0.5);
382 if (start_sample < half_width) {
385 new_cache_start = start_sample - half_width;
388 /* figure out how many frames we want */
390 rf1 = end_sample - start_sample + 1;
391 rf2 = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit * 2.0f));
392 required_frames = MAX(rf1,rf2);
394 /* but make sure it doesn't extend beyond the end of the source material */
396 rf3 = (gulong) (waveview->sourcefile_length_function (waveview->data_src)) + 1;
397 rf3 -= new_cache_start;
400 fprintf (stderr, "\n\nAVAILABLE FRAMES = %lu of %lu, start = %lu, sstart = %lu, cstart = %lu\n",
401 rf3, waveview->sourcefile_length_function (waveview->data_src),
402 waveview->region_start, start_sample, new_cache_start);
405 required_frames = MIN(required_frames,rf3);
407 new_cache_end = new_cache_start + required_frames - 1;
409 required_cache_entries = (gulong) floor (required_frames / waveview->samples_per_unit );
412 fprintf (stderr, "new cache = %lu - %lu\n", new_cache_start, new_cache_end);
413 fprintf(stderr,"required_cach_entries = %lu, samples_per_unit = %f\n",
414 required_cache_entries,waveview->samples_per_unit);
417 if (required_cache_entries > cache->allocated) {
418 cache->data = g_realloc (cache->data, sizeof (GnomeCanvasWaveViewCacheEntry) * required_cache_entries);
419 cache->allocated = required_cache_entries;
424 ostart = new_cache_start;
426 #undef CACHE_MEMMOVE_OPTIMIZATION
427 #ifdef CACHE_MEMMOVE_OPTIMIZATION
429 /* data is not entirely in the cache, so go fetch it, making sure to fill the cache */
431 /* some of the required cache entries are in the cache, but in the wrong
432 locations. use memmove to fix this.
435 if (cache->start < new_cache_start && new_cache_start < cache->end) {
437 /* case one: the common area is at the end of the existing cache. move it
438 to the beginning of the cache, and set up to refill whatever remains.
441 wv->cache_start wv->cache_end
442 |-------------------------------------------------------| cache
443 |--------------------------------| requested
444 <------------------->
446 new_cache_start new_cache_end
450 present_frames = cache->end - new_cache_start;
451 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
454 fprintf (stderr, "existing material at end of current cache, move to start of new cache\n"
455 "\tcopy from %lu to start\n", cache->data_size - present_entries);
458 memmove (&cache->data[0],
459 &cache->data[cache->data_size - present_entries],
460 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
463 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
464 present_frames, required_frames, present_entries, new_cache_start + present_entries,
465 cache->data + present_entries);
468 copied = present_entries;
469 offset = present_entries;
470 new_cache_start += present_frames;
471 required_frames -= present_frames;
473 } else if (new_cache_end > cache->start && new_cache_end < cache->end) {
475 /* case two: the common area lives at the beginning of the existing cache.
477 wv->cache_start wv->cache_end
478 |-----------------------------------------------------|
479 |--------------------------------|
483 new_cache_start new_cache_end
486 present_frames = new_cache_end - cache->start;
487 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
489 memmove (&cache->data[cache->data_size - present_entries],
491 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
494 fprintf (stderr, "existing material at start of current cache, move to start of end cache\n");
498 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
499 present_entries, required_frames, present_entries, new_cache_start + present_entries,
500 cache->data + present_entries);
503 copied = present_entries;
505 required_frames -= present_frames;
518 #endif /* CACHE_MEMMOVE_OPTIMIZATION */
520 // fprintf(stderr,"length == %lu\n",waveview->length_function (waveview->data_src));
521 // required_frames = MIN (waveview->length_function (waveview->data_src) - new_cache_start, required_frames);
522 npeaks = (gulong) floor (required_frames / waveview->samples_per_unit);
523 npeaks = MAX (1, npeaks);
524 required_frames = npeaks * waveview->samples_per_unit;
529 printf ("requesting %lu/%f to cover %lu-%lu at %f spu (request was %lu-%lu) into cache + %lu\n",
530 required_frames, required_frames/waveview->samples_per_unit, new_cache_start, new_cache_end,
531 waveview->samples_per_unit, start_sample, end_sample, offset);
535 // printf ("cache holds %lu entries, requesting %lu to cover %lu-%lu (request was %lu-%lu)\n",
536 // cache->data_size, npeaks, new_cache_start, new_cache_end,
537 // start_sample, end_sample);
540 waveview->peak_function (waveview->data_src, npeaks, new_cache_start, required_frames, cache->data + offset, waveview->channel,waveview->samples_per_unit);
542 /* take into account any copied peaks */
546 if (npeaks < cache->allocated) {
548 fprintf (stderr, "zero fill cache for %lu at %lu\n", cache->allocated - npeaks, npeaks);
550 memset (&cache->data[npeaks], 0, sizeof (GnomeCanvasWaveViewCacheEntry) * (cache->allocated - npeaks));
551 cache->data_size = npeaks;
553 cache->data_size = cache->allocated;
556 if (waveview->gain_curve_function) {
559 gain = (float*) malloc (sizeof (float) * cache->data_size);
561 waveview->gain_curve_function (waveview->gain_src, new_cache_start, new_cache_end, gain, cache->data_size);
563 for (n = 0; n < cache->data_size; ++n) {
564 cache->data[n].min *= gain[n];
565 cache->data[n].max *= gain[n];
572 cache->start = ostart;
573 cache->end = new_cache_end;
577 fprintf (stderr, "return cache index = %d\n",
578 (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5));
580 return (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5);
585 gnome_canvas_waveview_set_data_src (GnomeCanvasWaveView *waveview, void *data_src)
588 if (waveview->cache_updater) {
589 if (waveview->data_src == data_src) {
590 waveview->reload_cache_in_render = TRUE;
594 waveview->cache->start = 0;
595 waveview->cache->end = 0;
598 waveview->data_src = data_src;
602 gnome_canvas_waveview_set_channel (GnomeCanvasWaveView *waveview, guint32 chan)
604 if (waveview->channel == chan) {
608 waveview->channel = chan;
612 gnome_canvas_waveview_reset_bounds (GnomeCanvasItem *item)
615 double x1, x2, y1, y2;
618 int Ix1, Ix2, Iy1, Iy2;
621 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
628 gnome_canvas_item_i2w_affine (item, i2w);
629 art_affine_point (&w1, &i1, i2w);
630 art_affine_point (&w2, &i2, i2w);
632 Ix1 = (int) rint(w1.x);
633 Ix2 = (int) rint(w2.x);
634 Iy1 = (int) rint(w1.y);
635 Iy2 = (int) rint(w2.y);
637 gnome_canvas_update_bbox (item, Ix1, Iy1, Ix2, Iy2);
645 gnome_canvas_waveview_set_property (GObject *object,
651 GnomeCanvasItem *item;
652 GnomeCanvasWaveView *waveview;
654 int calc_bounds = FALSE;
656 g_return_if_fail (object != NULL);
657 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
659 item = GNOME_CANVAS_ITEM (object);
660 waveview = GNOME_CANVAS_WAVEVIEW (object);
664 gnome_canvas_waveview_set_data_src (waveview, g_value_get_pointer(value));
669 gnome_canvas_waveview_set_channel (waveview, g_value_get_uint(value));
673 case PROP_LENGTH_FUNCTION:
674 waveview->length_function = g_value_get_pointer(value);
677 case PROP_SOURCEFILE_LENGTH_FUNCTION:
678 waveview->sourcefile_length_function = g_value_get_pointer(value);
682 case PROP_PEAK_FUNCTION:
683 waveview->peak_function = g_value_get_pointer(value);
687 case PROP_GAIN_FUNCTION:
688 waveview->gain_curve_function = g_value_get_pointer(value);
693 waveview->gain_src = g_value_get_pointer(value);
694 if (waveview->cache_updater) {
695 waveview->cache->start = 0;
696 waveview->cache->end = 0;
703 waveview->cache = g_value_get_pointer(value);
708 case PROP_CACHE_UPDATER:
709 waveview->cache_updater = g_value_get_boolean(value);
713 case PROP_SAMPLES_PER_UNIT:
714 if ((waveview->samples_per_unit = g_value_get_double(value)) < 1.0) {
715 waveview->samples_per_unit = 1.0;
717 if (waveview->cache_updater) {
718 waveview->cache->start = 0;
719 waveview->cache->end = 0;
725 case PROP_AMPLITUDE_ABOVE_AXIS:
726 waveview->amplitude_above_axis = g_value_get_double(value);
731 if (waveview->x != g_value_get_double (value)) {
732 waveview->x = g_value_get_double (value);
738 if (waveview->y != g_value_get_double (value)) {
739 waveview->y = g_value_get_double (value);
745 if (waveview->height != fabs (g_value_get_double (value))) {
746 waveview->height = fabs (g_value_get_double (value));
751 case PROP_WAVE_COLOR:
752 if (waveview->wave_color != g_value_get_uint(value)) {
753 waveview->wave_color = g_value_get_uint(value);
759 if (waveview->rectified != g_value_get_boolean(value)) {
760 waveview->rectified = g_value_get_boolean(value);
764 case PROP_REGION_START:
765 waveview->region_start = g_value_get_uint(value);
776 gnome_canvas_waveview_reset_bounds (item);
780 gnome_canvas_item_request_update (item);
786 gnome_canvas_waveview_get_property (GObject *object,
793 g_return_if_fail (object != NULL);
794 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
796 GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (object);
800 g_value_set_pointer(value, waveview->data_src);
804 g_value_set_uint(value, waveview->channel);
807 case PROP_LENGTH_FUNCTION:
808 g_value_set_pointer(value, waveview->length_function);
811 case PROP_SOURCEFILE_LENGTH_FUNCTION:
812 g_value_set_pointer(value, waveview->sourcefile_length_function);
815 case PROP_PEAK_FUNCTION:
816 g_value_set_pointer(value, waveview->peak_function);
819 case PROP_GAIN_FUNCTION:
820 g_value_set_pointer(value, waveview->gain_curve_function);
824 g_value_set_pointer(value, waveview->gain_src);
828 g_value_set_pointer(value, waveview->cache);
831 case PROP_CACHE_UPDATER:
832 g_value_set_boolean(value, waveview->cache_updater);
835 case PROP_SAMPLES_PER_UNIT:
836 g_value_set_double(value, waveview->samples_per_unit);
839 case PROP_AMPLITUDE_ABOVE_AXIS:
840 g_value_set_double(value, waveview->amplitude_above_axis);
844 g_value_set_double (value, waveview->x);
848 g_value_set_double (value, waveview->y);
852 g_value_set_double (value, waveview->height);
855 case PROP_WAVE_COLOR:
856 g_value_set_uint (value, waveview->wave_color);
860 g_value_set_boolean (value, waveview->rectified);
862 case PROP_REGION_START:
863 g_value_set_uint (value, waveview->region_start);
865 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
871 gnome_canvas_waveview_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
873 GnomeCanvasWaveView *waveview;
876 waveview = GNOME_CANVAS_WAVEVIEW (item);
878 // check_cache (waveview, "start of update");
880 if (parent_class->update)
881 (* parent_class->update) (item, affine, clip_path, flags);
883 gnome_canvas_waveview_reset_bounds (item);
885 /* get the canvas coordinates of the view. Do NOT use affines
886 for this, because they do not round to the integer units used
887 by the canvas, resulting in subtle pixel-level errors later.
893 gnome_canvas_item_i2w (item, &x, &y);
894 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_ulx, &waveview->bbox_uly);
896 waveview->samples = waveview->length_function (waveview->data_src);
898 x = waveview->x + (waveview->samples / waveview->samples_per_unit);
899 y = waveview->y + waveview->height;
901 gnome_canvas_item_i2w (item, &x, &y);
902 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_lrx, &waveview->bbox_lry);
904 /* cache the half-height and the end point in canvas units */
906 waveview->half_height = waveview->height / 2.0;
908 /* parse the color */
910 UINT_TO_RGBA (waveview->wave_color, &waveview->wave_r, &waveview->wave_g, &waveview->wave_b,
913 // check_cache (waveview, "end of update");
917 gnome_canvas_waveview_render (GnomeCanvasItem *item,
920 GnomeCanvasWaveView *waveview;
928 waveview = GNOME_CANVAS_WAVEVIEW (item);
930 // check_cache (waveview, "start of render");
932 if (parent_class->render) {
933 (*parent_class->render) (item, buf);
937 gnome_canvas_buf_ensure_buf (buf);
941 begin = MAX(waveview->bbox_ulx,buf->rect.x0);
943 if (waveview->bbox_lrx >= 0) {
944 end = MIN(waveview->bbox_lrx,buf->rect.x1);
953 s1 = floor ((begin - waveview->bbox_ulx) * waveview->samples_per_unit) ;
955 // fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit);
957 if (end == waveview->bbox_lrx) {
958 /* This avoids minor rounding errors when we have the
959 entire region visible.
961 s2 = waveview->samples;
963 s2 = s1 + floor ((end - begin) * waveview->samples_per_unit);
967 printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)"
968 " b/e %d..%d s= %lu..%lu\n",
981 /* now ensure that the cache is full and properly
985 // check_cache (waveview, "pre-ensure");
987 if (waveview->cache_updater && waveview->reload_cache_in_render) {
988 waveview->cache->start = 0;
989 waveview->cache->end = 0;
990 waveview->reload_cache_in_render = FALSE;
993 cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
995 // check_cache (waveview, "post-ensure");
998 Now draw each line, clipping it appropriately. The clipping
999 is done by the macros PAINT_FOO().
1002 half_height = waveview->half_height;
1004 /* this makes it slightly easier to comprehend whats going on */
1006 #define origin half_height
1008 for (x = begin; x < end; x++) {
1011 int clip_max, clip_min;
1016 max = waveview->cache->data[cache_index].max;
1017 min = waveview->cache->data[cache_index].min;
1029 /* don't rectify at single-sample zoom */
1031 if (waveview->rectified && waveview->samples_per_unit > 1) {
1033 if (fabs (min) > fabs (max)) {
1037 max = max * waveview->height;
1039 pymax = (int) rint ((item->y1 + waveview->height - max) * item->canvas->pixels_per_unit);
1040 pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
1044 max = max * half_height;
1045 min = min * half_height;
1047 pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
1048 pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
1051 /* OK, now fill the RGB buffer at x=i with a line between pymin and pymax,
1052 or, if samples_per_unit == 1, then a dot at each location.
1055 if (pymax == pymin) {
1056 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
1058 PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, pymin);
1061 /* show clipped waveforms with small red lines */
1063 if (clip_max || clip_min) {
1064 clip_length = MIN(5,(waveview->height/4));
1068 PAINT_VERT(buf, 255, 0, 0, x, pymax, pymax+clip_length);
1072 PAINT_VERT(buf, 255, 0, 0, x, pymin-clip_length, pymin);
1075 /* presto, we're done */
1085 gnome_canvas_waveview_draw (GnomeCanvasItem *item,
1086 GdkDrawable *drawable,
1088 int width, int height)
1090 GnomeCanvasWaveView *waveview;
1092 waveview = GNOME_CANVAS_WAVEVIEW (item);
1094 if (parent_class->draw) {
1095 (* parent_class->draw) (item, drawable, x, y, width, height);
1098 fprintf (stderr, "please don't use the CanvasWaveView item in a non-aa Canvas\n");
1103 gnome_canvas_waveview_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
1105 GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (item);
1110 *x2 = ceil (*x1 + (waveview->length_function (waveview->data_src) / waveview->samples_per_unit));
1111 *y2 = *y1 + waveview->height;
1115 gnome_canvas_item_i2w (item, &x, &y);
1116 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &a, &b);
1119 gnome_canvas_item_i2w (item, &x, &y);
1120 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &c, &d);
1121 printf ("item bounds now (%g,%g),(%g,%g)\n", a, b, c, d);
1127 gnome_canvas_waveview_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item)
1129 /* XXX for now, point is never inside the wave
1130 GnomeCanvasWaveView *waveview;
1131 double x1, y1, x2, y2;
1138 waveview = GNOME_CANVAS_WAVEVIEW (item);
1140 *actual_item = item;
1142 /* Find the bounds for the rectangle plus its outline width */
1144 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
1146 /* Is point inside rectangle */
1148 if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
1152 /* Point is outside rectangle */
1168 return sqrt (dx * dx + dy * dy);