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"
42 ARG_SAMPLES_PER_PIXEL,
43 ARG_AMPLITUDE_ABOVE_AXIS,
49 ARG_SOURCEFILE_LENGTH_FUNCTION,
53 static void gnome_canvas_waveview_class_init (GnomeCanvasWaveViewClass *class);
54 static void gnome_canvas_waveview_init (GnomeCanvasWaveView *waveview);
55 static void gnome_canvas_waveview_set_arg (GtkObject *object,
58 static void gnome_canvas_waveview_get_arg (GtkObject *object,
62 static void gnome_canvas_waveview_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
63 static void gnome_canvas_waveview_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2);
64 static double gnome_canvas_waveview_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item);
66 static void gnome_canvas_waveview_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf);
67 static void gnome_canvas_waveview_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int w, int h);
69 static void gnome_canvas_waveview_set_data_src (GnomeCanvasWaveView *, void *);
70 static void gnome_canvas_waveview_set_channel (GnomeCanvasWaveView *, guint32);
72 static gint32 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_sample, gulong end_sample);
74 static GnomeCanvasItemClass *parent_class;
77 gnome_canvas_waveview_get_type (void)
79 static GtkType waveview_type = 0;
82 GtkTypeInfo waveview_info = {
83 "GnomeCanvasWaveView",
84 sizeof (GnomeCanvasWaveView),
85 sizeof (GnomeCanvasWaveViewClass),
86 (GtkClassInitFunc) gnome_canvas_waveview_class_init,
87 (GtkObjectInitFunc) gnome_canvas_waveview_init,
88 NULL, /* reserved_1 */
89 NULL, /* reserved_2 */
90 (GtkClassInitFunc) NULL
93 waveview_type = gtk_type_unique (gnome_canvas_item_get_type (), &waveview_info);
100 gnome_canvas_waveview_class_init (GnomeCanvasWaveViewClass *class)
102 GtkObjectClass *object_class;
103 GnomeCanvasItemClass *item_class;
105 object_class = (GtkObjectClass *) class;
106 item_class = (GnomeCanvasItemClass *) class;
108 parent_class = gtk_type_class (gnome_canvas_item_get_type ());
110 gtk_object_add_arg_type ("GnomeCanvasWaveView::data-src", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_DATA_SRC);
111 gtk_object_add_arg_type ("GnomeCanvasWaveView::channel", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_CHANNEL);
112 gtk_object_add_arg_type ("GnomeCanvasWaveView::length-function", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_LENGTH_FUNCTION);
113 gtk_object_add_arg_type ("GnomeCanvasWaveView::sourcefile-length-function", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_SOURCEFILE_LENGTH_FUNCTION);
114 gtk_object_add_arg_type ("GnomeCanvasWaveView::peak-function", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_PEAK_FUNCTION);
115 gtk_object_add_arg_type ("GnomeCanvasWaveView::gain-function", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_GAIN_FUNCTION);
116 gtk_object_add_arg_type ("GnomeCanvasWaveView::gain-src", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_GAIN_SRC);
117 gtk_object_add_arg_type ("GnomeCanvasWaveView::cache", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_CACHE);
118 gtk_object_add_arg_type ("GnomeCanvasWaveView::cache-updater", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_CACHE_UPDATER);
119 gtk_object_add_arg_type ("GnomeCanvasWaveView::samples-per-unit", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_SAMPLES_PER_PIXEL);
120 gtk_object_add_arg_type ("GnomeCanvasWaveView::amplitude_above_axis", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_AMPLITUDE_ABOVE_AXIS);
121 gtk_object_add_arg_type ("GnomeCanvasWaveView::x", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X);
122 gtk_object_add_arg_type ("GnomeCanvasWaveView::y", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y);
123 gtk_object_add_arg_type ("GnomeCanvasWaveView::height", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_HEIGHT);
124 gtk_object_add_arg_type ("GnomeCanvasWaveView::wave-color", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_WAVE_COLOR);
125 gtk_object_add_arg_type ("GnomeCanvasWaveView::rectified", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_RECTIFIED);
126 gtk_object_add_arg_type ("GnomeCanvasWaveView::region-start", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_REGION_START);
128 object_class->set_arg = gnome_canvas_waveview_set_arg;
129 object_class->get_arg = gnome_canvas_waveview_get_arg;
131 item_class->update = gnome_canvas_waveview_update;
132 item_class->bounds = gnome_canvas_waveview_bounds;
133 item_class->point = gnome_canvas_waveview_point;
134 item_class->render = gnome_canvas_waveview_render;
135 item_class->draw = gnome_canvas_waveview_draw;
138 GnomeCanvasWaveViewCache*
139 gnome_canvas_waveview_cache_new ()
141 GnomeCanvasWaveViewCache *c;
143 c = g_malloc (sizeof (GnomeCanvasWaveViewCache));
146 c->data = g_malloc (sizeof (GnomeCanvasWaveViewCacheEntry) * c->allocated);
155 gnome_canvas_waveview_cache_destroy (GnomeCanvasWaveViewCache* cache)
157 g_free (cache->data);
162 gnome_canvas_waveview_init (GnomeCanvasWaveView *waveview)
167 waveview->cache_updater = FALSE;
168 waveview->data_src = NULL;
169 waveview->channel = 0;
170 waveview->peak_function = NULL;
171 waveview->length_function = NULL;
172 waveview->sourcefile_length_function = NULL;
173 waveview->gain_curve_function = NULL;
174 waveview->gain_src = NULL;
175 waveview->rectified = FALSE;
176 waveview->region_start = 0;
177 waveview->samples_per_unit = 1.0;
178 waveview->amplitude_above_axis = 1.0;
179 waveview->height = 100.0;
180 waveview->screen_width = gdk_screen_width ();
181 waveview->reload_cache_in_render = FALSE;
183 waveview->wave_color = RGBA_TO_UINT(44,35,126,255);
186 // GNOME_CANVAS_ITEM(waveview)->object.flags |= GNOME_CANVAS_ITEM_NO_AUTO_REDRAW;
189 #define DEBUG_CACHE 0
192 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_sample, gulong end_sample)
194 gulong required_cache_entries;
195 gulong rf1, rf2,rf3, required_frames;
196 gulong new_cache_start, new_cache_end;
202 GnomeCanvasWaveViewCache *cache;
205 cache = waveview->cache;
207 start_sample = start_sample + waveview->region_start;
208 end_sample = end_sample + waveview->region_start;
210 // printf("waveview->region_start == %lu\n",waveview->region_start);
211 printf ("=> 0x%x cache @ 0x%x range: %lu - %lu request: %lu - %lu (%lu frames)\n",
213 cache->start, cache->end,
214 start_sample, end_sample, end_sample - start_sample);
217 if (cache->start <= start_sample && cache->end >= end_sample) {
219 // printf ("0x%x: cache hit for %lu-%lu (cache holds: %lu-%lu\n",
220 // waveview, start_sample, end_sample, cache->start, cache->end);
225 /* make sure the cache is at least twice as wide as the screen width, and put the start sample
226 in the middle, ensuring that we cover the end_sample.
229 /* Note the assumption that we have a 1:1 units:pixel ratio for the canvas. Its everywhere ... */
231 half_width = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit)/2.0 + 0.5);
233 if (start_sample < half_width) {
236 new_cache_start = start_sample - half_width;
239 /* figure out how many frames we want */
241 rf1 = end_sample - start_sample + 1;
242 rf2 = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit * 2.0f));
243 required_frames = MAX(rf1,rf2);
245 /* but make sure it doesn't extend beyond the end of the source material */
247 rf3 = (gulong) (waveview->sourcefile_length_function (waveview->data_src)) + 1;
248 rf3 -= new_cache_start;
251 fprintf (stderr, "\n\nAVAILABLE FRAMES = %lu of %lu, start = %lu, sstart = %lu, cstart = %lu\n",
252 rf3, waveview->sourcefile_length_function (waveview->data_src),
253 waveview->region_start, start_sample, new_cache_start);
256 required_frames = MIN(required_frames,rf3);
258 new_cache_end = new_cache_start + required_frames - 1;
260 required_cache_entries = (gulong) floor (required_frames / waveview->samples_per_unit );
263 fprintf (stderr, "new cache = %lu - %lu\n", new_cache_start, new_cache_end);
264 fprintf(stderr,"required_cach_entries = %lu, samples_per_unit = %f\n",
265 required_cache_entries,waveview->samples_per_unit);
268 if (required_cache_entries > cache->allocated) {
269 cache->data = g_realloc (cache->data, sizeof (GnomeCanvasWaveViewCacheEntry) * required_cache_entries);
270 cache->allocated = required_cache_entries;
275 ostart = new_cache_start;
277 #undef CACHE_MEMMOVE_OPTIMIZATION
278 #ifdef CACHE_MEMMOVE_OPTIMIZATION
280 /* data is not entirely in the cache, so go fetch it, making sure to fill the cache */
282 /* some of the required cache entries are in the cache, but in the wrong
283 locations. use memmove to fix this.
286 if (cache->start < new_cache_start && new_cache_start < cache->end) {
288 /* case one: the common area is at the end of the existing cache. move it
289 to the beginning of the cache, and set up to refill whatever remains.
292 wv->cache_start wv->cache_end
293 |-------------------------------------------------------| cache
294 |--------------------------------| requested
295 <------------------->
297 new_cache_start new_cache_end
301 present_frames = cache->end - new_cache_start;
302 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
305 fprintf (stderr, "existing material at end of current cache, move to start of new cache\n"
306 "\tcopy from %lu to start\n", cache->data_size - present_entries);
309 memmove (&cache->data[0],
310 &cache->data[cache->data_size - present_entries],
311 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
314 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
315 present_frames, required_frames, present_entries, new_cache_start + present_entries,
316 cache->data + present_entries);
319 copied = present_entries;
320 offset = present_entries;
321 new_cache_start += present_frames;
322 required_frames -= present_frames;
324 } else if (new_cache_end > cache->start && new_cache_end < cache->end) {
326 /* case two: the common area lives at the beginning of the existing cache.
328 wv->cache_start wv->cache_end
329 |-----------------------------------------------------|
330 |--------------------------------|
334 new_cache_start new_cache_end
337 present_frames = new_cache_end - cache->start;
338 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
340 memmove (&cache->data[cache->data_size - present_entries],
342 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
345 fprintf (stderr, "existing material at start of current cache, move to start of end cache\n");
349 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
350 present_entries, required_frames, present_entries, new_cache_start + present_entries,
351 cache->data + present_entries);
354 copied = present_entries;
356 required_frames -= present_frames;
369 #endif /* CACHE_MEMMOVE_OPTIMIZATION */
371 // fprintf(stderr,"length == %lu\n",waveview->length_function (waveview->data_src));
372 // required_frames = MIN (waveview->length_function (waveview->data_src) - new_cache_start, required_frames);
373 npeaks = (gulong) floor (required_frames / waveview->samples_per_unit);
374 npeaks = MAX (1, npeaks);
375 required_frames = npeaks * waveview->samples_per_unit;
380 printf ("requesting %lu/%f to cover %lu-%lu at %f spu (request was %lu-%lu) into cache + %lu\n",
381 required_frames, required_frames/waveview->samples_per_unit, new_cache_start, new_cache_end,
382 waveview->samples_per_unit, start_sample, end_sample, offset);
386 // printf ("cache holds %lu entries, requesting %lu to cover %lu-%lu (request was %lu-%lu)\n",
387 // cache->data_size, npeaks, new_cache_start, new_cache_end,
388 // start_sample, end_sample);
391 waveview->peak_function (waveview->data_src, npeaks, new_cache_start, required_frames, cache->data + offset, waveview->channel,waveview->samples_per_unit);
393 /* take into account any copied peaks */
397 if (npeaks < cache->allocated) {
399 fprintf (stderr, "zero fill cache for %lu at %lu\n", cache->allocated - npeaks, npeaks);
401 memset (&cache->data[npeaks], 0, sizeof (GnomeCanvasWaveViewCacheEntry) * (cache->allocated - npeaks));
402 cache->data_size = npeaks;
404 cache->data_size = cache->allocated;
407 if (waveview->gain_curve_function) {
410 gain = (float*) malloc (sizeof (float) * cache->data_size);
412 waveview->gain_curve_function (waveview->gain_src, new_cache_start, new_cache_end, gain, cache->data_size);
414 for (n = 0; n < cache->data_size; ++n) {
415 cache->data[n].min *= gain[n];
416 cache->data[n].max *= gain[n];
423 cache->start = ostart;
424 cache->end = new_cache_end;
428 fprintf (stderr, "return cache index = %d\n",
429 (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5));
431 return (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5);
436 gnome_canvas_waveview_set_data_src (GnomeCanvasWaveView *waveview, void *data_src)
439 if (waveview->cache_updater) {
440 if (waveview->data_src == data_src) {
441 waveview->reload_cache_in_render = TRUE;
445 waveview->cache->start = 0;
446 waveview->cache->end = 0;
449 waveview->data_src = data_src;
453 gnome_canvas_waveview_set_channel (GnomeCanvasWaveView *waveview, guint32 chan)
455 if (waveview->channel == chan) {
459 waveview->channel = chan;
463 gnome_canvas_waveview_reset_bounds (GnomeCanvasItem *item)
466 double x1, x2, y1, y2;
469 int Ix1, Ix2, Iy1, Iy2;
472 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
479 gnome_canvas_item_i2w_affine (item, i2w);
480 art_affine_point (&w1, &i1, i2w);
481 art_affine_point (&w2, &i2, i2w);
483 Ix1 = (int) rint(w1.x);
484 Ix2 = (int) rint(w2.x);
485 Iy1 = (int) rint(w1.y);
486 Iy2 = (int) rint(w2.y);
488 gnome_canvas_update_bbox (item, Ix1, Iy1, Ix2, Iy2);
496 gnome_canvas_waveview_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
498 GnomeCanvasItem *item;
499 GnomeCanvasWaveView *waveview;
503 item = GNOME_CANVAS_ITEM (object);
504 waveview = GNOME_CANVAS_WAVEVIEW (object);
511 gnome_canvas_waveview_set_data_src (waveview, GTK_VALUE_POINTER(*arg));
516 gnome_canvas_waveview_set_channel (waveview, GTK_VALUE_UINT(*arg));
520 case ARG_LENGTH_FUNCTION:
521 waveview->length_function = GTK_VALUE_POINTER(*arg);
524 case ARG_SOURCEFILE_LENGTH_FUNCTION:
525 waveview->sourcefile_length_function = GTK_VALUE_POINTER(*arg);
529 case ARG_PEAK_FUNCTION:
530 waveview->peak_function = GTK_VALUE_POINTER(*arg);
534 case ARG_GAIN_FUNCTION:
535 waveview->gain_curve_function = GTK_VALUE_POINTER(*arg);
540 waveview->gain_src = GTK_VALUE_POINTER(*arg);
541 if (waveview->cache_updater) {
542 waveview->cache->start = 0;
543 waveview->cache->end = 0;
550 waveview->cache = GTK_VALUE_POINTER(*arg);
555 case ARG_CACHE_UPDATER:
556 waveview->cache_updater = GTK_VALUE_BOOL(*arg);
560 case ARG_SAMPLES_PER_PIXEL:
561 if ((waveview->samples_per_unit = GTK_VALUE_DOUBLE(*arg)) < 1.0) {
562 waveview->samples_per_unit = 1.0;
564 if (waveview->cache_updater) {
565 waveview->cache->start = 0;
566 waveview->cache->end = 0;
572 case ARG_AMPLITUDE_ABOVE_AXIS:
573 waveview->amplitude_above_axis = GTK_VALUE_DOUBLE(*arg);
578 if (waveview->x != GTK_VALUE_DOUBLE (*arg)) {
579 waveview->x = GTK_VALUE_DOUBLE (*arg);
585 if (waveview->y != GTK_VALUE_DOUBLE (*arg)) {
586 waveview->y = GTK_VALUE_DOUBLE (*arg);
592 if (waveview->height != fabs (GTK_VALUE_DOUBLE (*arg))) {
593 waveview->height = fabs (GTK_VALUE_DOUBLE (*arg));
599 if (waveview->wave_color != GTK_VALUE_INT(*arg)) {
600 waveview->wave_color = GTK_VALUE_INT(*arg);
606 if (waveview->rectified != GTK_VALUE_BOOL(*arg)) {
607 waveview->rectified = GTK_VALUE_BOOL(*arg);
611 case ARG_REGION_START:
612 waveview->region_start = GTK_VALUE_UINT(*arg);
623 gnome_canvas_waveview_reset_bounds (item);
627 gnome_canvas_item_request_update (item);
633 gnome_canvas_waveview_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
635 GnomeCanvasWaveView *waveview;
637 waveview = GNOME_CANVAS_WAVEVIEW (object);
641 GTK_VALUE_POINTER(*arg) = waveview->data_src;
645 GTK_VALUE_UINT(*arg) = waveview->channel;
648 case ARG_LENGTH_FUNCTION:
649 GTK_VALUE_POINTER(*arg) = waveview->length_function;
652 case ARG_SOURCEFILE_LENGTH_FUNCTION:
653 GTK_VALUE_POINTER(*arg) = waveview->sourcefile_length_function;
656 case ARG_PEAK_FUNCTION:
657 GTK_VALUE_POINTER(*arg) = waveview->peak_function;
660 case ARG_GAIN_FUNCTION:
661 GTK_VALUE_POINTER(*arg) = waveview->gain_curve_function;
665 GTK_VALUE_POINTER(*arg) = waveview->gain_src;
669 GTK_VALUE_POINTER(*arg) = waveview->cache;
672 case ARG_CACHE_UPDATER:
673 GTK_VALUE_BOOL(*arg) = waveview->cache_updater;
676 case ARG_SAMPLES_PER_PIXEL:
677 GTK_VALUE_DOUBLE(*arg) = waveview->samples_per_unit;
680 case ARG_AMPLITUDE_ABOVE_AXIS:
681 GTK_VALUE_DOUBLE(*arg) = waveview->amplitude_above_axis;
685 GTK_VALUE_DOUBLE (*arg) = waveview->x;
689 GTK_VALUE_DOUBLE (*arg) = waveview->y;
693 GTK_VALUE_DOUBLE (*arg) = waveview->height;
697 GTK_VALUE_INT (*arg) = waveview->wave_color;
701 GTK_VALUE_BOOL (*arg) = waveview->rectified;
703 case ARG_REGION_START:
704 GTK_VALUE_UINT (*arg) = waveview->region_start;
706 arg->type = GTK_TYPE_INVALID;
712 gnome_canvas_waveview_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
714 GnomeCanvasWaveView *waveview;
717 waveview = GNOME_CANVAS_WAVEVIEW (item);
719 // check_cache (waveview, "start of update");
721 if (parent_class->update)
722 (* parent_class->update) (item, affine, clip_path, flags);
724 gnome_canvas_waveview_reset_bounds (item);
726 /* get the canvas coordinates of the view. Do NOT use affines
727 for this, because they do not round to the integer units used
728 by the canvas, resulting in subtle pixel-level errors later.
734 gnome_canvas_item_i2w (item, &x, &y);
735 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_ulx, &waveview->bbox_uly);
737 waveview->samples = waveview->length_function (waveview->data_src);
739 x = waveview->x + (waveview->samples / waveview->samples_per_unit);
740 y = waveview->y + waveview->height;
742 gnome_canvas_item_i2w (item, &x, &y);
743 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_lrx, &waveview->bbox_lry);
745 /* cache the half-height and the end point in canvas units */
747 waveview->half_height = waveview->height / 2.0;
749 /* parse the color */
751 UINT_TO_RGBA (waveview->wave_color, &waveview->wave_r, &waveview->wave_g, &waveview->wave_b,
754 // check_cache (waveview, "end of update");
758 gnome_canvas_waveview_render (GnomeCanvasItem *item,
761 GnomeCanvasWaveView *waveview;
769 waveview = GNOME_CANVAS_WAVEVIEW (item);
771 // check_cache (waveview, "start of render");
773 if (parent_class->render) {
774 (*parent_class->render) (item, buf);
778 gnome_canvas_buf_ensure_buf (buf);
782 begin = MAX(waveview->bbox_ulx,buf->rect.x0);
784 if (waveview->bbox_lrx >= 0) {
785 end = MIN(waveview->bbox_lrx,buf->rect.x1);
794 s1 = floor ((begin - waveview->bbox_ulx) * waveview->samples_per_unit) ;
796 // fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit);
798 if (end == waveview->bbox_lrx) {
799 /* This avoids minor rounding errors when we have the
800 entire region visible.
802 s2 = waveview->samples;
804 s2 = s1 + floor ((end - begin) * waveview->samples_per_unit);
808 printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)"
809 " b/e %d..%d s= %lu..%lu\n",
822 /* now ensure that the cache is full and properly
826 // check_cache (waveview, "pre-ensure");
828 if (waveview->cache_updater && waveview->reload_cache_in_render) {
829 waveview->cache->start = 0;
830 waveview->cache->end = 0;
831 waveview->reload_cache_in_render = FALSE;
834 cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
836 // check_cache (waveview, "post-ensure");
839 Now draw each line, clipping it appropriately. The clipping
840 is done by the macros PAINT_FOO().
843 half_height = waveview->half_height;
845 /* this makes it slightly easier to comprehend whats going on */
847 #define origin half_height
849 for (x = begin; x < end; x++) {
852 int clip_max, clip_min;
857 max = waveview->cache->data[cache_index].max;
858 min = waveview->cache->data[cache_index].min;
870 /* don't rectify at single-sample zoom */
872 if (waveview->rectified && waveview->samples_per_unit > 1) {
874 if (fabs (min) > fabs (max)) {
878 max = max * waveview->height;
880 pymax = (int) rint ((item->y1 + waveview->height - max) * item->canvas->pixels_per_unit);
881 pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
885 max = max * half_height;
886 min = min * half_height;
888 pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
889 pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
892 /* OK, now fill the RGB buffer at x=i with a line between pymin and pymax,
893 or, if samples_per_unit == 1, then a dot at each location.
896 if (pymax == pymin) {
897 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
899 PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, pymin);
902 /* show clipped waveforms with small red lines */
904 if (clip_max || clip_min) {
905 clip_length = MIN(5,(waveview->height/4));
909 PAINT_VERT(buf, 255, 0, 0, x, pymax, pymax+clip_length);
913 PAINT_VERT(buf, 255, 0, 0, x, pymin-clip_length, pymin);
916 /* presto, we're done */
926 gnome_canvas_waveview_draw (GnomeCanvasItem *item,
927 GdkDrawable *drawable,
929 int width, int height)
931 GnomeCanvasWaveView *waveview;
933 waveview = GNOME_CANVAS_WAVEVIEW (item);
935 if (parent_class->draw) {
936 (* parent_class->draw) (item, drawable, x, y, width, height);
939 fprintf (stderr, "please don't use the CanvasWaveView item in a non-aa Canvas\n");
944 gnome_canvas_waveview_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
946 GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (item);
951 *x2 = ceil (*x1 + (waveview->length_function (waveview->data_src) / waveview->samples_per_unit));
952 *y2 = *y1 + waveview->height;
956 gnome_canvas_item_i2w (item, &x, &y);
957 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &a, &b);
960 gnome_canvas_item_i2w (item, &x, &y);
961 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &c, &d);
962 printf ("item bounds now (%g,%g),(%g,%g)\n", a, b, c, d);
968 gnome_canvas_waveview_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item)
970 /* XXX for now, point is never inside the wave
971 GnomeCanvasWaveView *waveview;
972 double x1, y1, x2, y2;
979 waveview = GNOME_CANVAS_WAVEVIEW (item);
983 /* Find the bounds for the rectangle plus its outline width */
985 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
987 /* Is point inside rectangle */
989 if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
993 /* Point is outside rectangle */
1009 return sqrt (dx * dx + dy * dy);