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_boxed ("data_src", NULL, NULL,
155 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
157 g_object_class_install_property
160 g_param_spec_uint ("channel", NULL, NULL,
162 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
164 g_object_class_install_property
166 PROP_LENGTH_FUNCTION,
167 g_param_spec_boxed ("length_function", NULL, NULL,
169 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
171 g_object_class_install_property
173 PROP_SOURCEFILE_LENGTH_FUNCTION,
174 g_param_spec_boxed ("sourcefile_length_function", NULL, NULL,
176 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
178 g_object_class_install_property
181 g_param_spec_boxed ("peak_function", NULL, NULL,
183 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
185 g_object_class_install_property
188 g_param_spec_boxed ("gain_function", NULL, NULL,
190 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
192 g_object_class_install_property
195 g_param_spec_boxed ("gain_src", NULL, NULL,
197 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
199 g_object_class_install_property
202 g_param_spec_boxed ("cache", NULL, NULL,
204 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
206 g_object_class_install_property
209 g_param_spec_boolean ("cache_updater", NULL, NULL,
211 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
213 g_object_class_install_property
215 PROP_SAMPLES_PER_UNIT,
216 g_param_spec_double ("sample_per_unit", NULL, NULL,
217 0.0, G_MAXDOUBLE, 0.0,
218 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
220 g_object_class_install_property
222 PROP_AMPLITUDE_ABOVE_AXIS,
223 g_param_spec_double ("amplitude_above_axis", 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 ("x", 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 ("y", 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_double ("height", NULL, NULL,
245 0.0, G_MAXDOUBLE, 0.0,
246 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
248 g_object_class_install_property
251 g_param_spec_uint ("wave_color", NULL, NULL,
253 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
255 g_object_class_install_property
258 g_param_spec_boolean ("rectified", NULL, NULL,
260 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
262 g_object_class_install_property
265 g_param_spec_uint ("region_start", NULL, NULL,
267 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
269 object_class->destroy = gnome_canvas_waveview_destroy;
271 item_class->update = gnome_canvas_waveview_update;
272 item_class->bounds = gnome_canvas_waveview_bounds;
273 item_class->point = gnome_canvas_waveview_point;
274 item_class->render = gnome_canvas_waveview_render;
275 item_class->draw = gnome_canvas_waveview_draw;
278 GnomeCanvasWaveViewCache*
279 gnome_canvas_waveview_cache_new ()
281 GnomeCanvasWaveViewCache *c;
283 c = g_malloc (sizeof (GnomeCanvasWaveViewCache));
286 c->data = g_malloc (sizeof (GnomeCanvasWaveViewCacheEntry) * c->allocated);
295 gnome_canvas_waveview_cache_destroy (GnomeCanvasWaveViewCache* cache)
297 g_free (cache->data);
302 gnome_canvas_waveview_init (GnomeCanvasWaveView *waveview)
307 waveview->cache_updater = FALSE;
308 waveview->data_src = NULL;
309 waveview->channel = 0;
310 waveview->peak_function = NULL;
311 waveview->length_function = NULL;
312 waveview->sourcefile_length_function = NULL;
313 waveview->gain_curve_function = NULL;
314 waveview->gain_src = NULL;
315 waveview->rectified = FALSE;
316 waveview->region_start = 0;
317 waveview->samples_per_unit = 1.0;
318 waveview->amplitude_above_axis = 1.0;
319 waveview->height = 100.0;
320 waveview->screen_width = gdk_screen_width ();
321 waveview->reload_cache_in_render = FALSE;
323 waveview->wave_color = RGBA_TO_UINT(44,35,126,255);
326 // GNOME_CANVAS_ITEM(waveview)->object.flags |= GNOME_CANVAS_ITEM_NO_AUTO_REDRAW;
330 gnome_canvas_waveview_destroy (GtkObject *object)
332 GnomeCanvasWaveView *waveview;
334 g_return_if_fail (object != NULL);
335 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
337 waveview = GNOME_CANVAS_WAVEVIEW (object);
339 gnome_canvas_waveview_cache_destroy (waveview->cache);
341 if (GTK_OBJECT_CLASS (parent_class)->destroy)
342 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
345 #define DEBUG_CACHE 0
348 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_sample, gulong end_sample)
350 gulong required_cache_entries;
351 gulong rf1, rf2,rf3, required_frames;
352 gulong new_cache_start, new_cache_end;
358 GnomeCanvasWaveViewCache *cache;
361 cache = waveview->cache;
363 start_sample = start_sample + waveview->region_start;
364 end_sample = end_sample + waveview->region_start;
366 // printf("waveview->region_start == %lu\n",waveview->region_start);
367 printf ("=> 0x%x cache @ 0x%x range: %lu - %lu request: %lu - %lu (%lu frames)\n",
369 cache->start, cache->end,
370 start_sample, end_sample, end_sample - start_sample);
373 if (cache->start <= start_sample && cache->end >= end_sample) {
375 // printf ("0x%x: cache hit for %lu-%lu (cache holds: %lu-%lu\n",
376 // waveview, start_sample, end_sample, cache->start, cache->end);
381 /* make sure the cache is at least twice as wide as the screen width, and put the start sample
382 in the middle, ensuring that we cover the end_sample.
385 /* Note the assumption that we have a 1:1 units:pixel ratio for the canvas. Its everywhere ... */
387 half_width = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit)/2.0 + 0.5);
389 if (start_sample < half_width) {
392 new_cache_start = start_sample - half_width;
395 /* figure out how many frames we want */
397 rf1 = end_sample - start_sample + 1;
398 rf2 = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit * 2.0f));
399 required_frames = MAX(rf1,rf2);
401 /* but make sure it doesn't extend beyond the end of the source material */
403 rf3 = (gulong) (waveview->sourcefile_length_function (waveview->data_src)) + 1;
404 rf3 -= new_cache_start;
407 fprintf (stderr, "\n\nAVAILABLE FRAMES = %lu of %lu, start = %lu, sstart = %lu, cstart = %lu\n",
408 rf3, waveview->sourcefile_length_function (waveview->data_src),
409 waveview->region_start, start_sample, new_cache_start);
412 required_frames = MIN(required_frames,rf3);
414 new_cache_end = new_cache_start + required_frames - 1;
416 required_cache_entries = (gulong) floor (required_frames / waveview->samples_per_unit );
419 fprintf (stderr, "new cache = %lu - %lu\n", new_cache_start, new_cache_end);
420 fprintf(stderr,"required_cach_entries = %lu, samples_per_unit = %f\n",
421 required_cache_entries,waveview->samples_per_unit);
424 if (required_cache_entries > cache->allocated) {
425 cache->data = g_realloc (cache->data, sizeof (GnomeCanvasWaveViewCacheEntry) * required_cache_entries);
426 cache->allocated = required_cache_entries;
431 ostart = new_cache_start;
433 #undef CACHE_MEMMOVE_OPTIMIZATION
434 #ifdef CACHE_MEMMOVE_OPTIMIZATION
436 /* data is not entirely in the cache, so go fetch it, making sure to fill the cache */
438 /* some of the required cache entries are in the cache, but in the wrong
439 locations. use memmove to fix this.
442 if (cache->start < new_cache_start && new_cache_start < cache->end) {
444 /* case one: the common area is at the end of the existing cache. move it
445 to the beginning of the cache, and set up to refill whatever remains.
448 wv->cache_start wv->cache_end
449 |-------------------------------------------------------| cache
450 |--------------------------------| requested
451 <------------------->
453 new_cache_start new_cache_end
457 present_frames = cache->end - new_cache_start;
458 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
461 fprintf (stderr, "existing material at end of current cache, move to start of new cache\n"
462 "\tcopy from %lu to start\n", cache->data_size - present_entries);
465 memmove (&cache->data[0],
466 &cache->data[cache->data_size - present_entries],
467 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
470 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
471 present_frames, required_frames, present_entries, new_cache_start + present_entries,
472 cache->data + present_entries);
475 copied = present_entries;
476 offset = present_entries;
477 new_cache_start += present_frames;
478 required_frames -= present_frames;
480 } else if (new_cache_end > cache->start && new_cache_end < cache->end) {
482 /* case two: the common area lives at the beginning of the existing cache.
484 wv->cache_start wv->cache_end
485 |-----------------------------------------------------|
486 |--------------------------------|
490 new_cache_start new_cache_end
493 present_frames = new_cache_end - cache->start;
494 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
496 memmove (&cache->data[cache->data_size - present_entries],
498 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
501 fprintf (stderr, "existing material at start of current cache, move to start of end cache\n");
505 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
506 present_entries, required_frames, present_entries, new_cache_start + present_entries,
507 cache->data + present_entries);
510 copied = present_entries;
512 required_frames -= present_frames;
525 #endif /* CACHE_MEMMOVE_OPTIMIZATION */
527 // fprintf(stderr,"length == %lu\n",waveview->length_function (waveview->data_src));
528 // required_frames = MIN (waveview->length_function (waveview->data_src) - new_cache_start, required_frames);
529 npeaks = (gulong) floor (required_frames / waveview->samples_per_unit);
530 npeaks = MAX (1, npeaks);
531 required_frames = npeaks * waveview->samples_per_unit;
536 printf ("requesting %lu/%f to cover %lu-%lu at %f spu (request was %lu-%lu) into cache + %lu\n",
537 required_frames, required_frames/waveview->samples_per_unit, new_cache_start, new_cache_end,
538 waveview->samples_per_unit, start_sample, end_sample, offset);
542 // printf ("cache holds %lu entries, requesting %lu to cover %lu-%lu (request was %lu-%lu)\n",
543 // cache->data_size, npeaks, new_cache_start, new_cache_end,
544 // start_sample, end_sample);
547 waveview->peak_function (waveview->data_src, npeaks, new_cache_start, required_frames, cache->data + offset, waveview->channel,waveview->samples_per_unit);
549 /* take into account any copied peaks */
553 if (npeaks < cache->allocated) {
555 fprintf (stderr, "zero fill cache for %lu at %lu\n", cache->allocated - npeaks, npeaks);
557 memset (&cache->data[npeaks], 0, sizeof (GnomeCanvasWaveViewCacheEntry) * (cache->allocated - npeaks));
558 cache->data_size = npeaks;
560 cache->data_size = cache->allocated;
563 if (waveview->gain_curve_function) {
566 gain = (float*) malloc (sizeof (float) * cache->data_size);
568 waveview->gain_curve_function (waveview->gain_src, new_cache_start, new_cache_end, gain, cache->data_size);
570 for (n = 0; n < cache->data_size; ++n) {
571 cache->data[n].min *= gain[n];
572 cache->data[n].max *= gain[n];
579 cache->start = ostart;
580 cache->end = new_cache_end;
584 fprintf (stderr, "return cache index = %d\n",
585 (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5));
587 return (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5);
592 gnome_canvas_waveview_set_data_src (GnomeCanvasWaveView *waveview, void *data_src)
595 if (waveview->cache_updater) {
596 if (waveview->data_src == data_src) {
597 waveview->reload_cache_in_render = TRUE;
601 waveview->cache->start = 0;
602 waveview->cache->end = 0;
605 waveview->data_src = data_src;
609 gnome_canvas_waveview_set_channel (GnomeCanvasWaveView *waveview, guint32 chan)
611 if (waveview->channel == chan) {
615 waveview->channel = chan;
619 gnome_canvas_waveview_reset_bounds (GnomeCanvasItem *item)
622 double x1, x2, y1, y2;
625 int Ix1, Ix2, Iy1, Iy2;
628 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
635 gnome_canvas_item_i2w_affine (item, i2w);
636 art_affine_point (&w1, &i1, i2w);
637 art_affine_point (&w2, &i2, i2w);
639 Ix1 = (int) rint(w1.x);
640 Ix2 = (int) rint(w2.x);
641 Iy1 = (int) rint(w1.y);
642 Iy2 = (int) rint(w2.y);
644 gnome_canvas_update_bbox (item, Ix1, Iy1, Ix2, Iy2);
652 gnome_canvas_waveview_set_property (GObject *object,
658 GnomeCanvasItem *item;
659 GnomeCanvasWaveView *waveview;
661 int calc_bounds = FALSE;
663 g_return_if_fail (object != NULL);
664 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
666 item = GNOME_CANVAS_ITEM (object);
667 waveview = GNOME_CANVAS_WAVEVIEW (object);
671 gnome_canvas_waveview_set_data_src (waveview, g_value_get_pointer(value));
676 gnome_canvas_waveview_set_channel (waveview, g_value_get_uint(value));
680 case PROP_LENGTH_FUNCTION:
681 waveview->length_function = g_value_get_pointer(value);
684 case PROP_SOURCEFILE_LENGTH_FUNCTION:
685 waveview->sourcefile_length_function = g_value_get_pointer(value);
689 case PROP_PEAK_FUNCTION:
690 waveview->peak_function = g_value_get_pointer(value);
694 case PROP_GAIN_FUNCTION:
695 waveview->gain_curve_function = g_value_get_pointer(value);
700 waveview->gain_src = g_value_get_pointer(value);
701 if (waveview->cache_updater) {
702 waveview->cache->start = 0;
703 waveview->cache->end = 0;
710 waveview->cache = g_value_get_pointer(value);
715 case PROP_CACHE_UPDATER:
716 waveview->cache_updater = g_value_get_boolean(value);
720 case PROP_SAMPLES_PER_UNIT:
721 if ((waveview->samples_per_unit = g_value_get_double(value)) < 1.0) {
722 waveview->samples_per_unit = 1.0;
724 if (waveview->cache_updater) {
725 waveview->cache->start = 0;
726 waveview->cache->end = 0;
732 case PROP_AMPLITUDE_ABOVE_AXIS:
733 waveview->amplitude_above_axis = g_value_get_double(value);
738 if (waveview->x != g_value_get_double (value)) {
739 waveview->x = g_value_get_double (value);
745 if (waveview->y != g_value_get_double (value)) {
746 waveview->y = g_value_get_double (value);
752 if (waveview->height != fabs (g_value_get_double (value))) {
753 waveview->height = fabs (g_value_get_double (value));
758 case PROP_WAVE_COLOR:
759 if (waveview->wave_color != g_value_get_uint(value)) {
760 waveview->wave_color = g_value_get_uint(value);
766 if (waveview->rectified != g_value_get_boolean(value)) {
767 waveview->rectified = g_value_get_boolean(value);
771 case PROP_REGION_START:
772 waveview->region_start = g_value_get_uint(value);
783 gnome_canvas_waveview_reset_bounds (item);
787 gnome_canvas_item_request_update (item);
793 gnome_canvas_waveview_get_property (GObject *object,
800 g_return_if_fail (object != NULL);
801 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
803 GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (object);
807 g_value_set_pointer(value, waveview->data_src);
811 g_value_set_uint(value, waveview->channel);
814 case PROP_LENGTH_FUNCTION:
815 g_value_set_pointer(value, waveview->length_function);
818 case PROP_SOURCEFILE_LENGTH_FUNCTION:
819 g_value_set_pointer(value, waveview->sourcefile_length_function);
822 case PROP_PEAK_FUNCTION:
823 g_value_set_pointer(value, waveview->peak_function);
826 case PROP_GAIN_FUNCTION:
827 g_value_set_pointer(value, waveview->gain_curve_function);
831 g_value_set_pointer(value, waveview->gain_src);
835 g_value_set_pointer(value, waveview->cache);
838 case PROP_CACHE_UPDATER:
839 g_value_set_boolean(value, waveview->cache_updater);
842 case PROP_SAMPLES_PER_UNIT:
843 g_value_set_double(value, waveview->samples_per_unit);
846 case PROP_AMPLITUDE_ABOVE_AXIS:
847 g_value_set_double(value, waveview->amplitude_above_axis);
851 g_value_set_double (value, waveview->x);
855 g_value_set_double (value, waveview->y);
859 g_value_set_double (value, waveview->height);
862 case PROP_WAVE_COLOR:
863 g_value_set_uint (value, waveview->wave_color);
867 g_value_set_boolean (value, waveview->rectified);
869 case PROP_REGION_START:
870 g_value_set_uint (value, waveview->region_start);
872 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
878 gnome_canvas_waveview_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
880 GnomeCanvasWaveView *waveview;
883 waveview = GNOME_CANVAS_WAVEVIEW (item);
885 // check_cache (waveview, "start of update");
887 if (parent_class->update)
888 (* parent_class->update) (item, affine, clip_path, flags);
890 gnome_canvas_waveview_reset_bounds (item);
892 /* get the canvas coordinates of the view. Do NOT use affines
893 for this, because they do not round to the integer units used
894 by the canvas, resulting in subtle pixel-level errors later.
900 gnome_canvas_item_i2w (item, &x, &y);
901 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_ulx, &waveview->bbox_uly);
903 waveview->samples = waveview->length_function (waveview->data_src);
905 x = waveview->x + (waveview->samples / waveview->samples_per_unit);
906 y = waveview->y + waveview->height;
908 gnome_canvas_item_i2w (item, &x, &y);
909 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_lrx, &waveview->bbox_lry);
911 /* cache the half-height and the end point in canvas units */
913 waveview->half_height = waveview->height / 2.0;
915 /* parse the color */
917 UINT_TO_RGBA (waveview->wave_color, &waveview->wave_r, &waveview->wave_g, &waveview->wave_b,
920 // check_cache (waveview, "end of update");
924 gnome_canvas_waveview_render (GnomeCanvasItem *item,
927 GnomeCanvasWaveView *waveview;
935 waveview = GNOME_CANVAS_WAVEVIEW (item);
937 // check_cache (waveview, "start of render");
939 if (parent_class->render) {
940 (*parent_class->render) (item, buf);
944 gnome_canvas_buf_ensure_buf (buf);
948 begin = MAX(waveview->bbox_ulx,buf->rect.x0);
950 if (waveview->bbox_lrx >= 0) {
951 end = MIN(waveview->bbox_lrx,buf->rect.x1);
960 s1 = floor ((begin - waveview->bbox_ulx) * waveview->samples_per_unit) ;
962 // fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit);
964 if (end == waveview->bbox_lrx) {
965 /* This avoids minor rounding errors when we have the
966 entire region visible.
968 s2 = waveview->samples;
970 s2 = s1 + floor ((end - begin) * waveview->samples_per_unit);
974 printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)"
975 " b/e %d..%d s= %lu..%lu\n",
988 /* now ensure that the cache is full and properly
992 // check_cache (waveview, "pre-ensure");
994 if (waveview->cache_updater && waveview->reload_cache_in_render) {
995 waveview->cache->start = 0;
996 waveview->cache->end = 0;
997 waveview->reload_cache_in_render = FALSE;
1000 cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
1002 // check_cache (waveview, "post-ensure");
1005 Now draw each line, clipping it appropriately. The clipping
1006 is done by the macros PAINT_FOO().
1009 half_height = waveview->half_height;
1011 /* this makes it slightly easier to comprehend whats going on */
1013 #define origin half_height
1015 for (x = begin; x < end; x++) {
1018 int clip_max, clip_min;
1023 max = waveview->cache->data[cache_index].max;
1024 min = waveview->cache->data[cache_index].min;
1036 /* don't rectify at single-sample zoom */
1038 if (waveview->rectified && waveview->samples_per_unit > 1) {
1040 if (fabs (min) > fabs (max)) {
1044 max = max * waveview->height;
1046 pymax = (int) rint ((item->y1 + waveview->height - max) * item->canvas->pixels_per_unit);
1047 pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
1051 max = max * half_height;
1052 min = min * half_height;
1054 pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
1055 pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
1058 /* OK, now fill the RGB buffer at x=i with a line between pymin and pymax,
1059 or, if samples_per_unit == 1, then a dot at each location.
1062 if (pymax == pymin) {
1063 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
1065 PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, pymin);
1068 /* show clipped waveforms with small red lines */
1070 if (clip_max || clip_min) {
1071 clip_length = MIN(5,(waveview->height/4));
1075 PAINT_VERT(buf, 255, 0, 0, x, pymax, pymax+clip_length);
1079 PAINT_VERT(buf, 255, 0, 0, x, pymin-clip_length, pymin);
1082 /* presto, we're done */
1092 gnome_canvas_waveview_draw (GnomeCanvasItem *item,
1093 GdkDrawable *drawable,
1095 int width, int height)
1097 GnomeCanvasWaveView *waveview;
1099 waveview = GNOME_CANVAS_WAVEVIEW (item);
1101 if (parent_class->draw) {
1102 (* parent_class->draw) (item, drawable, x, y, width, height);
1105 fprintf (stderr, "please don't use the CanvasWaveView item in a non-aa Canvas\n");
1110 gnome_canvas_waveview_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
1112 GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (item);
1117 *x2 = ceil (*x1 + (waveview->length_function (waveview->data_src) / waveview->samples_per_unit));
1118 *y2 = *y1 + waveview->height;
1122 gnome_canvas_item_i2w (item, &x, &y);
1123 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &a, &b);
1126 gnome_canvas_item_i2w (item, &x, &y);
1127 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &c, &d);
1128 printf ("item bounds now (%g,%g),(%g,%g)\n", a, b, c, d);
1134 gnome_canvas_waveview_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item)
1136 /* XXX for now, point is never inside the wave
1137 GnomeCanvasWaveView *waveview;
1138 double x1, y1, x2, y2;
1145 waveview = GNOME_CANVAS_WAVEVIEW (item);
1147 *actual_item = item;
1149 /* Find the bounds for the rectangle plus its outline width */
1151 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
1153 /* Is point inside rectangle */
1155 if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
1159 /* Point is outside rectangle */
1175 return sqrt (dx * dx + dy * dy);