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 if (GTK_OBJECT_CLASS (parent_class)->destroy)
333 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
336 #define DEBUG_CACHE 0
339 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_sample, gulong end_sample)
341 gulong required_cache_entries;
342 gulong rf1, rf2,rf3, required_frames;
343 gulong new_cache_start, new_cache_end;
349 GnomeCanvasWaveViewCache *cache;
352 cache = waveview->cache;
354 start_sample = start_sample + waveview->region_start;
355 end_sample = end_sample + waveview->region_start;
357 // printf("waveview->region_start == %lu\n",waveview->region_start);
358 printf ("=> 0x%x cache @ 0x%x range: %lu - %lu request: %lu - %lu (%lu frames)\n",
360 cache->start, cache->end,
361 start_sample, end_sample, end_sample - start_sample);
364 if (cache->start <= start_sample && cache->end >= end_sample) {
366 // printf ("0x%x: cache hit for %lu-%lu (cache holds: %lu-%lu\n",
367 // waveview, start_sample, end_sample, cache->start, cache->end);
372 /* make sure the cache is at least twice as wide as the screen width, and put the start sample
373 in the middle, ensuring that we cover the end_sample.
376 /* Note the assumption that we have a 1:1 units:pixel ratio for the canvas. Its everywhere ... */
378 half_width = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit)/2.0 + 0.5);
380 if (start_sample < half_width) {
383 new_cache_start = start_sample - half_width;
386 /* figure out how many frames we want */
388 rf1 = end_sample - start_sample + 1;
389 rf2 = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit * 2.0f));
390 required_frames = MAX(rf1,rf2);
392 /* but make sure it doesn't extend beyond the end of the source material */
394 rf3 = (gulong) (waveview->sourcefile_length_function (waveview->data_src)) + 1;
395 rf3 -= new_cache_start;
398 fprintf (stderr, "\n\nAVAILABLE FRAMES = %lu of %lu, start = %lu, sstart = %lu, cstart = %lu\n",
399 rf3, waveview->sourcefile_length_function (waveview->data_src),
400 waveview->region_start, start_sample, new_cache_start);
403 required_frames = MIN(required_frames,rf3);
405 new_cache_end = new_cache_start + required_frames - 1;
407 required_cache_entries = (gulong) floor (required_frames / waveview->samples_per_unit );
410 fprintf (stderr, "new cache = %lu - %lu\n", new_cache_start, new_cache_end);
411 fprintf(stderr,"required_cach_entries = %lu, samples_per_unit = %f\n",
412 required_cache_entries,waveview->samples_per_unit);
415 if (required_cache_entries > cache->allocated) {
416 cache->data = g_realloc (cache->data, sizeof (GnomeCanvasWaveViewCacheEntry) * required_cache_entries);
417 cache->allocated = required_cache_entries;
422 ostart = new_cache_start;
424 #undef CACHE_MEMMOVE_OPTIMIZATION
425 #ifdef CACHE_MEMMOVE_OPTIMIZATION
427 /* data is not entirely in the cache, so go fetch it, making sure to fill the cache */
429 /* some of the required cache entries are in the cache, but in the wrong
430 locations. use memmove to fix this.
433 if (cache->start < new_cache_start && new_cache_start < cache->end) {
435 /* case one: the common area is at the end of the existing cache. move it
436 to the beginning of the cache, and set up to refill whatever remains.
439 wv->cache_start wv->cache_end
440 |-------------------------------------------------------| cache
441 |--------------------------------| requested
442 <------------------->
444 new_cache_start new_cache_end
448 present_frames = cache->end - new_cache_start;
449 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
452 fprintf (stderr, "existing material at end of current cache, move to start of new cache\n"
453 "\tcopy from %lu to start\n", cache->data_size - present_entries);
456 memmove (&cache->data[0],
457 &cache->data[cache->data_size - present_entries],
458 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
461 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
462 present_frames, required_frames, present_entries, new_cache_start + present_entries,
463 cache->data + present_entries);
466 copied = present_entries;
467 offset = present_entries;
468 new_cache_start += present_frames;
469 required_frames -= present_frames;
471 } else if (new_cache_end > cache->start && new_cache_end < cache->end) {
473 /* case two: the common area lives at the beginning of the existing cache.
475 wv->cache_start wv->cache_end
476 |-----------------------------------------------------|
477 |--------------------------------|
481 new_cache_start new_cache_end
484 present_frames = new_cache_end - cache->start;
485 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
487 memmove (&cache->data[cache->data_size - present_entries],
489 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
492 fprintf (stderr, "existing material at start of current cache, move to start of end cache\n");
496 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
497 present_entries, required_frames, present_entries, new_cache_start + present_entries,
498 cache->data + present_entries);
501 copied = present_entries;
503 required_frames -= present_frames;
516 #endif /* CACHE_MEMMOVE_OPTIMIZATION */
518 // fprintf(stderr,"length == %lu\n",waveview->length_function (waveview->data_src));
519 // required_frames = MIN (waveview->length_function (waveview->data_src) - new_cache_start, required_frames);
520 npeaks = (gulong) floor (required_frames / waveview->samples_per_unit);
521 npeaks = MAX (1, npeaks);
522 required_frames = npeaks * waveview->samples_per_unit;
527 printf ("requesting %lu/%f to cover %lu-%lu at %f spu (request was %lu-%lu) into cache + %lu\n",
528 required_frames, required_frames/waveview->samples_per_unit, new_cache_start, new_cache_end,
529 waveview->samples_per_unit, start_sample, end_sample, offset);
533 // printf ("cache holds %lu entries, requesting %lu to cover %lu-%lu (request was %lu-%lu)\n",
534 // cache->data_size, npeaks, new_cache_start, new_cache_end,
535 // start_sample, end_sample);
538 waveview->peak_function (waveview->data_src, npeaks, new_cache_start, required_frames, cache->data + offset, waveview->channel,waveview->samples_per_unit);
540 /* take into account any copied peaks */
544 if (npeaks < cache->allocated) {
546 fprintf (stderr, "zero fill cache for %lu at %lu\n", cache->allocated - npeaks, npeaks);
548 memset (&cache->data[npeaks], 0, sizeof (GnomeCanvasWaveViewCacheEntry) * (cache->allocated - npeaks));
549 cache->data_size = npeaks;
551 cache->data_size = cache->allocated;
554 if (waveview->gain_curve_function) {
557 gain = (float*) malloc (sizeof (float) * cache->data_size);
559 waveview->gain_curve_function (waveview->gain_src, new_cache_start, new_cache_end, gain, cache->data_size);
561 for (n = 0; n < cache->data_size; ++n) {
562 cache->data[n].min *= gain[n];
563 cache->data[n].max *= gain[n];
570 cache->start = ostart;
571 cache->end = new_cache_end;
575 fprintf (stderr, "return cache index = %d\n",
576 (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5));
578 return (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5);
583 gnome_canvas_waveview_set_data_src (GnomeCanvasWaveView *waveview, void *data_src)
586 if (waveview->cache_updater) {
587 if (waveview->data_src == data_src) {
588 waveview->reload_cache_in_render = TRUE;
592 waveview->cache->start = 0;
593 waveview->cache->end = 0;
596 waveview->data_src = data_src;
600 gnome_canvas_waveview_set_channel (GnomeCanvasWaveView *waveview, guint32 chan)
602 if (waveview->channel == chan) {
606 waveview->channel = chan;
610 gnome_canvas_waveview_reset_bounds (GnomeCanvasItem *item)
613 double x1, x2, y1, y2;
616 int Ix1, Ix2, Iy1, Iy2;
619 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
626 gnome_canvas_item_i2w_affine (item, i2w);
627 art_affine_point (&w1, &i1, i2w);
628 art_affine_point (&w2, &i2, i2w);
630 Ix1 = (int) rint(w1.x);
631 Ix2 = (int) rint(w2.x);
632 Iy1 = (int) rint(w1.y);
633 Iy2 = (int) rint(w2.y);
635 gnome_canvas_update_bbox (item, Ix1, Iy1, Ix2, Iy2);
643 gnome_canvas_waveview_set_property (GObject *object,
649 GnomeCanvasItem *item;
650 GnomeCanvasWaveView *waveview;
652 int calc_bounds = FALSE;
654 g_return_if_fail (object != NULL);
655 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
657 item = GNOME_CANVAS_ITEM (object);
658 waveview = GNOME_CANVAS_WAVEVIEW (object);
662 gnome_canvas_waveview_set_data_src (waveview, g_value_get_pointer(value));
667 gnome_canvas_waveview_set_channel (waveview, g_value_get_uint(value));
671 case PROP_LENGTH_FUNCTION:
672 waveview->length_function = g_value_get_pointer(value);
675 case PROP_SOURCEFILE_LENGTH_FUNCTION:
676 waveview->sourcefile_length_function = g_value_get_pointer(value);
680 case PROP_PEAK_FUNCTION:
681 waveview->peak_function = g_value_get_pointer(value);
685 case PROP_GAIN_FUNCTION:
686 waveview->gain_curve_function = g_value_get_pointer(value);
691 waveview->gain_src = g_value_get_pointer(value);
692 if (waveview->cache_updater) {
693 waveview->cache->start = 0;
694 waveview->cache->end = 0;
701 waveview->cache = g_value_get_pointer(value);
706 case PROP_CACHE_UPDATER:
707 waveview->cache_updater = g_value_get_boolean(value);
711 case PROP_SAMPLES_PER_UNIT:
712 if ((waveview->samples_per_unit = g_value_get_double(value)) < 1.0) {
713 waveview->samples_per_unit = 1.0;
715 if (waveview->cache_updater) {
716 waveview->cache->start = 0;
717 waveview->cache->end = 0;
723 case PROP_AMPLITUDE_ABOVE_AXIS:
724 waveview->amplitude_above_axis = g_value_get_double(value);
729 if (waveview->x != g_value_get_double (value)) {
730 waveview->x = g_value_get_double (value);
736 if (waveview->y != g_value_get_double (value)) {
737 waveview->y = g_value_get_double (value);
743 if (waveview->height != fabs (g_value_get_double (value))) {
744 waveview->height = fabs (g_value_get_double (value));
749 case PROP_WAVE_COLOR:
750 if (waveview->wave_color != g_value_get_uint(value)) {
751 waveview->wave_color = g_value_get_uint(value);
757 if (waveview->rectified != g_value_get_boolean(value)) {
758 waveview->rectified = g_value_get_boolean(value);
762 case PROP_REGION_START:
763 waveview->region_start = g_value_get_uint(value);
774 gnome_canvas_waveview_reset_bounds (item);
778 gnome_canvas_item_request_update (item);
784 gnome_canvas_waveview_get_property (GObject *object,
791 g_return_if_fail (object != NULL);
792 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
794 GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (object);
798 g_value_set_pointer(value, waveview->data_src);
802 g_value_set_uint(value, waveview->channel);
805 case PROP_LENGTH_FUNCTION:
806 g_value_set_pointer(value, waveview->length_function);
809 case PROP_SOURCEFILE_LENGTH_FUNCTION:
810 g_value_set_pointer(value, waveview->sourcefile_length_function);
813 case PROP_PEAK_FUNCTION:
814 g_value_set_pointer(value, waveview->peak_function);
817 case PROP_GAIN_FUNCTION:
818 g_value_set_pointer(value, waveview->gain_curve_function);
822 g_value_set_pointer(value, waveview->gain_src);
826 g_value_set_pointer(value, waveview->cache);
829 case PROP_CACHE_UPDATER:
830 g_value_set_boolean(value, waveview->cache_updater);
833 case PROP_SAMPLES_PER_UNIT:
834 g_value_set_double(value, waveview->samples_per_unit);
837 case PROP_AMPLITUDE_ABOVE_AXIS:
838 g_value_set_double(value, waveview->amplitude_above_axis);
842 g_value_set_double (value, waveview->x);
846 g_value_set_double (value, waveview->y);
850 g_value_set_double (value, waveview->height);
853 case PROP_WAVE_COLOR:
854 g_value_set_uint (value, waveview->wave_color);
858 g_value_set_boolean (value, waveview->rectified);
860 case PROP_REGION_START:
861 g_value_set_uint (value, waveview->region_start);
863 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
869 gnome_canvas_waveview_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
871 GnomeCanvasWaveView *waveview;
874 waveview = GNOME_CANVAS_WAVEVIEW (item);
876 // check_cache (waveview, "start of update");
878 if (parent_class->update)
879 (* parent_class->update) (item, affine, clip_path, flags);
881 gnome_canvas_waveview_reset_bounds (item);
883 /* get the canvas coordinates of the view. Do NOT use affines
884 for this, because they do not round to the integer units used
885 by the canvas, resulting in subtle pixel-level errors later.
891 gnome_canvas_item_i2w (item, &x, &y);
892 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_ulx, &waveview->bbox_uly);
894 waveview->samples = waveview->length_function (waveview->data_src);
896 x = waveview->x + (waveview->samples / waveview->samples_per_unit);
897 y = waveview->y + waveview->height;
899 gnome_canvas_item_i2w (item, &x, &y);
900 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_lrx, &waveview->bbox_lry);
902 /* cache the half-height and the end point in canvas units */
904 waveview->half_height = waveview->height / 2.0;
906 /* parse the color */
908 UINT_TO_RGBA (waveview->wave_color, &waveview->wave_r, &waveview->wave_g, &waveview->wave_b,
911 // check_cache (waveview, "end of update");
915 gnome_canvas_waveview_render (GnomeCanvasItem *item,
918 GnomeCanvasWaveView *waveview;
926 waveview = GNOME_CANVAS_WAVEVIEW (item);
928 // check_cache (waveview, "start of render");
930 if (parent_class->render) {
931 (*parent_class->render) (item, buf);
935 gnome_canvas_buf_ensure_buf (buf);
939 begin = MAX(waveview->bbox_ulx,buf->rect.x0);
941 if (waveview->bbox_lrx >= 0) {
942 end = MIN(waveview->bbox_lrx,buf->rect.x1);
951 s1 = floor ((begin - waveview->bbox_ulx) * waveview->samples_per_unit) ;
953 // fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit);
955 if (end == waveview->bbox_lrx) {
956 /* This avoids minor rounding errors when we have the
957 entire region visible.
959 s2 = waveview->samples;
961 s2 = s1 + floor ((end - begin) * waveview->samples_per_unit);
965 printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)"
966 " b/e %d..%d s= %lu..%lu\n",
979 /* now ensure that the cache is full and properly
983 // check_cache (waveview, "pre-ensure");
985 if (waveview->cache_updater && waveview->reload_cache_in_render) {
986 waveview->cache->start = 0;
987 waveview->cache->end = 0;
988 waveview->reload_cache_in_render = FALSE;
991 cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
993 // check_cache (waveview, "post-ensure");
996 Now draw each line, clipping it appropriately. The clipping
997 is done by the macros PAINT_FOO().
1000 half_height = waveview->half_height;
1002 /* this makes it slightly easier to comprehend whats going on */
1004 #define origin half_height
1006 for (x = begin; x < end; x++) {
1009 int clip_max, clip_min;
1014 max = waveview->cache->data[cache_index].max;
1015 min = waveview->cache->data[cache_index].min;
1027 /* don't rectify at single-sample zoom */
1029 if (waveview->rectified && waveview->samples_per_unit > 1) {
1031 if (fabs (min) > fabs (max)) {
1035 max = max * waveview->height;
1037 pymax = (int) rint ((item->y1 + waveview->height - max) * item->canvas->pixels_per_unit);
1038 pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
1042 max = max * half_height;
1043 min = min * half_height;
1045 pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
1046 pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
1049 /* OK, now fill the RGB buffer at x=i with a line between pymin and pymax,
1050 or, if samples_per_unit == 1, then a dot at each location.
1053 if (pymax == pymin) {
1054 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
1056 PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, pymin);
1059 /* show clipped waveforms with small red lines */
1061 if (clip_max || clip_min) {
1062 clip_length = MIN(5,(waveview->height/4));
1066 PAINT_VERT(buf, 255, 0, 0, x, pymax, pymax+clip_length);
1070 PAINT_VERT(buf, 255, 0, 0, x, pymin-clip_length, pymin);
1073 /* presto, we're done */
1083 gnome_canvas_waveview_draw (GnomeCanvasItem *item,
1084 GdkDrawable *drawable,
1086 int width, int height)
1088 GnomeCanvasWaveView *waveview;
1090 waveview = GNOME_CANVAS_WAVEVIEW (item);
1092 if (parent_class->draw) {
1093 (* parent_class->draw) (item, drawable, x, y, width, height);
1096 fprintf (stderr, "please don't use the CanvasWaveView item in a non-aa Canvas\n");
1101 gnome_canvas_waveview_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
1103 GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (item);
1108 *x2 = ceil (*x1 + (waveview->length_function (waveview->data_src) / waveview->samples_per_unit));
1109 *y2 = *y1 + waveview->height;
1113 gnome_canvas_item_i2w (item, &x, &y);
1114 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &a, &b);
1117 gnome_canvas_item_i2w (item, &x, &y);
1118 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &c, &d);
1119 printf ("item bounds now (%g,%g),(%g,%g)\n", a, b, c, d);
1125 gnome_canvas_waveview_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item)
1127 /* XXX for now, point is never inside the wave
1128 GnomeCanvasWaveView *waveview;
1129 double x1, y1, x2, y2;
1136 waveview = GNOME_CANVAS_WAVEVIEW (item);
1138 *actual_item = item;
1140 /* Find the bounds for the rectangle plus its outline width */
1142 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
1144 /* Is point inside rectangle */
1146 if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
1150 /* Point is outside rectangle */
1166 return sqrt (dx * dx + dy * dy);