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"
32 extern void c_stacktrace();
39 PROP_SOURCEFILE_LENGTH_FUNCTION,
45 PROP_SAMPLES_PER_UNIT,
46 PROP_AMPLITUDE_ABOVE_AXIS,
55 static void gnome_canvas_waveview_class_init (GnomeCanvasWaveViewClass *class);
57 static void gnome_canvas_waveview_init (GnomeCanvasWaveView *waveview);
59 static void gnome_canvas_waveview_destroy (GtkObject *object);
61 static void gnome_canvas_waveview_set_property (GObject *object,
65 static void gnome_canvas_waveview_get_property (GObject *object,
70 static void gnome_canvas_waveview_update (GnomeCanvasItem *item,
75 static void gnome_canvas_waveview_bounds (GnomeCanvasItem *item,
81 static double gnome_canvas_waveview_point (GnomeCanvasItem *item,
86 GnomeCanvasItem **actual_item);
88 static void gnome_canvas_waveview_render (GnomeCanvasItem *item,
91 static void gnome_canvas_waveview_draw (GnomeCanvasItem *item,
92 GdkDrawable *drawable,
98 static void gnome_canvas_waveview_set_data_src (GnomeCanvasWaveView *,
101 static void gnome_canvas_waveview_set_channel (GnomeCanvasWaveView *,
104 static gint32 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview,
108 static GnomeCanvasItemClass *parent_class;
111 gnome_canvas_waveview_get_type (void)
113 static GType waveview_type;
115 if (!waveview_type) {
116 static const GTypeInfo object_info = {
117 sizeof (GnomeCanvasWaveViewClass),
118 (GBaseInitFunc) NULL,
119 (GBaseFinalizeFunc) NULL,
120 (GClassInitFunc) gnome_canvas_waveview_class_init,
121 (GClassFinalizeFunc) NULL,
122 NULL, /* class_data */
123 sizeof (GnomeCanvasWaveView),
125 (GInstanceInitFunc) gnome_canvas_waveview_init,
126 NULL /* value_table */
129 waveview_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasWaveView",
133 return waveview_type;
137 gnome_canvas_waveview_class_init (GnomeCanvasWaveViewClass *class)
139 GObjectClass *gobject_class;
140 GtkObjectClass *object_class;
141 GnomeCanvasItemClass *item_class;
143 gobject_class = (GObjectClass *) class;
144 object_class = (GtkObjectClass *) class;
145 item_class = (GnomeCanvasItemClass *) class;
147 parent_class = g_type_class_peek_parent (class);
149 gobject_class->set_property = gnome_canvas_waveview_set_property;
150 gobject_class->get_property = gnome_canvas_waveview_get_property;
152 g_object_class_install_property
155 g_param_spec_pointer ("data_src", NULL, NULL,
156 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
158 g_object_class_install_property
161 g_param_spec_uint ("channel", NULL, NULL,
163 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
165 g_object_class_install_property
167 PROP_LENGTH_FUNCTION,
168 g_param_spec_pointer ("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_pointer ("sourcefile_length_function", NULL, NULL,
175 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
177 g_object_class_install_property
180 g_param_spec_pointer ("peak_function", NULL, NULL,
181 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
183 g_object_class_install_property
186 g_param_spec_pointer ("gain_function", NULL, NULL,
187 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
189 g_object_class_install_property
192 g_param_spec_pointer ("gain_src", NULL, NULL,
193 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
195 g_object_class_install_property
198 g_param_spec_pointer ("cache", NULL, NULL,
199 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
201 g_object_class_install_property
204 g_param_spec_boolean ("cache_updater", NULL, NULL,
206 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
208 g_object_class_install_property
210 PROP_SAMPLES_PER_UNIT,
211 g_param_spec_double ("samples_per_unit", NULL, NULL,
212 0.0, G_MAXDOUBLE, 0.0,
213 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
215 g_object_class_install_property
217 PROP_AMPLITUDE_ABOVE_AXIS,
218 g_param_spec_double ("amplitude_above_axis", NULL, NULL,
219 0.0, G_MAXDOUBLE, 0.0,
220 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
222 g_object_class_install_property
225 g_param_spec_double ("x", NULL, NULL,
226 0.0, G_MAXDOUBLE, 0.0,
227 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
229 g_object_class_install_property
232 g_param_spec_double ("y", NULL, NULL,
233 0.0, G_MAXDOUBLE, 0.0,
234 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
236 g_object_class_install_property
239 g_param_spec_double ("height", NULL, NULL,
240 0.0, G_MAXDOUBLE, 0.0,
241 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
243 g_object_class_install_property
246 g_param_spec_uint ("wave_color", NULL, NULL,
248 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
250 g_object_class_install_property
253 g_param_spec_boolean ("rectified", NULL, NULL,
255 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
257 g_object_class_install_property
260 g_param_spec_uint ("region_start", NULL, NULL,
262 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
264 object_class->destroy = gnome_canvas_waveview_destroy;
266 item_class->update = gnome_canvas_waveview_update;
267 item_class->bounds = gnome_canvas_waveview_bounds;
268 item_class->point = gnome_canvas_waveview_point;
269 item_class->render = gnome_canvas_waveview_render;
270 item_class->draw = gnome_canvas_waveview_draw;
273 GnomeCanvasWaveViewCache*
274 gnome_canvas_waveview_cache_new ()
276 GnomeCanvasWaveViewCache *c;
278 c = g_malloc (sizeof (GnomeCanvasWaveViewCache));
281 c->data = g_malloc (sizeof (GnomeCanvasWaveViewCacheEntry) * c->allocated);
290 gnome_canvas_waveview_cache_destroy (GnomeCanvasWaveViewCache* cache)
292 g_free (cache->data);
297 gnome_canvas_waveview_init (GnomeCanvasWaveView *waveview)
302 waveview->cache_updater = FALSE;
303 waveview->data_src = NULL;
304 waveview->channel = 0;
305 waveview->peak_function = NULL;
306 waveview->length_function = NULL;
307 waveview->sourcefile_length_function = NULL;
308 waveview->gain_curve_function = NULL;
309 waveview->gain_src = NULL;
310 waveview->rectified = FALSE;
311 waveview->region_start = 0;
312 waveview->samples_per_unit = 1.0;
313 waveview->amplitude_above_axis = 1.0;
314 waveview->height = 100.0;
315 waveview->screen_width = gdk_screen_width ();
316 waveview->reload_cache_in_render = FALSE;
318 waveview->wave_color = RGBA_TO_UINT(44,35,126,255);
322 gnome_canvas_waveview_destroy (GtkObject *object)
324 GnomeCanvasWaveView *waveview;
326 g_return_if_fail (object != NULL);
327 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
329 waveview = GNOME_CANVAS_WAVEVIEW (object);
331 if (GTK_OBJECT_CLASS (parent_class)->destroy)
332 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
335 #define DEBUG_CACHE 0
336 #undef CACHE_MEMMOVE_OPTIMIZATION
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;
351 #ifdef CACHE_MEMMOVE_OPTIMIZATION
352 gulong present_frames;
353 gulong present_entries;
356 cache = waveview->cache;
358 start_sample = start_sample + waveview->region_start;
359 end_sample = end_sample + waveview->region_start;
361 // printf("waveview->region_start == %lu\n",waveview->region_start);
362 printf ("=> 0x%x cache @ 0x%x range: %lu - %lu request: %lu - %lu (%lu frames)\n",
364 cache->start, cache->end,
365 start_sample, end_sample, end_sample - start_sample);
368 if (cache->start <= start_sample && cache->end >= end_sample) {
370 // printf ("0x%x: cache hit for %lu-%lu (cache holds: %lu-%lu\n",
371 // waveview, start_sample, end_sample, cache->start, cache->end);
376 /* make sure the cache is at least twice as wide as the screen width, and put the start sample
377 in the middle, ensuring that we cover the end_sample.
380 /* Note the assumption that we have a 1:1 units:pixel ratio for the canvas. Its everywhere ... */
382 half_width = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit)/2.0 + 0.5);
384 if (start_sample < half_width) {
387 new_cache_start = start_sample - half_width;
390 /* figure out how many frames we want */
392 rf1 = end_sample - start_sample + 1;
393 rf2 = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit * 2.0f));
394 required_frames = MAX(rf1,rf2);
396 /* but make sure it doesn't extend beyond the end of the source material */
398 rf3 = (gulong) (waveview->sourcefile_length_function (waveview->data_src, waveview->samples_per_unit)) + 1;
399 if (rf3 < new_cache_start) {
402 rf3 -= new_cache_start;
406 fprintf (stderr, "\n\nAVAILABLE FRAMES = %lu of %lu, start = %lu, sstart = %lu, cstart = %lu\n",
407 rf3, waveview->sourcefile_length_function (waveview->data_src, waveview->samples_per_unit),
408 waveview->region_start, start_sample, new_cache_start);
411 required_frames = MIN(required_frames,rf3);
413 new_cache_end = new_cache_start + required_frames - 1;
415 required_cache_entries = (gulong) floor (required_frames / waveview->samples_per_unit );
418 fprintf (stderr, "new cache = %lu - %lu\n", new_cache_start, new_cache_end);
419 fprintf(stderr,"required_cach_entries = %lu, samples_per_unit = %f req frames = %lu\n",
420 required_cache_entries,waveview->samples_per_unit, required_frames);
423 if (required_cache_entries > cache->allocated) {
424 cache->data = g_realloc (cache->data, sizeof (GnomeCanvasWaveViewCacheEntry) * required_cache_entries);
425 cache->allocated = required_cache_entries;
430 ostart = new_cache_start;
432 #ifdef CACHE_MEMMOVE_OPTIMIZATION
434 /* data is not entirely in the cache, so go fetch it, making sure to fill the cache */
436 /* some of the required cache entries are in the cache, but in the wrong
437 locations. use memmove to fix this.
440 if (cache->start < new_cache_start && new_cache_start < cache->end) {
442 /* case one: the common area is at the end of the existing cache. move it
443 to the beginning of the cache, and set up to refill whatever remains.
446 wv->cache_start wv->cache_end
447 |-------------------------------------------------------| cache
448 |--------------------------------| requested
449 <------------------->
451 new_cache_start new_cache_end
455 present_frames = cache->end - new_cache_start;
456 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
459 fprintf (stderr, "existing material at end of current cache, move to start of new cache\n"
460 "\tcopy from %lu to start\n", cache->data_size - present_entries);
463 memmove (&cache->data[0],
464 &cache->data[cache->data_size - present_entries],
465 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
468 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
469 present_frames, required_frames, present_entries, new_cache_start + present_entries,
470 cache->data + present_entries);
473 copied = present_entries;
474 offset = present_entries;
475 new_cache_start += present_frames;
476 required_frames -= present_frames;
478 } else if (new_cache_end > cache->start && new_cache_end < cache->end) {
480 /* case two: the common area lives at the beginning of the existing cache.
482 wv->cache_start wv->cache_end
483 |-----------------------------------------------------|
484 |--------------------------------|
488 new_cache_start new_cache_end
491 present_frames = new_cache_end - cache->start;
492 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
494 memmove (&cache->data[cache->data_size - present_entries],
496 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
499 fprintf (stderr, "existing material at start of current cache, move to start of end cache\n");
503 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
504 present_entries, required_frames, present_entries, new_cache_start + present_entries,
505 cache->data + present_entries);
508 copied = present_entries;
510 required_frames -= present_frames;
523 #endif /* CACHE_MEMMOVE_OPTIMIZATION */
525 // fprintf(stderr,"length == %lu\n",waveview->length_function (waveview->data_src));
526 // required_frames = MIN (waveview->length_function (waveview->data_src) - new_cache_start, required_frames);
528 npeaks = (gulong) floor (required_frames / waveview->samples_per_unit);
529 required_frames = npeaks * waveview->samples_per_unit;
534 printf ("requesting %lu/%f to cover %lu-%lu at %f spu (request was %lu-%lu) into cache + %lu\n",
535 required_frames, required_frames/waveview->samples_per_unit, new_cache_start, new_cache_end,
536 waveview->samples_per_unit, start_sample, end_sample, offset);
540 // printf ("cache holds %lu entries, requesting %lu to cover %lu-%lu (request was %lu-%lu)\n",
541 // cache->data_size, npeaks, new_cache_start, new_cache_end,
542 // start_sample, end_sample);
545 if (required_frames) {
546 waveview->peak_function (waveview->data_src, npeaks, new_cache_start, required_frames, cache->data + offset, waveview->channel,waveview->samples_per_unit);
548 /* take into account any copied peaks */
555 if (npeaks < cache->allocated) {
557 fprintf (stderr, "zero fill cache for %lu at %lu\n", cache->allocated - npeaks, npeaks);
559 memset (&cache->data[npeaks], 0, sizeof (GnomeCanvasWaveViewCacheEntry) * (cache->allocated - npeaks));
560 cache->data_size = npeaks;
562 cache->data_size = cache->allocated;
565 if (waveview->gain_curve_function) {
568 gain = (float*) malloc (sizeof (float) * cache->data_size);
570 waveview->gain_curve_function (waveview->gain_src, new_cache_start, new_cache_end, gain, cache->data_size);
572 for (n = 0; n < cache->data_size; ++n) {
573 cache->data[n].min *= gain[n];
574 cache->data[n].max *= gain[n];
581 cache->start = ostart;
582 cache->end = new_cache_end;
586 fprintf (stderr, "return cache index = %d\n",
587 (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5));
589 return (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5);
594 gnome_canvas_waveview_set_data_src (GnomeCanvasWaveView *waveview, void *data_src)
597 if (waveview->cache_updater) {
598 if (waveview->data_src == data_src) {
599 waveview->reload_cache_in_render = TRUE;
603 waveview->cache->start = 0;
604 waveview->cache->end = 0;
607 waveview->data_src = data_src;
611 gnome_canvas_waveview_set_channel (GnomeCanvasWaveView *waveview, guint32 chan)
613 if (waveview->channel == chan) {
617 waveview->channel = chan;
621 gnome_canvas_waveview_reset_bounds (GnomeCanvasItem *item)
624 double x1, x2, y1, y2;
627 int Ix1, Ix2, Iy1, Iy2;
630 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
637 gnome_canvas_item_i2w_affine (item, i2w);
638 art_affine_point (&w1, &i1, i2w);
639 art_affine_point (&w2, &i2, i2w);
641 Ix1 = (int) rint(w1.x);
642 Ix2 = (int) rint(w2.x);
643 Iy1 = (int) rint(w1.y);
644 Iy2 = (int) rint(w2.y);
646 gnome_canvas_update_bbox (item, Ix1, Iy1, Ix2, Iy2);
654 gnome_canvas_waveview_set_property (GObject *object,
660 GnomeCanvasItem *item;
661 GnomeCanvasWaveView *waveview;
663 int calc_bounds = FALSE;
665 g_return_if_fail (object != NULL);
666 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
668 item = GNOME_CANVAS_ITEM (object);
669 waveview = GNOME_CANVAS_WAVEVIEW (object);
673 gnome_canvas_waveview_set_data_src (waveview, g_value_get_pointer(value));
678 gnome_canvas_waveview_set_channel (waveview, g_value_get_uint(value));
682 case PROP_LENGTH_FUNCTION:
683 waveview->length_function = g_value_get_pointer(value);
686 case PROP_SOURCEFILE_LENGTH_FUNCTION:
687 waveview->sourcefile_length_function = g_value_get_pointer(value);
691 case PROP_PEAK_FUNCTION:
692 waveview->peak_function = g_value_get_pointer(value);
696 case PROP_GAIN_FUNCTION:
697 waveview->gain_curve_function = g_value_get_pointer(value);
702 waveview->gain_src = g_value_get_pointer(value);
703 if (waveview->cache_updater) {
704 waveview->cache->start = 0;
705 waveview->cache->end = 0;
712 waveview->cache = g_value_get_pointer(value);
717 case PROP_CACHE_UPDATER:
718 waveview->cache_updater = g_value_get_boolean(value);
722 case PROP_SAMPLES_PER_UNIT:
723 if ((waveview->samples_per_unit = g_value_get_double(value)) < 1.0) {
724 waveview->samples_per_unit = 1.0;
726 if (waveview->cache_updater) {
727 waveview->cache->start = 0;
728 waveview->cache->end = 0;
734 case PROP_AMPLITUDE_ABOVE_AXIS:
735 waveview->amplitude_above_axis = g_value_get_double(value);
740 if (waveview->x != g_value_get_double (value)) {
741 waveview->x = g_value_get_double (value);
747 if (waveview->y != g_value_get_double (value)) {
748 waveview->y = g_value_get_double (value);
754 if (waveview->height != fabs (g_value_get_double (value))) {
755 waveview->height = fabs (g_value_get_double (value));
760 case PROP_WAVE_COLOR:
761 if (waveview->wave_color != g_value_get_uint(value)) {
762 waveview->wave_color = g_value_get_uint(value);
768 if (waveview->rectified != g_value_get_boolean(value)) {
769 waveview->rectified = g_value_get_boolean(value);
773 case PROP_REGION_START:
774 waveview->region_start = g_value_get_uint(value);
785 gnome_canvas_waveview_reset_bounds (item);
789 gnome_canvas_item_request_update (item);
795 gnome_canvas_waveview_get_property (GObject *object,
802 g_return_if_fail (object != NULL);
803 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
805 GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (object);
809 g_value_set_pointer(value, waveview->data_src);
813 g_value_set_uint(value, waveview->channel);
816 case PROP_LENGTH_FUNCTION:
817 g_value_set_pointer(value, waveview->length_function);
820 case PROP_SOURCEFILE_LENGTH_FUNCTION:
821 g_value_set_pointer(value, waveview->sourcefile_length_function);
824 case PROP_PEAK_FUNCTION:
825 g_value_set_pointer(value, waveview->peak_function);
828 case PROP_GAIN_FUNCTION:
829 g_value_set_pointer(value, waveview->gain_curve_function);
833 g_value_set_pointer(value, waveview->gain_src);
837 g_value_set_pointer(value, waveview->cache);
840 case PROP_CACHE_UPDATER:
841 g_value_set_boolean(value, waveview->cache_updater);
844 case PROP_SAMPLES_PER_UNIT:
845 g_value_set_double(value, waveview->samples_per_unit);
848 case PROP_AMPLITUDE_ABOVE_AXIS:
849 g_value_set_double(value, waveview->amplitude_above_axis);
853 g_value_set_double (value, waveview->x);
857 g_value_set_double (value, waveview->y);
861 g_value_set_double (value, waveview->height);
864 case PROP_WAVE_COLOR:
865 g_value_set_uint (value, waveview->wave_color);
869 g_value_set_boolean (value, waveview->rectified);
872 case PROP_REGION_START:
873 g_value_set_uint (value, waveview->region_start);
877 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
883 gnome_canvas_waveview_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
885 GnomeCanvasWaveView *waveview;
888 waveview = GNOME_CANVAS_WAVEVIEW (item);
890 // check_cache (waveview, "start of update");
892 if (parent_class->update)
893 (* parent_class->update) (item, affine, clip_path, flags);
895 gnome_canvas_waveview_reset_bounds (item);
897 /* get the canvas coordinates of the view. Do NOT use affines
898 for this, because they do not round to the integer units used
899 by the canvas, resulting in subtle pixel-level errors later.
905 gnome_canvas_item_i2w (item, &x, &y);
906 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_ulx, &waveview->bbox_uly);
908 waveview->samples = waveview->length_function (waveview->data_src);
910 x = waveview->x + (waveview->samples / waveview->samples_per_unit);
911 y = waveview->y + waveview->height;
913 gnome_canvas_item_i2w (item, &x, &y);
914 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_lrx, &waveview->bbox_lry);
916 /* cache the half-height and the end point in canvas units */
918 waveview->half_height = waveview->height / 2.0;
920 /* parse the color */
922 UINT_TO_RGBA (waveview->wave_color, &waveview->wave_r, &waveview->wave_g, &waveview->wave_b,
925 // check_cache (waveview, "end of update");
929 gnome_canvas_waveview_render (GnomeCanvasItem *item,
932 GnomeCanvasWaveView *waveview;
940 waveview = GNOME_CANVAS_WAVEVIEW (item);
942 // check_cache (waveview, "start of render");
944 if (parent_class->render) {
945 (*parent_class->render) (item, buf);
949 gnome_canvas_buf_ensure_buf (buf);
953 begin = MAX(waveview->bbox_ulx,buf->rect.x0);
955 if (waveview->bbox_lrx >= 0) {
956 end = MIN(waveview->bbox_lrx,buf->rect.x1);
965 s1 = floor ((begin - waveview->bbox_ulx) * waveview->samples_per_unit) ;
967 // fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit);
969 if (end == waveview->bbox_lrx) {
970 /* This avoids minor rounding errors when we have the
971 entire region visible.
973 s2 = waveview->samples;
975 s2 = s1 + floor ((end - begin) * waveview->samples_per_unit);
979 printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)"
980 " b/e %d..%d s= %lu..%lu @ %f\n",
991 waveview->samples_per_unit);
994 /* now ensure that the cache is full and properly
998 // check_cache (waveview, "pre-ensure");
1000 if (waveview->cache_updater && waveview->reload_cache_in_render) {
1001 waveview->cache->start = 0;
1002 waveview->cache->end = 0;
1003 waveview->reload_cache_in_render = FALSE;
1006 cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
1008 // check_cache (waveview, "post-ensure");
1011 Now draw each line, clipping it appropriately. The clipping
1012 is done by the macros PAINT_FOO().
1015 half_height = waveview->half_height;
1017 /* this makes it slightly easier to comprehend whats going on */
1019 #define origin half_height
1021 for (x = begin; x < end; x++) {
1024 int clip_max, clip_min;
1029 max = waveview->cache->data[cache_index].max;
1030 min = waveview->cache->data[cache_index].min;
1042 /* don't rectify at single-sample zoom */
1044 if (waveview->rectified && waveview->samples_per_unit > 1) {
1046 if (fabs (min) > fabs (max)) {
1050 max = max * waveview->height;
1052 pymax = (int) rint ((item->y1 + waveview->height - max) * item->canvas->pixels_per_unit);
1053 pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
1057 max = max * half_height;
1058 min = min * half_height;
1060 pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
1061 pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
1064 /* OK, now fill the RGB buffer at x=i with a line between pymin and pymax,
1065 or, if samples_per_unit == 1, then a dot at each location.
1068 if (pymax == pymin) {
1069 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
1071 PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, pymin);
1074 /* show clipped waveforms with small red lines */
1076 if (clip_max || clip_min) {
1077 clip_length = MIN(5,(waveview->height/4));
1081 PAINT_VERT(buf, 255, 0, 0, x, pymax, pymax+clip_length);
1085 PAINT_VERT(buf, 255, 0, 0, x, pymin-clip_length, pymin);
1088 /* presto, we're done */
1098 gnome_canvas_waveview_draw (GnomeCanvasItem *item,
1099 GdkDrawable *drawable,
1101 int width, int height)
1103 GnomeCanvasWaveView *waveview;
1105 waveview = GNOME_CANVAS_WAVEVIEW (item);
1107 if (parent_class->draw) {
1108 (* parent_class->draw) (item, drawable, x, y, width, height);
1111 fprintf (stderr, "please don't use the CanvasWaveView item in a non-aa Canvas\n");
1116 gnome_canvas_waveview_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
1118 GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (item);
1123 *x2 = ceil (*x1 + (waveview->length_function (waveview->data_src) / waveview->samples_per_unit));
1124 *y2 = *y1 + waveview->height;
1128 gnome_canvas_item_i2w (item, &x, &y);
1129 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &a, &b);
1132 gnome_canvas_item_i2w (item, &x, &y);
1133 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &c, &d);
1134 printf ("item bounds now (%g,%g),(%g,%g)\n", a, b, c, d);
1140 gnome_canvas_waveview_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item)
1142 /* XXX for now, point is never inside the wave
1143 GnomeCanvasWaveView *waveview;
1144 double x1, y1, x2, y2;
1151 waveview = GNOME_CANVAS_WAVEVIEW (item);
1153 *actual_item = item;
1155 /* Find the bounds for the rectangle plus its outline width */
1157 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
1159 /* Is point inside rectangle */
1161 if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
1165 /* Point is outside rectangle */
1181 return sqrt (dx * dx + dy * dy);