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 rf3 -= new_cache_start;
395 fprintf (stderr, "\n\nAVAILABLE FRAMES = %lu of %lu, start = %lu, sstart = %lu, cstart = %lu\n",
396 rf3, waveview->sourcefile_length_function (waveview->data_src, waveview->samples_per_unit),
397 waveview->region_start, start_sample, new_cache_start);
400 required_frames = MIN(required_frames,rf3);
402 new_cache_end = new_cache_start + required_frames - 1;
404 required_cache_entries = (gulong) floor (required_frames / waveview->samples_per_unit );
407 fprintf (stderr, "new cache = %lu - %lu\n", new_cache_start, new_cache_end);
408 fprintf(stderr,"required_cach_entries = %lu, samples_per_unit = %f\n",
409 required_cache_entries,waveview->samples_per_unit);
412 if (required_cache_entries > cache->allocated) {
413 cache->data = g_realloc (cache->data, sizeof (GnomeCanvasWaveViewCacheEntry) * required_cache_entries);
414 cache->allocated = required_cache_entries;
419 ostart = new_cache_start;
421 #undef CACHE_MEMMOVE_OPTIMIZATION
422 #ifdef CACHE_MEMMOVE_OPTIMIZATION
424 /* data is not entirely in the cache, so go fetch it, making sure to fill the cache */
426 /* some of the required cache entries are in the cache, but in the wrong
427 locations. use memmove to fix this.
430 if (cache->start < new_cache_start && new_cache_start < cache->end) {
432 /* case one: the common area is at the end of the existing cache. move it
433 to the beginning of the cache, and set up to refill whatever remains.
436 wv->cache_start wv->cache_end
437 |-------------------------------------------------------| cache
438 |--------------------------------| requested
439 <------------------->
441 new_cache_start new_cache_end
445 present_frames = cache->end - new_cache_start;
446 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
449 fprintf (stderr, "existing material at end of current cache, move to start of new cache\n"
450 "\tcopy from %lu to start\n", cache->data_size - present_entries);
453 memmove (&cache->data[0],
454 &cache->data[cache->data_size - present_entries],
455 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
458 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
459 present_frames, required_frames, present_entries, new_cache_start + present_entries,
460 cache->data + present_entries);
463 copied = present_entries;
464 offset = present_entries;
465 new_cache_start += present_frames;
466 required_frames -= present_frames;
468 } else if (new_cache_end > cache->start && new_cache_end < cache->end) {
470 /* case two: the common area lives at the beginning of the existing cache.
472 wv->cache_start wv->cache_end
473 |-----------------------------------------------------|
474 |--------------------------------|
478 new_cache_start new_cache_end
481 present_frames = new_cache_end - cache->start;
482 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
484 memmove (&cache->data[cache->data_size - present_entries],
486 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
489 fprintf (stderr, "existing material at start of current cache, move to start of end cache\n");
493 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
494 present_entries, required_frames, present_entries, new_cache_start + present_entries,
495 cache->data + present_entries);
498 copied = present_entries;
500 required_frames -= present_frames;
513 #endif /* CACHE_MEMMOVE_OPTIMIZATION */
515 // fprintf(stderr,"length == %lu\n",waveview->length_function (waveview->data_src));
516 // required_frames = MIN (waveview->length_function (waveview->data_src) - new_cache_start, required_frames);
517 npeaks = (gulong) floor (required_frames / waveview->samples_per_unit);
518 npeaks = MAX (1, npeaks);
519 required_frames = npeaks * waveview->samples_per_unit;
524 printf ("requesting %lu/%f to cover %lu-%lu at %f spu (request was %lu-%lu) into cache + %lu\n",
525 required_frames, required_frames/waveview->samples_per_unit, new_cache_start, new_cache_end,
526 waveview->samples_per_unit, start_sample, end_sample, offset);
530 // printf ("cache holds %lu entries, requesting %lu to cover %lu-%lu (request was %lu-%lu)\n",
531 // cache->data_size, npeaks, new_cache_start, new_cache_end,
532 // start_sample, end_sample);
535 waveview->peak_function (waveview->data_src, npeaks, new_cache_start, required_frames, cache->data + offset, waveview->channel,waveview->samples_per_unit);
537 /* take into account any copied peaks */
541 if (npeaks < cache->allocated) {
543 fprintf (stderr, "zero fill cache for %lu at %lu\n", cache->allocated - npeaks, npeaks);
545 memset (&cache->data[npeaks], 0, sizeof (GnomeCanvasWaveViewCacheEntry) * (cache->allocated - npeaks));
546 cache->data_size = npeaks;
548 cache->data_size = cache->allocated;
551 if (waveview->gain_curve_function) {
554 gain = (float*) malloc (sizeof (float) * cache->data_size);
556 waveview->gain_curve_function (waveview->gain_src, new_cache_start, new_cache_end, gain, cache->data_size);
558 for (n = 0; n < cache->data_size; ++n) {
559 cache->data[n].min *= gain[n];
560 cache->data[n].max *= gain[n];
567 cache->start = ostart;
568 cache->end = new_cache_end;
572 fprintf (stderr, "return cache index = %d\n",
573 (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5));
575 return (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5);
580 gnome_canvas_waveview_set_data_src (GnomeCanvasWaveView *waveview, void *data_src)
583 if (waveview->cache_updater) {
584 if (waveview->data_src == data_src) {
585 waveview->reload_cache_in_render = TRUE;
589 waveview->cache->start = 0;
590 waveview->cache->end = 0;
593 waveview->data_src = data_src;
597 gnome_canvas_waveview_set_channel (GnomeCanvasWaveView *waveview, guint32 chan)
599 if (waveview->channel == chan) {
603 waveview->channel = chan;
607 gnome_canvas_waveview_reset_bounds (GnomeCanvasItem *item)
610 double x1, x2, y1, y2;
613 int Ix1, Ix2, Iy1, Iy2;
616 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
623 gnome_canvas_item_i2w_affine (item, i2w);
624 art_affine_point (&w1, &i1, i2w);
625 art_affine_point (&w2, &i2, i2w);
627 Ix1 = (int) rint(w1.x);
628 Ix2 = (int) rint(w2.x);
629 Iy1 = (int) rint(w1.y);
630 Iy2 = (int) rint(w2.y);
632 gnome_canvas_update_bbox (item, Ix1, Iy1, Ix2, Iy2);
640 gnome_canvas_waveview_set_property (GObject *object,
646 GnomeCanvasItem *item;
647 GnomeCanvasWaveView *waveview;
649 int calc_bounds = FALSE;
651 g_return_if_fail (object != NULL);
652 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
654 item = GNOME_CANVAS_ITEM (object);
655 waveview = GNOME_CANVAS_WAVEVIEW (object);
659 gnome_canvas_waveview_set_data_src (waveview, g_value_get_pointer(value));
664 gnome_canvas_waveview_set_channel (waveview, g_value_get_uint(value));
668 case PROP_LENGTH_FUNCTION:
669 waveview->length_function = g_value_get_pointer(value);
672 case PROP_SOURCEFILE_LENGTH_FUNCTION:
673 waveview->sourcefile_length_function = g_value_get_pointer(value);
677 case PROP_PEAK_FUNCTION:
678 waveview->peak_function = g_value_get_pointer(value);
682 case PROP_GAIN_FUNCTION:
683 waveview->gain_curve_function = g_value_get_pointer(value);
688 waveview->gain_src = g_value_get_pointer(value);
689 if (waveview->cache_updater) {
690 waveview->cache->start = 0;
691 waveview->cache->end = 0;
698 waveview->cache = g_value_get_pointer(value);
703 case PROP_CACHE_UPDATER:
704 waveview->cache_updater = g_value_get_boolean(value);
708 case PROP_SAMPLES_PER_UNIT:
709 if ((waveview->samples_per_unit = g_value_get_double(value)) < 1.0) {
710 waveview->samples_per_unit = 1.0;
712 if (waveview->cache_updater) {
713 waveview->cache->start = 0;
714 waveview->cache->end = 0;
720 case PROP_AMPLITUDE_ABOVE_AXIS:
721 waveview->amplitude_above_axis = g_value_get_double(value);
726 if (waveview->x != g_value_get_double (value)) {
727 waveview->x = g_value_get_double (value);
733 if (waveview->y != g_value_get_double (value)) {
734 waveview->y = g_value_get_double (value);
740 if (waveview->height != fabs (g_value_get_double (value))) {
741 waveview->height = fabs (g_value_get_double (value));
746 case PROP_WAVE_COLOR:
747 if (waveview->wave_color != g_value_get_uint(value)) {
748 waveview->wave_color = g_value_get_uint(value);
754 if (waveview->rectified != g_value_get_boolean(value)) {
755 waveview->rectified = g_value_get_boolean(value);
759 case PROP_REGION_START:
760 waveview->region_start = g_value_get_uint(value);
771 gnome_canvas_waveview_reset_bounds (item);
775 gnome_canvas_item_request_update (item);
781 gnome_canvas_waveview_get_property (GObject *object,
788 g_return_if_fail (object != NULL);
789 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
791 GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (object);
795 g_value_set_pointer(value, waveview->data_src);
799 g_value_set_uint(value, waveview->channel);
802 case PROP_LENGTH_FUNCTION:
803 g_value_set_pointer(value, waveview->length_function);
806 case PROP_SOURCEFILE_LENGTH_FUNCTION:
807 g_value_set_pointer(value, waveview->sourcefile_length_function);
810 case PROP_PEAK_FUNCTION:
811 g_value_set_pointer(value, waveview->peak_function);
814 case PROP_GAIN_FUNCTION:
815 g_value_set_pointer(value, waveview->gain_curve_function);
819 g_value_set_pointer(value, waveview->gain_src);
823 g_value_set_pointer(value, waveview->cache);
826 case PROP_CACHE_UPDATER:
827 g_value_set_boolean(value, waveview->cache_updater);
830 case PROP_SAMPLES_PER_UNIT:
831 g_value_set_double(value, waveview->samples_per_unit);
834 case PROP_AMPLITUDE_ABOVE_AXIS:
835 g_value_set_double(value, waveview->amplitude_above_axis);
839 g_value_set_double (value, waveview->x);
843 g_value_set_double (value, waveview->y);
847 g_value_set_double (value, waveview->height);
850 case PROP_WAVE_COLOR:
851 g_value_set_uint (value, waveview->wave_color);
855 g_value_set_boolean (value, waveview->rectified);
857 case PROP_REGION_START:
858 g_value_set_uint (value, waveview->region_start);
860 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
866 gnome_canvas_waveview_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
868 GnomeCanvasWaveView *waveview;
871 waveview = GNOME_CANVAS_WAVEVIEW (item);
873 // check_cache (waveview, "start of update");
875 if (parent_class->update)
876 (* parent_class->update) (item, affine, clip_path, flags);
878 gnome_canvas_waveview_reset_bounds (item);
880 /* get the canvas coordinates of the view. Do NOT use affines
881 for this, because they do not round to the integer units used
882 by the canvas, resulting in subtle pixel-level errors later.
888 gnome_canvas_item_i2w (item, &x, &y);
889 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_ulx, &waveview->bbox_uly);
891 waveview->samples = waveview->length_function (waveview->data_src);
893 x = waveview->x + (waveview->samples / waveview->samples_per_unit);
894 y = waveview->y + waveview->height;
896 gnome_canvas_item_i2w (item, &x, &y);
897 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_lrx, &waveview->bbox_lry);
899 /* cache the half-height and the end point in canvas units */
901 waveview->half_height = waveview->height / 2.0;
903 /* parse the color */
905 UINT_TO_RGBA (waveview->wave_color, &waveview->wave_r, &waveview->wave_g, &waveview->wave_b,
908 // check_cache (waveview, "end of update");
912 gnome_canvas_waveview_render (GnomeCanvasItem *item,
915 GnomeCanvasWaveView *waveview;
923 waveview = GNOME_CANVAS_WAVEVIEW (item);
925 // check_cache (waveview, "start of render");
927 if (parent_class->render) {
928 (*parent_class->render) (item, buf);
932 gnome_canvas_buf_ensure_buf (buf);
936 begin = MAX(waveview->bbox_ulx,buf->rect.x0);
938 if (waveview->bbox_lrx >= 0) {
939 end = MIN(waveview->bbox_lrx,buf->rect.x1);
948 s1 = floor ((begin - waveview->bbox_ulx) * waveview->samples_per_unit) ;
950 // fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit);
952 if (end == waveview->bbox_lrx) {
953 /* This avoids minor rounding errors when we have the
954 entire region visible.
956 s2 = waveview->samples;
958 s2 = s1 + floor ((end - begin) * waveview->samples_per_unit);
962 printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)"
963 " b/e %d..%d s= %lu..%lu\n",
976 /* now ensure that the cache is full and properly
980 // check_cache (waveview, "pre-ensure");
982 if (waveview->cache_updater && waveview->reload_cache_in_render) {
983 waveview->cache->start = 0;
984 waveview->cache->end = 0;
985 waveview->reload_cache_in_render = FALSE;
988 cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
990 // check_cache (waveview, "post-ensure");
993 Now draw each line, clipping it appropriately. The clipping
994 is done by the macros PAINT_FOO().
997 half_height = waveview->half_height;
999 /* this makes it slightly easier to comprehend whats going on */
1001 #define origin half_height
1003 for (x = begin; x < end; x++) {
1006 int clip_max, clip_min;
1011 max = waveview->cache->data[cache_index].max;
1012 min = waveview->cache->data[cache_index].min;
1024 /* don't rectify at single-sample zoom */
1026 if (waveview->rectified && waveview->samples_per_unit > 1) {
1028 if (fabs (min) > fabs (max)) {
1032 max = max * waveview->height;
1034 pymax = (int) rint ((item->y1 + waveview->height - max) * item->canvas->pixels_per_unit);
1035 pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
1039 max = max * half_height;
1040 min = min * half_height;
1042 pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
1043 pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
1046 /* OK, now fill the RGB buffer at x=i with a line between pymin and pymax,
1047 or, if samples_per_unit == 1, then a dot at each location.
1050 if (pymax == pymin) {
1051 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
1053 PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, pymin);
1056 /* show clipped waveforms with small red lines */
1058 if (clip_max || clip_min) {
1059 clip_length = MIN(5,(waveview->height/4));
1063 PAINT_VERT(buf, 255, 0, 0, x, pymax, pymax+clip_length);
1067 PAINT_VERT(buf, 255, 0, 0, x, pymin-clip_length, pymin);
1070 /* presto, we're done */
1080 gnome_canvas_waveview_draw (GnomeCanvasItem *item,
1081 GdkDrawable *drawable,
1083 int width, int height)
1085 GnomeCanvasWaveView *waveview;
1087 waveview = GNOME_CANVAS_WAVEVIEW (item);
1089 if (parent_class->draw) {
1090 (* parent_class->draw) (item, drawable, x, y, width, height);
1093 fprintf (stderr, "please don't use the CanvasWaveView item in a non-aa Canvas\n");
1098 gnome_canvas_waveview_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
1100 GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (item);
1105 *x2 = ceil (*x1 + (waveview->length_function (waveview->data_src) / waveview->samples_per_unit));
1106 *y2 = *y1 + waveview->height;
1110 gnome_canvas_item_i2w (item, &x, &y);
1111 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &a, &b);
1114 gnome_canvas_item_i2w (item, &x, &y);
1115 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &c, &d);
1116 printf ("item bounds now (%g,%g),(%g,%g)\n", a, b, c, d);
1122 gnome_canvas_waveview_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item)
1124 /* XXX for now, point is never inside the wave
1125 GnomeCanvasWaveView *waveview;
1126 double x1, y1, x2, y2;
1133 waveview = GNOME_CANVAS_WAVEVIEW (item);
1135 *actual_item = item;
1137 /* Find the bounds for the rectangle plus its outline width */
1139 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
1141 /* Is point inside rectangle */
1143 if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
1147 /* Point is outside rectangle */
1163 return sqrt (dx * dx + dy * dy);