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);
320 gnome_canvas_waveview_destroy (GtkObject *object)
322 GnomeCanvasWaveView *waveview;
324 g_return_if_fail (object != NULL);
325 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
327 waveview = GNOME_CANVAS_WAVEVIEW (object);
329 if (GTK_OBJECT_CLASS (parent_class)->destroy)
330 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
333 #define DEBUG_CACHE 0
336 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_sample, gulong end_sample)
338 gulong required_cache_entries;
339 gulong rf1, rf2,rf3, required_frames;
340 gulong new_cache_start, new_cache_end;
346 GnomeCanvasWaveViewCache *cache;
349 cache = waveview->cache;
351 start_sample = start_sample + waveview->region_start;
352 end_sample = end_sample + waveview->region_start;
354 // printf("waveview->region_start == %lu\n",waveview->region_start);
355 printf ("=> 0x%x cache @ 0x%x range: %lu - %lu request: %lu - %lu (%lu frames)\n",
357 cache->start, cache->end,
358 start_sample, end_sample, end_sample - start_sample);
361 if (cache->start <= start_sample && cache->end >= end_sample) {
363 // printf ("0x%x: cache hit for %lu-%lu (cache holds: %lu-%lu\n",
364 // waveview, start_sample, end_sample, cache->start, cache->end);
369 /* make sure the cache is at least twice as wide as the screen width, and put the start sample
370 in the middle, ensuring that we cover the end_sample.
373 /* Note the assumption that we have a 1:1 units:pixel ratio for the canvas. Its everywhere ... */
375 half_width = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit)/2.0 + 0.5);
377 if (start_sample < half_width) {
380 new_cache_start = start_sample - half_width;
383 /* figure out how many frames we want */
385 rf1 = end_sample - start_sample + 1;
386 rf2 = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit * 2.0f));
387 required_frames = MAX(rf1,rf2);
389 /* but make sure it doesn't extend beyond the end of the source material */
391 rf3 = (gulong) (waveview->sourcefile_length_function (waveview->data_src, waveview->samples_per_unit)) + 1;
392 if (rf3 < new_cache_start) {
395 rf3 -= new_cache_start;
399 fprintf (stderr, "\n\nAVAILABLE FRAMES = %lu of %lu, start = %lu, sstart = %lu, cstart = %lu\n",
400 rf3, waveview->sourcefile_length_function (waveview->data_src, waveview->samples_per_unit),
401 waveview->region_start, start_sample, new_cache_start);
404 required_frames = MIN(required_frames,rf3);
406 new_cache_end = new_cache_start + required_frames - 1;
408 required_cache_entries = (gulong) floor (required_frames / waveview->samples_per_unit );
411 fprintf (stderr, "new cache = %lu - %lu\n", new_cache_start, new_cache_end);
412 fprintf(stderr,"required_cach_entries = %lu, samples_per_unit = %f req frames = %lu\n",
413 required_cache_entries,waveview->samples_per_unit, required_frames);
416 if (required_cache_entries > cache->allocated) {
417 cache->data = g_realloc (cache->data, sizeof (GnomeCanvasWaveViewCacheEntry) * required_cache_entries);
418 cache->allocated = required_cache_entries;
423 ostart = new_cache_start;
425 #undef CACHE_MEMMOVE_OPTIMIZATION
426 #ifdef CACHE_MEMMOVE_OPTIMIZATION
428 /* data is not entirely in the cache, so go fetch it, making sure to fill the cache */
430 /* some of the required cache entries are in the cache, but in the wrong
431 locations. use memmove to fix this.
434 if (cache->start < new_cache_start && new_cache_start < cache->end) {
436 /* case one: the common area is at the end of the existing cache. move it
437 to the beginning of the cache, and set up to refill whatever remains.
440 wv->cache_start wv->cache_end
441 |-------------------------------------------------------| cache
442 |--------------------------------| requested
443 <------------------->
445 new_cache_start new_cache_end
449 present_frames = cache->end - new_cache_start;
450 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
453 fprintf (stderr, "existing material at end of current cache, move to start of new cache\n"
454 "\tcopy from %lu to start\n", cache->data_size - present_entries);
457 memmove (&cache->data[0],
458 &cache->data[cache->data_size - present_entries],
459 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
462 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
463 present_frames, required_frames, present_entries, new_cache_start + present_entries,
464 cache->data + present_entries);
467 copied = present_entries;
468 offset = present_entries;
469 new_cache_start += present_frames;
470 required_frames -= present_frames;
472 } else if (new_cache_end > cache->start && new_cache_end < cache->end) {
474 /* case two: the common area lives at the beginning of the existing cache.
476 wv->cache_start wv->cache_end
477 |-----------------------------------------------------|
478 |--------------------------------|
482 new_cache_start new_cache_end
485 present_frames = new_cache_end - cache->start;
486 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
488 memmove (&cache->data[cache->data_size - present_entries],
490 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
493 fprintf (stderr, "existing material at start of current cache, move to start of end cache\n");
497 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
498 present_entries, required_frames, present_entries, new_cache_start + present_entries,
499 cache->data + present_entries);
502 copied = present_entries;
504 required_frames -= present_frames;
517 #endif /* CACHE_MEMMOVE_OPTIMIZATION */
519 // fprintf(stderr,"length == %lu\n",waveview->length_function (waveview->data_src));
520 // 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 required_frames = npeaks * waveview->samples_per_unit;
528 printf ("requesting %lu/%f to cover %lu-%lu at %f spu (request was %lu-%lu) into cache + %lu\n",
529 required_frames, required_frames/waveview->samples_per_unit, new_cache_start, new_cache_end,
530 waveview->samples_per_unit, start_sample, end_sample, offset);
534 // printf ("cache holds %lu entries, requesting %lu to cover %lu-%lu (request was %lu-%lu)\n",
535 // cache->data_size, npeaks, new_cache_start, new_cache_end,
536 // start_sample, end_sample);
539 if (required_frames) {
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 */
549 if (npeaks < cache->allocated) {
551 fprintf (stderr, "zero fill cache for %lu at %lu\n", cache->allocated - npeaks, npeaks);
553 memset (&cache->data[npeaks], 0, sizeof (GnomeCanvasWaveViewCacheEntry) * (cache->allocated - npeaks));
554 cache->data_size = npeaks;
556 cache->data_size = cache->allocated;
559 if (waveview->gain_curve_function) {
562 gain = (float*) malloc (sizeof (float) * cache->data_size);
564 waveview->gain_curve_function (waveview->gain_src, new_cache_start, new_cache_end, gain, cache->data_size);
566 for (n = 0; n < cache->data_size; ++n) {
567 cache->data[n].min *= gain[n];
568 cache->data[n].max *= gain[n];
575 cache->start = ostart;
576 cache->end = new_cache_end;
580 fprintf (stderr, "return cache index = %d\n",
581 (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5));
583 return (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5);
588 gnome_canvas_waveview_set_data_src (GnomeCanvasWaveView *waveview, void *data_src)
591 if (waveview->cache_updater) {
592 if (waveview->data_src == data_src) {
593 waveview->reload_cache_in_render = TRUE;
597 waveview->cache->start = 0;
598 waveview->cache->end = 0;
601 waveview->data_src = data_src;
605 gnome_canvas_waveview_set_channel (GnomeCanvasWaveView *waveview, guint32 chan)
607 if (waveview->channel == chan) {
611 waveview->channel = chan;
615 gnome_canvas_waveview_reset_bounds (GnomeCanvasItem *item)
618 double x1, x2, y1, y2;
621 int Ix1, Ix2, Iy1, Iy2;
624 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
631 gnome_canvas_item_i2w_affine (item, i2w);
632 art_affine_point (&w1, &i1, i2w);
633 art_affine_point (&w2, &i2, i2w);
635 Ix1 = (int) rint(w1.x);
636 Ix2 = (int) rint(w2.x);
637 Iy1 = (int) rint(w1.y);
638 Iy2 = (int) rint(w2.y);
640 gnome_canvas_update_bbox (item, Ix1, Iy1, Ix2, Iy2);
648 gnome_canvas_waveview_set_property (GObject *object,
654 GnomeCanvasItem *item;
655 GnomeCanvasWaveView *waveview;
657 int calc_bounds = FALSE;
659 g_return_if_fail (object != NULL);
660 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
662 item = GNOME_CANVAS_ITEM (object);
663 waveview = GNOME_CANVAS_WAVEVIEW (object);
667 gnome_canvas_waveview_set_data_src (waveview, g_value_get_pointer(value));
672 gnome_canvas_waveview_set_channel (waveview, g_value_get_uint(value));
676 case PROP_LENGTH_FUNCTION:
677 waveview->length_function = g_value_get_pointer(value);
680 case PROP_SOURCEFILE_LENGTH_FUNCTION:
681 waveview->sourcefile_length_function = g_value_get_pointer(value);
685 case PROP_PEAK_FUNCTION:
686 waveview->peak_function = g_value_get_pointer(value);
690 case PROP_GAIN_FUNCTION:
691 waveview->gain_curve_function = g_value_get_pointer(value);
696 waveview->gain_src = g_value_get_pointer(value);
697 if (waveview->cache_updater) {
698 waveview->cache->start = 0;
699 waveview->cache->end = 0;
706 waveview->cache = g_value_get_pointer(value);
711 case PROP_CACHE_UPDATER:
712 waveview->cache_updater = g_value_get_boolean(value);
716 case PROP_SAMPLES_PER_UNIT:
717 if ((waveview->samples_per_unit = g_value_get_double(value)) < 1.0) {
718 waveview->samples_per_unit = 1.0;
720 if (waveview->cache_updater) {
721 waveview->cache->start = 0;
722 waveview->cache->end = 0;
728 case PROP_AMPLITUDE_ABOVE_AXIS:
729 waveview->amplitude_above_axis = g_value_get_double(value);
734 if (waveview->x != g_value_get_double (value)) {
735 waveview->x = g_value_get_double (value);
741 if (waveview->y != g_value_get_double (value)) {
742 waveview->y = g_value_get_double (value);
748 if (waveview->height != fabs (g_value_get_double (value))) {
749 waveview->height = fabs (g_value_get_double (value));
754 case PROP_WAVE_COLOR:
755 if (waveview->wave_color != g_value_get_uint(value)) {
756 waveview->wave_color = g_value_get_uint(value);
762 if (waveview->rectified != g_value_get_boolean(value)) {
763 waveview->rectified = g_value_get_boolean(value);
767 case PROP_REGION_START:
768 waveview->region_start = g_value_get_uint(value);
779 gnome_canvas_waveview_reset_bounds (item);
783 gnome_canvas_item_request_update (item);
789 gnome_canvas_waveview_get_property (GObject *object,
796 g_return_if_fail (object != NULL);
797 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
799 GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (object);
803 g_value_set_pointer(value, waveview->data_src);
807 g_value_set_uint(value, waveview->channel);
810 case PROP_LENGTH_FUNCTION:
811 g_value_set_pointer(value, waveview->length_function);
814 case PROP_SOURCEFILE_LENGTH_FUNCTION:
815 g_value_set_pointer(value, waveview->sourcefile_length_function);
818 case PROP_PEAK_FUNCTION:
819 g_value_set_pointer(value, waveview->peak_function);
822 case PROP_GAIN_FUNCTION:
823 g_value_set_pointer(value, waveview->gain_curve_function);
827 g_value_set_pointer(value, waveview->gain_src);
831 g_value_set_pointer(value, waveview->cache);
834 case PROP_CACHE_UPDATER:
835 g_value_set_boolean(value, waveview->cache_updater);
838 case PROP_SAMPLES_PER_UNIT:
839 g_value_set_double(value, waveview->samples_per_unit);
842 case PROP_AMPLITUDE_ABOVE_AXIS:
843 g_value_set_double(value, waveview->amplitude_above_axis);
847 g_value_set_double (value, waveview->x);
851 g_value_set_double (value, waveview->y);
855 g_value_set_double (value, waveview->height);
858 case PROP_WAVE_COLOR:
859 g_value_set_uint (value, waveview->wave_color);
863 g_value_set_boolean (value, waveview->rectified);
865 case PROP_REGION_START:
866 g_value_set_uint (value, waveview->region_start);
868 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
874 gnome_canvas_waveview_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
876 GnomeCanvasWaveView *waveview;
879 waveview = GNOME_CANVAS_WAVEVIEW (item);
881 // check_cache (waveview, "start of update");
883 if (parent_class->update)
884 (* parent_class->update) (item, affine, clip_path, flags);
886 gnome_canvas_waveview_reset_bounds (item);
888 /* get the canvas coordinates of the view. Do NOT use affines
889 for this, because they do not round to the integer units used
890 by the canvas, resulting in subtle pixel-level errors later.
896 gnome_canvas_item_i2w (item, &x, &y);
897 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_ulx, &waveview->bbox_uly);
899 waveview->samples = waveview->length_function (waveview->data_src);
901 x = waveview->x + (waveview->samples / waveview->samples_per_unit);
902 y = waveview->y + waveview->height;
904 gnome_canvas_item_i2w (item, &x, &y);
905 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_lrx, &waveview->bbox_lry);
907 /* cache the half-height and the end point in canvas units */
909 waveview->half_height = waveview->height / 2.0;
911 /* parse the color */
913 UINT_TO_RGBA (waveview->wave_color, &waveview->wave_r, &waveview->wave_g, &waveview->wave_b,
916 // check_cache (waveview, "end of update");
920 gnome_canvas_waveview_render (GnomeCanvasItem *item,
923 GnomeCanvasWaveView *waveview;
931 waveview = GNOME_CANVAS_WAVEVIEW (item);
933 // check_cache (waveview, "start of render");
935 if (parent_class->render) {
936 (*parent_class->render) (item, buf);
940 gnome_canvas_buf_ensure_buf (buf);
944 begin = MAX(waveview->bbox_ulx,buf->rect.x0);
946 if (waveview->bbox_lrx >= 0) {
947 end = MIN(waveview->bbox_lrx,buf->rect.x1);
956 s1 = floor ((begin - waveview->bbox_ulx) * waveview->samples_per_unit) ;
958 // fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit);
960 if (end == waveview->bbox_lrx) {
961 /* This avoids minor rounding errors when we have the
962 entire region visible.
964 s2 = waveview->samples;
966 s2 = s1 + floor ((end - begin) * waveview->samples_per_unit);
970 printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)"
971 " b/e %d..%d s= %lu..%lu\n",
984 /* now ensure that the cache is full and properly
988 // check_cache (waveview, "pre-ensure");
990 if (waveview->cache_updater && waveview->reload_cache_in_render) {
991 waveview->cache->start = 0;
992 waveview->cache->end = 0;
993 waveview->reload_cache_in_render = FALSE;
996 cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
998 // check_cache (waveview, "post-ensure");
1001 Now draw each line, clipping it appropriately. The clipping
1002 is done by the macros PAINT_FOO().
1005 half_height = waveview->half_height;
1007 /* this makes it slightly easier to comprehend whats going on */
1009 #define origin half_height
1011 for (x = begin; x < end; x++) {
1014 int clip_max, clip_min;
1019 max = waveview->cache->data[cache_index].max;
1020 min = waveview->cache->data[cache_index].min;
1032 /* don't rectify at single-sample zoom */
1034 if (waveview->rectified && waveview->samples_per_unit > 1) {
1036 if (fabs (min) > fabs (max)) {
1040 max = max * waveview->height;
1042 pymax = (int) rint ((item->y1 + waveview->height - max) * item->canvas->pixels_per_unit);
1043 pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
1047 max = max * half_height;
1048 min = min * half_height;
1050 pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
1051 pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
1054 /* OK, now fill the RGB buffer at x=i with a line between pymin and pymax,
1055 or, if samples_per_unit == 1, then a dot at each location.
1058 if (pymax == pymin) {
1059 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
1061 PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, pymin);
1064 /* show clipped waveforms with small red lines */
1066 if (clip_max || clip_min) {
1067 clip_length = MIN(5,(waveview->height/4));
1071 PAINT_VERT(buf, 255, 0, 0, x, pymax, pymax+clip_length);
1075 PAINT_VERT(buf, 255, 0, 0, x, pymin-clip_length, pymin);
1078 /* presto, we're done */
1088 gnome_canvas_waveview_draw (GnomeCanvasItem *item,
1089 GdkDrawable *drawable,
1091 int width, int height)
1093 GnomeCanvasWaveView *waveview;
1095 waveview = GNOME_CANVAS_WAVEVIEW (item);
1097 if (parent_class->draw) {
1098 (* parent_class->draw) (item, drawable, x, y, width, height);
1101 fprintf (stderr, "please don't use the CanvasWaveView item in a non-aa Canvas\n");
1106 gnome_canvas_waveview_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
1108 GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (item);
1113 *x2 = ceil (*x1 + (waveview->length_function (waveview->data_src) / waveview->samples_per_unit));
1114 *y2 = *y1 + waveview->height;
1118 gnome_canvas_item_i2w (item, &x, &y);
1119 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &a, &b);
1122 gnome_canvas_item_i2w (item, &x, &y);
1123 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &c, &d);
1124 printf ("item bounds now (%g,%g),(%g,%g)\n", a, b, c, d);
1130 gnome_canvas_waveview_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item)
1132 /* XXX for now, point is never inside the wave
1133 GnomeCanvasWaveView *waveview;
1134 double x1, y1, x2, y2;
1141 waveview = GNOME_CANVAS_WAVEVIEW (item);
1143 *actual_item = item;
1145 /* Find the bounds for the rectangle plus its outline width */
1147 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
1149 /* Is point inside rectangle */
1151 if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
1155 /* Point is outside rectangle */
1171 return sqrt (dx * dx + dy * dy);