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);
185 GNOME_CANVAS_ITEM(waveview)->object.flags |= GNOME_CANVAS_ITEM_NO_AUTO_REDRAW;
188 #define DEBUG_CACHE 0
191 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_sample, gulong end_sample)
193 gulong required_cache_entries;
194 gulong rf1, rf2,rf3, required_frames;
195 gulong new_cache_start, new_cache_end;
200 gulong present_frames;
201 gulong present_entries;
203 GnomeCanvasWaveViewCache *cache;
206 cache = waveview->cache;
208 start_sample = start_sample + waveview->region_start;
209 end_sample = end_sample + waveview->region_start;
211 // printf("waveview->region_start == %lu\n",waveview->region_start);
212 printf ("=> 0x%x cache @ 0x%x range: %lu - %lu request: %lu - %lu (%lu frames)\n",
214 cache->start, cache->end,
215 start_sample, end_sample, end_sample - start_sample);
218 if (cache->start <= start_sample && cache->end >= end_sample) {
220 // printf ("0x%x: cache hit for %lu-%lu (cache holds: %lu-%lu\n",
221 // waveview, start_sample, end_sample, cache->start, cache->end);
226 /* make sure the cache is at least twice as wide as the screen width, and put the start sample
227 in the middle, ensuring that we cover the end_sample.
230 /* Note the assumption that we have a 1:1 units:pixel ratio for the canvas. Its everywhere ... */
232 half_width = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit)/2.0 + 0.5);
234 if (start_sample < half_width) {
237 new_cache_start = start_sample - half_width;
240 /* figure out how many frames we want */
242 rf1 = end_sample - start_sample + 1;
243 rf2 = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit * 2.0f));
244 required_frames = MAX(rf1,rf2);
246 /* but make sure it doesn't extend beyond the end of the source material */
248 rf3 = (gulong) (waveview->sourcefile_length_function (waveview->data_src)) + 1;
249 rf3 -= new_cache_start;
252 fprintf (stderr, "\n\nAVAILABLE FRAMES = %lu of %lu, start = %lu, sstart = %lu, cstart = %lu\n",
253 rf3, waveview->sourcefile_length_function (waveview->data_src),
254 waveview->region_start, start_sample, new_cache_start);
257 required_frames = MIN(required_frames,rf3);
259 new_cache_end = new_cache_start + required_frames - 1;
261 required_cache_entries = (gulong) floor (required_frames / waveview->samples_per_unit );
264 fprintf (stderr, "new cache = %lu - %lu\n", new_cache_start, new_cache_end);
265 fprintf(stderr,"required_cach_entries = %lu, samples_per_unit = %f\n",
266 required_cache_entries,waveview->samples_per_unit);
269 if (required_cache_entries > cache->allocated) {
270 cache->data = g_realloc (cache->data, sizeof (GnomeCanvasWaveViewCacheEntry) * required_cache_entries);
271 cache->allocated = required_cache_entries;
276 ostart = new_cache_start;
278 #undef CACHE_MEMMOVE_OPTIMIZATION
279 #ifdef CACHE_MEMMOVE_OPTIMIZATION
281 /* data is not entirely in the cache, so go fetch it, making sure to fill the cache */
283 /* some of the required cache entries are in the cache, but in the wrong
284 locations. use memmove to fix this.
287 if (cache->start < new_cache_start && new_cache_start < cache->end) {
289 /* case one: the common area is at the end of the existing cache. move it
290 to the beginning of the cache, and set up to refill whatever remains.
293 wv->cache_start wv->cache_end
294 |-------------------------------------------------------| cache
295 |--------------------------------| requested
296 <------------------->
298 new_cache_start new_cache_end
302 present_frames = cache->end - new_cache_start;
303 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
306 fprintf (stderr, "existing material at end of current cache, move to start of new cache\n"
307 "\tcopy from %lu to start\n", cache->data_size - present_entries);
310 memmove (&cache->data[0],
311 &cache->data[cache->data_size - present_entries],
312 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
315 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
316 present_frames, required_frames, present_entries, new_cache_start + present_entries,
317 cache->data + present_entries);
320 copied = present_entries;
321 offset = present_entries;
322 new_cache_start += present_frames;
323 required_frames -= present_frames;
325 } else if (new_cache_end > cache->start && new_cache_end < cache->end) {
327 /* case two: the common area lives at the beginning of the existing cache.
329 wv->cache_start wv->cache_end
330 |-----------------------------------------------------|
331 |--------------------------------|
335 new_cache_start new_cache_end
338 present_frames = new_cache_end - cache->start;
339 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
341 memmove (&cache->data[cache->data_size - present_entries],
343 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
346 fprintf (stderr, "existing material at start of current cache, move to start of end cache\n");
350 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
351 present_entries, required_frames, present_entries, new_cache_start + present_entries,
352 cache->data + present_entries);
355 copied = present_entries;
357 required_frames -= present_frames;
370 #endif /* CACHE_MEMMOVE_OPTIMIZATION */
372 // fprintf(stderr,"length == %lu\n",waveview->length_function (waveview->data_src));
373 // required_frames = MIN (waveview->length_function (waveview->data_src) - new_cache_start, required_frames);
374 npeaks = (gulong) floor (required_frames / waveview->samples_per_unit);
375 npeaks = MAX (1, npeaks);
376 required_frames = npeaks * waveview->samples_per_unit;
381 printf ("requesting %lu/%f to cover %lu-%lu at %f spu (request was %lu-%lu) into cache + %lu\n",
382 required_frames, required_frames/waveview->samples_per_unit, new_cache_start, new_cache_end,
383 waveview->samples_per_unit, start_sample, end_sample, offset);
387 // printf ("cache holds %lu entries, requesting %lu to cover %lu-%lu (request was %lu-%lu)\n",
388 // cache->data_size, npeaks, new_cache_start, new_cache_end,
389 // start_sample, end_sample);
392 waveview->peak_function (waveview->data_src, npeaks, new_cache_start, required_frames, cache->data + offset, waveview->channel,waveview->samples_per_unit);
394 /* take into account any copied peaks */
398 if (npeaks < cache->allocated) {
400 fprintf (stderr, "zero fill cache for %lu at %lu\n", cache->allocated - npeaks, npeaks);
402 memset (&cache->data[npeaks], 0, sizeof (GnomeCanvasWaveViewCacheEntry) * (cache->allocated - npeaks));
403 cache->data_size = npeaks;
405 cache->data_size = cache->allocated;
408 if (waveview->gain_curve_function) {
411 gain = (float*) malloc (sizeof (float) * cache->data_size);
413 waveview->gain_curve_function (waveview->gain_src, new_cache_start, new_cache_end, gain, cache->data_size);
415 for (n = 0; n < cache->data_size; ++n) {
416 cache->data[n].min *= gain[n];
417 cache->data[n].max *= gain[n];
424 cache->start = ostart;
425 cache->end = new_cache_end;
429 fprintf (stderr, "return cache index = %d\n",
430 (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5));
432 return (gint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5);
437 gnome_canvas_waveview_set_data_src (GnomeCanvasWaveView *waveview, void *data_src)
440 if (waveview->cache_updater) {
441 if (waveview->data_src == data_src) {
442 waveview->reload_cache_in_render = TRUE;
446 waveview->cache->start = 0;
447 waveview->cache->end = 0;
450 waveview->data_src = data_src;
454 gnome_canvas_waveview_set_channel (GnomeCanvasWaveView *waveview, guint32 chan)
456 if (waveview->channel == chan) {
460 waveview->channel = chan;
464 gnome_canvas_waveview_reset_bounds (GnomeCanvasItem *item)
467 double x1, x2, y1, y2;
470 int Ix1, Ix2, Iy1, Iy2;
473 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
480 gnome_canvas_item_i2w_affine (item, i2w);
481 art_affine_point (&w1, &i1, i2w);
482 art_affine_point (&w2, &i2, i2w);
484 Ix1 = (int) rint(w1.x);
485 Ix2 = (int) rint(w2.x);
486 Iy1 = (int) rint(w1.y);
487 Iy2 = (int) rint(w2.y);
489 gnome_canvas_update_bbox (item, Ix1, Iy1, Ix2, Iy2);
497 gnome_canvas_waveview_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
499 GnomeCanvasItem *item;
500 GnomeCanvasWaveView *waveview;
504 item = GNOME_CANVAS_ITEM (object);
505 waveview = GNOME_CANVAS_WAVEVIEW (object);
512 gnome_canvas_waveview_set_data_src (waveview, GTK_VALUE_POINTER(*arg));
517 gnome_canvas_waveview_set_channel (waveview, GTK_VALUE_UINT(*arg));
521 case ARG_LENGTH_FUNCTION:
522 waveview->length_function = GTK_VALUE_POINTER(*arg);
525 case ARG_SOURCEFILE_LENGTH_FUNCTION:
526 waveview->sourcefile_length_function = GTK_VALUE_POINTER(*arg);
530 case ARG_PEAK_FUNCTION:
531 waveview->peak_function = GTK_VALUE_POINTER(*arg);
535 case ARG_GAIN_FUNCTION:
536 waveview->gain_curve_function = GTK_VALUE_POINTER(*arg);
541 waveview->gain_src = GTK_VALUE_POINTER(*arg);
542 if (waveview->cache_updater) {
543 waveview->cache->start = 0;
544 waveview->cache->end = 0;
551 waveview->cache = GTK_VALUE_POINTER(*arg);
556 case ARG_CACHE_UPDATER:
557 waveview->cache_updater = GTK_VALUE_BOOL(*arg);
561 case ARG_SAMPLES_PER_PIXEL:
562 if ((waveview->samples_per_unit = GTK_VALUE_DOUBLE(*arg)) < 1.0) {
563 waveview->samples_per_unit = 1.0;
565 if (waveview->cache_updater) {
566 waveview->cache->start = 0;
567 waveview->cache->end = 0;
573 case ARG_AMPLITUDE_ABOVE_AXIS:
574 waveview->amplitude_above_axis = GTK_VALUE_DOUBLE(*arg);
579 if (waveview->x != GTK_VALUE_DOUBLE (*arg)) {
580 waveview->x = GTK_VALUE_DOUBLE (*arg);
586 if (waveview->y != GTK_VALUE_DOUBLE (*arg)) {
587 waveview->y = GTK_VALUE_DOUBLE (*arg);
593 if (waveview->height != fabs (GTK_VALUE_DOUBLE (*arg))) {
594 waveview->height = fabs (GTK_VALUE_DOUBLE (*arg));
600 if (waveview->wave_color != GTK_VALUE_INT(*arg)) {
601 waveview->wave_color = GTK_VALUE_INT(*arg);
607 if (waveview->rectified != GTK_VALUE_BOOL(*arg)) {
608 waveview->rectified = GTK_VALUE_BOOL(*arg);
612 case ARG_REGION_START:
613 waveview->region_start = GTK_VALUE_UINT(*arg);
624 gnome_canvas_waveview_reset_bounds (item);
628 gnome_canvas_item_request_update (item);
634 gnome_canvas_waveview_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
636 GnomeCanvasWaveView *waveview;
638 waveview = GNOME_CANVAS_WAVEVIEW (object);
642 GTK_VALUE_POINTER(*arg) = waveview->data_src;
646 GTK_VALUE_UINT(*arg) = waveview->channel;
649 case ARG_LENGTH_FUNCTION:
650 GTK_VALUE_POINTER(*arg) = waveview->length_function;
653 case ARG_SOURCEFILE_LENGTH_FUNCTION:
654 GTK_VALUE_POINTER(*arg) = waveview->sourcefile_length_function;
657 case ARG_PEAK_FUNCTION:
658 GTK_VALUE_POINTER(*arg) = waveview->peak_function;
661 case ARG_GAIN_FUNCTION:
662 GTK_VALUE_POINTER(*arg) = waveview->gain_curve_function;
666 GTK_VALUE_POINTER(*arg) = waveview->gain_src;
670 GTK_VALUE_POINTER(*arg) = waveview->cache;
673 case ARG_CACHE_UPDATER:
674 GTK_VALUE_BOOL(*arg) = waveview->cache_updater;
677 case ARG_SAMPLES_PER_PIXEL:
678 GTK_VALUE_DOUBLE(*arg) = waveview->samples_per_unit;
681 case ARG_AMPLITUDE_ABOVE_AXIS:
682 GTK_VALUE_DOUBLE(*arg) = waveview->amplitude_above_axis;
686 GTK_VALUE_DOUBLE (*arg) = waveview->x;
690 GTK_VALUE_DOUBLE (*arg) = waveview->y;
694 GTK_VALUE_DOUBLE (*arg) = waveview->height;
698 GTK_VALUE_INT (*arg) = waveview->wave_color;
702 GTK_VALUE_BOOL (*arg) = waveview->rectified;
704 case ARG_REGION_START:
705 GTK_VALUE_UINT (*arg) = waveview->region_start;
707 arg->type = GTK_TYPE_INVALID;
713 gnome_canvas_waveview_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
715 GnomeCanvasWaveView *waveview;
718 waveview = GNOME_CANVAS_WAVEVIEW (item);
720 // check_cache (waveview, "start of update");
722 if (parent_class->update)
723 (* parent_class->update) (item, affine, clip_path, flags);
725 gnome_canvas_waveview_reset_bounds (item);
727 /* get the canvas coordinates of the view. Do NOT use affines
728 for this, because they do not round to the integer units used
729 by the canvas, resulting in subtle pixel-level errors later.
735 gnome_canvas_item_i2w (item, &x, &y);
736 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_ulx, &waveview->bbox_uly);
738 waveview->samples = waveview->length_function (waveview->data_src);
740 x = waveview->x + (waveview->samples / waveview->samples_per_unit);
741 y = waveview->y + waveview->height;
743 gnome_canvas_item_i2w (item, &x, &y);
744 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_lrx, &waveview->bbox_lry);
746 /* cache the half-height and the end point in canvas units */
748 waveview->half_height = waveview->height / 2.0;
750 /* parse the color */
752 UINT_TO_RGBA (waveview->wave_color, &waveview->wave_r, &waveview->wave_g, &waveview->wave_b,
755 // check_cache (waveview, "end of update");
759 gnome_canvas_waveview_render (GnomeCanvasItem *item,
762 GnomeCanvasWaveView *waveview;
770 waveview = GNOME_CANVAS_WAVEVIEW (item);
772 // check_cache (waveview, "start of render");
774 if (parent_class->render) {
775 (*parent_class->render) (item, buf);
779 gnome_canvas_buf_ensure_buf (buf);
783 begin = MAX(waveview->bbox_ulx,buf->rect.x0);
785 if (waveview->bbox_lrx >= 0) {
786 end = MIN(waveview->bbox_lrx,buf->rect.x1);
795 s1 = floor ((begin - waveview->bbox_ulx) * waveview->samples_per_unit) ;
797 // fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit);
799 if (end == waveview->bbox_lrx) {
800 /* This avoids minor rounding errors when we have the
801 entire region visible.
803 s2 = waveview->samples;
805 s2 = s1 + floor ((end - begin) * waveview->samples_per_unit);
809 printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)"
810 " b/e %d..%d s= %lu..%lu\n",
823 /* now ensure that the cache is full and properly
827 // check_cache (waveview, "pre-ensure");
829 if (waveview->cache_updater && waveview->reload_cache_in_render) {
830 waveview->cache->start = 0;
831 waveview->cache->end = 0;
832 waveview->reload_cache_in_render = FALSE;
835 cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
837 // check_cache (waveview, "post-ensure");
840 Now draw each line, clipping it appropriately. The clipping
841 is done by the macros PAINT_FOO().
844 half_height = waveview->half_height;
846 /* this makes it slightly easier to comprehend whats going on */
848 #define origin half_height
850 for (x = begin; x < end; x++) {
853 int clip_max, clip_min;
858 max = waveview->cache->data[cache_index].max;
859 min = waveview->cache->data[cache_index].min;
871 /* don't rectify at single-sample zoom */
873 if (waveview->rectified && waveview->samples_per_unit > 1) {
875 if (fabs (min) > fabs (max)) {
879 max = max * waveview->height;
881 pymax = (int) rint ((item->y1 + waveview->height - max) * item->canvas->pixels_per_unit);
882 pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
886 max = max * half_height;
887 min = min * half_height;
889 pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
890 pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
893 /* OK, now fill the RGB buffer at x=i with a line between pymin and pymax,
894 or, if samples_per_unit == 1, then a dot at each location.
897 if (pymax == pymin) {
898 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
900 PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, pymin);
903 /* show clipped waveforms with small red lines */
905 if (clip_max || clip_min) {
906 clip_length = MIN(5,(waveview->height/4));
910 PAINT_VERT(buf, 255, 0, 0, x, pymax, pymax+clip_length);
914 PAINT_VERT(buf, 255, 0, 0, x, pymin-clip_length, pymin);
917 /* presto, we're done */
927 gnome_canvas_waveview_draw (GnomeCanvasItem *item,
928 GdkDrawable *drawable,
930 int width, int height)
932 GnomeCanvasWaveView *waveview;
934 waveview = GNOME_CANVAS_WAVEVIEW (item);
936 if (parent_class->draw) {
937 (* parent_class->draw) (item, drawable, x, y, width, height);
940 fprintf (stderr, "please don't use the CanvasWaveView item in a non-aa Canvas\n");
945 gnome_canvas_waveview_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
947 GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (item);
952 *x2 = ceil (*x1 + (waveview->length_function (waveview->data_src) / waveview->samples_per_unit));
953 *y2 = *y1 + waveview->height;
957 gnome_canvas_item_i2w (item, &x, &y);
958 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &a, &b);
961 gnome_canvas_item_i2w (item, &x, &y);
962 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &c, &d);
963 printf ("item bounds now (%g,%g),(%g,%g)\n", a, b, c, d);
969 gnome_canvas_waveview_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item)
971 /* XXX for now, point is never inside the wave
972 GnomeCanvasWaveView *waveview;
973 double x1, y1, x2, y2;
980 waveview = GNOME_CANVAS_WAVEVIEW (item);
984 /* Find the bounds for the rectangle plus its outline width */
986 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
988 /* Is point inside rectangle */
990 if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
994 /* Point is outside rectangle */
1010 return sqrt (dx * dx + dy * dy);