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>
28 #include "ardour/dB.h"
31 #include "canvas-waveview.h"
32 #include "rgb_macros.h"
35 extern void c_stacktrace();
42 PROP_SOURCEFILE_LENGTH_FUNCTION
,
48 PROP_SAMPLES_PER_UNIT
,
49 PROP_AMPLITUDE_ABOVE_AXIS
,
64 static void gnome_canvas_waveview_class_init (GnomeCanvasWaveViewClass
*class);
66 static void gnome_canvas_waveview_init (GnomeCanvasWaveView
*waveview
);
68 static void gnome_canvas_waveview_destroy (GtkObject
*object
);
70 static void gnome_canvas_waveview_set_property (GObject
*object
,
74 static void gnome_canvas_waveview_get_property (GObject
*object
,
79 static void gnome_canvas_waveview_update (GnomeCanvasItem
*item
,
84 static void gnome_canvas_waveview_bounds (GnomeCanvasItem
*item
,
90 static double gnome_canvas_waveview_point (GnomeCanvasItem
*item
,
95 GnomeCanvasItem
**actual_item
);
97 static void gnome_canvas_waveview_render (GnomeCanvasItem
*item
,
100 static void gnome_canvas_waveview_draw (GnomeCanvasItem
*item
,
101 GdkDrawable
*drawable
,
107 static void gnome_canvas_waveview_set_data_src (GnomeCanvasWaveView
*,
110 static void gnome_canvas_waveview_set_channel (GnomeCanvasWaveView
*,
113 static guint32
gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView
*waveview
,
117 static GnomeCanvasItemClass
*parent_class
;
120 gnome_canvas_waveview_get_type (void)
122 static GType waveview_type
;
124 if (!waveview_type
) {
125 static const GTypeInfo object_info
= {
126 sizeof (GnomeCanvasWaveViewClass
),
127 (GBaseInitFunc
) NULL
,
128 (GBaseFinalizeFunc
) NULL
,
129 (GClassInitFunc
) gnome_canvas_waveview_class_init
,
130 (GClassFinalizeFunc
) NULL
,
131 NULL
, /* class_data */
132 sizeof (GnomeCanvasWaveView
),
134 (GInstanceInitFunc
) gnome_canvas_waveview_init
,
135 NULL
/* value_table */
138 waveview_type
= g_type_register_static (GNOME_TYPE_CANVAS_ITEM
, "GnomeCanvasWaveView",
142 return waveview_type
;
146 gnome_canvas_waveview_class_init (GnomeCanvasWaveViewClass
*class)
148 GObjectClass
*gobject_class
;
149 GtkObjectClass
*object_class
;
150 GnomeCanvasItemClass
*item_class
;
152 gobject_class
= (GObjectClass
*) class;
153 object_class
= (GtkObjectClass
*) class;
154 item_class
= (GnomeCanvasItemClass
*) class;
156 parent_class
= g_type_class_peek_parent (class);
158 gobject_class
->set_property
= gnome_canvas_waveview_set_property
;
159 gobject_class
->get_property
= gnome_canvas_waveview_get_property
;
161 g_object_class_install_property
164 g_param_spec_pointer ("data_src", NULL
, NULL
,
165 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
167 g_object_class_install_property
170 g_param_spec_uint ("channel", NULL
, NULL
,
172 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
174 g_object_class_install_property
176 PROP_LENGTH_FUNCTION
,
177 g_param_spec_pointer ("length_function", NULL
, NULL
,
178 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
180 g_object_class_install_property
182 PROP_SOURCEFILE_LENGTH_FUNCTION
,
183 g_param_spec_pointer ("sourcefile_length_function", NULL
, NULL
,
184 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
186 g_object_class_install_property
189 g_param_spec_pointer ("peak_function", NULL
, NULL
,
190 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
192 g_object_class_install_property
195 g_param_spec_pointer ("gain_function", NULL
, NULL
,
196 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
198 g_object_class_install_property
201 g_param_spec_pointer ("gain_src", NULL
, NULL
,
202 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
204 g_object_class_install_property
207 g_param_spec_pointer ("cache", NULL
, NULL
,
208 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
210 g_object_class_install_property
213 g_param_spec_boolean ("cache_updater", NULL
, NULL
,
215 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
217 g_object_class_install_property
219 PROP_SAMPLES_PER_UNIT
,
220 g_param_spec_double ("samples_per_unit", NULL
, NULL
,
221 0.0, G_MAXDOUBLE
, 0.0,
222 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
224 g_object_class_install_property
226 PROP_AMPLITUDE_ABOVE_AXIS
,
227 g_param_spec_double ("amplitude_above_axis", NULL
, NULL
,
228 0.0, G_MAXDOUBLE
, 0.0,
229 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
231 g_object_class_install_property
234 g_param_spec_double ("x", 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 ("y", 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 ("height", 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_uint ("wave_color", NULL
, NULL
,
257 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
259 g_object_class_install_property
262 g_param_spec_uint ("clip_color", NULL
, NULL
,
264 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
266 g_object_class_install_property
269 g_param_spec_uint ("zero_color", NULL
, NULL
,
271 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
273 g_object_class_install_property
276 g_param_spec_uint ("fill_color", NULL
, NULL
,
278 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
280 g_object_class_install_property
283 g_param_spec_boolean ("filled", NULL
, NULL
,
285 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
287 g_object_class_install_property
290 g_param_spec_boolean ("rectified", NULL
, NULL
,
292 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
294 g_object_class_install_property
297 g_param_spec_boolean ("zero_line", NULL
, NULL
,
299 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
301 g_object_class_install_property
304 g_param_spec_boolean ("logscaled", NULL
, NULL
,
306 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
308 g_object_class_install_property
311 g_param_spec_uint ("region_start", NULL
, NULL
,
313 (G_PARAM_READABLE
| G_PARAM_WRITABLE
)));
315 object_class
->destroy
= gnome_canvas_waveview_destroy
;
317 item_class
->update
= gnome_canvas_waveview_update
;
318 item_class
->bounds
= gnome_canvas_waveview_bounds
;
319 item_class
->point
= gnome_canvas_waveview_point
;
320 item_class
->render
= gnome_canvas_waveview_render
;
321 item_class
->draw
= gnome_canvas_waveview_draw
;
324 GnomeCanvasWaveViewCache
*
325 gnome_canvas_waveview_cache_new ()
327 GnomeCanvasWaveViewCache
*c
;
329 c
= g_malloc (sizeof (GnomeCanvasWaveViewCache
));
332 c
->data
= g_malloc (sizeof (GnomeCanvasWaveViewCacheEntry
) * c
->allocated
);
341 gnome_canvas_waveview_cache_destroy (GnomeCanvasWaveViewCache
* cache
)
343 g_free (cache
->data
);
348 gnome_canvas_waveview_init (GnomeCanvasWaveView
*waveview
)
353 waveview
->cache_updater
= FALSE
;
354 waveview
->data_src
= NULL
;
355 waveview
->channel
= 0;
356 waveview
->peak_function
= NULL
;
357 waveview
->length_function
= NULL
;
358 waveview
->sourcefile_length_function
= NULL
;
359 waveview
->gain_curve_function
= NULL
;
360 waveview
->gain_src
= NULL
;
361 waveview
->rectified
= FALSE
;
362 waveview
->logscaled
= FALSE
;
363 waveview
->filled
= TRUE
;
364 waveview
->zero_line
= FALSE
;
365 waveview
->region_start
= 0;
366 waveview
->samples_per_unit
= 1.0;
367 waveview
->amplitude_above_axis
= 1.0;
368 waveview
->height
= 100.0;
369 waveview
->screen_width
= gdk_screen_width ();
370 waveview
->reload_cache_in_render
= FALSE
;
372 waveview
->wave_color
= 0;
373 waveview
->clip_color
= 0;
374 waveview
->zero_color
= 0;
375 waveview
->fill_color
= 0;
379 gnome_canvas_waveview_destroy (GtkObject
*object
)
381 GnomeCanvasWaveView
*waveview
;
383 g_return_if_fail (object
!= NULL
);
384 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object
));
386 waveview
= GNOME_CANVAS_WAVEVIEW (object
);
388 if (GTK_OBJECT_CLASS (parent_class
)->destroy
)
389 (* GTK_OBJECT_CLASS (parent_class
)->destroy
) (object
);
392 #define DEBUG_CACHE 0
393 #undef CACHE_MEMMOVE_OPTIMIZATION
395 /** @return cache index of start_sample within the cache */
397 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView
*waveview
, gulong start_sample
, gulong end_sample
)
399 gulong required_cache_entries
;
400 gulong rf1
, rf2
,rf3
, required_frames
;
401 gulong new_cache_start
, new_cache_end
;
407 GnomeCanvasWaveViewCache
*cache
;
409 #ifdef CACHE_MEMMOVE_OPTIMIZATION
410 gulong present_frames
;
411 gulong present_entries
;
414 cache
= waveview
->cache
;
416 start_sample
= start_sample
+ waveview
->region_start
;
417 end_sample
= end_sample
+ waveview
->region_start
;
419 // printf("waveview->region_start == %lu\n",waveview->region_start);
421 printf ("\n\n=> 0x%x cache @ 0x%x range: %lu - %lu request: %lu - %lu (%lu frames)\n",
423 cache
->start
, cache
->end
,
424 start_sample
, end_sample
, end_sample
- start_sample
);
427 if (cache
->start
<= start_sample
&& cache
->end
>= end_sample
) {
429 // printf ("0x%x: cache hit for %lu-%lu (cache holds: %lu-%lu\n",
430 // waveview, start_sample, end_sample, cache->start, cache->end);
435 /* make sure the cache is at least twice as wide as the screen width, and put the start sample
436 in the middle, ensuring that we cover the end_sample.
439 /* Note the assumption that we have a 1:1 units:pixel ratio for the canvas. Its everywhere ... */
441 half_width
= (gulong
) floor ((waveview
->screen_width
* waveview
->samples_per_unit
)/2.0 + 0.5);
443 if (start_sample
< half_width
) {
446 new_cache_start
= start_sample
- half_width
;
449 /* figure out how many frames we want */
451 rf1
= end_sample
- start_sample
+ 1;
452 rf2
= (gulong
) floor ((waveview
->screen_width
* waveview
->samples_per_unit
* 2.0f
));
453 required_frames
= MAX(rf1
,rf2
);
455 /* but make sure it doesn't extend beyond the end of the source material */
457 rf3
= (gulong
) (waveview
->sourcefile_length_function (waveview
->data_src
, waveview
->samples_per_unit
)) + 1;
458 if (rf3
< new_cache_start
) {
461 rf3
-= new_cache_start
;
465 fprintf (stderr
, "AVAILABLE FRAMES = %lu of %lu, start = %lu, sstart = %lu, cstart = %lu\n",
466 rf3
, waveview
->sourcefile_length_function (waveview
->data_src
, waveview
->samples_per_unit
),
467 waveview
->region_start
, start_sample
, new_cache_start
);
470 required_frames
= MIN(required_frames
,rf3
);
472 new_cache_end
= new_cache_start
+ required_frames
- 1;
474 required_cache_entries
= (gulong
) floor (required_frames
/ waveview
->samples_per_unit
);
477 fprintf (stderr
, "new cache = %lu - %lu\n", new_cache_start
, new_cache_end
);
478 fprintf(stderr
,"required_cach_entries = %lu, samples_per_unit = %f req frames = %lu\n",
479 required_cache_entries
,waveview
->samples_per_unit
, required_frames
);
482 if (required_cache_entries
> cache
->allocated
) {
483 cache
->data
= g_realloc (cache
->data
, sizeof (GnomeCanvasWaveViewCacheEntry
) * required_cache_entries
);
484 cache
->allocated
= required_cache_entries
;
489 ostart
= new_cache_start
;
491 #ifdef CACHE_MEMMOVE_OPTIMIZATION
493 /* data is not entirely in the cache, so go fetch it, making sure to fill the cache */
495 /* some of the required cache entries are in the cache, but in the wrong
496 locations. use memmove to fix this.
499 if (cache
->start
< new_cache_start
&& new_cache_start
< cache
->end
) {
501 /* case one: the common area is at the end of the existing cache. move it
502 to the beginning of the cache, and set up to refill whatever remains.
505 wv->cache_start wv->cache_end
506 |-------------------------------------------------------| cache
507 |--------------------------------| requested
508 <------------------->
510 new_cache_start new_cache_end
514 present_frames
= cache
->end
- new_cache_start
;
515 present_entries
= (gulong
) floor (present_frames
/ waveview
->samples_per_unit
);
518 fprintf (stderr
, "existing material at end of current cache, move to start of new cache\n"
519 "\tcopy from %lu to start\n", cache
->data_size
- present_entries
);
522 memmove (&cache
->data
[0],
523 &cache
->data
[cache
->data_size
- present_entries
],
524 present_entries
* sizeof (GnomeCanvasWaveViewCacheEntry
));
527 fprintf (stderr
, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
528 present_frames
, required_frames
, present_entries
, new_cache_start
+ present_entries
,
529 cache
->data
+ present_entries
);
532 copied
= present_entries
;
533 offset
= present_entries
;
534 new_cache_start
+= present_frames
;
535 required_frames
-= present_frames
;
537 } else if (new_cache_end
> cache
->start
&& new_cache_end
< cache
->end
) {
539 /* case two: the common area lives at the beginning of the existing cache.
541 wv->cache_start wv->cache_end
542 |-----------------------------------------------------|
543 |--------------------------------|
547 new_cache_start new_cache_end
550 present_frames
= new_cache_end
- cache
->start
;
551 present_entries
= (gulong
) floor (present_frames
/ waveview
->samples_per_unit
);
553 memmove (&cache
->data
[cache
->data_size
- present_entries
],
555 present_entries
* sizeof (GnomeCanvasWaveViewCacheEntry
));
558 fprintf (stderr
, "existing material at start of current cache, move to start of end cache\n");
562 fprintf (stderr
, "satisfied %lu of %lu frames, offset = %lu, will start at %lu (ptr = 0x%x)\n",
563 present_entries
, required_frames
, present_entries
, new_cache_start
+ present_entries
,
564 cache
->data
+ present_entries
);
567 copied
= present_entries
;
569 required_frames
-= present_frames
;
582 #endif /* CACHE_MEMMOVE_OPTIMIZATION */
584 // fprintf(stderr,"length == %lu\n",waveview->length_function (waveview->data_src));
585 // required_frames = MIN (waveview->length_function (waveview->data_src) - new_cache_start, required_frames);
587 npeaks
= (gulong
) floor (required_frames
/ waveview
->samples_per_unit
);
588 required_frames
= npeaks
* waveview
->samples_per_unit
;
593 printf ("requesting %lu/%f to cover %lu-%lu at %f spu (request was %lu-%lu) into cache + %lu\n",
594 required_frames
, required_frames
/waveview
->samples_per_unit
, new_cache_start
, new_cache_end
,
595 waveview
->samples_per_unit
, start_sample
, end_sample
, offset
);
599 // printf ("cache holds %lu entries, requesting %lu to cover %lu-%lu (request was %lu-%lu)\n",
600 // cache->data_size, npeaks, new_cache_start, new_cache_end,
601 // start_sample, end_sample);
604 if (required_frames
) {
605 waveview
->peak_function (waveview
->data_src
, npeaks
, new_cache_start
, required_frames
, cache
->data
+ offset
, waveview
->channel
,waveview
->samples_per_unit
);
607 /* take into account any copied peaks */
614 if (npeaks
< cache
->allocated
) {
616 fprintf (stderr
, "zero fill cache for %lu at %lu\n", cache
->allocated
- npeaks
, npeaks
);
618 memset (&cache
->data
[npeaks
], 0, sizeof (GnomeCanvasWaveViewCacheEntry
) * (cache
->allocated
- npeaks
));
619 cache
->data_size
= npeaks
;
621 cache
->data_size
= cache
->allocated
;
624 if (waveview
->gain_curve_function
) {
627 gain
= (float*) malloc (sizeof (float) * cache
->data_size
);
629 waveview
->gain_curve_function (waveview
->gain_src
, new_cache_start
, new_cache_end
, gain
, cache
->data_size
);
631 for (n
= 0; n
< cache
->data_size
; ++n
) {
632 cache
->data
[n
].min
*= gain
[n
];
633 cache
->data
[n
].max
*= gain
[n
];
640 /* do optional log scaling. this implementation is not particularly efficient */
642 if (waveview
->logscaled
) {
644 GnomeCanvasWaveViewCacheEntry
* buf
= cache
->data
;
646 for (n
= 0; n
< cache
->data_size
; ++n
) {
648 if (buf
[n
].max
> 0.0f
) {
649 buf
[n
].max
= alt_log_meter(fast_coefficient_to_dB(buf
[n
].max
));
650 } else if (buf
[n
].max
< 0.0f
) {
651 buf
[n
].max
= -alt_log_meter(fast_coefficient_to_dB(-buf
[n
].max
));
654 if (buf
[n
].min
> 0.0f
) {
655 buf
[n
].min
= alt_log_meter(fast_coefficient_to_dB(buf
[n
].min
));
656 } else if (buf
[n
].min
< 0.0f
) {
657 buf
[n
].min
= -alt_log_meter(fast_coefficient_to_dB(-buf
[n
].min
));
662 cache
->start
= ostart
;
663 cache
->end
= new_cache_end
;
667 fprintf (stderr
, "return cache index = %d\n",
668 (guint32
) floor ((((double) (start_sample
- cache
->start
)) / waveview
->samples_per_unit
) + 0.5));
670 return (guint32
) floor ((((double) (start_sample
- cache
->start
)) / waveview
->samples_per_unit
) + 0.5);
675 gnome_canvas_waveview_set_data_src (GnomeCanvasWaveView
*waveview
, void *data_src
)
678 if (waveview
->cache_updater
) {
679 if (waveview
->data_src
== data_src
) {
680 waveview
->reload_cache_in_render
= TRUE
;
684 waveview
->cache
->start
= 0;
685 waveview
->cache
->end
= 0;
688 waveview
->data_src
= data_src
;
692 gnome_canvas_waveview_set_channel (GnomeCanvasWaveView
*waveview
, guint32 chan
)
694 if (waveview
->channel
== chan
) {
698 waveview
->channel
= chan
;
702 gnome_canvas_waveview_reset_bounds (GnomeCanvasItem
*item
)
705 double x1
, x2
, y1
, y2
;
708 int Ix1
, Ix2
, Iy1
, Iy2
;
711 gnome_canvas_waveview_bounds (item
, &x1
, &y1
, &x2
, &y2
);
718 gnome_canvas_item_i2w_affine (item
, i2w
);
719 art_affine_point (&w1
, &i1
, i2w
);
720 art_affine_point (&w2
, &i2
, i2w
);
722 Ix1
= (int) rint(w1
.x
);
723 Ix2
= (int) rint(w2
.x
);
724 Iy1
= (int) rint(w1
.y
);
725 Iy2
= (int) rint(w2
.y
);
727 gnome_canvas_update_bbox (item
, Ix1
, Iy1
, Ix2
, Iy2
);
735 gnome_canvas_waveview_set_property (GObject
*object
,
743 GnomeCanvasItem
*item
;
744 GnomeCanvasWaveView
*waveview
;
746 int calc_bounds
= FALSE
;
748 g_return_if_fail (object
!= NULL
);
749 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object
));
751 item
= GNOME_CANVAS_ITEM (object
);
752 waveview
= GNOME_CANVAS_WAVEVIEW (object
);
756 gnome_canvas_waveview_set_data_src (waveview
, g_value_get_pointer(value
));
761 gnome_canvas_waveview_set_channel (waveview
, g_value_get_uint(value
));
765 case PROP_LENGTH_FUNCTION
:
766 waveview
->length_function
= (waveview_length_function_t
) g_value_get_pointer(value
);
770 case PROP_SOURCEFILE_LENGTH_FUNCTION
:
771 waveview
->sourcefile_length_function
= (waveview_sourcefile_length_function_t
) g_value_get_pointer(value
);
775 case PROP_PEAK_FUNCTION
:
776 waveview
->peak_function
= (waveview_peak_function_t
) g_value_get_pointer(value
);
780 case PROP_GAIN_FUNCTION
:
781 waveview
->gain_curve_function
= (waveview_gain_curve_function_t
) g_value_get_pointer(value
);
786 waveview
->gain_src
= g_value_get_pointer(value
);
787 if (waveview
->cache_updater
) {
788 waveview
->cache
->start
= 0;
789 waveview
->cache
->end
= 0;
796 waveview
->cache
= g_value_get_pointer(value
);
801 case PROP_CACHE_UPDATER
:
802 waveview
->cache_updater
= g_value_get_boolean(value
);
806 case PROP_SAMPLES_PER_UNIT
:
807 if ((waveview
->samples_per_unit
= g_value_get_double(value
)) < 1.0) {
808 waveview
->samples_per_unit
= 1.0;
810 if (waveview
->cache_updater
) {
811 waveview
->cache
->start
= 0;
812 waveview
->cache
->end
= 0;
818 case PROP_AMPLITUDE_ABOVE_AXIS
:
819 waveview
->amplitude_above_axis
= g_value_get_double(value
);
824 if (waveview
->x
!= g_value_get_double (value
)) {
825 waveview
->x
= g_value_get_double (value
);
831 if (waveview
->y
!= g_value_get_double (value
)) {
832 waveview
->y
= g_value_get_double (value
);
838 if (waveview
->height
!= fabs (g_value_get_double (value
))) {
839 waveview
->height
= fabs (g_value_get_double (value
));
844 case PROP_WAVE_COLOR
:
845 if (waveview
->wave_color
!= g_value_get_uint(value
)) {
846 waveview
->wave_color
= g_value_get_uint(value
);
851 case PROP_CLIP_COLOR
:
852 if (waveview
->clip_color
!= g_value_get_uint(value
)) {
853 waveview
->clip_color
= g_value_get_uint(value
);
858 case PROP_ZERO_COLOR
:
859 if (waveview
->zero_color
!= g_value_get_uint(value
)) {
860 waveview
->zero_color
= g_value_get_uint(value
);
865 case PROP_FILL_COLOR
:
866 if (waveview
->fill_color
!= g_value_get_uint(value
)) {
867 waveview
->fill_color
= g_value_get_uint(value
);
873 if (waveview
->filled
!= g_value_get_boolean(value
)) {
874 waveview
->filled
= g_value_get_boolean(value
);
880 if (waveview
->rectified
!= g_value_get_boolean(value
)) {
881 waveview
->rectified
= g_value_get_boolean(value
);
887 if (waveview
->zero_line
!= g_value_get_boolean(value
)) {
888 waveview
->zero_line
= g_value_get_boolean(value
);
894 if (waveview
->logscaled
!= g_value_get_boolean(value
)) {
895 waveview
->logscaled
= g_value_get_boolean(value
);
896 if (waveview
->cache_updater
) {
897 waveview
->cache
->start
= 0;
898 waveview
->cache
->end
= 0;
904 case PROP_REGION_START
:
905 waveview
->region_start
= g_value_get_uint(value
);
916 gnome_canvas_waveview_reset_bounds (item
);
920 gnome_canvas_item_request_update (item
);
926 gnome_canvas_waveview_get_property (
934 g_return_if_fail (object
!= NULL
);
935 g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object
));
937 GnomeCanvasWaveView
*waveview
= GNOME_CANVAS_WAVEVIEW (object
);
941 g_value_set_pointer(value
, waveview
->data_src
);
945 g_value_set_uint(value
, waveview
->channel
);
948 case PROP_LENGTH_FUNCTION
:
949 g_value_set_pointer(value
, (void*) waveview
->length_function
);
952 case PROP_SOURCEFILE_LENGTH_FUNCTION
:
953 g_value_set_pointer(value
, (void*) waveview
->sourcefile_length_function
);
956 case PROP_PEAK_FUNCTION
:
957 g_value_set_pointer(value
, (void*) waveview
->peak_function
);
960 case PROP_GAIN_FUNCTION
:
961 g_value_set_pointer(value
, (void*) waveview
->gain_curve_function
);
965 g_value_set_pointer(value
, waveview
->gain_src
);
969 g_value_set_pointer(value
, waveview
->cache
);
972 case PROP_CACHE_UPDATER
:
973 g_value_set_boolean(value
, waveview
->cache_updater
);
976 case PROP_SAMPLES_PER_UNIT
:
977 g_value_set_double(value
, waveview
->samples_per_unit
);
980 case PROP_AMPLITUDE_ABOVE_AXIS
:
981 g_value_set_double(value
, waveview
->amplitude_above_axis
);
985 g_value_set_double (value
, waveview
->x
);
989 g_value_set_double (value
, waveview
->y
);
993 g_value_set_double (value
, waveview
->height
);
996 case PROP_WAVE_COLOR
:
997 g_value_set_uint (value
, waveview
->wave_color
);
1000 case PROP_CLIP_COLOR
:
1001 g_value_set_uint (value
, waveview
->clip_color
);
1004 case PROP_ZERO_COLOR
:
1005 g_value_set_uint (value
, waveview
->zero_color
);
1008 case PROP_FILL_COLOR
:
1009 g_value_set_uint (value
, waveview
->fill_color
);
1013 g_value_set_boolean (value
, waveview
->filled
);
1016 case PROP_RECTIFIED
:
1017 g_value_set_boolean (value
, waveview
->rectified
);
1020 case PROP_ZERO_LINE
:
1021 g_value_set_boolean (value
, waveview
->zero_line
);
1024 case PROP_LOGSCALED
:
1025 g_value_set_boolean (value
, waveview
->logscaled
);
1028 case PROP_REGION_START
:
1029 g_value_set_uint (value
, waveview
->region_start
);
1033 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
1039 gnome_canvas_waveview_update (GnomeCanvasItem
*item
, double *affine
, ArtSVP
*clip_path
, int flags
)
1041 GnomeCanvasWaveView
*waveview
;
1044 waveview
= GNOME_CANVAS_WAVEVIEW (item
);
1046 // check_cache (waveview, "start of update");
1048 if (parent_class
->update
)
1049 (* parent_class
->update
) (item
, affine
, clip_path
, flags
);
1051 gnome_canvas_waveview_reset_bounds (item
);
1053 /* get the canvas coordinates of the view. Do NOT use affines
1054 for this, because they do not round to the integer units used
1055 by the canvas, resulting in subtle pixel-level errors later.
1061 gnome_canvas_item_i2w (item
, &x
, &y
);
1062 gnome_canvas_w2c (GNOME_CANVAS(item
->canvas
), x
, y
, &waveview
->bbox_ulx
, &waveview
->bbox_uly
);
1064 waveview
->samples
= waveview
->length_function (waveview
->data_src
);
1066 x
= waveview
->x
+ (waveview
->samples
/ waveview
->samples_per_unit
);
1067 y
= waveview
->y
+ waveview
->height
;
1069 gnome_canvas_item_i2w (item
, &x
, &y
);
1070 gnome_canvas_w2c (GNOME_CANVAS(item
->canvas
), x
, y
, &waveview
->bbox_lrx
, &waveview
->bbox_lry
);
1072 /* cache the half-height and the end point in canvas units */
1074 waveview
->half_height
= waveview
->height
/ 2.0;
1076 /* parse the color */
1078 UINT_TO_RGBA (waveview
->wave_color
, &waveview
->wave_r
, &waveview
->wave_g
, &waveview
->wave_b
,
1080 UINT_TO_RGBA (waveview
->clip_color
, &waveview
->clip_r
, &waveview
->clip_g
, &waveview
->clip_b
,
1082 UINT_TO_RGBA (waveview
->fill_color
, &waveview
->fill_r
, &waveview
->fill_g
, &waveview
->fill_b
,
1085 // check_cache (waveview, "end of update");
1089 gnome_canvas_waveview_render (GnomeCanvasItem
*item
,
1090 GnomeCanvasBuf
*buf
)
1092 GnomeCanvasWaveView
*waveview
;
1094 int clip_length
= 0;
1101 waveview
= GNOME_CANVAS_WAVEVIEW (item
);
1103 // check_cache (waveview, "start of render");
1105 if (parent_class
->render
) {
1106 (*parent_class
->render
) (item
, buf
);
1110 gnome_canvas_buf_ensure_buf (buf
);
1114 /* a "unit" means a pixel */
1116 /* begin: render start x (units) */
1117 int const begin
= MAX (waveview
->bbox_ulx
, buf
->rect
.x0
);
1119 /* zbegin: start x for zero line (units) */
1120 int const zbegin
= (begin
== waveview
->bbox_ulx
) ? (begin
+ 1) : begin
;
1122 /* end: render end x (units) */
1123 int const end
= (waveview
->bbox_lrx
>= 0) ? MIN (waveview
->bbox_lrx
,buf
->rect
.x1
) : buf
->rect
.x1
;
1125 /* zend: end x for zero-line (units) */
1126 int const zend
= (end
== waveview
->bbox_lrx
) ? (end
- 1) : end
;
1136 s1
= floor ((begin
- waveview
->bbox_ulx
) * waveview
->samples_per_unit
);
1138 // fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit);
1140 if (end
== waveview
->bbox_lrx
) {
1141 /* This avoids minor rounding errors when we have the
1142 entire region visible.
1144 s2
= waveview
->samples
;
1146 s2
= s1
+ floor ((end
- begin
) * waveview
->samples_per_unit
);
1150 printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)"
1151 " b/e %d..%d s= %lu..%lu @ %f\n",
1162 waveview
->samples_per_unit
);
1165 /* now ensure that the cache is full and properly
1169 // check_cache (waveview, "pre-ensure");
1171 if (waveview
->cache_updater
&& waveview
->reload_cache_in_render
) {
1172 waveview
->cache
->start
= 0;
1173 waveview
->cache
->end
= 0;
1174 waveview
->reload_cache_in_render
= FALSE
;
1177 // check_cache (waveview, "post-ensure");
1179 /* don't rectify at single-sample zoom */
1180 if (waveview
->rectified
&& waveview
->samples_per_unit
> 1) {
1187 clip_length
= MIN(5,(waveview
->height
/4));
1190 Now draw each line, clipping it appropriately. The clipping
1191 is done by the macros PAINT_FOO().
1194 half_height
= waveview
->half_height
;
1196 /* this makes it slightly easier to comprehend whats going on */
1197 #define origin half_height
1199 if (waveview
->filled
&& !rectify
) {
1204 int next_pymin
, next_pymax
;
1206 int next_clip_max
= 0;
1207 int next_clip_min
= 0;
1209 if (s1
< waveview
->samples_per_unit
) {
1210 /* we haven't got a prev vars to compare with, so outline the whole line here */
1211 prev_pymax
= (int) rint ((item
->y1
+ origin
) * item
->canvas
->pixels_per_unit
);
1212 prev_pymin
= prev_pymax
;
1215 s1
-= waveview
->samples_per_unit
;
1218 if(end
== waveview
->bbox_lrx
) {
1219 /* we don't have the NEXT vars for the last sample */
1220 last_pymax
= (int) rint ((item
->y1
+ origin
) * item
->canvas
->pixels_per_unit
);
1221 last_pymin
= last_pymax
;
1224 s2
+= waveview
->samples_per_unit
;
1227 cache_index
= gnome_canvas_waveview_ensure_cache (waveview
, s1
, s2
);
1230 * Compute the variables outside the rendering rect
1232 if(prev_pymax
!= prev_pymin
) {
1234 prev_pymax
= (int) rint ((item
->y1
+ origin
- MIN(waveview
->cache
->data
[cache_index
].max
, 1.0) * half_height
) * item
->canvas
->pixels_per_unit
);
1235 prev_pymin
= (int) rint ((item
->y1
+ origin
- MAX(waveview
->cache
->data
[cache_index
].min
, -1.0) * half_height
) * item
->canvas
->pixels_per_unit
);
1238 if(last_pymax
!= last_pymin
) {
1239 /* take the index of one sample right of what we render */
1240 guint index
= cache_index
+ (end
- begin
);
1242 if (index
>= waveview
->cache
->data_size
) {
1244 /* the data we want is off the end of the cache, which must mean its beyond
1245 the end of the region's source; hence the peak values are 0 */
1246 last_pymax
= (int) rint ((item
->y1
+ origin
) * item
->canvas
->pixels_per_unit
);
1247 last_pymin
= (int) rint ((item
->y1
+ origin
) * item
->canvas
->pixels_per_unit
);
1251 last_pymax
= (int) rint ((item
->y1
+ origin
- MIN(waveview
->cache
->data
[index
].max
, 1.0) * half_height
) * item
->canvas
->pixels_per_unit
);
1252 last_pymin
= (int) rint ((item
->y1
+ origin
- MAX(waveview
->cache
->data
[index
].min
, -1.0) * half_height
) * item
->canvas
->pixels_per_unit
);
1259 * initialize NEXT* variables for the first run, duplicated in the loop for speed
1261 max
= waveview
->cache
->data
[cache_index
].max
;
1262 min
= waveview
->cache
->data
[cache_index
].min
;
1277 next_pymax
= (int) rint ((item
->y1
+ origin
- max
) * item
->canvas
->pixels_per_unit
);
1278 next_pymin
= (int) rint ((item
->y1
+ origin
- min
) * item
->canvas
->pixels_per_unit
);
1283 for(x
= begin
; x
< end
; ++x
) {
1284 int clip_max
= next_clip_max
;
1285 int clip_min
= next_clip_min
;
1286 int fill_max
, fill_min
;
1293 /*next is now the last column, which is outside the rendering rect, and possibly outside the region*/
1294 next_pymax
= last_pymax
;
1295 next_pymin
= last_pymin
;
1300 if (cache_index
< waveview
->cache
->data_size
) {
1301 max
= waveview
->cache
->data
[cache_index
].max
;
1302 min
= waveview
->cache
->data
[cache_index
].min
;
1323 next_pymax
= (int) rint ((item
->y1
+ origin
- max
) * item
->canvas
->pixels_per_unit
);
1324 next_pymin
= (int) rint ((item
->y1
+ origin
- min
) * item
->canvas
->pixels_per_unit
);
1328 if (pymax
== pymin
) {
1329 PAINT_DOTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymin
);
1331 if((prev_pymax
< pymax
&& next_pymax
< pymax
) ||
1332 (prev_pymax
== pymax
&& next_pymax
== pymax
)) {
1333 fill_max
= pymax
+ 1;
1334 PAINT_DOTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymax
);
1337 fill_max
= MAX(prev_pymax
, next_pymax
);
1338 if(pymax
== fill_max
) {
1339 PAINT_DOTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymax
);
1343 PAINT_VERTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymax
, fill_max
);
1347 if((prev_pymin
> pymin
&& next_pymin
> pymin
) ||
1348 (prev_pymin
== pymin
&& next_pymin
== pymin
)) {
1349 fill_min
= pymin
- 1;
1350 PAINT_DOTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymin
-1);
1353 fill_min
= MIN(prev_pymin
, next_pymin
);
1354 if(pymin
== fill_min
) {
1355 PAINT_DOTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymin
);
1358 PAINT_VERTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, fill_min
, pymin
);
1362 if(fill_max
< fill_min
) {
1363 PAINT_VERTA(buf
, waveview
->fill_r
, waveview
->fill_g
, waveview
->fill_b
, waveview
->fill_a
, x
, fill_max
, fill_min
);
1365 else if(fill_max
== fill_min
) {
1366 PAINT_DOTA(buf
, waveview
->fill_r
, waveview
->fill_g
, waveview
->fill_b
, waveview
->fill_a
, x
, fill_max
);
1371 PAINT_VERTA(buf
, waveview
->clip_r
, waveview
->clip_g
, waveview
->clip_b
, waveview
->clip_a
, x
, pymax
, pymax
+clip_length
);
1375 PAINT_VERTA(buf
, waveview
->clip_r
, waveview
->clip_g
, waveview
->clip_b
, waveview
->clip_a
, x
, pymin
-clip_length
, pymin
);
1382 } else if (waveview
->filled
&& rectify
) {
1384 int prev_pymax
= -1;
1385 int last_pymax
= -1;
1388 int next_clip_max
= 0;
1389 int next_clip_min
= 0;
1391 // for rectified, this stays constant throughout the loop
1392 pymin
= (int) rint ((item
->y1
+ waveview
->height
) * item
->canvas
->pixels_per_unit
);
1394 if(s1
< waveview
->samples_per_unit
) {
1395 /* we haven't got a prev vars to compare with, so outline the whole line here */
1399 s1
-= waveview
->samples_per_unit
;
1402 if(end
== waveview
->bbox_lrx
) {
1403 /* we don't have the NEXT vars for the last sample */
1407 s2
+= waveview
->samples_per_unit
;
1410 cache_index
= gnome_canvas_waveview_ensure_cache (waveview
, s1
, s2
);
1413 * Compute the variables outside the rendering rect
1415 if(prev_pymax
< 0) {
1416 max
= MIN(waveview
->cache
->data
[cache_index
].max
, 1.0);
1417 min
= MAX(waveview
->cache
->data
[cache_index
].min
, -1.0);
1419 if (fabs (min
) > fabs (max
)) {
1423 prev_pymax
= (int) rint ((item
->y1
+ waveview
->height
- max
* waveview
->height
) * item
->canvas
->pixels_per_unit
);
1426 if(last_pymax
< 0) {
1427 /* take the index of one sample right of what we render */
1428 int index
= cache_index
+ (end
- begin
);
1430 max
= MIN(waveview
->cache
->data
[index
].max
, 1.0);
1431 min
= MAX(waveview
->cache
->data
[index
].min
, -1.0);
1433 if (fabs (min
) > fabs (max
)) {
1437 last_pymax
= (int) rint ((item
->y1
+ waveview
->height
- max
* waveview
->height
) * item
->canvas
->pixels_per_unit
);
1441 * initialize NEXT* variables for the first run, duplicated in the loop for speed
1443 max
= waveview
->cache
->data
[cache_index
].max
;
1444 min
= waveview
->cache
->data
[cache_index
].min
;
1456 if (fabs (min
) > fabs (max
)) {
1460 next_pymax
= (int) rint ((item
->y1
+ waveview
->height
- max
* waveview
->height
) * item
->canvas
->pixels_per_unit
);
1465 for(x
= begin
; x
< end
; ++x
) {
1466 int clip_max
= next_clip_max
;
1467 int clip_min
= next_clip_min
;
1474 /*next is now the last column, which is outside the rendering rect, and possibly outside the region*/
1475 next_pymax
= last_pymax
;
1480 max
= waveview
->cache
->data
[cache_index
].max
;
1481 min
= waveview
->cache
->data
[cache_index
].min
;
1493 if (fabs (min
) > fabs (max
)) {
1497 next_pymax
= (int) rint ((item
->y1
+ waveview
->height
- max
* waveview
->height
) * item
->canvas
->pixels_per_unit
);
1501 if (pymax
== pymin
) {
1502 PAINT_DOTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymin
);
1504 if((prev_pymax
< pymax
&& next_pymax
< pymax
) ||
1505 (prev_pymax
== pymax
&& next_pymax
== pymax
)) {
1506 fill_max
= pymax
+ 1;
1507 PAINT_DOTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymax
);
1510 fill_max
= MAX(prev_pymax
, next_pymax
);
1511 if(pymax
== fill_max
) {
1512 PAINT_DOTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymax
);
1516 PAINT_VERTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymax
, fill_max
);
1520 if(fill_max
< pymin
) {
1521 PAINT_VERTA(buf
, waveview
->fill_r
, waveview
->fill_g
, waveview
->fill_b
, waveview
->fill_a
, x
, fill_max
, pymin
);
1523 else if(fill_max
== pymin
) {
1524 PAINT_DOTA(buf
, waveview
->fill_r
, waveview
->fill_g
, waveview
->fill_b
, waveview
->fill_a
, x
, pymin
);
1529 PAINT_VERTA(buf
, waveview
->clip_r
, waveview
->clip_g
, waveview
->clip_b
, waveview
->clip_a
, x
, pymax
, pymax
+clip_length
);
1533 PAINT_VERTA(buf
, waveview
->clip_r
, waveview
->clip_g
, waveview
->clip_b
, waveview
->clip_a
, x
, pymin
-clip_length
, pymin
);
1540 cache_index
= gnome_canvas_waveview_ensure_cache (waveview
, s1
, s2
);
1542 for (x
= begin
; x
< end
; x
++) {
1545 int clip_max
, clip_min
;
1550 max
= waveview
->cache
->data
[cache_index
].max
;
1551 min
= waveview
->cache
->data
[cache_index
].min
;
1565 if (fabs (min
) > fabs (max
)) {
1569 max
= max
* waveview
->height
;
1571 pymax
= (int) rint ((item
->y1
+ waveview
->height
- max
) * item
->canvas
->pixels_per_unit
);
1572 pymin
= (int) rint ((item
->y1
+ waveview
->height
) * item
->canvas
->pixels_per_unit
);
1576 max
= max
* half_height
;
1577 min
= min
* half_height
;
1579 pymax
= (int) rint ((item
->y1
+ origin
- max
) * item
->canvas
->pixels_per_unit
);
1580 pymin
= (int) rint ((item
->y1
+ origin
- min
) * item
->canvas
->pixels_per_unit
);
1583 /* OK, now fill the RGB buffer at x=i with a line between pymin and pymax,
1584 or, if samples_per_unit == 1, then a dot at each location.
1587 if (pymax
== pymin
) {
1588 PAINT_DOTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymin
);
1590 PAINT_VERTA(buf
, waveview
->wave_r
, waveview
->wave_g
, waveview
->wave_b
, waveview
->wave_a
, x
, pymax
, pymin
);
1593 /* show clipped waveforms with small red lines */
1596 PAINT_VERTA(buf
, waveview
->clip_r
, waveview
->clip_g
, waveview
->clip_b
, waveview
->clip_a
, x
, pymax
, pymax
+clip_length
);
1600 PAINT_VERTA(buf
, waveview
->clip_r
, waveview
->clip_g
, waveview
->clip_b
, waveview
->clip_a
, x
, pymin
-clip_length
, pymin
);
1603 /* presto, we're done */
1609 if (!waveview
->rectified
&& waveview
->zero_line
) {
1611 //PAINT_HORIZA(buf, waveview->zero_r, waveview->zero_g, waveview->zero_b, waveview->zero_a, begin, endi-1, origin );
1613 unsigned char zero_r
, zero_g
, zero_b
, zero_a
;
1614 UINT_TO_RGBA( waveview
->zero_color
, &zero_r
, &zero_g
, &zero_b
, &zero_a
);
1615 int zeroline_y
= (int) rint ((item
->y1
+ origin
) * item
->canvas
->pixels_per_unit
);
1616 PAINT_HORIZA(buf
, zero_r
, zero_g
, zero_b
, zero_a
, zbegin
, zend
, zeroline_y
);
1623 gnome_canvas_waveview_draw (GnomeCanvasItem
*item
,
1624 GdkDrawable
*drawable
,
1626 int width
, int height
)
1628 GnomeCanvasWaveView
*waveview
;
1642 waveview
= GNOME_CANVAS_WAVEVIEW (item
);
1644 /* compute intersection of Drawable area and waveview,
1645 in canvas coordinate space
1648 if (x
> waveview
->bbox_ulx
) {
1651 ulx
= waveview
->bbox_ulx
;
1654 if (y
> waveview
->bbox_uly
) {
1657 uly
= waveview
->bbox_uly
;
1660 if (x
+ width
> waveview
->bbox_lrx
) {
1661 lrx
= waveview
->bbox_lrx
;
1666 if (y
+ height
> waveview
->bbox_lry
) {
1667 lry
= waveview
->bbox_lry
;
1672 /* figure out which samples we need for the resulting intersection */
1674 s1
= floor ((ulx
- waveview
->bbox_ulx
) * waveview
->samples_per_unit
) ;
1676 if (lrx
== waveview
->bbox_lrx
) {
1677 /* This avoids minor rounding errors when we have the
1678 entire region visible.
1680 s2
= waveview
->samples
;
1682 s2
= s1
+ floor ((lrx
- ulx
) * waveview
->samples_per_unit
);
1685 /* translate back to buffer coordinate space */
1692 /* don't rectify at single-sample zoom */
1693 if(waveview
->rectified
&& waveview
->samples_per_unit
> 1.0) {
1699 clip_length
= MIN(5,(waveview
->height
/4));
1701 cr
= gdk_cairo_create (drawable
);
1702 cairo_set_line_width (cr
, 0.5);
1704 origin
= waveview
->bbox_uly
- y
+ waveview
->half_height
;
1706 cairo_rectangle (cr
, ulx
, uly
, lrx
- ulx
, lry
- uly
);
1709 if (waveview
->cache_updater
&& waveview
->reload_cache_in_render
) {
1710 waveview
->cache
->start
= 0;
1711 waveview
->cache
->end
= 0;
1712 waveview
->reload_cache_in_render
= FALSE
;
1715 cache_index
= gnome_canvas_waveview_ensure_cache (waveview
, s1
, s2
);
1718 printf ("%p r (%d,%d)(%d,%d)[%d x %d] bbox (%d,%d)(%d,%d)[%d x %d]"
1719 " draw (%.1f,%.1f)(%.1f,%.1f)[%.1f x %.1f] s= %lu..%lu\n",
1730 waveview
->bbox_lrx
- waveview
->bbox_ulx
,
1731 waveview
->bbox_lry
- waveview
->bbox_uly
,
1739 /* draw the top half */
1741 for (xoff
= ulx
; xoff
< lrx
; xoff
++) {
1744 max
= waveview
->cache
->data
[cache_index
].max
;
1745 min
= waveview
->cache
->data
[cache_index
].min
;
1756 if (fabs (min
) > fabs (max
)) {
1761 yoff
= origin
- (waveview
->half_height
* max
) + 0.5;
1765 cairo_move_to (cr
, xoff
+0.5, yoff
);
1767 cairo_line_to (cr
, xoff
+0.5, yoff
);
1773 /* from the final top point, move out of the clip zone */
1775 cairo_line_to (cr
, xoff
+ 10, yoff
);
1777 /* now draw the bottom half */
1779 for (--xoff
, --cache_index
; xoff
>= ulx
; --xoff
) {
1782 min
= waveview
->cache
->data
[cache_index
].min
;
1788 yoff
= origin
- (waveview
->half_height
* min
) + 0.5;
1790 cairo_line_to (cr
, xoff
+0.5, yoff
);
1794 /* from the final lower point, move out of the clip zone */
1796 cairo_line_to (cr
, xoff
- 10, yoff
);
1798 /* close path to fill */
1800 cairo_close_path (cr
);
1802 /* fill and stroke */
1804 cairo_set_source_rgba (cr
,
1805 (waveview
->fill_r
/255.0),
1806 (waveview
->fill_g
/255.0),
1807 (waveview
->fill_b
/255.0),
1808 (waveview
->fill_a
/255.0));
1809 cairo_fill_preserve (cr
);
1810 cairo_set_source_rgba (cr
,
1811 (waveview
->wave_r
/255.0),
1812 (waveview
->wave_g
/255.0),
1813 (waveview
->wave_b
/255.0),
1814 (waveview
->wave_a
/255.0));
1821 if (clip_max
|| clip_min
) {
1822 cairo_set_source_rgba (cr
, waveview
->clip_r
, waveview
->clip_g
, waveview
->clip_b
, waveview
->clip_a
);
1826 cairo_move_to (cr
, xoff
, yoff1
);
1827 cairo_line_to (cr
, xoff
, yoff1
+ clip_length
);
1832 cairo_move_to (cr
, xoff
, yoff2
);
1833 cairo_line_to (cr
, xoff
, yoff2
- clip_length
);
1840 gnome_canvas_waveview_bounds (GnomeCanvasItem
*item
, double *x1
, double *y1
, double *x2
, double *y2
)
1842 GnomeCanvasWaveView
*waveview
= GNOME_CANVAS_WAVEVIEW (item
);
1847 *x2
= ceil (*x1
+ (waveview
->length_function (waveview
->data_src
) / waveview
->samples_per_unit
));
1848 *y2
= *y1
+ waveview
->height
;
1852 gnome_canvas_item_i2w (item
, &x
, &y
);
1853 gnome_canvas_w2c_d (GNOME_CANVAS(item
->canvas
), x
, y
, &a
, &b
);
1856 gnome_canvas_item_i2w (item
, &x
, &y
);
1857 gnome_canvas_w2c_d (GNOME_CANVAS(item
->canvas
), x
, y
, &c
, &d
);
1858 printf ("item bounds now (%g,%g),(%g,%g)\n", a
, b
, c
, d
);
1864 gnome_canvas_waveview_point (GnomeCanvasItem
*item
, double x
, double y
, int cx
, int cy
, GnomeCanvasItem
**actual_item
)
1873 /* XXX for now, point is never inside the wave
1874 GnomeCanvasWaveView *waveview;
1875 double x1, y1, x2, y2;
1882 waveview
= GNOME_CANVAS_WAVEVIEW (item
);
1884 *actual_item
= item
;
1886 /* Find the bounds for the rectangle plus its outline width */
1888 gnome_canvas_waveview_bounds (item
, &x1
, &y1
, &x2
, &y2
);
1890 /* Is point inside rectangle */
1892 if ((x
>= x1
) && (y
>= y1
) && (x
<= x2
) && (y
<= y2
)) {
1896 /* Point is outside rectangle */
1912 return sqrt (dx
* dx
+ dy
* dy
);