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
,
124 static GnomeCanvasItemClass
*parent_class
;
127 gnome_canvas_waveview_get_type (void)
129 static GType waveview_type
;
131 if (!waveview_type
) {
132 static const GTypeInfo object_info
= {
133 sizeof (GnomeCanvasWaveViewClass
),
134 (GBaseInitFunc
) NULL
,
135 (GBaseFinalizeFunc
) NULL
,
136 (GClassInitFunc
) gnome_canvas_waveview_class_init
,
137 (GClassFinalizeFunc
) NULL
,
138 NULL
, /* class_data */
139 sizeof (GnomeCanvasWaveView
),
141 (GInstanceInitFunc
) gnome_canvas_waveview_init
,
142 NULL
/* value_table */
145 waveview_type
= g_type_register_static (GNOME_TYPE_CANVAS_ITEM
, "GnomeCanvasWaveView",
149 return waveview_type
;
153 gnome_canvas_waveview_class_init (GnomeCanvasWaveViewClass
*class)
155 GObjectClass
*gobject_class
;
156 GtkObjectClass
*object_class
;
157 GnomeCanvasItemClass
*item_class
;
159 gobject_class
= (GObjectClass
*) class;
160 object_class
= (GtkObjectClass
*) class;
161 item_class
= (GnomeCanvasItemClass
*) class;
163 parent_class
= g_type_class_peek_parent (class);
165 gobject_class
->set_property
= gnome_canvas_waveview_set_property
;
166 gobject_class
->get_property
= gnome_canvas_waveview_get_property
;
168 g_object_class_install_property
171 g_param_spec_pointer ("data_src", NULL
, NULL
,
172 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
174 g_object_class_install_property
177 g_param_spec_uint ("channel", NULL
, NULL
,
179 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
181 g_object_class_install_property
183 PROP_LENGTH_FUNCTION
,
184 g_param_spec_pointer ("length_function", NULL
, NULL
,
185 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
187 g_object_class_install_property
189 PROP_SOURCEFILE_LENGTH_FUNCTION
,
190 g_param_spec_pointer ("sourcefile_length_function", NULL
, NULL
,
191 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
193 g_object_class_install_property
196 g_param_spec_pointer ("peak_function", NULL
, NULL
,
197 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
199 g_object_class_install_property
202 g_param_spec_pointer ("gain_function", NULL
, NULL
,
203 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
205 g_object_class_install_property
208 g_param_spec_pointer ("gain_src", NULL
, NULL
,
209 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
211 g_object_class_install_property
214 g_param_spec_pointer ("cache", NULL
, NULL
,
215 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
217 g_object_class_install_property
220 g_param_spec_boolean ("cache_updater", NULL
, NULL
,
222 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
224 g_object_class_install_property
226 PROP_SAMPLES_PER_UNIT
,
227 g_param_spec_double ("samples_per_unit", NULL
, NULL
,
228 0.0, G_MAXDOUBLE
, 0.0,
229 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
231 g_object_class_install_property
233 PROP_AMPLITUDE_ABOVE_AXIS
,
234 g_param_spec_double ("amplitude_above_axis", NULL
, NULL
,
235 0.0, G_MAXDOUBLE
, 0.0,
236 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
238 g_object_class_install_property
241 g_param_spec_double ("x", NULL
, NULL
,
242 0.0, G_MAXDOUBLE
, 0.0,
243 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
245 g_object_class_install_property
248 g_param_spec_double ("y", NULL
, NULL
,
249 0.0, G_MAXDOUBLE
, 0.0,
250 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
252 g_object_class_install_property
255 g_param_spec_double ("height", NULL
, NULL
,
256 0.0, G_MAXDOUBLE
, 0.0,
257 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
259 g_object_class_install_property
262 g_param_spec_uint ("wave_color", NULL
, NULL
,
264 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
266 g_object_class_install_property
269 g_param_spec_uint ("clip_color", NULL
, NULL
,
271 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
273 g_object_class_install_property
276 g_param_spec_uint ("zero_color", NULL
, NULL
,
278 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
280 g_object_class_install_property
283 g_param_spec_uint ("fill_color", NULL
, NULL
,
285 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
287 g_object_class_install_property
290 g_param_spec_boolean ("filled", NULL
, NULL
,
292 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
294 g_object_class_install_property
297 g_param_spec_boolean ("rectified", NULL
, NULL
,
299 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
301 g_object_class_install_property
304 g_param_spec_boolean ("zero_line", NULL
, NULL
,
306 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
308 g_object_class_install_property
311 g_param_spec_boolean ("logscaled", NULL
, NULL
,
313 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
315 g_object_class_install_property
318 g_param_spec_uint ("region_start", NULL
, NULL
,
320 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
322 object_class
->destroy
= gnome_canvas_waveview_destroy
;
324 item_class
->update
= gnome_canvas_waveview_update
;
325 item_class
->bounds
= gnome_canvas_waveview_bounds
;
326 item_class
->point
= gnome_canvas_waveview_point
;
327 item_class
->render
= gnome_canvas_waveview_render
;
328 item_class
->draw
= gnome_canvas_waveview_draw
;
331 GnomeCanvasWaveViewCache
*
332 gnome_canvas_waveview_cache_new ()
334 GnomeCanvasWaveViewCache
*c
;
336 c
= g_malloc (sizeof (GnomeCanvasWaveViewCache
));
339 c
->data
= g_malloc (sizeof (GnomeCanvasWaveViewCacheEntry
) * c
->allocated
);
348 gnome_canvas_waveview_cache_destroy (GnomeCanvasWaveViewCache
* cache
)
350 g_free (cache
->data
);
355 gnome_canvas_waveview_init (GnomeCanvasWaveView
*waveview
)
360 waveview
->cache_updater
= FALSE
;
361 waveview
->data_src
= NULL
;
362 waveview
->channel
= 0;
363 waveview
->peak_function
= NULL
;
364 waveview
->length_function
= NULL
;
365 waveview
->sourcefile_length_function
= NULL
;
366 waveview
->gain_curve_function
= NULL
;
367 waveview
->gain_src
= NULL
;
368 waveview
->rectified
= FALSE
;
369 waveview
->logscaled
= FALSE
;
370 waveview
->filled
= TRUE
;
371 waveview
->zero_line
= FALSE
;
372 waveview
->region_start
= 0;
373 waveview
->samples_per_unit
= 1.0;
374 waveview
->amplitude_above_axis
= 1.0;
375 waveview
->height
= 100.0;
376 waveview
->screen_width
= gdk_screen_width ();
377 waveview
->reload_cache_in_render
= FALSE
;
379 waveview
->wave_color
= 0;
380 waveview
->clip_color
= 0;
381 waveview
->zero_color
= 0;
382 waveview
->fill_color
= 0;
386 gnome_canvas_waveview_destroy (GtkObject
*object
)
388 GnomeCanvasWaveView
*waveview
;
390 g_return_if_fail (object
!= NULL
);
391 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object
));
393 waveview
= GNOME_CANVAS_WAVEVIEW (object
);
395 if (GTK_OBJECT_CLASS (parent_class
)->destroy
)
396 (* GTK_OBJECT_CLASS (parent_class
)->destroy
) (object
);
399 #define DEBUG_CACHE 0
400 #undef CACHE_MEMMOVE_OPTIMIZATION
402 /** @return cache index of start_sample within the cache */
404 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView
*waveview
, gulong start_sample
, gulong end_sample
)
406 gulong required_cache_entries
;
407 gulong rf1
, rf2
,rf3
, required_frames
;
408 gulong new_cache_start
, new_cache_end
;
414 GnomeCanvasWaveViewCache
*cache
;
416 #ifdef CACHE_MEMMOVE_OPTIMIZATION
417 gulong present_frames
;
418 gulong present_entries
;
421 cache
= waveview
->cache
;
423 start_sample
= start_sample
+ waveview
->region_start
;
424 end_sample
= end_sample
+ waveview
->region_start
;
426 // printf("waveview->region_start == %lu\n",waveview->region_start);
428 printf ("\n\n=> 0x%x cache @ 0x%x range: %lu - %lu request: %lu - %lu (%lu frames)\n",
430 cache
->start
, cache
->end
,
431 start_sample
, end_sample
, end_sample
- start_sample
);
434 if (cache
->start
<= start_sample
&& cache
->end
>= end_sample
) {
436 // printf ("0x%x: cache hit for %lu-%lu (cache holds: %lu-%lu\n",
437 // waveview, start_sample, end_sample, cache->start, cache->end);
442 /* make sure the cache is at least twice as wide as the screen width, and put the start sample
443 in the middle, ensuring that we cover the end_sample.
446 /* Note the assumption that we have a 1:1 units:pixel ratio for the canvas. Its everywhere ... */
448 half_width
= (gulong
) floor ((waveview
->screen_width
* waveview
->samples_per_unit
)/2.0 + 0.5);
450 if (start_sample
< half_width
) {
453 new_cache_start
= start_sample
- half_width
;
456 /* figure out how many frames we want */
458 rf1
= end_sample
- start_sample
+ 1;
459 rf2
= (gulong
) floor ((waveview
->screen_width
* waveview
->samples_per_unit
* 2.0f
));
460 required_frames
= MAX(rf1
,rf2
);
462 /* but make sure it doesn't extend beyond the end of the source material */
464 rf3
= (gulong
) (waveview
->sourcefile_length_function (waveview
->data_src
, waveview
->samples_per_unit
)) + 1;
465 if (rf3
< new_cache_start
) {
468 rf3
-= new_cache_start
;
472 fprintf (stderr
, "AVAILABLE FRAMES = %lu of %lu, start = %lu, sstart = %lu, cstart = %lu\n",
473 rf3
, waveview
->sourcefile_length_function (waveview
->data_src
, waveview
->samples_per_unit
),
474 waveview
->region_start
, start_sample
, new_cache_start
);
477 required_frames
= MIN(required_frames
,rf3
);
479 new_cache_end
= new_cache_start
+ required_frames
- 1;
481 required_cache_entries
= (gulong
) floor (required_frames
/ waveview
->samples_per_unit
);
484 fprintf (stderr
, "new cache = %lu - %lu\n", new_cache_start
, new_cache_end
);
485 fprintf(stderr
,"required_cach_entries = %lu, samples_per_unit = %f req frames = %lu\n",
486 required_cache_entries
,waveview
->samples_per_unit
, required_frames
);
489 if (required_cache_entries
> cache
->allocated
) {
490 cache
->data
= g_realloc (cache
->data
, sizeof (GnomeCanvasWaveViewCacheEntry
) * required_cache_entries
);
491 cache
->allocated
= required_cache_entries
;
496 ostart
= new_cache_start
;
498 #ifdef CACHE_MEMMOVE_OPTIMIZATION
500 /* data is not entirely in the cache, so go fetch it, making sure to fill the cache */
502 /* some of the required cache entries are in the cache, but in the wrong
503 locations. use memmove to fix this.
506 if (cache
->start
< new_cache_start
&& new_cache_start
< cache
->end
) {
508 /* case one: the common area is at the end of the existing cache. move it
509 to the beginning of the cache, and set up to refill whatever remains.
512 wv->cache_start wv->cache_end
513 |-------------------------------------------------------| cache
514 |--------------------------------| requested
515 <------------------->
517 new_cache_start new_cache_end
521 present_frames
= cache
->end
- new_cache_start
;
522 present_entries
= (gulong
) floor (present_frames
/ waveview
->samples_per_unit
);
525 fprintf (stderr
, "existing material at end of current cache, move to start of new cache\n"
526 "\tcopy from %lu to start\n", cache
->data_size
- present_entries
);
529 memmove (&cache
->data
[0],
530 &cache
->data
[cache
->data_size
- present_entries
],
531 present_entries
* sizeof (GnomeCanvasWaveViewCacheEntry
));
534 fprintf (stderr
, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
535 present_frames
, required_frames
, present_entries
, new_cache_start
+ present_entries
,
536 cache
->data
+ present_entries
);
539 copied
= present_entries
;
540 offset
= present_entries
;
541 new_cache_start
+= present_frames
;
542 required_frames
-= present_frames
;
544 } else if (new_cache_end
> cache
->start
&& new_cache_end
< cache
->end
) {
546 /* case two: the common area lives at the beginning of the existing cache.
548 wv->cache_start wv->cache_end
549 |-----------------------------------------------------|
550 |--------------------------------|
554 new_cache_start new_cache_end
557 present_frames
= new_cache_end
- cache
->start
;
558 present_entries
= (gulong
) floor (present_frames
/ waveview
->samples_per_unit
);
560 memmove (&cache
->data
[cache
->data_size
- present_entries
],
562 present_entries
* sizeof (GnomeCanvasWaveViewCacheEntry
));
565 fprintf (stderr
, "existing material at start of current cache, move to start of end cache\n");
569 fprintf (stderr
, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
570 present_entries
, required_frames
, present_entries
, new_cache_start
+ present_entries
,
571 cache
->data
+ present_entries
);
574 copied
= present_entries
;
576 required_frames
-= present_frames
;
589 #endif /* CACHE_MEMMOVE_OPTIMIZATION */
591 // fprintf(stderr,"length == %lu\n",waveview->length_function (waveview->data_src));
592 // required_frames = MIN (waveview->length_function (waveview->data_src) - new_cache_start, required_frames);
594 npeaks
= (gulong
) floor (required_frames
/ waveview
->samples_per_unit
);
595 required_frames
= npeaks
* waveview
->samples_per_unit
;
600 printf ("requesting %lu/%f to cover %lu-%lu at %f spu (request was %lu-%lu) into cache + %lu\n",
601 required_frames
, required_frames
/waveview
->samples_per_unit
, new_cache_start
, new_cache_end
,
602 waveview
->samples_per_unit
, start_sample
, end_sample
, offset
);
606 // printf ("cache holds %lu entries, requesting %lu to cover %lu-%lu (request was %lu-%lu)\n",
607 // cache->data_size, npeaks, new_cache_start, new_cache_end,
608 // start_sample, end_sample);
611 if (required_frames
) {
612 waveview
->peak_function (waveview
->data_src
, npeaks
, new_cache_start
, required_frames
, cache
->data
+ offset
, waveview
->channel
,waveview
->samples_per_unit
);
614 /* take into account any copied peaks */
621 if (npeaks
< cache
->allocated
) {
623 fprintf (stderr
, "zero fill cache for %lu at %lu\n", cache
->allocated
- npeaks
, npeaks
);
625 memset (&cache
->data
[npeaks
], 0, sizeof (GnomeCanvasWaveViewCacheEntry
) * (cache
->allocated
- npeaks
));
626 cache
->data_size
= npeaks
;
628 cache
->data_size
= cache
->allocated
;
631 if (waveview
->gain_curve_function
) {
634 gain
= (float*) malloc (sizeof (float) * cache
->data_size
);
636 waveview
->gain_curve_function (waveview
->gain_src
, new_cache_start
, new_cache_end
, gain
, cache
->data_size
);
638 for (n
= 0; n
< cache
->data_size
; ++n
) {
639 cache
->data
[n
].min
*= gain
[n
];
640 cache
->data
[n
].max
*= gain
[n
];
647 /* do optional log scaling. this implementation is not particularly efficient */
649 if (waveview
->logscaled
) {
651 GnomeCanvasWaveViewCacheEntry
* buf
= cache
->data
;
653 for (n
= 0; n
< cache
->data_size
; ++n
) {
655 if (buf
[n
].max
> 0.0f
) {
656 buf
[n
].max
= alt_log_meter(fast_coefficient_to_dB(buf
[n
].max
));
657 } else if (buf
[n
].max
< 0.0f
) {
658 buf
[n
].max
= -alt_log_meter(fast_coefficient_to_dB(-buf
[n
].max
));
661 if (buf
[n
].min
> 0.0f
) {
662 buf
[n
].min
= alt_log_meter(fast_coefficient_to_dB(buf
[n
].min
));
663 } else if (buf
[n
].min
< 0.0f
) {
664 buf
[n
].min
= -alt_log_meter(fast_coefficient_to_dB(-buf
[n
].min
));
669 cache
->start
= ostart
;
670 cache
->end
= new_cache_end
;
674 fprintf (stderr
, "return cache index = %d\n",
675 (guint32
) floor ((((double) (start_sample
- cache
->start
)) / waveview
->samples_per_unit
) + 0.5));
677 return (guint32
) floor ((((double) (start_sample
- cache
->start
)) / waveview
->samples_per_unit
) + 0.5);
682 gnome_canvas_waveview_set_data_src (GnomeCanvasWaveView
*waveview
, void *data_src
)
685 if (waveview
->cache_updater
) {
686 if (waveview
->data_src
== data_src
) {
687 waveview
->reload_cache_in_render
= TRUE
;
691 waveview
->cache
->start
= 0;
692 waveview
->cache
->end
= 0;
695 waveview
->data_src
= data_src
;
699 gnome_canvas_waveview_set_channel (GnomeCanvasWaveView
*waveview
, guint32 chan
)
701 if (waveview
->channel
== chan
) {
705 waveview
->channel
= chan
;
709 gnome_canvas_waveview_reset_bounds (GnomeCanvasItem
*item
)
712 double x1
, x2
, y1
, y2
;
715 int Ix1
, Ix2
, Iy1
, Iy2
;
718 gnome_canvas_waveview_bounds (item
, &x1
, &y1
, &x2
, &y2
);
725 gnome_canvas_item_i2w_affine (item
, i2w
);
726 art_affine_point (&w1
, &i1
, i2w
);
727 art_affine_point (&w2
, &i2
, i2w
);
729 Ix1
= (int) rint(w1
.x
);
730 Ix2
= (int) rint(w2
.x
);
731 Iy1
= (int) rint(w1
.y
);
732 Iy2
= (int) rint(w2
.y
);
734 gnome_canvas_update_bbox (item
, Ix1
, Iy1
, Ix2
, Iy2
);
742 gnome_canvas_waveview_set_property (GObject
*object
,
750 GnomeCanvasItem
*item
;
751 GnomeCanvasWaveView
*waveview
;
753 int calc_bounds
= FALSE
;
755 g_return_if_fail (object
!= NULL
);
756 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object
));
758 item
= GNOME_CANVAS_ITEM (object
);
759 waveview
= GNOME_CANVAS_WAVEVIEW (object
);
764 gnome_canvas_waveview_set_data_src (waveview
, g_value_get_pointer(value
));
769 gnome_canvas_waveview_set_channel (waveview
, g_value_get_uint(value
));
773 case PROP_LENGTH_FUNCTION
:
774 ptr
= g_value_get_pointer(value
);
775 waveview
->length_function
= POSIX_FUNC_PTR_CAST(waveview_length_function_t
, ptr
);
779 case PROP_SOURCEFILE_LENGTH_FUNCTION
:
780 ptr
= g_value_get_pointer(value
);
781 waveview
->sourcefile_length_function
= POSIX_FUNC_PTR_CAST(waveview_sourcefile_length_function_t
, ptr
);
785 case PROP_PEAK_FUNCTION
:
786 ptr
= g_value_get_pointer(value
);
787 waveview
->peak_function
= POSIX_FUNC_PTR_CAST(waveview_peak_function_t
, ptr
);
791 case PROP_GAIN_FUNCTION
:
792 ptr
= g_value_get_pointer(value
);
793 waveview
->gain_curve_function
= POSIX_FUNC_PTR_CAST(waveview_gain_curve_function_t
, ptr
);
798 waveview
->gain_src
= g_value_get_pointer(value
);
799 if (waveview
->cache_updater
) {
800 waveview
->cache
->start
= 0;
801 waveview
->cache
->end
= 0;
808 waveview
->cache
= g_value_get_pointer(value
);
813 case PROP_CACHE_UPDATER
:
814 waveview
->cache_updater
= g_value_get_boolean(value
);
818 case PROP_SAMPLES_PER_UNIT
:
819 if ((waveview
->samples_per_unit
= g_value_get_double(value
)) < 1.0) {
820 waveview
->samples_per_unit
= 1.0;
822 if (waveview
->cache_updater
) {
823 waveview
->cache
->start
= 0;
824 waveview
->cache
->end
= 0;
830 case PROP_AMPLITUDE_ABOVE_AXIS
:
831 waveview
->amplitude_above_axis
= g_value_get_double(value
);
836 if (waveview
->x
!= g_value_get_double (value
)) {
837 waveview
->x
= g_value_get_double (value
);
843 if (waveview
->y
!= g_value_get_double (value
)) {
844 waveview
->y
= g_value_get_double (value
);
850 if (waveview
->height
!= fabs (g_value_get_double (value
))) {
851 waveview
->height
= fabs (g_value_get_double (value
));
856 case PROP_WAVE_COLOR
:
857 if (waveview
->wave_color
!= g_value_get_uint(value
)) {
858 waveview
->wave_color
= g_value_get_uint(value
);
863 case PROP_CLIP_COLOR
:
864 if (waveview
->clip_color
!= g_value_get_uint(value
)) {
865 waveview
->clip_color
= g_value_get_uint(value
);
870 case PROP_ZERO_COLOR
:
871 if (waveview
->zero_color
!= g_value_get_uint(value
)) {
872 waveview
->zero_color
= g_value_get_uint(value
);
877 case PROP_FILL_COLOR
:
878 if (waveview
->fill_color
!= g_value_get_uint(value
)) {
879 waveview
->fill_color
= g_value_get_uint(value
);
885 if (waveview
->filled
!= g_value_get_boolean(value
)) {
886 waveview
->filled
= g_value_get_boolean(value
);
892 if (waveview
->rectified
!= g_value_get_boolean(value
)) {
893 waveview
->rectified
= g_value_get_boolean(value
);
899 if (waveview
->zero_line
!= g_value_get_boolean(value
)) {
900 waveview
->zero_line
= g_value_get_boolean(value
);
906 if (waveview
->logscaled
!= g_value_get_boolean(value
)) {
907 waveview
->logscaled
= g_value_get_boolean(value
);
908 if (waveview
->cache_updater
) {
909 waveview
->cache
->start
= 0;
910 waveview
->cache
->end
= 0;
916 case PROP_REGION_START
:
917 waveview
->region_start
= g_value_get_uint(value
);
928 gnome_canvas_waveview_reset_bounds (item
);
932 gnome_canvas_item_request_update (item
);
938 gnome_canvas_waveview_get_property (
946 g_return_if_fail (object
!= NULL
);
947 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object
));
949 GnomeCanvasWaveView
*waveview
= GNOME_CANVAS_WAVEVIEW (object
);
953 g_value_set_pointer(value
, waveview
->data_src
);
957 g_value_set_uint(value
, waveview
->channel
);
960 case PROP_LENGTH_FUNCTION
:
961 g_value_set_pointer(value
, POSIX_FUNC_PTR_CAST(void*, waveview
->length_function
));
964 case PROP_SOURCEFILE_LENGTH_FUNCTION
:
965 g_value_set_pointer(value
, POSIX_FUNC_PTR_CAST(void*, waveview
->sourcefile_length_function
));
968 case PROP_PEAK_FUNCTION
:
969 g_value_set_pointer(value
, POSIX_FUNC_PTR_CAST(void*, waveview
->peak_function
));
972 case PROP_GAIN_FUNCTION
:
973 g_value_set_pointer(value
, POSIX_FUNC_PTR_CAST(void*, waveview
->gain_curve_function
));
977 g_value_set_pointer(value
, waveview
->gain_src
);
981 g_value_set_pointer(value
, waveview
->cache
);
984 case PROP_CACHE_UPDATER
:
985 g_value_set_boolean(value
, waveview
->cache_updater
);
988 case PROP_SAMPLES_PER_UNIT
:
989 g_value_set_double(value
, waveview
->samples_per_unit
);
992 case PROP_AMPLITUDE_ABOVE_AXIS
:
993 g_value_set_double(value
, waveview
->amplitude_above_axis
);
997 g_value_set_double (value
, waveview
->x
);
1001 g_value_set_double (value
, waveview
->y
);
1005 g_value_set_double (value
, waveview
->height
);
1008 case PROP_WAVE_COLOR
:
1009 g_value_set_uint (value
, waveview
->wave_color
);
1012 case PROP_CLIP_COLOR
:
1013 g_value_set_uint (value
, waveview
->clip_color
);
1016 case PROP_ZERO_COLOR
:
1017 g_value_set_uint (value
, waveview
->zero_color
);
1020 case PROP_FILL_COLOR
:
1021 g_value_set_uint (value
, waveview
->fill_color
);
1025 g_value_set_boolean (value
, waveview
->filled
);
1028 case PROP_RECTIFIED
:
1029 g_value_set_boolean (value
, waveview
->rectified
);
1032 case PROP_ZERO_LINE
:
1033 g_value_set_boolean (value
, waveview
->zero_line
);
1036 case PROP_LOGSCALED
:
1037 g_value_set_boolean (value
, waveview
->logscaled
);
1040 case PROP_REGION_START
:
1041 g_value_set_uint (value
, waveview
->region_start
);
1045 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
1051 gnome_canvas_waveview_update (GnomeCanvasItem
*item
, double *affine
, ArtSVP
*clip_path
, int flags
)
1053 GnomeCanvasWaveView
*waveview
;
1056 waveview
= GNOME_CANVAS_WAVEVIEW (item
);
1058 // check_cache (waveview, "start of update");
1060 if (parent_class
->update
)
1061 (* parent_class
->update
) (item
, affine
, clip_path
, flags
);
1063 gnome_canvas_waveview_reset_bounds (item
);
1065 /* get the canvas coordinates of the view. Do NOT use affines
1066 for this, because they do not round to the integer units used
1067 by the canvas, resulting in subtle pixel-level errors later.
1073 gnome_canvas_item_i2w (item
, &x
, &y
);
1074 gnome_canvas_w2c (GNOME_CANVAS(item
->canvas
), x
, y
, &waveview
->bbox_ulx
, &waveview
->bbox_uly
);
1076 waveview
->samples
= waveview
->length_function (waveview
->data_src
);
1078 x
= waveview
->x
+ (waveview
->samples
/ waveview
->samples_per_unit
);
1079 y
= waveview
->y
+ waveview
->height
;
1081 gnome_canvas_item_i2w (item
, &x
, &y
);
1082 gnome_canvas_w2c (GNOME_CANVAS(item
->canvas
), x
, y
, &waveview
->bbox_lrx
, &waveview
->bbox_lry
);
1084 /* cache the half-height and the end point in canvas units */
1086 waveview
->half_height
= waveview
->height
/ 2.0;
1088 /* parse the color */
1090 UINT_TO_RGBA (waveview
->wave_color
, &waveview
->wave_r
, &waveview
->wave_g
, &waveview
->wave_b
,
1092 UINT_TO_RGBA (waveview
->clip_color
, &waveview
->clip_r
, &waveview
->clip_g
, &waveview
->clip_b
,
1094 UINT_TO_RGBA (waveview
->fill_color
, &waveview
->fill_r
, &waveview
->fill_g
, &waveview
->fill_b
,
1097 // check_cache (waveview, "end of update");
1101 gnome_canvas_waveview_render (GnomeCanvasItem
*item
,
1102 GnomeCanvasBuf
*buf
)
1104 GnomeCanvasWaveView
*waveview
;
1106 int clip_length
= 0;
1113 waveview
= GNOME_CANVAS_WAVEVIEW (item
);
1115 // check_cache (waveview, "start of render");
1117 if (parent_class
->render
) {
1118 (*parent_class
->render
) (item
, buf
);
1122 gnome_canvas_buf_ensure_buf (buf
);
1126 /* a "unit" means a pixel */
1128 /* begin: render start x (units) */
1129 int const begin
= MAX (waveview
->bbox_ulx
, buf
->rect
.x0
);
1131 /* zbegin: start x for zero line (units) */
1132 int const zbegin
= (begin
== waveview
->bbox_ulx
) ? (begin
+ 1) : begin
;
1134 /* end: render end x (units) */
1135 int const end
= (waveview
->bbox_lrx
>= 0) ? MIN (waveview
->bbox_lrx
,buf
->rect
.x1
) : buf
->rect
.x1
;
1137 /* zend: end x for zero-line (units) */
1138 int const zend
= (end
== waveview
->bbox_lrx
) ? (end
- 1) : end
;
1148 s1
= floor ((begin
- waveview
->bbox_ulx
) * waveview
->samples_per_unit
);
1150 // fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit);
1152 if (end
== waveview
->bbox_lrx
) {
1153 /* This avoids minor rounding errors when we have the
1154 entire region visible.
1156 s2
= waveview
->samples
;
1158 s2
= s1
+ floor ((end
- begin
) * waveview
->samples_per_unit
);
1162 printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)"
1163 " b/e %d..%d s= %lu..%lu @ %f\n",
1174 waveview
->samples_per_unit
);
1177 /* now ensure that the cache is full and properly
1181 // check_cache (waveview, "pre-ensure");
1183 if (waveview
->cache_updater
&& waveview
->reload_cache_in_render
) {
1184 waveview
->cache
->start
= 0;
1185 waveview
->cache
->end
= 0;
1186 waveview
->reload_cache_in_render
= FALSE
;
1189 // check_cache (waveview, "post-ensure");
1191 /* don't rectify at single-sample zoom */
1192 if (waveview
->rectified
&& waveview
->samples_per_unit
> 1) {
1199 clip_length
= MIN(5,(waveview
->height
/4));
1202 Now draw each line, clipping it appropriately. The clipping
1203 is done by the macros PAINT_FOO().
1206 half_height
= waveview
->half_height
;
1208 /* this makes it slightly easier to comprehend whats going on */
1209 #define origin half_height
1211 if (waveview
->filled
&& !rectify
) {
1216 int next_pymin
, next_pymax
;
1218 int next_clip_max
= 0;
1219 int next_clip_min
= 0;
1221 if (s1
< waveview
->samples_per_unit
) {
1222 /* we haven't got a prev vars to compare with, so outline the whole line here */
1223 prev_pymax
= (int) rint ((item
->y1
+ origin
) * item
->canvas
->pixels_per_unit
);
1224 prev_pymin
= prev_pymax
;
1227 s1
-= waveview
->samples_per_unit
;
1230 if(end
== waveview
->bbox_lrx
) {
1231 /* we don't have the NEXT vars for the last sample */
1232 last_pymax
= (int) rint ((item
->y1
+ origin
) * item
->canvas
->pixels_per_unit
);
1233 last_pymin
= last_pymax
;
1236 s2
+= waveview
->samples_per_unit
;
1239 cache_index
= gnome_canvas_waveview_ensure_cache (waveview
, s1
, s2
);
1242 * Compute the variables outside the rendering rect
1244 if(prev_pymax
!= prev_pymin
) {
1246 prev_pymax
= (int) rint ((item
->y1
+ origin
- MIN(waveview
->cache
->data
[cache_index
].max
, 1.0) * half_height
) * item
->canvas
->pixels_per_unit
);
1247 prev_pymin
= (int) rint ((item
->y1
+ origin
- MAX(waveview
->cache
->data
[cache_index
].min
, -1.0) * half_height
) * item
->canvas
->pixels_per_unit
);
1250 if(last_pymax
!= last_pymin
) {
1251 /* take the index of one sample right of what we render */
1252 guint index
= cache_index
+ (end
- begin
);
1254 if (index
>= waveview
->cache
->data_size
) {
1256 /* the data we want is off the end of the cache, which must mean its beyond
1257 the end of the region's source; hence the peak values are 0 */
1258 last_pymax
= (int) rint ((item
->y1
+ origin
) * item
->canvas
->pixels_per_unit
);
1259 last_pymin
= (int) rint ((item
->y1
+ origin
) * item
->canvas
->pixels_per_unit
);
1263 last_pymax
= (int) rint ((item
->y1
+ origin
- MIN(waveview
->cache
->data
[index
].max
, 1.0) * half_height
) * item
->canvas
->pixels_per_unit
);
1264 last_pymin
= (int) rint ((item
->y1
+ origin
- MAX(waveview
->cache
->data
[index
].min
, -1.0) * half_height
) * item
->canvas
->pixels_per_unit
);
1271 * initialize NEXT* variables for the first run, duplicated in the loop for speed
1273 max
= waveview
->cache
->data
[cache_index
].max
;
1274 min
= waveview
->cache
->data
[cache_index
].min
;
1289 next_pymax
= (int) rint ((item
->y1
+ origin
- max
) * item
->canvas
->pixels_per_unit
);
1290 next_pymin
= (int) rint ((item
->y1
+ origin
- min
) * item
->canvas
->pixels_per_unit
);
1295 for(x
= begin
; x
< end
; ++x
) {
1296 int clip_max
= next_clip_max
;
1297 int clip_min
= next_clip_min
;
1298 int fill_max
, fill_min
;
1305 /*next is now the last column, which is outside the rendering rect, and possibly outside the region*/
1306 next_pymax
= last_pymax
;
1307 next_pymin
= last_pymin
;
1312 if (cache_index
< waveview
->cache
->data_size
) {
1313 max
= waveview
->cache
->data
[cache_index
].max
;
1314 min
= waveview
->cache
->data
[cache_index
].min
;
1335 next_pymax
= (int) rint ((item
->y1
+ origin
- max
) * item
->canvas
->pixels_per_unit
);
1336 next_pymin
= (int) rint ((item
->y1
+ origin
- min
) * item
->canvas
->pixels_per_unit
);
1340 if (pymax
== pymin
) {
1341 PAINT_DOTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymin
);
1343 if((prev_pymax
< pymax
&& next_pymax
< pymax
) ||
1344 (prev_pymax
== pymax
&& next_pymax
== pymax
)) {
1345 fill_max
= pymax
+ 1;
1346 PAINT_DOTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymax
);
1349 fill_max
= MAX(prev_pymax
, next_pymax
);
1350 if(pymax
== fill_max
) {
1351 PAINT_DOTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymax
);
1355 PAINT_VERTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymax
, fill_max
);
1359 if((prev_pymin
> pymin
&& next_pymin
> pymin
) ||
1360 (prev_pymin
== pymin
&& next_pymin
== pymin
)) {
1361 fill_min
= pymin
- 1;
1362 PAINT_DOTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymin
-1);
1365 fill_min
= MIN(prev_pymin
, next_pymin
);
1366 if(pymin
== fill_min
) {
1367 PAINT_DOTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymin
);
1370 PAINT_VERTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, fill_min
, pymin
);
1374 if(fill_max
< fill_min
) {
1375 PAINT_VERTA(buf
, waveview
->fill_r
, waveview
->fill_g
, waveview
->fill_b
, waveview
->fill_a
, x
, fill_max
, fill_min
);
1377 else if(fill_max
== fill_min
) {
1378 PAINT_DOTA(buf
, waveview
->fill_r
, waveview
->fill_g
, waveview
->fill_b
, waveview
->fill_a
, x
, fill_max
);
1383 PAINT_VERTA(buf
, waveview
->clip_r
, waveview
->clip_g
, waveview
->clip_b
, waveview
->clip_a
, x
, pymax
, pymax
+clip_length
);
1387 PAINT_VERTA(buf
, waveview
->clip_r
, waveview
->clip_g
, waveview
->clip_b
, waveview
->clip_a
, x
, pymin
-clip_length
, pymin
);
1394 } else if (waveview
->filled
&& rectify
) {
1396 int prev_pymax
= -1;
1397 int last_pymax
= -1;
1400 int next_clip_max
= 0;
1401 int next_clip_min
= 0;
1403 // for rectified, this stays constant throughout the loop
1404 pymin
= (int) rint ((item
->y1
+ waveview
->height
) * item
->canvas
->pixels_per_unit
);
1406 if(s1
< waveview
->samples_per_unit
) {
1407 /* we haven't got a prev vars to compare with, so outline the whole line here */
1411 s1
-= waveview
->samples_per_unit
;
1414 if(end
== waveview
->bbox_lrx
) {
1415 /* we don't have the NEXT vars for the last sample */
1419 s2
+= waveview
->samples_per_unit
;
1422 cache_index
= gnome_canvas_waveview_ensure_cache (waveview
, s1
, s2
);
1425 * Compute the variables outside the rendering rect
1427 if(prev_pymax
< 0) {
1428 max
= MIN(waveview
->cache
->data
[cache_index
].max
, 1.0);
1429 min
= MAX(waveview
->cache
->data
[cache_index
].min
, -1.0);
1431 if (fabs (min
) > fabs (max
)) {
1435 prev_pymax
= (int) rint ((item
->y1
+ waveview
->height
- max
* waveview
->height
) * item
->canvas
->pixels_per_unit
);
1438 if(last_pymax
< 0) {
1439 /* take the index of one sample right of what we render */
1440 int index
= cache_index
+ (end
- begin
);
1442 max
= MIN(waveview
->cache
->data
[index
].max
, 1.0);
1443 min
= MAX(waveview
->cache
->data
[index
].min
, -1.0);
1445 if (fabs (min
) > fabs (max
)) {
1449 last_pymax
= (int) rint ((item
->y1
+ waveview
->height
- max
* waveview
->height
) * item
->canvas
->pixels_per_unit
);
1453 * initialize NEXT* variables for the first run, duplicated in the loop for speed
1455 max
= waveview
->cache
->data
[cache_index
].max
;
1456 min
= waveview
->cache
->data
[cache_index
].min
;
1468 if (fabs (min
) > fabs (max
)) {
1472 next_pymax
= (int) rint ((item
->y1
+ waveview
->height
- max
* waveview
->height
) * item
->canvas
->pixels_per_unit
);
1477 for(x
= begin
; x
< end
; ++x
) {
1478 int clip_max
= next_clip_max
;
1479 int clip_min
= next_clip_min
;
1486 /*next is now the last column, which is outside the rendering rect, and possibly outside the region*/
1487 next_pymax
= last_pymax
;
1492 max
= waveview
->cache
->data
[cache_index
].max
;
1493 min
= waveview
->cache
->data
[cache_index
].min
;
1505 if (fabs (min
) > fabs (max
)) {
1509 next_pymax
= (int) rint ((item
->y1
+ waveview
->height
- max
* waveview
->height
) * item
->canvas
->pixels_per_unit
);
1513 if (pymax
== pymin
) {
1514 PAINT_DOTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymin
);
1516 if((prev_pymax
< pymax
&& next_pymax
< pymax
) ||
1517 (prev_pymax
== pymax
&& next_pymax
== pymax
)) {
1518 fill_max
= pymax
+ 1;
1519 PAINT_DOTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymax
);
1522 fill_max
= MAX(prev_pymax
, next_pymax
);
1523 if(pymax
== fill_max
) {
1524 PAINT_DOTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymax
);
1528 PAINT_VERTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymax
, fill_max
);
1532 if(fill_max
< pymin
) {
1533 PAINT_VERTA(buf
, waveview
->fill_r
, waveview
->fill_g
, waveview
->fill_b
, waveview
->fill_a
, x
, fill_max
, pymin
);
1535 else if(fill_max
== pymin
) {
1536 PAINT_DOTA(buf
, waveview
->fill_r
, waveview
->fill_g
, waveview
->fill_b
, waveview
->fill_a
, x
, pymin
);
1541 PAINT_VERTA(buf
, waveview
->clip_r
, waveview
->clip_g
, waveview
->clip_b
, waveview
->clip_a
, x
, pymax
, pymax
+clip_length
);
1545 PAINT_VERTA(buf
, waveview
->clip_r
, waveview
->clip_g
, waveview
->clip_b
, waveview
->clip_a
, x
, pymin
-clip_length
, pymin
);
1552 cache_index
= gnome_canvas_waveview_ensure_cache (waveview
, s1
, s2
);
1554 for (x
= begin
; x
< end
; x
++) {
1557 int clip_max
, clip_min
;
1562 max
= waveview
->cache
->data
[cache_index
].max
;
1563 min
= waveview
->cache
->data
[cache_index
].min
;
1577 if (fabs (min
) > fabs (max
)) {
1581 max
= max
* waveview
->height
;
1583 pymax
= (int) rint ((item
->y1
+ waveview
->height
- max
) * item
->canvas
->pixels_per_unit
);
1584 pymin
= (int) rint ((item
->y1
+ waveview
->height
) * item
->canvas
->pixels_per_unit
);
1588 max
= max
* half_height
;
1589 min
= min
* half_height
;
1591 pymax
= (int) rint ((item
->y1
+ origin
- max
) * item
->canvas
->pixels_per_unit
);
1592 pymin
= (int) rint ((item
->y1
+ origin
- min
) * item
->canvas
->pixels_per_unit
);
1595 /* OK, now fill the RGB buffer at x=i with a line between pymin and pymax,
1596 or, if samples_per_unit == 1, then a dot at each location.
1599 if (pymax
== pymin
) {
1600 PAINT_DOTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymin
);
1602 PAINT_VERTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymax
, pymin
);
1605 /* show clipped waveforms with small red lines */
1608 PAINT_VERTA(buf
, waveview
->clip_r
, waveview
->clip_g
, waveview
->clip_b
, waveview
->clip_a
, x
, pymax
, pymax
+clip_length
);
1612 PAINT_VERTA(buf
, waveview
->clip_r
, waveview
->clip_g
, waveview
->clip_b
, waveview
->clip_a
, x
, pymin
-clip_length
, pymin
);
1615 /* presto, we're done */
1621 if (!waveview
->rectified
&& waveview
->zero_line
&& waveview
->height
>= 100) {
1624 unsigned char zero_r
, zero_g
, zero_b
, zero_a
;
1625 UINT_TO_RGBA( waveview
->zero_color
, &zero_r
, &zero_g
, &zero_b
, &zero_a
);
1626 int zeroline_y
= (int) rint ((item
->y1
+ origin
) * item
->canvas
->pixels_per_unit
);
1627 PAINT_HORIZA(buf
, zero_r
, zero_g
, zero_b
, zero_a
, zbegin
, zend
, zeroline_y
);
1634 gnome_canvas_waveview_draw (GnomeCanvasItem
*item
,
1635 GdkDrawable
*drawable
,
1637 int width
, int height
)
1639 GnomeCanvasWaveView
*waveview
;
1653 waveview
= GNOME_CANVAS_WAVEVIEW (item
);
1655 /* compute intersection of Drawable area and waveview,
1656 in canvas coordinate space
1659 if (x
> waveview
->bbox_ulx
) {
1662 ulx
= waveview
->bbox_ulx
;
1665 if (y
> waveview
->bbox_uly
) {
1668 uly
= waveview
->bbox_uly
;
1671 if (x
+ width
> waveview
->bbox_lrx
) {
1672 lrx
= waveview
->bbox_lrx
;
1677 if (y
+ height
> waveview
->bbox_lry
) {
1678 lry
= waveview
->bbox_lry
;
1683 /* figure out which samples we need for the resulting intersection */
1685 s1
= floor ((ulx
- waveview
->bbox_ulx
) * waveview
->samples_per_unit
) ;
1687 if (lrx
== waveview
->bbox_lrx
) {
1688 /* This avoids minor rounding errors when we have the
1689 entire region visible.
1691 s2
= waveview
->samples
;
1693 s2
= s1
+ floor ((lrx
- ulx
) * waveview
->samples_per_unit
);
1696 /* translate back to buffer coordinate space */
1703 /* don't rectify at single-sample zoom */
1704 if(waveview
->rectified
&& waveview
->samples_per_unit
> 1.0) {
1710 clip_length
= MIN(5,(waveview
->height
/4));
1712 cr
= gdk_cairo_create (drawable
);
1713 cairo_set_line_width (cr
, 0.5);
1715 origin
= waveview
->bbox_uly
- y
+ waveview
->half_height
;
1717 cairo_rectangle (cr
, ulx
, uly
, lrx
- ulx
, lry
- uly
);
1720 if (waveview
->cache_updater
&& waveview
->reload_cache_in_render
) {
1721 waveview
->cache
->start
= 0;
1722 waveview
->cache
->end
= 0;
1723 waveview
->reload_cache_in_render
= FALSE
;
1726 cache_index
= gnome_canvas_waveview_ensure_cache (waveview
, s1
, s2
);
1729 printf ("%p r (%d,%d)(%d,%d)[%d x %d] bbox (%d,%d)(%d,%d)[%d x %d]"
1730 " draw (%.1f,%.1f)(%.1f,%.1f)[%.1f x %.1f] s= %lu..%lu\n",
1741 waveview
->bbox_lrx
- waveview
->bbox_ulx
,
1742 waveview
->bbox_lry
- waveview
->bbox_uly
,
1750 /* draw the top half */
1752 for (xoff
= ulx
; xoff
< lrx
; xoff
++) {
1755 max
= waveview
->cache
->data
[cache_index
].max
;
1756 min
= waveview
->cache
->data
[cache_index
].min
;
1767 if (fabs (min
) > fabs (max
)) {
1772 yoff
= origin
- (waveview
->half_height
* max
) + 0.5;
1776 cairo_move_to (cr
, xoff
+0.5, yoff
);
1778 cairo_line_to (cr
, xoff
+0.5, yoff
);
1784 /* from the final top point, move out of the clip zone */
1786 cairo_line_to (cr
, xoff
+ 10, yoff
);
1788 /* now draw the bottom half */
1790 for (--xoff
, --cache_index
; xoff
>= ulx
; --xoff
) {
1793 min
= waveview
->cache
->data
[cache_index
].min
;
1799 yoff
= origin
- (waveview
->half_height
* min
) + 0.5;
1801 cairo_line_to (cr
, xoff
+0.5, yoff
);
1805 /* from the final lower point, move out of the clip zone */
1807 cairo_line_to (cr
, xoff
- 10, yoff
);
1809 /* close path to fill */
1811 cairo_close_path (cr
);
1813 /* fill and stroke */
1815 cairo_set_source_rgba (cr
,
1816 (waveview
->fill_r
/255.0),
1817 (waveview
->fill_g
/255.0),
1818 (waveview
->fill_b
/255.0),
1819 (waveview
->fill_a
/255.0));
1820 cairo_fill_preserve (cr
);
1821 cairo_set_source_rgba (cr
,
1822 (waveview
->wave_r
/255.0),
1823 (waveview
->wave_g
/255.0),
1824 (waveview
->wave_b
/255.0),
1825 (waveview
->wave_a
/255.0));
1832 if (clip_max
|| clip_min
) {
1833 cairo_set_source_rgba (cr
, waveview
->clip_r
, waveview
->clip_g
, waveview
->clip_b
, waveview
->clip_a
);
1837 cairo_move_to (cr
, xoff
, yoff1
);
1838 cairo_line_to (cr
, xoff
, yoff1
+ clip_length
);
1843 cairo_move_to (cr
, xoff
, yoff2
);
1844 cairo_line_to (cr
, xoff
, yoff2
- clip_length
);
1851 gnome_canvas_waveview_bounds (GnomeCanvasItem
*item
, double *x1
, double *y1
, double *x2
, double *y2
)
1853 GnomeCanvasWaveView
*waveview
= GNOME_CANVAS_WAVEVIEW (item
);
1858 *x2
= ceil (*x1
+ (waveview
->length_function (waveview
->data_src
) / waveview
->samples_per_unit
));
1859 *y2
= *y1
+ waveview
->height
;
1863 gnome_canvas_item_i2w (item
, &x
, &y
);
1864 gnome_canvas_w2c_d (GNOME_CANVAS(item
->canvas
), x
, y
, &a
, &b
);
1867 gnome_canvas_item_i2w (item
, &x
, &y
);
1868 gnome_canvas_w2c_d (GNOME_CANVAS(item
->canvas
), x
, y
, &c
, &d
);
1869 printf ("item bounds now (%g,%g),(%g,%g)\n", a
, b
, c
, d
);
1875 gnome_canvas_waveview_point (GnomeCanvasItem
*item
, double x
, double y
, int cx
, int cy
, GnomeCanvasItem
**actual_item
)
1884 /* XXX for now, point is never inside the wave
1885 GnomeCanvasWaveView *waveview;
1886 double x1, y1, x2, y2;
1893 waveview
= GNOME_CANVAS_WAVEVIEW (item
);
1895 *actual_item
= item
;
1897 /* Find the bounds for the rectangle plus its outline width */
1899 gnome_canvas_waveview_bounds (item
, &x1
, &y1
, &x2
, &y2
);
1901 /* Is point inside rectangle */
1903 if ((x
>= x1
) && (y
>= y1
) && (x
<= x2
) && (y
<= y2
)) {
1907 /* Point is outside rectangle */
1923 return sqrt (dx
* dx
+ dy
* dy
);