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>
29 #include "ardour/dB.h"
32 #include "canvas-waveview.h"
33 #include "rgb_macros.h"
35 /* POSIX guarantees casting between void* and function pointers, ISO C doesn't
36 * We can work around warnings by going one step deeper in our casts
39 #define POSIX_FUNC_PTR_CAST(type, object) *((type*) &(object))
40 #endif // _POSIX_VERSION
42 extern void c_stacktrace();
49 PROP_SOURCEFILE_LENGTH_FUNCTION,
55 PROP_SAMPLES_PER_UNIT,
56 PROP_AMPLITUDE_ABOVE_AXIS,
71 static void gnome_canvas_waveview_class_init (GnomeCanvasWaveViewClass *class);
73 static void gnome_canvas_waveview_init (GnomeCanvasWaveView *waveview);
75 static void gnome_canvas_waveview_destroy (GtkObject *object);
77 static void gnome_canvas_waveview_set_property (GObject *object,
81 static void gnome_canvas_waveview_get_property (GObject *object,
86 static void gnome_canvas_waveview_update (GnomeCanvasItem *item,
91 static void gnome_canvas_waveview_bounds (GnomeCanvasItem *item,
97 static double gnome_canvas_waveview_point (GnomeCanvasItem *item,
102 GnomeCanvasItem **actual_item);
104 static void gnome_canvas_waveview_render (GnomeCanvasItem *item,
105 GnomeCanvasBuf *buf);
107 static void gnome_canvas_waveview_draw (GnomeCanvasItem *item,
108 GdkDrawable *drawable,
114 static void gnome_canvas_waveview_set_data_src (GnomeCanvasWaveView *,
117 static void gnome_canvas_waveview_set_channel (GnomeCanvasWaveView *,
120 static guint32 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview,
125 static int _gradient_rendering = 0;
127 static GnomeCanvasItemClass *parent_class;
130 gnome_canvas_waveview_get_type (void)
132 static GType waveview_type;
134 if (!waveview_type) {
135 static const GTypeInfo object_info = {
136 sizeof (GnomeCanvasWaveViewClass),
137 (GBaseInitFunc) NULL,
138 (GBaseFinalizeFunc) NULL,
139 (GClassInitFunc) gnome_canvas_waveview_class_init,
140 (GClassFinalizeFunc) NULL,
141 NULL, /* class_data */
142 sizeof (GnomeCanvasWaveView),
144 (GInstanceInitFunc) gnome_canvas_waveview_init,
145 NULL /* value_table */
148 waveview_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasWaveView",
152 return waveview_type;
156 gnome_canvas_waveview_class_init (GnomeCanvasWaveViewClass *class)
158 GObjectClass *gobject_class;
159 GtkObjectClass *object_class;
160 GnomeCanvasItemClass *item_class;
162 gobject_class = (GObjectClass *) class;
163 object_class = (GtkObjectClass *) class;
164 item_class = (GnomeCanvasItemClass *) class;
166 parent_class = g_type_class_peek_parent (class);
168 gobject_class->set_property = gnome_canvas_waveview_set_property;
169 gobject_class->get_property = gnome_canvas_waveview_get_property;
171 g_object_class_install_property
174 g_param_spec_pointer ("data_src", NULL, NULL,
175 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
177 g_object_class_install_property
180 g_param_spec_uint ("channel", NULL, NULL,
182 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
184 g_object_class_install_property
186 PROP_LENGTH_FUNCTION,
187 g_param_spec_pointer ("length_function", NULL, NULL,
188 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
190 g_object_class_install_property
192 PROP_SOURCEFILE_LENGTH_FUNCTION,
193 g_param_spec_pointer ("sourcefile_length_function", NULL, NULL,
194 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
196 g_object_class_install_property
199 g_param_spec_pointer ("peak_function", NULL, NULL,
200 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
202 g_object_class_install_property
205 g_param_spec_pointer ("gain_function", NULL, NULL,
206 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
208 g_object_class_install_property
211 g_param_spec_pointer ("gain_src", NULL, NULL,
212 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
214 g_object_class_install_property
217 g_param_spec_pointer ("cache", NULL, NULL,
218 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
220 g_object_class_install_property
223 g_param_spec_boolean ("cache_updater", NULL, NULL,
225 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
227 g_object_class_install_property
229 PROP_SAMPLES_PER_UNIT,
230 g_param_spec_double ("samples_per_unit", NULL, NULL,
231 0.0, G_MAXDOUBLE, 0.0,
232 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
234 g_object_class_install_property
236 PROP_AMPLITUDE_ABOVE_AXIS,
237 g_param_spec_double ("amplitude_above_axis", 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 ("x", 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_double ("y", NULL, NULL,
252 0.0, G_MAXDOUBLE, 0.0,
253 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
255 g_object_class_install_property
258 g_param_spec_double ("height", NULL, NULL,
259 0.0, G_MAXDOUBLE, 0.0,
260 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
262 g_object_class_install_property
265 g_param_spec_uint ("wave_color", NULL, NULL,
267 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
269 g_object_class_install_property
272 g_param_spec_uint ("clip_color", NULL, NULL,
274 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
276 g_object_class_install_property
279 g_param_spec_uint ("zero_color", NULL, NULL,
281 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
283 g_object_class_install_property
286 g_param_spec_uint ("fill_color", NULL, NULL,
288 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
290 g_object_class_install_property
293 g_param_spec_boolean ("filled", NULL, NULL,
295 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
297 g_object_class_install_property
300 g_param_spec_boolean ("rectified", NULL, NULL,
302 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
304 g_object_class_install_property
307 g_param_spec_boolean ("zero_line", NULL, NULL,
309 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
311 g_object_class_install_property
314 g_param_spec_boolean ("logscaled", NULL, NULL,
316 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
318 g_object_class_install_property
321 g_param_spec_uint ("region_start", NULL, NULL,
323 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
325 object_class->destroy = gnome_canvas_waveview_destroy;
327 item_class->update = gnome_canvas_waveview_update;
328 item_class->bounds = gnome_canvas_waveview_bounds;
329 item_class->point = gnome_canvas_waveview_point;
330 item_class->render = gnome_canvas_waveview_render;
331 item_class->draw = gnome_canvas_waveview_draw;
335 gnome_canvas_waveview_set_gradient_waveforms (int yn)
337 _gradient_rendering = yn;
340 GnomeCanvasWaveViewCache*
341 gnome_canvas_waveview_cache_new ()
343 GnomeCanvasWaveViewCache *c;
345 c = g_malloc (sizeof (GnomeCanvasWaveViewCache));
348 c->data = g_malloc (sizeof (GnomeCanvasWaveViewCacheEntry) * c->allocated);
357 gnome_canvas_waveview_cache_destroy (GnomeCanvasWaveViewCache* cache)
359 g_free (cache->data);
364 gnome_canvas_waveview_init (GnomeCanvasWaveView *waveview)
369 waveview->cache_updater = FALSE;
370 waveview->data_src = NULL;
371 waveview->channel = 0;
372 waveview->peak_function = NULL;
373 waveview->length_function = NULL;
374 waveview->sourcefile_length_function = NULL;
375 waveview->gain_curve_function = NULL;
376 waveview->gain_src = NULL;
377 waveview->rectified = FALSE;
378 waveview->logscaled = FALSE;
379 waveview->filled = TRUE;
380 waveview->zero_line = FALSE;
381 waveview->region_start = 0;
382 waveview->samples_per_unit = 1.0;
383 waveview->amplitude_above_axis = 1.0;
384 waveview->height = 100.0;
385 waveview->screen_width = gdk_screen_width ();
386 waveview->reload_cache_in_render = FALSE;
388 waveview->wave_color = 0;
389 waveview->clip_color = 0;
390 waveview->zero_color = 0;
391 waveview->fill_color = 0;
395 gnome_canvas_waveview_destroy (GtkObject *object)
397 g_return_if_fail (object != NULL);
398 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
400 if (GTK_OBJECT_CLASS (parent_class)->destroy)
401 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
404 #define DEBUG_CACHE 0
405 #undef CACHE_MEMMOVE_OPTIMIZATION
407 /** @return cache index of start_sample within the cache */
409 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_sample, gulong end_sample)
411 gulong required_cache_entries;
412 gulong rf1, rf2,rf3, required_frames;
413 gulong new_cache_start, new_cache_end;
419 GnomeCanvasWaveViewCache *cache;
421 #ifdef CACHE_MEMMOVE_OPTIMIZATION
422 gulong present_frames;
423 gulong present_entries;
426 cache = waveview->cache;
428 start_sample = start_sample + waveview->region_start;
429 end_sample = end_sample + waveview->region_start;
431 // printf("waveview->region_start == %lu\n",waveview->region_start);
433 printf ("\n\n=> 0x%x cache @ 0x%x range: %lu - %lu request: %lu - %lu (%lu frames)\n",
435 cache->start, cache->end,
436 start_sample, end_sample, end_sample - start_sample);
439 if (cache->start <= start_sample && cache->end >= end_sample) {
441 // printf ("0x%x: cache hit for %lu-%lu (cache holds: %lu-%lu\n",
442 // waveview, start_sample, end_sample, cache->start, cache->end);
447 /* make sure the cache is at least twice as wide as the screen width, and put the start sample
448 in the middle, ensuring that we cover the end_sample.
451 /* Note the assumption that we have a 1:1 units:pixel ratio for the canvas. Its everywhere ... */
453 half_width = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit)/2.0 + 0.5);
455 if (start_sample < half_width) {
458 new_cache_start = start_sample - half_width;
461 /* figure out how many frames we want */
463 rf1 = end_sample - start_sample + 1;
464 rf2 = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit * 2.0f));
465 required_frames = MAX(rf1,rf2);
467 /* but make sure it doesn't extend beyond the end of the source material */
469 rf3 = (gulong) (waveview->sourcefile_length_function (waveview->data_src, waveview->samples_per_unit)) + 1;
470 if (rf3 < new_cache_start) {
473 rf3 -= new_cache_start;
477 fprintf (stderr, "AVAILABLE FRAMES = %lu of %lu, start = %lu, sstart = %lu, cstart = %lu\n",
478 rf3, waveview->sourcefile_length_function (waveview->data_src, waveview->samples_per_unit),
479 waveview->region_start, start_sample, new_cache_start);
482 required_frames = MIN(required_frames,rf3);
484 new_cache_end = new_cache_start + required_frames - 1;
486 required_cache_entries = (gulong) floor (required_frames / waveview->samples_per_unit );
489 fprintf (stderr, "new cache = %lu - %lu\n", new_cache_start, new_cache_end);
490 fprintf(stderr,"required_cach_entries = %lu, samples_per_unit = %f req frames = %lu\n",
491 required_cache_entries,waveview->samples_per_unit, required_frames);
494 if (required_cache_entries > cache->allocated) {
495 cache->data = g_realloc (cache->data, sizeof (GnomeCanvasWaveViewCacheEntry) * required_cache_entries);
496 cache->allocated = required_cache_entries;
501 ostart = new_cache_start;
503 #ifdef CACHE_MEMMOVE_OPTIMIZATION
505 /* data is not entirely in the cache, so go fetch it, making sure to fill the cache */
507 /* some of the required cache entries are in the cache, but in the wrong
508 locations. use memmove to fix this.
511 if (cache->start < new_cache_start && new_cache_start < cache->end) {
513 /* case one: the common area is at the end of the existing cache. move it
514 to the beginning of the cache, and set up to refill whatever remains.
517 wv->cache_start wv->cache_end
518 |-------------------------------------------------------| cache
519 |--------------------------------| requested
520 <------------------->
522 new_cache_start new_cache_end
526 present_frames = cache->end - new_cache_start;
527 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
530 fprintf (stderr, "existing material at end of current cache, move to start of new cache\n"
531 "\tcopy from %lu to start\n", cache->data_size - present_entries);
534 memmove (&cache->data[0],
535 &cache->data[cache->data_size - present_entries],
536 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
539 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
540 present_frames, required_frames, present_entries, new_cache_start + present_entries,
541 cache->data + present_entries);
544 copied = present_entries;
545 offset = present_entries;
546 new_cache_start += present_frames;
547 required_frames -= present_frames;
549 } else if (new_cache_end > cache->start && new_cache_end < cache->end) {
551 /* case two: the common area lives at the beginning of the existing cache.
553 wv->cache_start wv->cache_end
554 |-----------------------------------------------------|
555 |--------------------------------|
559 new_cache_start new_cache_end
562 present_frames = new_cache_end - cache->start;
563 present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
565 memmove (&cache->data[cache->data_size - present_entries],
567 present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
570 fprintf (stderr, "existing material at start of current cache, move to start of end cache\n");
574 fprintf (stderr, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
575 present_entries, required_frames, present_entries, new_cache_start + present_entries,
576 cache->data + present_entries);
579 copied = present_entries;
581 required_frames -= present_frames;
594 #endif /* CACHE_MEMMOVE_OPTIMIZATION */
596 // fprintf(stderr,"length == %lu\n",waveview->length_function (waveview->data_src));
597 // required_frames = MIN (waveview->length_function (waveview->data_src) - new_cache_start, required_frames);
599 npeaks = (gulong) floor (required_frames / waveview->samples_per_unit);
600 required_frames = npeaks * waveview->samples_per_unit;
605 printf ("requesting %lu/%f to cover %lu-%lu at %f spu (request was %lu-%lu) into cache + %lu\n",
606 required_frames, required_frames/waveview->samples_per_unit, new_cache_start, new_cache_end,
607 waveview->samples_per_unit, start_sample, end_sample, offset);
611 // printf ("cache holds %lu entries, requesting %lu to cover %lu-%lu (request was %lu-%lu)\n",
612 // cache->data_size, npeaks, new_cache_start, new_cache_end,
613 // start_sample, end_sample);
616 if (required_frames) {
617 waveview->peak_function (waveview->data_src, npeaks, new_cache_start, required_frames, cache->data + offset, waveview->channel,waveview->samples_per_unit);
619 /* take into account any copied peaks */
626 if (npeaks < cache->allocated) {
628 fprintf (stderr, "zero fill cache for %lu at %lu\n", cache->allocated - npeaks, npeaks);
630 memset (&cache->data[npeaks], 0, sizeof (GnomeCanvasWaveViewCacheEntry) * (cache->allocated - npeaks));
631 cache->data_size = npeaks;
633 cache->data_size = cache->allocated;
636 if (waveview->gain_curve_function) {
639 gain = (float*) malloc (sizeof (float) * cache->data_size);
641 waveview->gain_curve_function (waveview->gain_src, new_cache_start, new_cache_end, gain, cache->data_size);
643 for (n = 0; n < cache->data_size; ++n) {
644 cache->data[n].min *= gain[n];
645 cache->data[n].max *= gain[n];
652 /* do optional log scaling. this implementation is not particularly efficient */
654 if (waveview->logscaled) {
656 GnomeCanvasWaveViewCacheEntry* buf = cache->data;
658 for (n = 0; n < cache->data_size; ++n) {
660 if (buf[n].max > 0.0f) {
661 buf[n].max = alt_log_meter(fast_coefficient_to_dB(buf[n].max));
662 } else if (buf[n].max < 0.0f) {
663 buf[n].max = -alt_log_meter(fast_coefficient_to_dB(-buf[n].max));
666 if (buf[n].min > 0.0f) {
667 buf[n].min = alt_log_meter(fast_coefficient_to_dB(buf[n].min));
668 } else if (buf[n].min < 0.0f) {
669 buf[n].min = -alt_log_meter(fast_coefficient_to_dB(-buf[n].min));
674 cache->start = ostart;
675 cache->end = new_cache_end;
679 fprintf (stderr, "return cache index = %d\n",
680 (guint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5));
682 return (guint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5);
687 gnome_canvas_waveview_set_data_src (GnomeCanvasWaveView *waveview, void *data_src)
690 if (waveview->cache_updater) {
691 if (waveview->data_src == data_src) {
692 waveview->reload_cache_in_render = TRUE;
696 waveview->cache->start = 0;
697 waveview->cache->end = 0;
700 waveview->data_src = data_src;
704 gnome_canvas_waveview_set_channel (GnomeCanvasWaveView *waveview, guint32 chan)
706 if (waveview->channel == chan) {
710 waveview->channel = chan;
714 gnome_canvas_waveview_reset_bounds (GnomeCanvasItem *item)
717 double x1, x2, y1, y2;
720 int Ix1, Ix2, Iy1, Iy2;
723 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
730 gnome_canvas_item_i2w_affine (item, i2w);
731 art_affine_point (&w1, &i1, i2w);
732 art_affine_point (&w2, &i2, i2w);
734 Ix1 = (int) rint(w1.x);
735 Ix2 = (int) rint(w2.x);
736 Iy1 = (int) rint(w1.y);
737 Iy2 = (int) rint(w2.y);
739 gnome_canvas_update_bbox (item, Ix1, Iy1, Ix2, Iy2);
747 gnome_canvas_waveview_set_property (GObject *object,
755 GnomeCanvasItem *item;
756 GnomeCanvasWaveView *waveview;
758 int calc_bounds = FALSE;
760 g_return_if_fail (object != NULL);
761 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
763 item = GNOME_CANVAS_ITEM (object);
764 waveview = GNOME_CANVAS_WAVEVIEW (object);
769 gnome_canvas_waveview_set_data_src (waveview, g_value_get_pointer(value));
774 gnome_canvas_waveview_set_channel (waveview, g_value_get_uint(value));
778 case PROP_LENGTH_FUNCTION:
779 ptr = g_value_get_pointer(value);
780 waveview->length_function = POSIX_FUNC_PTR_CAST(waveview_length_function_t, ptr);
784 case PROP_SOURCEFILE_LENGTH_FUNCTION:
785 ptr = g_value_get_pointer(value);
786 waveview->sourcefile_length_function = POSIX_FUNC_PTR_CAST(waveview_sourcefile_length_function_t, ptr);
790 case PROP_PEAK_FUNCTION:
791 ptr = g_value_get_pointer(value);
792 waveview->peak_function = POSIX_FUNC_PTR_CAST(waveview_peak_function_t, ptr);
796 case PROP_GAIN_FUNCTION:
797 ptr = g_value_get_pointer(value);
798 waveview->gain_curve_function = POSIX_FUNC_PTR_CAST(waveview_gain_curve_function_t, ptr);
803 waveview->gain_src = g_value_get_pointer(value);
804 if (waveview->cache_updater) {
805 waveview->cache->start = 0;
806 waveview->cache->end = 0;
813 waveview->cache = g_value_get_pointer(value);
818 case PROP_CACHE_UPDATER:
819 waveview->cache_updater = g_value_get_boolean(value);
823 case PROP_SAMPLES_PER_UNIT:
824 if ((waveview->samples_per_unit = g_value_get_double(value)) < 1.0) {
825 waveview->samples_per_unit = 1.0;
827 if (waveview->cache_updater) {
828 waveview->cache->start = 0;
829 waveview->cache->end = 0;
835 case PROP_AMPLITUDE_ABOVE_AXIS:
836 waveview->amplitude_above_axis = g_value_get_double(value);
841 if (waveview->x != g_value_get_double (value)) {
842 waveview->x = g_value_get_double (value);
848 if (waveview->y != g_value_get_double (value)) {
849 waveview->y = g_value_get_double (value);
855 if (waveview->height != fabs (g_value_get_double (value))) {
856 waveview->height = fabs (g_value_get_double (value));
861 case PROP_WAVE_COLOR:
862 if (waveview->wave_color != g_value_get_uint(value)) {
863 waveview->wave_color = g_value_get_uint(value);
868 case PROP_CLIP_COLOR:
869 if (waveview->clip_color != g_value_get_uint(value)) {
870 waveview->clip_color = g_value_get_uint(value);
875 case PROP_ZERO_COLOR:
876 if (waveview->zero_color != g_value_get_uint(value)) {
877 waveview->zero_color = g_value_get_uint(value);
882 case PROP_FILL_COLOR:
883 if (waveview->fill_color != g_value_get_uint(value)) {
884 waveview->fill_color = g_value_get_uint(value);
890 if (waveview->filled != g_value_get_boolean(value)) {
891 waveview->filled = g_value_get_boolean(value);
897 if (waveview->rectified != g_value_get_boolean(value)) {
898 waveview->rectified = g_value_get_boolean(value);
904 if (waveview->zero_line != g_value_get_boolean(value)) {
905 waveview->zero_line = g_value_get_boolean(value);
911 if (waveview->logscaled != g_value_get_boolean(value)) {
912 waveview->logscaled = g_value_get_boolean(value);
913 if (waveview->cache_updater) {
914 waveview->cache->start = 0;
915 waveview->cache->end = 0;
921 case PROP_REGION_START:
922 waveview->region_start = g_value_get_uint(value);
933 gnome_canvas_waveview_reset_bounds (item);
937 gnome_canvas_item_request_update (item);
943 gnome_canvas_waveview_get_property (
951 g_return_if_fail (object != NULL);
952 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
954 GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (object);
958 g_value_set_pointer(value, waveview->data_src);
962 g_value_set_uint(value, waveview->channel);
965 case PROP_LENGTH_FUNCTION:
966 g_value_set_pointer(value, POSIX_FUNC_PTR_CAST(void*, waveview->length_function));
969 case PROP_SOURCEFILE_LENGTH_FUNCTION:
970 g_value_set_pointer(value, POSIX_FUNC_PTR_CAST(void*, waveview->sourcefile_length_function));
973 case PROP_PEAK_FUNCTION:
974 g_value_set_pointer(value, POSIX_FUNC_PTR_CAST(void*, waveview->peak_function));
977 case PROP_GAIN_FUNCTION:
978 g_value_set_pointer(value, POSIX_FUNC_PTR_CAST(void*, waveview->gain_curve_function));
982 g_value_set_pointer(value, waveview->gain_src);
986 g_value_set_pointer(value, waveview->cache);
989 case PROP_CACHE_UPDATER:
990 g_value_set_boolean(value, waveview->cache_updater);
993 case PROP_SAMPLES_PER_UNIT:
994 g_value_set_double(value, waveview->samples_per_unit);
997 case PROP_AMPLITUDE_ABOVE_AXIS:
998 g_value_set_double(value, waveview->amplitude_above_axis);
1002 g_value_set_double (value, waveview->x);
1006 g_value_set_double (value, waveview->y);
1010 g_value_set_double (value, waveview->height);
1013 case PROP_WAVE_COLOR:
1014 g_value_set_uint (value, waveview->wave_color);
1017 case PROP_CLIP_COLOR:
1018 g_value_set_uint (value, waveview->clip_color);
1021 case PROP_ZERO_COLOR:
1022 g_value_set_uint (value, waveview->zero_color);
1025 case PROP_FILL_COLOR:
1026 g_value_set_uint (value, waveview->fill_color);
1030 g_value_set_boolean (value, waveview->filled);
1033 case PROP_RECTIFIED:
1034 g_value_set_boolean (value, waveview->rectified);
1037 case PROP_ZERO_LINE:
1038 g_value_set_boolean (value, waveview->zero_line);
1041 case PROP_LOGSCALED:
1042 g_value_set_boolean (value, waveview->logscaled);
1045 case PROP_REGION_START:
1046 g_value_set_uint (value, waveview->region_start);
1050 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1056 gnome_canvas_waveview_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
1058 GnomeCanvasWaveView *waveview;
1061 waveview = GNOME_CANVAS_WAVEVIEW (item);
1063 // check_cache (waveview, "start of update");
1065 if (parent_class->update)
1066 (* parent_class->update) (item, affine, clip_path, flags);
1068 gnome_canvas_waveview_reset_bounds (item);
1070 /* get the canvas coordinates of the view. Do NOT use affines
1071 for this, because they do not round to the integer units used
1072 by the canvas, resulting in subtle pixel-level errors later.
1078 gnome_canvas_item_i2w (item, &x, &y);
1079 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_ulx, &waveview->bbox_uly);
1081 waveview->samples = waveview->length_function (waveview->data_src);
1083 x = waveview->x + (waveview->samples / waveview->samples_per_unit);
1084 y = waveview->y + waveview->height;
1086 gnome_canvas_item_i2w (item, &x, &y);
1087 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_lrx, &waveview->bbox_lry);
1089 /* cache the half-height and the end point in canvas units */
1091 waveview->half_height = waveview->height / 2.0;
1093 /* parse the color */
1095 UINT_TO_RGBA (waveview->wave_color, &waveview->wave_r, &waveview->wave_g, &waveview->wave_b,
1097 UINT_TO_RGBA (waveview->clip_color, &waveview->clip_r, &waveview->clip_g, &waveview->clip_b,
1099 UINT_TO_RGBA (waveview->fill_color, &waveview->fill_r, &waveview->fill_g, &waveview->fill_b,
1102 // check_cache (waveview, "end of update");
1106 gnome_canvas_waveview_gradient_render (GnomeCanvasItem *item,
1107 GnomeCanvasBuf *buf)
1109 GnomeCanvasWaveView *waveview;
1111 int clip_length = 0;
1118 waveview = GNOME_CANVAS_WAVEVIEW (item);
1120 // check_cache (waveview, "start of render");
1122 if (parent_class->render) {
1123 (*parent_class->render) (item, buf);
1127 gnome_canvas_buf_ensure_buf (buf);
1131 /* a "unit" means a pixel */
1133 /* begin: render start x (units) */
1134 int const begin = MAX (waveview->bbox_ulx, buf->rect.x0);
1136 /* zbegin: start x for zero line (units) */
1137 int const zbegin = (begin == waveview->bbox_ulx) ? (begin + 1) : begin;
1139 /* end: render end x (units) */
1140 int const end = (waveview->bbox_lrx >= 0) ? MIN (waveview->bbox_lrx,buf->rect.x1) : buf->rect.x1;
1142 /* zend: end x for zero-line (units) */
1143 int const zend = (end == waveview->bbox_lrx) ? (end - 1) : end;
1153 s1 = floor ((begin - waveview->bbox_ulx) * waveview->samples_per_unit);
1155 // fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit);
1157 if (end == waveview->bbox_lrx) {
1158 /* This avoids minor rounding errors when we have the
1159 entire region visible.
1161 s2 = waveview->samples;
1163 s2 = s1 + floor ((end - begin) * waveview->samples_per_unit);
1167 printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)"
1168 " b/e %d..%d s= %lu..%lu @ %f\n",
1179 waveview->samples_per_unit);
1182 /* now ensure that the cache is full and properly
1186 // check_cache (waveview, "pre-ensure");
1188 if (waveview->cache_updater && waveview->reload_cache_in_render) {
1189 waveview->cache->start = 0;
1190 waveview->cache->end = 0;
1191 waveview->reload_cache_in_render = FALSE;
1194 // check_cache (waveview, "post-ensure");
1196 /* don't rectify at single-sample zoom */
1197 if (waveview->rectified && waveview->samples_per_unit > 1) {
1204 clip_length = MIN(5,(waveview->height/4));
1207 Now draw each line, clipping it appropriately. The clipping
1208 is done by the macros PAINT_FOO().
1211 half_height = waveview->half_height;
1213 /* this makes it slightly easier to comprehend whats going on */
1214 #define origin half_height
1216 if (waveview->filled && !rectify) {
1221 int next_pymin, next_pymax;
1223 int next_clip_max = 0;
1224 int next_clip_min = 0;
1226 int wave_middle = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
1227 int wave_top = (int) rint ((item->y1) * item->canvas->pixels_per_unit);
1229 if (s1 < waveview->samples_per_unit) {
1230 /* we haven't got a prev vars to compare with, so outline the whole line here */
1231 prev_pymax = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
1232 prev_pymin = prev_pymax;
1235 s1 -= waveview->samples_per_unit;
1238 if(end == waveview->bbox_lrx) {
1239 /* we don't have the NEXT vars for the last sample */
1240 last_pymax = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
1241 last_pymin = last_pymax;
1244 s2 += waveview->samples_per_unit;
1247 cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
1250 * Compute the variables outside the rendering rect
1252 if(prev_pymax != prev_pymin) {
1254 prev_pymax = (int) rint ((item->y1 + origin - MIN(waveview->cache->data[cache_index].max, 1.0) * half_height) * item->canvas->pixels_per_unit);
1255 prev_pymin = (int) rint ((item->y1 + origin - MAX(waveview->cache->data[cache_index].min, -1.0) * half_height) * item->canvas->pixels_per_unit);
1258 if(last_pymax != last_pymin) {
1259 /* take the index of one sample right of what we render */
1260 guint index = cache_index + (end - begin);
1262 if (index >= waveview->cache->data_size) {
1264 /* the data we want is off the end of the cache, which must mean its beyond
1265 the end of the region's source; hence the peak values are 0 */
1266 last_pymax = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
1267 last_pymin = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
1271 last_pymax = (int) rint ((item->y1 + origin - MIN(waveview->cache->data[index].max, 1.0) * half_height) * item->canvas->pixels_per_unit);
1272 last_pymin = (int) rint ((item->y1 + origin - MAX(waveview->cache->data[index].min, -1.0) * half_height) * item->canvas->pixels_per_unit);
1279 * initialize NEXT* variables for the first run, duplicated in the loop for speed
1281 max = waveview->cache->data[cache_index].max;
1282 min = waveview->cache->data[cache_index].min;
1297 next_pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
1298 next_pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
1303 for(x = begin; x < end; ++x) {
1304 int clip_max = next_clip_max;
1305 int clip_min = next_clip_min;
1306 int fill_max, fill_min;
1313 /*next is now the last column, which is outside the rendering rect, and possibly outside the region*/
1314 next_pymax = last_pymax;
1315 next_pymin = last_pymin;
1320 if (cache_index < waveview->cache->data_size) {
1321 max = waveview->cache->data[cache_index].max;
1322 min = waveview->cache->data[cache_index].min;
1343 next_pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
1344 next_pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
1348 if (pymax == pymin) {
1349 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
1351 if((prev_pymax < pymax && next_pymax < pymax) ||
1352 (prev_pymax == pymax && next_pymax == pymax)) {
1353 fill_max = pymax + 1;
1354 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
1357 fill_max = MAX(prev_pymax, next_pymax);
1358 if(pymax == fill_max) {
1359 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
1362 PAINT_VERTA_GR(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max, wave_middle, wave_top);
1367 if((prev_pymin > pymin && next_pymin > pymin) ||
1368 (prev_pymin == pymin && next_pymin == pymin)) {
1369 fill_min = pymin - 1;
1370 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin-1);
1373 fill_min = MIN(prev_pymin, next_pymin);
1374 if(pymin == fill_min) {
1375 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
1378 PAINT_VERTA_GR(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, fill_min, pymin, wave_middle, wave_top);
1382 if(fill_max < fill_min) {
1383 PAINT_VERTA_GR(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max, fill_min, wave_middle, wave_top);
1385 else if(fill_max == fill_min) {
1386 PAINT_DOTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max);
1391 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax + clip_length);
1392 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x + 1, pymax, pymax + (clip_length -1));
1393 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x - 1, pymax, pymax + (clip_length - 1));
1398 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a , x, pymin - clip_length, pymin);
1399 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x + 1, pymin - (clip_length - 1), pymin);
1400 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x - 1, pymin - (clip_length - 1), pymin);
1407 } else if (waveview->filled && rectify) {
1409 int prev_pymax = -1;
1410 int last_pymax = -1;
1413 int next_clip_max = 0;
1414 int next_clip_min = 0;
1416 int wave_middle = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
1417 int wave_top = (int) rint ((item->y1) * item->canvas->pixels_per_unit);
1419 // for rectified, this stays constant throughout the loop
1420 pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
1422 if(s1 < waveview->samples_per_unit) {
1423 /* we haven't got a prev vars to compare with, so outline the whole line here */
1427 s1 -= waveview->samples_per_unit;
1430 if(end == waveview->bbox_lrx) {
1431 /* we don't have the NEXT vars for the last sample */
1435 s2 += waveview->samples_per_unit;
1438 cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
1441 * Compute the variables outside the rendering rect
1443 if(prev_pymax < 0) {
1444 max = MIN(waveview->cache->data[cache_index].max, 1.0);
1445 min = MAX(waveview->cache->data[cache_index].min, -1.0);
1447 if (fabs (min) > fabs (max)) {
1451 prev_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
1454 if(last_pymax < 0) {
1455 /* take the index of one sample right of what we render */
1456 int index = cache_index + (end - begin);
1458 max = MIN(waveview->cache->data[index].max, 1.0);
1459 min = MAX(waveview->cache->data[index].min, -1.0);
1461 if (fabs (min) > fabs (max)) {
1465 last_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
1469 * initialize NEXT* variables for the first run, duplicated in the loop for speed
1471 max = waveview->cache->data[cache_index].max;
1472 min = waveview->cache->data[cache_index].min;
1484 if (fabs (min) > fabs (max)) {
1488 next_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
1493 for(x = begin; x < end; ++x) {
1494 int clip_max = next_clip_max;
1495 int clip_min = next_clip_min;
1502 /*next is now the last column, which is outside the rendering rect, and possibly outside the region*/
1503 next_pymax = last_pymax;
1508 max = waveview->cache->data[cache_index].max;
1509 min = waveview->cache->data[cache_index].min;
1521 if (fabs (min) > fabs (max)) {
1525 next_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
1529 if (pymax == pymin) {
1530 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
1532 if((prev_pymax < pymax && next_pymax < pymax) ||
1533 (prev_pymax == pymax && next_pymax == pymax)) {
1534 fill_max = pymax + 1;
1535 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
1538 fill_max = MAX(prev_pymax, next_pymax);
1539 if(pymax == fill_max) {
1540 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
1544 PAINT_VERTA_GR(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max, wave_middle, wave_top);
1548 if(fill_max < pymin) {
1549 PAINT_VERTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max, pymin);
1551 else if(fill_max == pymin) {
1552 PAINT_DOTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, pymin);
1557 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax + clip_length);
1558 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x + 1, pymax, pymax + (clip_length -1));
1559 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x - 1, pymax, pymax + (clip_length - 1));
1563 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a , x, pymin - clip_length, pymin);
1564 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x + 1, pymin - (clip_length - 1), pymin);
1565 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x - 1, pymin - (clip_length - 1), pymin);
1572 cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
1574 for (x = begin; x < end; x++) {
1577 int clip_max, clip_min;
1582 max = waveview->cache->data[cache_index].max;
1583 min = waveview->cache->data[cache_index].min;
1597 if (fabs (min) > fabs (max)) {
1601 max = max * waveview->height;
1603 pymax = (int) rint ((item->y1 + waveview->height - max) * item->canvas->pixels_per_unit);
1604 pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
1608 max = max * half_height;
1609 min = min * half_height;
1611 pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
1612 pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
1615 /* OK, now fill the RGB buffer at x=i with a line between pymin and pymax,
1616 or, if samples_per_unit == 1, then a dot at each location.
1619 if (pymax == pymin) {
1620 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
1622 PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, pymin);
1625 /* show clipped waveforms with small red lines */
1628 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length);
1632 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin);
1635 /* presto, we're done */
1641 if (!waveview->rectified && waveview->zero_line && waveview->height >= 100) {
1644 unsigned char zero_r, zero_g, zero_b, zero_a;
1645 UINT_TO_RGBA( waveview->zero_color, &zero_r, &zero_g, &zero_b, &zero_a);
1646 int zeroline_y = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
1647 PAINT_HORIZA(buf, zero_r, zero_g, zero_b, zero_a, zbegin, zend, zeroline_y);
1654 gnome_canvas_waveview_flat_render (GnomeCanvasItem *item,
1655 GnomeCanvasBuf *buf)
1657 GnomeCanvasWaveView *waveview;
1659 int clip_length = 0;
1666 waveview = GNOME_CANVAS_WAVEVIEW (item);
1668 // check_cache (waveview, "start of render");
1670 if (parent_class->render) {
1671 (*parent_class->render) (item, buf);
1675 gnome_canvas_buf_ensure_buf (buf);
1679 /* a "unit" means a pixel */
1681 /* begin: render start x (units) */
1682 int const begin = MAX (waveview->bbox_ulx, buf->rect.x0);
1684 /* zbegin: start x for zero line (units) */
1685 int const zbegin = (begin == waveview->bbox_ulx) ? (begin + 1) : begin;
1687 /* end: render end x (units) */
1688 int const end = (waveview->bbox_lrx >= 0) ? MIN (waveview->bbox_lrx,buf->rect.x1) : buf->rect.x1;
1690 /* zend: end x for zero-line (units) */
1691 int const zend = (end == waveview->bbox_lrx) ? (end - 1) : end;
1701 s1 = floor ((begin - waveview->bbox_ulx) * waveview->samples_per_unit);
1703 // fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit);
1705 if (end == waveview->bbox_lrx) {
1706 /* This avoids minor rounding errors when we have the
1707 entire region visible.
1709 s2 = waveview->samples;
1711 s2 = s1 + floor ((end - begin) * waveview->samples_per_unit);
1715 printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)"
1716 " b/e %d..%d s= %lu..%lu @ %f\n",
1727 waveview->samples_per_unit);
1730 /* now ensure that the cache is full and properly
1734 // check_cache (waveview, "pre-ensure");
1736 if (waveview->cache_updater && waveview->reload_cache_in_render) {
1737 waveview->cache->start = 0;
1738 waveview->cache->end = 0;
1739 waveview->reload_cache_in_render = FALSE;
1742 // check_cache (waveview, "post-ensure");
1744 /* don't rectify at single-sample zoom */
1745 if (waveview->rectified && waveview->samples_per_unit > 1) {
1752 clip_length = MIN(5,(waveview->height/4));
1755 Now draw each line, clipping it appropriately. The clipping
1756 is done by the macros PAINT_FOO().
1759 half_height = waveview->half_height;
1761 /* this makes it slightly easier to comprehend whats going on */
1762 #define origin half_height
1764 if (waveview->filled && !rectify) {
1769 int next_pymin, next_pymax;
1771 int next_clip_max = 0;
1772 int next_clip_min = 0;
1774 if (s1 < waveview->samples_per_unit) {
1775 /* we haven't got a prev vars to compare with, so outline the whole line here */
1776 prev_pymax = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
1777 prev_pymin = prev_pymax;
1780 s1 -= waveview->samples_per_unit;
1783 if(end == waveview->bbox_lrx) {
1784 /* we don't have the NEXT vars for the last sample */
1785 last_pymax = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
1786 last_pymin = last_pymax;
1789 s2 += waveview->samples_per_unit;
1792 cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
1795 * Compute the variables outside the rendering rect
1797 if(prev_pymax != prev_pymin) {
1799 prev_pymax = (int) rint ((item->y1 + origin - MIN(waveview->cache->data[cache_index].max, 1.0) * half_height) * item->canvas->pixels_per_unit);
1800 prev_pymin = (int) rint ((item->y1 + origin - MAX(waveview->cache->data[cache_index].min, -1.0) * half_height) * item->canvas->pixels_per_unit);
1803 if(last_pymax != last_pymin) {
1804 /* take the index of one sample right of what we render */
1805 guint index = cache_index + (end - begin);
1807 if (index >= waveview->cache->data_size) {
1809 /* the data we want is off the end of the cache, which must mean its beyond
1810 the end of the region's source; hence the peak values are 0 */
1811 last_pymax = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
1812 last_pymin = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
1816 last_pymax = (int) rint ((item->y1 + origin - MIN(waveview->cache->data[index].max, 1.0) * half_height) * item->canvas->pixels_per_unit);
1817 last_pymin = (int) rint ((item->y1 + origin - MAX(waveview->cache->data[index].min, -1.0) * half_height) * item->canvas->pixels_per_unit);
1824 * initialize NEXT* variables for the first run, duplicated in the loop for speed
1826 max = waveview->cache->data[cache_index].max;
1827 min = waveview->cache->data[cache_index].min;
1842 next_pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
1843 next_pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
1848 for(x = begin; x < end; ++x) {
1849 int clip_max = next_clip_max;
1850 int clip_min = next_clip_min;
1851 int fill_max, fill_min;
1858 /*next is now the last column, which is outside the rendering rect, and possibly outside the region*/
1859 next_pymax = last_pymax;
1860 next_pymin = last_pymin;
1865 if (cache_index < waveview->cache->data_size) {
1866 max = waveview->cache->data[cache_index].max;
1867 min = waveview->cache->data[cache_index].min;
1888 next_pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
1889 next_pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
1893 if (pymax == pymin) {
1894 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
1896 if((prev_pymax < pymax && next_pymax < pymax) ||
1897 (prev_pymax == pymax && next_pymax == pymax)) {
1898 fill_max = pymax + 1;
1899 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
1902 fill_max = MAX(prev_pymax, next_pymax);
1903 if(pymax == fill_max) {
1904 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
1908 PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max);
1912 if((prev_pymin > pymin && next_pymin > pymin) ||
1913 (prev_pymin == pymin && next_pymin == pymin)) {
1914 fill_min = pymin - 1;
1915 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin-1);
1918 fill_min = MIN(prev_pymin, next_pymin);
1919 if(pymin == fill_min) {
1920 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
1923 PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, fill_min, pymin);
1927 if(fill_max < fill_min) {
1928 PAINT_VERTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max, fill_min);
1930 else if(fill_max == fill_min) {
1931 PAINT_DOTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max);
1936 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length);
1940 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin);
1947 } else if (waveview->filled && rectify) {
1949 int prev_pymax = -1;
1950 int last_pymax = -1;
1953 int next_clip_max = 0;
1954 int next_clip_min = 0;
1956 // for rectified, this stays constant throughout the loop
1957 pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
1959 if(s1 < waveview->samples_per_unit) {
1960 /* we haven't got a prev vars to compare with, so outline the whole line here */
1964 s1 -= waveview->samples_per_unit;
1967 if(end == waveview->bbox_lrx) {
1968 /* we don't have the NEXT vars for the last sample */
1972 s2 += waveview->samples_per_unit;
1975 cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
1978 * Compute the variables outside the rendering rect
1980 if(prev_pymax < 0) {
1981 max = MIN(waveview->cache->data[cache_index].max, 1.0);
1982 min = MAX(waveview->cache->data[cache_index].min, -1.0);
1984 if (fabs (min) > fabs (max)) {
1988 prev_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
1991 if(last_pymax < 0) {
1992 /* take the index of one sample right of what we render */
1993 int index = cache_index + (end - begin);
1995 max = MIN(waveview->cache->data[index].max, 1.0);
1996 min = MAX(waveview->cache->data[index].min, -1.0);
1998 if (fabs (min) > fabs (max)) {
2002 last_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
2006 * initialize NEXT* variables for the first run, duplicated in the loop for speed
2008 max = waveview->cache->data[cache_index].max;
2009 min = waveview->cache->data[cache_index].min;
2021 if (fabs (min) > fabs (max)) {
2025 next_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
2030 for(x = begin; x < end; ++x) {
2031 int clip_max = next_clip_max;
2032 int clip_min = next_clip_min;
2039 /*next is now the last column, which is outside the rendering rect, and possibly outside the region*/
2040 next_pymax = last_pymax;
2045 max = waveview->cache->data[cache_index].max;
2046 min = waveview->cache->data[cache_index].min;
2058 if (fabs (min) > fabs (max)) {
2062 next_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
2066 if (pymax == pymin) {
2067 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
2069 if((prev_pymax < pymax && next_pymax < pymax) ||
2070 (prev_pymax == pymax && next_pymax == pymax)) {
2071 fill_max = pymax + 1;
2072 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
2075 fill_max = MAX(prev_pymax, next_pymax);
2076 if(pymax == fill_max) {
2077 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
2081 PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max);
2085 if(fill_max < pymin) {
2086 PAINT_VERTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max, pymin);
2088 else if(fill_max == pymin) {
2089 PAINT_DOTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, pymin);
2094 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length);
2098 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin);
2105 cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
2107 for (x = begin; x < end; x++) {
2110 int clip_max, clip_min;
2115 max = waveview->cache->data[cache_index].max;
2116 min = waveview->cache->data[cache_index].min;
2130 if (fabs (min) > fabs (max)) {
2134 max = max * waveview->height;
2136 pymax = (int) rint ((item->y1 + waveview->height - max) * item->canvas->pixels_per_unit);
2137 pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
2141 max = max * half_height;
2142 min = min * half_height;
2144 pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
2145 pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
2148 /* OK, now fill the RGB buffer at x=i with a line between pymin and pymax,
2149 or, if samples_per_unit == 1, then a dot at each location.
2152 if (pymax == pymin) {
2153 PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
2155 PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, pymin);
2158 /* show clipped waveforms with small red lines */
2161 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length);
2165 PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin);
2168 /* presto, we're done */
2174 if (!waveview->rectified && waveview->zero_line && waveview->height >= 100) {
2177 unsigned char zero_r, zero_g, zero_b, zero_a;
2178 UINT_TO_RGBA( waveview->zero_color, &zero_r, &zero_g, &zero_b, &zero_a);
2179 int zeroline_y = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
2180 PAINT_HORIZA(buf, zero_r, zero_g, zero_b, zero_a, zbegin, zend, zeroline_y);
2186 gnome_canvas_waveview_render (GnomeCanvasItem *item,
2187 GnomeCanvasBuf *buf)
2189 if (_gradient_rendering) {
2190 gnome_canvas_waveview_gradient_render (item, buf);
2192 gnome_canvas_waveview_flat_render (item, buf);
2197 gnome_canvas_waveview_draw (GnomeCanvasItem *item,
2198 GdkDrawable *drawable,
2200 int width, int height)
2202 GnomeCanvasWaveView *waveview;
2215 waveview = GNOME_CANVAS_WAVEVIEW (item);
2217 /* compute intersection of Drawable area and waveview,
2218 in canvas coordinate space
2221 if (x > waveview->bbox_ulx) {
2224 ulx = waveview->bbox_ulx;
2227 if (y > waveview->bbox_uly) {
2230 uly = waveview->bbox_uly;
2233 if (x + width > waveview->bbox_lrx) {
2234 lrx = waveview->bbox_lrx;
2239 if (y + height > waveview->bbox_lry) {
2240 lry = waveview->bbox_lry;
2245 /* figure out which samples we need for the resulting intersection */
2247 s1 = floor ((ulx - waveview->bbox_ulx) * waveview->samples_per_unit) ;
2249 if (lrx == waveview->bbox_lrx) {
2250 /* This avoids minor rounding errors when we have the
2251 entire region visible.
2253 s2 = waveview->samples;
2255 s2 = s1 + floor ((lrx - ulx) * waveview->samples_per_unit);
2258 /* translate back to buffer coordinate space */
2265 /* don't rectify at single-sample zoom */
2266 if(waveview->rectified && waveview->samples_per_unit > 1.0) {
2272 cr = gdk_cairo_create (drawable);
2273 cairo_set_line_width (cr, 0.5);
2275 origin = waveview->bbox_uly - y + waveview->half_height;
2277 cairo_rectangle (cr, ulx, uly, lrx - ulx, lry - uly);
2280 if (waveview->cache_updater && waveview->reload_cache_in_render) {
2281 waveview->cache->start = 0;
2282 waveview->cache->end = 0;
2283 waveview->reload_cache_in_render = FALSE;
2286 cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
2289 printf ("%p r (%d,%d)(%d,%d)[%d x %d] bbox (%d,%d)(%d,%d)[%d x %d]"
2290 " draw (%.1f,%.1f)(%.1f,%.1f)[%.1f x %.1f] s= %lu..%lu\n",
2301 waveview->bbox_lrx - waveview->bbox_ulx,
2302 waveview->bbox_lry - waveview->bbox_uly,
2310 /* draw the top half */
2312 for (xoff = ulx; xoff < lrx; xoff++) {
2315 max = waveview->cache->data[cache_index].max;
2316 min = waveview->cache->data[cache_index].min;
2327 if (fabs (min) > fabs (max)) {
2332 yoff = origin - (waveview->half_height * max) + 0.5;
2336 cairo_move_to (cr, xoff+0.5, yoff);
2338 cairo_line_to (cr, xoff+0.5, yoff);
2344 /* from the final top point, move out of the clip zone */
2346 cairo_line_to (cr, xoff + 10, yoff);
2348 /* now draw the bottom half */
2350 for (--xoff, --cache_index; xoff >= ulx; --xoff) {
2353 min = waveview->cache->data[cache_index].min;
2359 yoff = origin - (waveview->half_height * min) + 0.5;
2361 cairo_line_to (cr, xoff+0.5, yoff);
2365 /* from the final lower point, move out of the clip zone */
2367 cairo_line_to (cr, xoff - 10, yoff);
2369 /* close path to fill */
2371 cairo_close_path (cr);
2373 /* fill and stroke */
2375 cairo_set_source_rgba (cr,
2376 (waveview->fill_r/255.0),
2377 (waveview->fill_g/255.0),
2378 (waveview->fill_b/255.0),
2379 (waveview->fill_a/255.0));
2380 cairo_fill_preserve (cr);
2381 cairo_set_source_rgba (cr,
2382 (waveview->wave_r/255.0),
2383 (waveview->wave_g/255.0),
2384 (waveview->wave_b/255.0),
2385 (waveview->wave_a/255.0));
2392 if (clip_max || clip_min) {
2393 cairo_set_source_rgba (cr, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a);
2397 cairo_move_to (cr, xoff, yoff1);
2398 cairo_line_to (cr, xoff, yoff1 + clip_length);
2403 cairo_move_to (cr, xoff, yoff2);
2404 cairo_line_to (cr, xoff, yoff2 - clip_length);
2411 gnome_canvas_waveview_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
2413 GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (item);
2418 *x2 = ceil (*x1 + (waveview->length_function (waveview->data_src) / waveview->samples_per_unit));
2419 *y2 = *y1 + waveview->height;
2423 gnome_canvas_item_i2w (item, &x, &y);
2424 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &a, &b);
2427 gnome_canvas_item_i2w (item, &x, &y);
2428 gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &c, &d);
2429 printf ("item bounds now (%g,%g),(%g,%g)\n", a, b, c, d);
2435 gnome_canvas_waveview_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item)
2444 /* XXX for now, point is never inside the wave
2445 GnomeCanvasWaveView *waveview;
2446 double x1, y1, x2, y2;
2453 waveview = GNOME_CANVAS_WAVEVIEW (item);
2455 *actual_item = item;
2457 /* Find the bounds for the rectangle plus its outline width */
2459 gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
2461 /* Is point inside rectangle */
2463 if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
2467 /* Point is outside rectangle */
2483 return sqrt (dx * dx + dy * dy);