ardour
canvas-waveview.c
Go to the documentation of this file.
1 /*
2  Copyright (C) 2000-2002 Paul Davis
3 
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.
8 
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.
13 
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.
17 
18  $Id$
19 */
20 
21 #include <stdio.h>
22 #include <math.h>
23 #include <libgnomecanvas/libgnomecanvas.h>
24 #include <cairo.h>
25 #include <string.h>
26 #include <limits.h>
27 #include <unistd.h>
28 
29 #include "ardour/dB.h"
30 
31 #include "logmeter.h"
32 #include "canvas-waveview.h"
33 #include "rgb_macros.h"
34 
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
37  */
38 #if defined(_POSIX_VERSION) || defined(COMPILER_MINGW)
39 #define POSIX_FUNC_PTR_CAST(type, object) *((type*) &(object))
40 #endif // _POSIX_VERSION
41 
42 extern void c_stacktrace(void);
43 
44 enum {
69 };
70 
72 
73 static void gnome_canvas_waveview_init (GnomeCanvasWaveView *waveview);
74 
75 static void gnome_canvas_waveview_destroy (GtkObject *object);
76 
77 static void gnome_canvas_waveview_set_property (GObject *object,
78  guint prop_id,
79  const GValue *value,
80  GParamSpec *pspec);
81 static void gnome_canvas_waveview_get_property (GObject *object,
82  guint prop_id,
83  GValue *value,
84  GParamSpec *pspec);
85 
86 static void gnome_canvas_waveview_update (GnomeCanvasItem *item,
87  double *affine,
88  ArtSVP *clip_path,
89  int flags);
90 
91 static void gnome_canvas_waveview_bounds (GnomeCanvasItem *item,
92  double *x1,
93  double *y1,
94  double *x2,
95  double *y2);
96 
97 static double gnome_canvas_waveview_point (GnomeCanvasItem *item,
98  double x,
99  double y,
100  int cx,
101  int cy,
102  GnomeCanvasItem **actual_item);
103 
104 static void gnome_canvas_waveview_render (GnomeCanvasItem *item,
105  GnomeCanvasBuf *buf);
106 
107 static void gnome_canvas_waveview_draw (GnomeCanvasItem *item,
108  GdkDrawable *drawable,
109  int x,
110  int y,
111  int w,
112  int h);
113 
115  void *);
116 
118  guint32);
119 
121  gulong start_sample,
122  gulong end_sample);
123 
124 
125 static int _gradient_rendering = 0;
126 
127 static GnomeCanvasItemClass *parent_class;
128 
129 GType
131 {
132  static GType waveview_type;
133 
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),
143  0, /* n_preallocs */
144  (GInstanceInitFunc) gnome_canvas_waveview_init,
145  NULL /* value_table */
146  };
147 
148  waveview_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasWaveView",
149  &object_info, 0);
150  }
151 
152  return waveview_type;
153  }
154 
155 static void
157 {
158  GObjectClass *gobject_class;
159  GtkObjectClass *object_class;
160  GnomeCanvasItemClass *item_class;
161 
162  gobject_class = (GObjectClass *) class;
163  object_class = (GtkObjectClass *) class;
164  item_class = (GnomeCanvasItemClass *) class;
165 
166  parent_class = g_type_class_peek_parent (class);
167 
168  gobject_class->set_property = gnome_canvas_waveview_set_property;
169  gobject_class->get_property = gnome_canvas_waveview_get_property;
170 
171  g_object_class_install_property
172  (gobject_class,
174  g_param_spec_pointer ("data_src", NULL, NULL,
175  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
176 
177  g_object_class_install_property
178  (gobject_class,
179  PROP_CHANNEL,
180  g_param_spec_uint ("channel", NULL, NULL,
181  0, G_MAXUINT, 0,
182  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
183 
184  g_object_class_install_property
185  (gobject_class,
187  g_param_spec_pointer ("length_function", NULL, NULL,
188  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
189 
190  g_object_class_install_property
191  (gobject_class,
193  g_param_spec_pointer ("sourcefile_length_function", NULL, NULL,
194  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
195 
196  g_object_class_install_property
197  (gobject_class,
199  g_param_spec_pointer ("peak_function", NULL, NULL,
200  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
201 
202  g_object_class_install_property
203  (gobject_class,
205  g_param_spec_pointer ("gain_function", NULL, NULL,
206  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
207 
208  g_object_class_install_property
209  (gobject_class,
211  g_param_spec_pointer ("gain_src", NULL, NULL,
212  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
213 
214  g_object_class_install_property
215  (gobject_class,
216  PROP_CACHE,
217  g_param_spec_pointer ("cache", NULL, NULL,
218  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
219 
220  g_object_class_install_property
221  (gobject_class,
223  g_param_spec_boolean ("cache_updater", NULL, NULL,
224  FALSE,
225  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
226 
227  g_object_class_install_property
228  (gobject_class,
230  g_param_spec_double ("samples_per_unit", NULL, NULL,
231  0.0, G_MAXDOUBLE, 0.0,
232  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
233 
234  g_object_class_install_property
235  (gobject_class,
237  g_param_spec_double ("amplitude_above_axis", NULL, NULL,
238  0.0, G_MAXDOUBLE, 0.0,
239  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
240 
241  g_object_class_install_property
242  (gobject_class,
243  PROP_X,
244  g_param_spec_double ("x", NULL, NULL,
245  0.0, G_MAXDOUBLE, 0.0,
246  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
247 
248  g_object_class_install_property
249  (gobject_class,
250  PROP_Y,
251  g_param_spec_double ("y", NULL, NULL,
252  0.0, G_MAXDOUBLE, 0.0,
253  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
254 
255  g_object_class_install_property
256  (gobject_class,
257  PROP_HEIGHT,
258  g_param_spec_double ("height", NULL, NULL,
259  0.0, G_MAXDOUBLE, 0.0,
260  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
261 
262  g_object_class_install_property
263  (gobject_class,
265  g_param_spec_uint ("wave_color", NULL, NULL,
266  0, G_MAXUINT, 0,
267  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
268 
269  g_object_class_install_property
270  (gobject_class,
272  g_param_spec_uint ("clip_color", NULL, NULL,
273  0, G_MAXUINT, 0,
274  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
275 
276  g_object_class_install_property
277  (gobject_class,
279  g_param_spec_uint ("zero_color", NULL, NULL,
280  0, G_MAXUINT, 0,
281  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
282 
283  g_object_class_install_property
284  (gobject_class,
286  g_param_spec_uint ("fill_color", NULL, NULL,
287  0, G_MAXUINT, 0,
288  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
289 
290  g_object_class_install_property
291  (gobject_class,
292  PROP_FILLED,
293  g_param_spec_boolean ("filled", NULL, NULL,
294  FALSE,
295  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
296 
297  g_object_class_install_property
298  (gobject_class,
300  g_param_spec_boolean ("rectified", NULL, NULL,
301  FALSE,
302  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
303 
304  g_object_class_install_property
305  (gobject_class,
307  g_param_spec_boolean ("zero_line", NULL, NULL,
308  FALSE,
309  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
310 
311  g_object_class_install_property
312  (gobject_class,
314  g_param_spec_boolean ("logscaled", NULL, NULL,
315  FALSE,
316  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
317 
318  g_object_class_install_property
319  (gobject_class,
321  g_param_spec_uint ("region_start", NULL, NULL,
322  0, G_MAXUINT, 0,
323  (G_PARAM_READABLE | G_PARAM_WRITABLE)));
324 
325  object_class->destroy = gnome_canvas_waveview_destroy;
326 
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;
332 }
333 
334 void
336 {
337  _gradient_rendering = yn;
338 }
339 
342 {
344 
345  c = g_malloc (sizeof (GnomeCanvasWaveViewCache));
346 
347  c->allocated = 2048;
348  c->data = g_malloc (sizeof (GnomeCanvasWaveViewCacheEntry) * c->allocated);
349  c->data_size = 0;
350  c->start = 0;
351  c->end = 0;
352 
353  return c;
354 }
355 
356 void
358 {
359  g_free (cache->data);
360  g_free (cache);
361 }
362 
363 static void
365 {
366  waveview->x = 0.0;
367  waveview->y = 0.0;
368  waveview->cache = 0;
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;
387 
388  waveview->wave_color = 0;
389  waveview->clip_color = 0;
390  waveview->zero_color = 0;
391  waveview->fill_color = 0;
392 }
393 
394 static void
395 gnome_canvas_waveview_destroy (GtkObject *object)
396 {
397  g_return_if_fail (object != NULL);
398  g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
399 
400  if (GTK_OBJECT_CLASS (parent_class)->destroy)
401  (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
402 }
403 
404 #define DEBUG_CACHE 0
405 #undef CACHE_MEMMOVE_OPTIMIZATION
406 
408 static guint32
409 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview, gulong start_sample, gulong end_sample)
410 {
411  gulong required_cache_entries;
412  gulong rf1, rf2,rf3, required_frames;
413  gulong new_cache_start, new_cache_end;
414  gulong half_width;
415  gulong npeaks;
416  gulong offset;
417  gulong ostart;
418  gulong copied;
420  float* gain;
421 #ifdef CACHE_MEMMOVE_OPTIMIZATION
422  gulong present_frames;
423  gulong present_entries;
424 #endif
425 
426  cache = waveview->cache;
427 
428  start_sample = start_sample + waveview->region_start;
429  end_sample = end_sample + waveview->region_start;
430 #if DEBUG_CACHE
431  // printf("waveview->region_start == %lu\n",waveview->region_start);
432  // c_stacktrace ();
433  printf ("\n\n=> 0x%x cache @ 0x%x range: %lu - %lu request: %lu - %lu (%lu frames)\n",
434  waveview, cache,
435  cache->start, cache->end,
436  start_sample, end_sample, end_sample - start_sample);
437 #endif
438 
439  if (cache->start <= start_sample && cache->end >= end_sample) {
440 #if DEBUG_CACHE
441  // printf ("0x%x: cache hit for %lu-%lu (cache holds: %lu-%lu\n",
442  // waveview, start_sample, end_sample, cache->start, cache->end);
443 #endif
444  goto out;
445  }
446 
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.
449  */
450 
451  /* Note the assumption that we have a 1:1 units:pixel ratio for the canvas. Its everywhere ... */
452 
453  half_width = (gulong) floor ((waveview->screen_width * waveview->samples_per_unit)/2.0 + 0.5);
454 
455  if (start_sample < half_width) {
456  new_cache_start = 0;
457  } else {
458  new_cache_start = start_sample - half_width;
459  }
460 
461  /* figure out how many frames we want */
462 
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);
466 
467  /* but make sure it doesn't extend beyond the end of the source material */
468 
469  rf3 = (gulong) (waveview->sourcefile_length_function (waveview->data_src, waveview->samples_per_unit)) + 1;
470  if (rf3 < new_cache_start) {
471  rf3 = 0;
472  } else {
473  rf3 -= new_cache_start;
474  }
475 
476 #if DEBUG_CACHE
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);
480 #endif
481 
482  required_frames = MIN(required_frames,rf3);
483 
484  new_cache_end = new_cache_start + required_frames - 1;
485 
486  required_cache_entries = (gulong) floor (required_frames / waveview->samples_per_unit );
487 
488 #if DEBUG_CACHE
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);
492 #endif
493 
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;
497  // cache->start = 0;
498  // cache->end = 0;
499  }
500 
501  ostart = new_cache_start;
502 
503 #ifdef CACHE_MEMMOVE_OPTIMIZATION
504 
505  /* data is not entirely in the cache, so go fetch it, making sure to fill the cache */
506 
507  /* some of the required cache entries are in the cache, but in the wrong
508  locations. use memmove to fix this.
509  */
510 
511  if (cache->start < new_cache_start && new_cache_start < cache->end) {
512 
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.
515 
516 
517  wv->cache_start wv->cache_end
518  |-------------------------------------------------------| cache
519  |--------------------------------| requested
520  <------------------->
521  "present"
522  new_cache_start new_cache_end
523  */
524 
525 
526  present_frames = cache->end - new_cache_start;
527  present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
528 
529 #if DEBUG_CACHE
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);
532 #endif
533 
534  memmove (&cache->data[0],
535  &cache->data[cache->data_size - present_entries],
536  present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
537 
538 #if DEBUG_CACHE
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);
542 #endif
543 
544  copied = present_entries;
545  offset = present_entries;
546  new_cache_start += present_frames;
547  required_frames -= present_frames;
548 
549  } else if (new_cache_end > cache->start && new_cache_end < cache->end) {
550 
551  /* case two: the common area lives at the beginning of the existing cache.
552 
553  wv->cache_start wv->cache_end
554  |-----------------------------------------------------|
555  |--------------------------------|
556  <----------------->
557  "present"
558 
559  new_cache_start new_cache_end
560  */
561 
562  present_frames = new_cache_end - cache->start;
563  present_entries = (gulong) floor (present_frames / waveview->samples_per_unit);
564 
565  memmove (&cache->data[cache->data_size - present_entries],
566  &cache->data[0],
567  present_entries * sizeof (GnomeCanvasWaveViewCacheEntry));
568 
569 #if DEBUG_CACHE
570  fprintf (stderr, "existing material at start of current cache, move to start of end cache\n");
571 #endif
572 
573 #if DEBUG_CACHE
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);
577 #endif
578 
579  copied = present_entries;
580  offset = 0;
581  required_frames -= present_frames;
582 
583 
584  } else {
585  copied = 0;
586  offset = 0;
587 
588  }
589 
590 #else
591  copied = 0;
592  offset = 0;
593 
594 #endif /* CACHE_MEMMOVE_OPTIMIZATION */
595 
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);
598 
599  npeaks = (gulong) floor (required_frames / waveview->samples_per_unit);
600  required_frames = npeaks * waveview->samples_per_unit;
601 
602 #if DEBUG_CACHE
603 
604 
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);
608 #endif
609 
610 #if DEBUG_CACHE
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);
614 #endif
615 
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);
618 
619  /* take into account any copied peaks */
620 
621  npeaks += copied;
622  } else {
623  npeaks = copied;
624  }
625 
626  if (npeaks < cache->allocated) {
627 #if DEBUG_CACHE
628  fprintf (stderr, "zero fill cache for %lu at %lu\n", cache->allocated - npeaks, npeaks);
629 #endif
630  memset (&cache->data[npeaks], 0, sizeof (GnomeCanvasWaveViewCacheEntry) * (cache->allocated - npeaks));
631  cache->data_size = npeaks;
632  } else {
633  cache->data_size = cache->allocated;
634  }
635 
636  if (waveview->gain_curve_function) {
637  guint32 n;
638 
639  gain = (float*) malloc (sizeof (float) * cache->data_size);
640 
641  waveview->gain_curve_function (waveview->gain_src, new_cache_start, new_cache_end, gain, cache->data_size);
642 
643  for (n = 0; n < cache->data_size; ++n) {
644  cache->data[n].min *= gain[n];
645  cache->data[n].max *= gain[n];
646  }
647 
648  free (gain);
649 
650  }
651 
652  /* do optional log scaling. this implementation is not particularly efficient */
653 
654  if (waveview->logscaled) {
655  guint32 n;
656  GnomeCanvasWaveViewCacheEntry* buf = cache->data;
657 
658  for (n = 0; n < cache->data_size; ++n) {
659 
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));
664  }
665 
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));
670  }
671  }
672  }
673 
674  cache->start = ostart;
675  cache->end = new_cache_end;
676 
677  out:
678 #if DEBUG_CACHE
679  fprintf (stderr, "return cache index = %d\n",
680  (guint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5));
681 #endif
682  return (guint32) floor ((((double) (start_sample - cache->start)) / waveview->samples_per_unit) + 0.5);
683 
684 }
685 
686 void
688 {
689 
690  if (waveview->cache_updater) {
691  if (waveview->data_src == data_src) {
692  waveview->reload_cache_in_render = TRUE;
693  return;
694  }
695 
696  waveview->cache->start = 0;
697  waveview->cache->end = 0;
698  }
699 
700  waveview->data_src = data_src;
701 }
702 
703 void
705 {
706  if (waveview->channel == chan) {
707  return;
708  }
709 
710  waveview->channel = chan;
711 }
712 
713 static void
714 gnome_canvas_waveview_reset_bounds (GnomeCanvasItem *item)
715 
716 {
717  double x1, x2, y1, y2;
718  ArtPoint i1, i2;
719  ArtPoint w1, w2;
720  int Ix1, Ix2, Iy1, Iy2;
721  double i2w[6];
722 
723  gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
724 
725  i1.x = x1;
726  i1.y = y1;
727  i2.x = x2;
728  i2.y = y2;
729 
730  gnome_canvas_item_i2w_affine (item, i2w);
731  art_affine_point (&w1, &i1, i2w);
732  art_affine_point (&w2, &i2, i2w);
733 
734  Ix1 = (int) rint(w1.x);
735  Ix2 = (int) rint(w2.x);
736  Iy1 = (int) rint(w1.y);
737  Iy2 = (int) rint(w2.y);
738 
739  gnome_canvas_update_bbox (item, Ix1, Iy1, Ix2, Iy2);
740 }
741 
742 /*
743  * CANVAS CALLBACKS
744  */
745 
746 static void
748  guint prop_id,
749  const GValue *value,
750  GParamSpec *pspec)
751 
752 {
753  (void) pspec;
754 
755  GnomeCanvasItem *item;
756  GnomeCanvasWaveView *waveview;
757  int redraw = FALSE;
758  int calc_bounds = FALSE;
759 
760  g_return_if_fail (object != NULL);
761  g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
762 
763  item = GNOME_CANVAS_ITEM (object);
764  waveview = GNOME_CANVAS_WAVEVIEW (object);
765 
766  void * ptr;
767  switch (prop_id) {
768  case PROP_DATA_SRC:
769  gnome_canvas_waveview_set_data_src (waveview, g_value_get_pointer(value));
770  redraw = TRUE;
771  break;
772 
773  case PROP_CHANNEL:
774  gnome_canvas_waveview_set_channel (waveview, g_value_get_uint(value));
775  redraw = TRUE;
776  break;
777 
779  ptr = g_value_get_pointer(value);
780  waveview->length_function = POSIX_FUNC_PTR_CAST(waveview_length_function_t, ptr);
781  redraw = TRUE;
782  break;
783 
785  ptr = g_value_get_pointer(value);
786  waveview->sourcefile_length_function = POSIX_FUNC_PTR_CAST(waveview_sourcefile_length_function_t, ptr);
787  redraw = TRUE;
788  break;
789 
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);
793  redraw = TRUE;
794  break;
795 
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);
799  redraw = TRUE;
800  break;
801 
802  case PROP_GAIN_SRC:
803  waveview->gain_src = g_value_get_pointer(value);
804  if (waveview->cache_updater) {
805  waveview->cache->start = 0;
806  waveview->cache->end = 0;
807  }
808  redraw = TRUE;
809  calc_bounds = TRUE;
810  break;
811 
812  case PROP_CACHE:
813  waveview->cache = g_value_get_pointer(value);
814  redraw = TRUE;
815  break;
816 
817 
818  case PROP_CACHE_UPDATER:
819  waveview->cache_updater = g_value_get_boolean(value);
820  redraw = TRUE;
821  break;
822 
824  if ((waveview->samples_per_unit = g_value_get_double(value)) < 1.0) {
825  waveview->samples_per_unit = 1.0;
826  }
827  if (waveview->cache_updater) {
828  waveview->cache->start = 0;
829  waveview->cache->end = 0;
830  }
831  redraw = TRUE;
832  calc_bounds = TRUE;
833  break;
834 
836  waveview->amplitude_above_axis = g_value_get_double(value);
837  redraw = TRUE;
838  break;
839 
840  case PROP_X:
841  if (waveview->x != g_value_get_double (value)) {
842  waveview->x = g_value_get_double (value);
843  calc_bounds = TRUE;
844  }
845  break;
846 
847  case PROP_Y:
848  if (waveview->y != g_value_get_double (value)) {
849  waveview->y = g_value_get_double (value);
850  calc_bounds = TRUE;
851  }
852  break;
853 
854  case PROP_HEIGHT:
855  if (waveview->height != fabs (g_value_get_double (value))) {
856  waveview->height = fabs (g_value_get_double (value));
857  redraw = TRUE;
858  }
859  break;
860 
861  case PROP_WAVE_COLOR:
862  if (waveview->wave_color != g_value_get_uint(value)) {
863  waveview->wave_color = g_value_get_uint(value);
864  redraw = TRUE;
865  }
866  break;
867 
868  case PROP_CLIP_COLOR:
869  if (waveview->clip_color != g_value_get_uint(value)) {
870  waveview->clip_color = g_value_get_uint(value);
871  redraw = TRUE;
872  }
873  break;
874 
875  case PROP_ZERO_COLOR:
876  if (waveview->zero_color != g_value_get_uint(value)) {
877  waveview->zero_color = g_value_get_uint(value);
878  redraw = TRUE;
879  }
880  break;
881 
882  case PROP_FILL_COLOR:
883  if (waveview->fill_color != g_value_get_uint(value)) {
884  waveview->fill_color = g_value_get_uint(value);
885  redraw = TRUE;
886  }
887  break;
888 
889  case PROP_FILLED:
890  if (waveview->filled != g_value_get_boolean(value)) {
891  waveview->filled = g_value_get_boolean(value);
892  redraw = TRUE;
893  }
894  break;
895 
896  case PROP_RECTIFIED:
897  if (waveview->rectified != g_value_get_boolean(value)) {
898  waveview->rectified = g_value_get_boolean(value);
899  redraw = TRUE;
900  }
901  break;
902 
903  case PROP_ZERO_LINE:
904  if (waveview->zero_line != g_value_get_boolean(value)) {
905  waveview->zero_line = g_value_get_boolean(value);
906  redraw = TRUE;
907  }
908  break;
909 
910  case PROP_LOGSCALED:
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;
916  }
917  redraw = TRUE;
918  calc_bounds = TRUE;
919  }
920  break;
921  case PROP_REGION_START:
922  waveview->region_start = g_value_get_uint(value);
923  redraw = TRUE;
924  calc_bounds = TRUE;
925  break;
926 
927 
928  default:
929  break;
930  }
931 
932  if (calc_bounds) {
934  }
935 
936  if (redraw) {
937  gnome_canvas_item_request_update (item);
938  }
939 
940 }
941 
942 static void
944  GObject *object,
945  guint prop_id,
946  GValue *value,
947  GParamSpec *pspec)
948 {
949 
950 
951  g_return_if_fail (object != NULL);
952  g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object));
953 
954  GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (object);
955 
956  switch (prop_id) {
957  case PROP_DATA_SRC:
958  g_value_set_pointer(value, waveview->data_src);
959  break;
960 
961  case PROP_CHANNEL:
962  g_value_set_uint(value, waveview->channel);
963  break;
964 
966  g_value_set_pointer(value, POSIX_FUNC_PTR_CAST(void*, waveview->length_function));
967  break;
968 
970  g_value_set_pointer(value, POSIX_FUNC_PTR_CAST(void*, waveview->sourcefile_length_function));
971  break;
972 
973  case PROP_PEAK_FUNCTION:
974  g_value_set_pointer(value, POSIX_FUNC_PTR_CAST(void*, waveview->peak_function));
975  break;
976 
977  case PROP_GAIN_FUNCTION:
978  g_value_set_pointer(value, POSIX_FUNC_PTR_CAST(void*, waveview->gain_curve_function));
979  break;
980 
981  case PROP_GAIN_SRC:
982  g_value_set_pointer(value, waveview->gain_src);
983  break;
984 
985  case PROP_CACHE:
986  g_value_set_pointer(value, waveview->cache);
987  break;
988 
989  case PROP_CACHE_UPDATER:
990  g_value_set_boolean(value, waveview->cache_updater);
991  break;
992 
994  g_value_set_double(value, waveview->samples_per_unit);
995  break;
996 
998  g_value_set_double(value, waveview->amplitude_above_axis);
999  break;
1000 
1001  case PROP_X:
1002  g_value_set_double (value, waveview->x);
1003  break;
1004 
1005  case PROP_Y:
1006  g_value_set_double (value, waveview->y);
1007  break;
1008 
1009  case PROP_HEIGHT:
1010  g_value_set_double (value, waveview->height);
1011  break;
1012 
1013  case PROP_WAVE_COLOR:
1014  g_value_set_uint (value, waveview->wave_color);
1015  break;
1016 
1017  case PROP_CLIP_COLOR:
1018  g_value_set_uint (value, waveview->clip_color);
1019  break;
1020 
1021  case PROP_ZERO_COLOR:
1022  g_value_set_uint (value, waveview->zero_color);
1023  break;
1024 
1025  case PROP_FILL_COLOR:
1026  g_value_set_uint (value, waveview->fill_color);
1027  break;
1028 
1029  case PROP_FILLED:
1030  g_value_set_boolean (value, waveview->filled);
1031  break;
1032 
1033  case PROP_RECTIFIED:
1034  g_value_set_boolean (value, waveview->rectified);
1035  break;
1036 
1037  case PROP_ZERO_LINE:
1038  g_value_set_boolean (value, waveview->zero_line);
1039  break;
1040 
1041  case PROP_LOGSCALED:
1042  g_value_set_boolean (value, waveview->logscaled);
1043  break;
1044 
1045  case PROP_REGION_START:
1046  g_value_set_uint (value, waveview->region_start);
1047  break;
1048 
1049  default:
1050  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1051  break;
1052  }
1053 }
1054 
1055 static void
1056 gnome_canvas_waveview_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
1057 {
1058  GnomeCanvasWaveView *waveview;
1059  double x, y;
1060 
1061  waveview = GNOME_CANVAS_WAVEVIEW (item);
1062 
1063 // check_cache (waveview, "start of update");
1064 
1065  if (parent_class->update)
1066  (* parent_class->update) (item, affine, clip_path, flags);
1067 
1069 
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.
1073  */
1074 
1075  x = waveview->x;
1076  y = waveview->y;
1077 
1078  gnome_canvas_item_i2w (item, &x, &y);
1079  gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_ulx, &waveview->bbox_uly);
1080 
1081  waveview->samples = waveview->length_function (waveview->data_src);
1082 
1083  x = waveview->x + (waveview->samples / waveview->samples_per_unit);
1084  y = waveview->y + waveview->height;
1085 
1086  gnome_canvas_item_i2w (item, &x, &y);
1087  gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &waveview->bbox_lrx, &waveview->bbox_lry);
1088 
1089  /* cache the half-height and the end point in canvas units */
1090 
1091  waveview->half_height = waveview->height / 2.0;
1092 
1093  /* parse the color */
1094 
1095  UINT_TO_RGBA (waveview->wave_color, &waveview->wave_r, &waveview->wave_g, &waveview->wave_b,
1096  &waveview->wave_a);
1097  UINT_TO_RGBA (waveview->clip_color, &waveview->clip_r, &waveview->clip_g, &waveview->clip_b,
1098  &waveview->clip_a);
1099  UINT_TO_RGBA (waveview->fill_color, &waveview->fill_r, &waveview->fill_g, &waveview->fill_b,
1100  &waveview->fill_a);
1101 
1102 // check_cache (waveview, "end of update");
1103 }
1104 
1105 static void
1107  GnomeCanvasBuf *buf)
1108 {
1109  GnomeCanvasWaveView *waveview;
1110  gulong s1, s2;
1111  int clip_length = 0;
1112  int pymin, pymax;
1113  guint cache_index;
1114  double half_height;
1115  int x;
1116  char rectify;
1117 
1118  waveview = GNOME_CANVAS_WAVEVIEW (item);
1119 
1120 // check_cache (waveview, "start of render");
1121 
1122  if (parent_class->render) {
1123  (*parent_class->render) (item, buf);
1124  }
1125 
1126  if (buf->is_bg) {
1127  gnome_canvas_buf_ensure_buf (buf);
1128  buf->is_bg = FALSE;
1129  }
1130 
1131  /* a "unit" means a pixel */
1132 
1133  /* begin: render start x (units) */
1134  int const begin = MAX (waveview->bbox_ulx, buf->rect.x0);
1135 
1136  /* zbegin: start x for zero line (units) */
1137  int const zbegin = (begin == waveview->bbox_ulx) ? (begin + 1) : begin;
1138 
1139  /* end: render end x (units) */
1140  int const end = (waveview->bbox_lrx >= 0) ? MIN (waveview->bbox_lrx,buf->rect.x1) : buf->rect.x1;
1141 
1142  /* zend: end x for zero-line (units) */
1143  int const zend = (end == waveview->bbox_lrx) ? (end - 1) : end;
1144 
1145  if (begin == end) {
1146  return;
1147  }
1148 
1149  /* s1: start sample
1150  s2: end sample
1151  */
1152 
1153  s1 = floor ((begin - waveview->bbox_ulx) * waveview->samples_per_unit);
1154 
1155  // fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit);
1156 
1157  if (end == waveview->bbox_lrx) {
1158  /* This avoids minor rounding errors when we have the
1159  entire region visible.
1160  */
1161  s2 = waveview->samples;
1162  } else {
1163  s2 = s1 + floor ((end - begin) * waveview->samples_per_unit);
1164  }
1165 
1166 #if 0
1167  printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)"
1168  " b/e %d..%d s= %lu..%lu @ %f\n",
1169  waveview,
1170  buf->rect.x0,
1171  buf->rect.x1,
1172  buf->rect.y0,
1173  buf->rect.y1,
1174  waveview->bbox_ulx,
1175  waveview->bbox_lrx,
1176  waveview->bbox_uly,
1177  waveview->bbox_lry,
1178  begin, end, s1, s2,
1179  waveview->samples_per_unit);
1180 #endif
1181 
1182  /* now ensure that the cache is full and properly
1183  positioned.
1184  */
1185 
1186 // check_cache (waveview, "pre-ensure");
1187 
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;
1192  }
1193 
1194 // check_cache (waveview, "post-ensure");
1195 
1196  /* don't rectify at single-sample zoom */
1197  if (waveview->rectified && waveview->samples_per_unit > 1) {
1198  rectify = TRUE;
1199  }
1200  else {
1201  rectify = FALSE;
1202  }
1203 
1204  clip_length = MIN(5,(waveview->height/4));
1205 
1206  /*
1207  Now draw each line, clipping it appropriately. The clipping
1208  is done by the macros PAINT_FOO().
1209  */
1210 
1211  half_height = waveview->half_height;
1212 
1213 /* this makes it slightly easier to comprehend whats going on */
1214 #define origin half_height
1215 
1216  if (waveview->filled && !rectify) {
1217  int prev_pymin = 1;
1218  int prev_pymax = 0;
1219  int last_pymin = 1;
1220  int last_pymax = 0;
1221  int next_pymin, next_pymax;
1222  double max, min;
1223  int next_clip_max = 0;
1224  int next_clip_min = 0;
1225 
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);
1228 
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;
1233  }
1234  else {
1235  s1 -= waveview->samples_per_unit;
1236  }
1237 
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;
1242  }
1243  else {
1244  s2 += waveview->samples_per_unit;
1245  }
1246 
1247  cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
1248 
1249  /*
1250  * Compute the variables outside the rendering rect
1251  */
1252  if(prev_pymax != prev_pymin) {
1253 
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);
1256  ++cache_index;
1257  }
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);
1261 
1262  if (index >= waveview->cache->data_size) {
1263 
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);
1268 
1269  } else {
1270 
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);
1273 
1274  }
1275 
1276  }
1277 
1278  /*
1279  * initialize NEXT* variables for the first run, duplicated in the loop for speed
1280  */
1281  max = waveview->cache->data[cache_index].max;
1282  min = waveview->cache->data[cache_index].min;
1283 
1284  if (max >= 1.0) {
1285  max = 1.0;
1286  next_clip_max = 1;
1287  }
1288 
1289  if (min <= -1.0) {
1290  min = -1.0;
1291  next_clip_min = 1;
1292  }
1293 
1294  max *= half_height;
1295  min *= half_height;
1296 
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);
1299 
1300  /*
1301  * And now the loop
1302  */
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;
1307 
1308  pymax = next_pymax;
1309  pymin = next_pymin;
1310 
1311  /* compute next */
1312  if(x == end - 1) {
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;
1316  }
1317  else {
1318  ++cache_index;
1319 
1320  if (cache_index < waveview->cache->data_size) {
1321  max = waveview->cache->data[cache_index].max;
1322  min = waveview->cache->data[cache_index].min;
1323  } else {
1324  max = min = 0;
1325  }
1326 
1327  next_clip_max = 0;
1328  next_clip_min = 0;
1329 
1330  if (max >= 1.0) {
1331  max = 1.0;
1332  next_clip_max = 1;
1333  }
1334 
1335  if (min <= -1.0) {
1336  min = -1.0;
1337  next_clip_min = 1;
1338  }
1339 
1340  max *= half_height;
1341  min *= half_height;
1342 
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);
1345  }
1346 
1347  /* render */
1348  if (pymax == pymin) {
1349  PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
1350  } else {
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);
1355  }
1356  else {
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);
1360  ++fill_max;
1361  } else {
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);
1363  }
1364 
1365  }
1366 
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);
1371  }
1372  else {
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);
1376  }
1377  else {
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);
1379  }
1380  }
1381 
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);
1384  }
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);
1387  }
1388  }
1389 
1390  if (clip_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));
1394 
1395  }
1396 
1397  if (clip_min) {
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);
1401  }
1402 
1403  prev_pymax = pymax;
1404  prev_pymin = pymin;
1405  }
1406 
1407  } else if (waveview->filled && rectify) {
1408 
1409  int prev_pymax = -1;
1410  int last_pymax = -1;
1411  int next_pymax;
1412  double max, min;
1413  int next_clip_max = 0;
1414  int next_clip_min = 0;
1415 
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);
1418 
1419  // for rectified, this stays constant throughout the loop
1420  pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
1421 
1422  if(s1 < waveview->samples_per_unit) {
1423  /* we haven't got a prev vars to compare with, so outline the whole line here */
1424  prev_pymax = pymin;
1425  }
1426  else {
1427  s1 -= waveview->samples_per_unit;
1428  }
1429 
1430  if(end == waveview->bbox_lrx) {
1431  /* we don't have the NEXT vars for the last sample */
1432  last_pymax = pymin;
1433  }
1434  else {
1435  s2 += waveview->samples_per_unit;
1436  }
1437 
1438  cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
1439 
1440  /*
1441  * Compute the variables outside the rendering rect
1442  */
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);
1446 
1447  if (fabs (min) > fabs (max)) {
1448  max = fabs (min);
1449  }
1450 
1451  prev_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
1452  ++cache_index;
1453  }
1454  if(last_pymax < 0) {
1455  /* take the index of one sample right of what we render */
1456  int index = cache_index + (end - begin);
1457 
1458  max = MIN(waveview->cache->data[index].max, 1.0);
1459  min = MAX(waveview->cache->data[index].min, -1.0);
1460 
1461  if (fabs (min) > fabs (max)) {
1462  max = fabs (min);
1463  }
1464 
1465  last_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
1466  }
1467 
1468  /*
1469  * initialize NEXT* variables for the first run, duplicated in the loop for speed
1470  */
1471  max = waveview->cache->data[cache_index].max;
1472  min = waveview->cache->data[cache_index].min;
1473 
1474  if (max >= 1.0) {
1475  max = 1.0;
1476  next_clip_max = 1;
1477  }
1478 
1479  if (min <= -1.0) {
1480  min = -1.0;
1481  next_clip_min = 1;
1482  }
1483 
1484  if (fabs (min) > fabs (max)) {
1485  max = fabs (min);
1486  }
1487 
1488  next_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
1489 
1490  /*
1491  * And now the loop
1492  */
1493  for(x = begin; x < end; ++x) {
1494  int clip_max = next_clip_max;
1495  int clip_min = next_clip_min;
1496  int fill_max;
1497 
1498  pymax = next_pymax;
1499 
1500  /* compute next */
1501  if(x == end - 1) {
1502  /*next is now the last column, which is outside the rendering rect, and possibly outside the region*/
1503  next_pymax = last_pymax;
1504  }
1505  else {
1506  ++cache_index;
1507 
1508  max = waveview->cache->data[cache_index].max;
1509  min = waveview->cache->data[cache_index].min;
1510 
1511  if (max >= 1.0) {
1512  max = 1.0;
1513  next_clip_max = 1;
1514  }
1515 
1516  if (min <= -1.0) {
1517  min = -1.0;
1518  next_clip_min = 1;
1519  }
1520 
1521  if (fabs (min) > fabs (max)) {
1522  max = fabs (min);
1523  }
1524 
1525  next_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
1526  }
1527 
1528  /* render */
1529  if (pymax == pymin) {
1530  PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
1531  } else {
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);
1536  }
1537  else {
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);
1541  ++fill_max;
1542  }
1543  else {
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);
1545  }
1546  }
1547 
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);
1550  }
1551  else if(fill_max == pymin) {
1552  PAINT_DOTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, pymin);
1553  }
1554  }
1555 
1556  if (clip_max) {
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));
1560  }
1561 
1562  if (clip_min) {
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);
1566  }
1567 
1568  prev_pymax = pymax;
1569  }
1570  }
1571  else {
1572  cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
1573 
1574  for (x = begin; x < end; x++) {
1575 
1576  double max, min;
1577  int clip_max, clip_min;
1578 
1579  clip_max = 0;
1580  clip_min = 0;
1581 
1582  max = waveview->cache->data[cache_index].max;
1583  min = waveview->cache->data[cache_index].min;
1584 
1585  if (max >= 1.0) {
1586  max = 1.0;
1587  clip_max = 1;
1588  }
1589 
1590  if (min <= -1.0) {
1591  min = -1.0;
1592  clip_min = 1;
1593  }
1594 
1595  if (rectify) {
1596 
1597  if (fabs (min) > fabs (max)) {
1598  max = fabs (min);
1599  }
1600 
1601  max = max * waveview->height;
1602 
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);
1605 
1606  } else {
1607 
1608  max = max * half_height;
1609  min = min * half_height;
1610 
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);
1613  }
1614 
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.
1617  */
1618 
1619  if (pymax == pymin) {
1620  PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
1621  } else {
1622  PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, pymin);
1623  }
1624 
1625  /* show clipped waveforms with small red lines */
1626 
1627  if (clip_max) {
1628  PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length);
1629  }
1630 
1631  if (clip_min) {
1632  PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin);
1633  }
1634 
1635  /* presto, we're done */
1636 
1637  cache_index++;
1638  }
1639  }
1640 
1641  if (!waveview->rectified && waveview->zero_line && waveview->height >= 100) {
1642  // Paint zeroline.
1643 
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);
1648  }
1649 #undef origin
1650 
1651 }
1652 
1653 static void
1654 gnome_canvas_waveview_flat_render (GnomeCanvasItem *item,
1655  GnomeCanvasBuf *buf)
1656 {
1657  GnomeCanvasWaveView *waveview;
1658  gulong s1, s2;
1659  int clip_length = 0;
1660  int pymin, pymax;
1661  guint cache_index;
1662  double half_height;
1663  int x;
1664  char rectify;
1665 
1666  waveview = GNOME_CANVAS_WAVEVIEW (item);
1667 
1668 // check_cache (waveview, "start of render");
1669 
1670  if (parent_class->render) {
1671  (*parent_class->render) (item, buf);
1672  }
1673 
1674  if (buf->is_bg) {
1675  gnome_canvas_buf_ensure_buf (buf);
1676  buf->is_bg = FALSE;
1677  }
1678 
1679  /* a "unit" means a pixel */
1680 
1681  /* begin: render start x (units) */
1682  int const begin = MAX (waveview->bbox_ulx, buf->rect.x0);
1683 
1684  /* zbegin: start x for zero line (units) */
1685  int const zbegin = (begin == waveview->bbox_ulx) ? (begin + 1) : begin;
1686 
1687  /* end: render end x (units) */
1688  int const end = (waveview->bbox_lrx >= 0) ? MIN (waveview->bbox_lrx,buf->rect.x1) : buf->rect.x1;
1689 
1690  /* zend: end x for zero-line (units) */
1691  int const zend = (end == waveview->bbox_lrx) ? (end - 1) : end;
1692 
1693  if (begin == end) {
1694  return;
1695  }
1696 
1697  /* s1: start sample
1698  s2: end sample
1699  */
1700 
1701  s1 = floor ((begin - waveview->bbox_ulx) * waveview->samples_per_unit);
1702 
1703  // fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit);
1704 
1705  if (end == waveview->bbox_lrx) {
1706  /* This avoids minor rounding errors when we have the
1707  entire region visible.
1708  */
1709  s2 = waveview->samples;
1710  } else {
1711  s2 = s1 + floor ((end - begin) * waveview->samples_per_unit);
1712  }
1713 
1714 #if 0
1715  printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)"
1716  " b/e %d..%d s= %lu..%lu @ %f\n",
1717  waveview,
1718  buf->rect.x0,
1719  buf->rect.x1,
1720  buf->rect.y0,
1721  buf->rect.y1,
1722  waveview->bbox_ulx,
1723  waveview->bbox_lrx,
1724  waveview->bbox_uly,
1725  waveview->bbox_lry,
1726  begin, end, s1, s2,
1727  waveview->samples_per_unit);
1728 #endif
1729 
1730  /* now ensure that the cache is full and properly
1731  positioned.
1732  */
1733 
1734 // check_cache (waveview, "pre-ensure");
1735 
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;
1740  }
1741 
1742 // check_cache (waveview, "post-ensure");
1743 
1744  /* don't rectify at single-sample zoom */
1745  if (waveview->rectified && waveview->samples_per_unit > 1) {
1746  rectify = TRUE;
1747  }
1748  else {
1749  rectify = FALSE;
1750  }
1751 
1752  clip_length = MIN(5,(waveview->height/4));
1753 
1754  /*
1755  Now draw each line, clipping it appropriately. The clipping
1756  is done by the macros PAINT_FOO().
1757  */
1758 
1759  half_height = waveview->half_height;
1760 
1761 /* this makes it slightly easier to comprehend whats going on */
1762 #define origin half_height
1763 
1764  if (waveview->filled && !rectify) {
1765  int prev_pymin = 1;
1766  int prev_pymax = 0;
1767  int last_pymin = 1;
1768  int last_pymax = 0;
1769  int next_pymin, next_pymax;
1770  double max, min;
1771  int next_clip_max = 0;
1772  int next_clip_min = 0;
1773 
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;
1778  }
1779  else {
1780  s1 -= waveview->samples_per_unit;
1781  }
1782 
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;
1787  }
1788  else {
1789  s2 += waveview->samples_per_unit;
1790  }
1791 
1792  cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
1793 
1794  /*
1795  * Compute the variables outside the rendering rect
1796  */
1797  if(prev_pymax != prev_pymin) {
1798 
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);
1801  ++cache_index;
1802  }
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);
1806 
1807  if (index >= waveview->cache->data_size) {
1808 
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);
1813 
1814  } else {
1815 
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);
1818 
1819  }
1820 
1821  }
1822 
1823  /*
1824  * initialize NEXT* variables for the first run, duplicated in the loop for speed
1825  */
1826  max = waveview->cache->data[cache_index].max;
1827  min = waveview->cache->data[cache_index].min;
1828 
1829  if (max >= 1.0) {
1830  max = 1.0;
1831  next_clip_max = 1;
1832  }
1833 
1834  if (min <= -1.0) {
1835  min = -1.0;
1836  next_clip_min = 1;
1837  }
1838 
1839  max *= half_height;
1840  min *= half_height;
1841 
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);
1844 
1845  /*
1846  * And now the loop
1847  */
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;
1852 
1853  pymax = next_pymax;
1854  pymin = next_pymin;
1855 
1856  /* compute next */
1857  if(x == end - 1) {
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;
1861  }
1862  else {
1863  ++cache_index;
1864 
1865  if (cache_index < waveview->cache->data_size) {
1866  max = waveview->cache->data[cache_index].max;
1867  min = waveview->cache->data[cache_index].min;
1868  } else {
1869  max = min = 0;
1870  }
1871 
1872  next_clip_max = 0;
1873  next_clip_min = 0;
1874 
1875  if (max >= 1.0) {
1876  max = 1.0;
1877  next_clip_max = 1;
1878  }
1879 
1880  if (min <= -1.0) {
1881  min = -1.0;
1882  next_clip_min = 1;
1883  }
1884 
1885  max *= half_height;
1886  min *= half_height;
1887 
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);
1890  }
1891 
1892  /* render */
1893  if (pymax == pymin) {
1894  PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
1895  } else {
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);
1900  }
1901  else {
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);
1905  ++fill_max;
1906  }
1907  else {
1908  PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max);
1909  }
1910  }
1911 
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);
1916  }
1917  else {
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);
1921  }
1922  else {
1923  PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, fill_min, pymin);
1924  }
1925  }
1926 
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);
1929  }
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);
1932  }
1933  }
1934 
1935  if (clip_max) {
1936  PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length);
1937  }
1938 
1939  if (clip_min) {
1940  PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin);
1941  }
1942 
1943  prev_pymax = pymax;
1944  prev_pymin = pymin;
1945  }
1946 
1947  } else if (waveview->filled && rectify) {
1948 
1949  int prev_pymax = -1;
1950  int last_pymax = -1;
1951  int next_pymax;
1952  double max, min;
1953  int next_clip_max = 0;
1954  int next_clip_min = 0;
1955 
1956  // for rectified, this stays constant throughout the loop
1957  pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
1958 
1959  if(s1 < waveview->samples_per_unit) {
1960  /* we haven't got a prev vars to compare with, so outline the whole line here */
1961  prev_pymax = pymin;
1962  }
1963  else {
1964  s1 -= waveview->samples_per_unit;
1965  }
1966 
1967  if(end == waveview->bbox_lrx) {
1968  /* we don't have the NEXT vars for the last sample */
1969  last_pymax = pymin;
1970  }
1971  else {
1972  s2 += waveview->samples_per_unit;
1973  }
1974 
1975  cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
1976 
1977  /*
1978  * Compute the variables outside the rendering rect
1979  */
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);
1983 
1984  if (fabs (min) > fabs (max)) {
1985  max = fabs (min);
1986  }
1987 
1988  prev_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
1989  ++cache_index;
1990  }
1991  if(last_pymax < 0) {
1992  /* take the index of one sample right of what we render */
1993  int index = cache_index + (end - begin);
1994 
1995  max = MIN(waveview->cache->data[index].max, 1.0);
1996  min = MAX(waveview->cache->data[index].min, -1.0);
1997 
1998  if (fabs (min) > fabs (max)) {
1999  max = fabs (min);
2000  }
2001 
2002  last_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
2003  }
2004 
2005  /*
2006  * initialize NEXT* variables for the first run, duplicated in the loop for speed
2007  */
2008  max = waveview->cache->data[cache_index].max;
2009  min = waveview->cache->data[cache_index].min;
2010 
2011  if (max >= 1.0) {
2012  max = 1.0;
2013  next_clip_max = 1;
2014  }
2015 
2016  if (min <= -1.0) {
2017  min = -1.0;
2018  next_clip_min = 1;
2019  }
2020 
2021  if (fabs (min) > fabs (max)) {
2022  max = fabs (min);
2023  }
2024 
2025  next_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
2026 
2027  /*
2028  * And now the loop
2029  */
2030  for(x = begin; x < end; ++x) {
2031  int clip_max = next_clip_max;
2032  int clip_min = next_clip_min;
2033  int fill_max;
2034 
2035  pymax = next_pymax;
2036 
2037  /* compute next */
2038  if(x == end - 1) {
2039  /*next is now the last column, which is outside the rendering rect, and possibly outside the region*/
2040  next_pymax = last_pymax;
2041  }
2042  else {
2043  ++cache_index;
2044 
2045  max = waveview->cache->data[cache_index].max;
2046  min = waveview->cache->data[cache_index].min;
2047 
2048  if (max >= 1.0) {
2049  max = 1.0;
2050  next_clip_max = 1;
2051  }
2052 
2053  if (min <= -1.0) {
2054  min = -1.0;
2055  next_clip_min = 1;
2056  }
2057 
2058  if (fabs (min) > fabs (max)) {
2059  max = fabs (min);
2060  }
2061 
2062  next_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
2063  }
2064 
2065  /* render */
2066  if (pymax == pymin) {
2067  PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
2068  } else {
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);
2073  }
2074  else {
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);
2078  ++fill_max;
2079  }
2080  else {
2081  PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max);
2082  }
2083  }
2084 
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);
2087  }
2088  else if(fill_max == pymin) {
2089  PAINT_DOTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, pymin);
2090  }
2091  }
2092 
2093  if (clip_max) {
2094  PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length);
2095  }
2096 
2097  if (clip_min) {
2098  PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin);
2099  }
2100 
2101  prev_pymax = pymax;
2102  }
2103  }
2104  else {
2105  cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
2106 
2107  for (x = begin; x < end; x++) {
2108 
2109  double max, min;
2110  int clip_max, clip_min;
2111 
2112  clip_max = 0;
2113  clip_min = 0;
2114 
2115  max = waveview->cache->data[cache_index].max;
2116  min = waveview->cache->data[cache_index].min;
2117 
2118  if (max >= 1.0) {
2119  max = 1.0;
2120  clip_max = 1;
2121  }
2122 
2123  if (min <= -1.0) {
2124  min = -1.0;
2125  clip_min = 1;
2126  }
2127 
2128  if (rectify) {
2129 
2130  if (fabs (min) > fabs (max)) {
2131  max = fabs (min);
2132  }
2133 
2134  max = max * waveview->height;
2135 
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);
2138 
2139  } else {
2140 
2141  max = max * half_height;
2142  min = min * half_height;
2143 
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);
2146  }
2147 
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.
2150  */
2151 
2152  if (pymax == pymin) {
2153  PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
2154  } else {
2155  PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, pymin);
2156  }
2157 
2158  /* show clipped waveforms with small red lines */
2159 
2160  if (clip_max) {
2161  PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length);
2162  }
2163 
2164  if (clip_min) {
2165  PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin);
2166  }
2167 
2168  /* presto, we're done */
2169 
2170  cache_index++;
2171  }
2172  }
2173 
2174  if (!waveview->rectified && waveview->zero_line && waveview->height >= 100) {
2175  // Paint zeroline.
2176 
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);
2181  }
2182 #undef origin
2183 }
2184 
2185 static void
2186 gnome_canvas_waveview_render (GnomeCanvasItem *item,
2187  GnomeCanvasBuf *buf)
2188 {
2189  if (_gradient_rendering) {
2191  } else {
2193  }
2194 }
2195 
2196 static void
2197 gnome_canvas_waveview_draw (GnomeCanvasItem *item,
2198  GdkDrawable *drawable,
2199  int x, int y,
2200  int width, int height)
2201 {
2202  GnomeCanvasWaveView *waveview;
2203  cairo_t* cr;
2204  gulong s1, s2;
2205  int cache_index;
2206  gboolean rectify;
2207  double origin;
2208  double xoff;
2209  double yoff = 0.0;
2210  double ulx;
2211  double uly;
2212  double lrx;
2213  double lry;
2214 
2215  waveview = GNOME_CANVAS_WAVEVIEW (item);
2216 
2217  /* compute intersection of Drawable area and waveview,
2218  in canvas coordinate space
2219  */
2220 
2221  if (x > waveview->bbox_ulx) {
2222  ulx = x;
2223  } else {
2224  ulx = waveview->bbox_ulx;
2225  }
2226 
2227  if (y > waveview->bbox_uly) {
2228  uly = y;
2229  } else {
2230  uly = waveview->bbox_uly;
2231  }
2232 
2233  if (x + width > waveview->bbox_lrx) {
2234  lrx = waveview->bbox_lrx;
2235  } else {
2236  lrx = x + width;
2237  }
2238 
2239  if (y + height > waveview->bbox_lry) {
2240  lry = waveview->bbox_lry;
2241  } else {
2242  lry = y + height;
2243  }
2244 
2245  /* figure out which samples we need for the resulting intersection */
2246 
2247  s1 = floor ((ulx - waveview->bbox_ulx) * waveview->samples_per_unit) ;
2248 
2249  if (lrx == waveview->bbox_lrx) {
2250  /* This avoids minor rounding errors when we have the
2251  entire region visible.
2252  */
2253  s2 = waveview->samples;
2254  } else {
2255  s2 = s1 + floor ((lrx - ulx) * waveview->samples_per_unit);
2256  }
2257 
2258  /* translate back to buffer coordinate space */
2259 
2260  ulx -= x;
2261  uly -= y;
2262  lrx -= x;
2263  lry -= y;
2264 
2265  /* don't rectify at single-sample zoom */
2266  if(waveview->rectified && waveview->samples_per_unit > 1.0) {
2267  rectify = TRUE;
2268  } else {
2269  rectify = FALSE;
2270  }
2271 
2272  cr = gdk_cairo_create (drawable);
2273  cairo_set_line_width (cr, 0.5);
2274 
2275  origin = waveview->bbox_uly - y + waveview->half_height;
2276 
2277  cairo_rectangle (cr, ulx, uly, lrx - ulx, lry - uly);
2278  cairo_clip (cr);
2279 
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;
2284  }
2285 
2286  cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
2287 
2288 #if 0
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",
2291  waveview,
2292  x, y,
2293  x + width,
2294  y + height,
2295  width,
2296  height,
2297  waveview->bbox_ulx,
2298  waveview->bbox_uly,
2299  waveview->bbox_lrx,
2300  waveview->bbox_lry,
2301  waveview->bbox_lrx - waveview->bbox_ulx,
2302  waveview->bbox_lry - waveview->bbox_uly,
2303  ulx, uly,
2304  lrx, lry,
2305  lrx - ulx,
2306  lry - uly,
2307  s1, s2);
2308 #endif
2309 
2310  /* draw the top half */
2311 
2312  for (xoff = ulx; xoff < lrx; xoff++) {
2313  double max, min;
2314 
2315  max = waveview->cache->data[cache_index].max;
2316  min = waveview->cache->data[cache_index].min;
2317 
2318  if (min <= -1.0) {
2319  min = -1.0;
2320  }
2321 
2322  if (max >= 1.0) {
2323  max = 1.0;
2324  }
2325 
2326  if (rectify) {
2327  if (fabs (min) > fabs (max)) {
2328  max = fabs (min);
2329  }
2330  }
2331 
2332  yoff = origin - (waveview->half_height * max) + 0.5;
2333 
2334  if (xoff == ulx) {
2335  /* first point */
2336  cairo_move_to (cr, xoff+0.5, yoff);
2337  } else {
2338  cairo_line_to (cr, xoff+0.5, yoff);
2339  }
2340 
2341  cache_index++;
2342  }
2343 
2344  /* from the final top point, move out of the clip zone */
2345 
2346  cairo_line_to (cr, xoff + 10, yoff);
2347 
2348  /* now draw the bottom half */
2349 
2350  for (--xoff, --cache_index; xoff >= ulx; --xoff) {
2351  double min;
2352 
2353  min = waveview->cache->data[cache_index].min;
2354 
2355  if (min <= -1.0) {
2356  min = -1.0;
2357  }
2358 
2359  yoff = origin - (waveview->half_height * min) + 0.5;
2360 
2361  cairo_line_to (cr, xoff+0.5, yoff);
2362  cache_index--;
2363  }
2364 
2365  /* from the final lower point, move out of the clip zone */
2366 
2367  cairo_line_to (cr, xoff - 10, yoff);
2368 
2369  /* close path to fill */
2370 
2371  cairo_close_path (cr);
2372 
2373  /* fill and stroke */
2374 
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));
2386  cairo_stroke (cr);
2387 
2388  cairo_destroy (cr);
2389 }
2390 
2391 #if 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);
2394  }
2395 
2396  if (clip_max) {
2397  cairo_move_to (cr, xoff, yoff1);
2398  cairo_line_to (cr, xoff, yoff1 + clip_length);
2399  cairo_stroke (cr);
2400  }
2401 
2402  if (clip_min) {
2403  cairo_move_to (cr, xoff, yoff2);
2404  cairo_line_to (cr, xoff, yoff2 - clip_length);
2405  cairo_stroke (cr);
2406  }
2407 
2408 #endif
2409 
2410 static void
2411 gnome_canvas_waveview_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
2412 {
2413  GnomeCanvasWaveView *waveview = GNOME_CANVAS_WAVEVIEW (item);
2414 
2415  *x1 = waveview->x;
2416  *y1 = waveview->y;
2417 
2418  *x2 = ceil (*x1 + (waveview->length_function (waveview->data_src) / waveview->samples_per_unit));
2419  *y2 = *y1 + waveview->height;
2420 
2421 #if 0
2422  x = 0; y = 0;
2423  gnome_canvas_item_i2w (item, &x, &y);
2424  gnome_canvas_w2c_d (GNOME_CANVAS(item->canvas), x, y, &a, &b);
2425  x = *x2;
2426  y = *y2;
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);
2430 #endif
2431 
2432 }
2433 
2434 static double
2435 gnome_canvas_waveview_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item)
2436 {
2437  (void) item;
2438  (void) x;
2439  (void) y;
2440  (void) cx;
2441  (void) cy;
2442  (void) actual_item;
2443 
2444  /* XXX for now, point is never inside the wave
2445  GnomeCanvasWaveView *waveview;
2446  double x1, y1, x2, y2;
2447  double dx, dy;
2448  */
2449 
2450  return DBL_MAX;
2451 
2452 #if 0
2453  waveview = GNOME_CANVAS_WAVEVIEW (item);
2454 
2455  *actual_item = item;
2456 
2457  /* Find the bounds for the rectangle plus its outline width */
2458 
2459  gnome_canvas_waveview_bounds (item, &x1, &y1, &x2, &y2);
2460 
2461  /* Is point inside rectangle */
2462 
2463  if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
2464  return 0.0;
2465  }
2466 
2467  /* Point is outside rectangle */
2468 
2469  if (x < x1)
2470  dx = x1 - x;
2471  else if (x > x2)
2472  dx = x - x2;
2473  else
2474  dx = 0.0;
2475 
2476  if (y < y1)
2477  dy = y1 - y;
2478  else if (y > y2)
2479  dy = y - y2;
2480  else
2481  dy = 0.0;
2482 
2483  return sqrt (dx * dx + dy * dy);
2484 #endif
2485 }
2486 
static double gnome_canvas_waveview_point(GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item)
void c_stacktrace(void)
Definition: utils.cc:768
GType gnome_canvas_waveview_get_type(void)
static float fast_coefficient_to_dB(float coeff)
Definition: dB.h:34
GnomeCanvasWaveViewCache * gnome_canvas_waveview_cache_new(void)
#define MAX(a, b)
Definition: session_ltc.cc:42
static void gnome_canvas_waveview_set_data_src(GnomeCanvasWaveView *, void *)
void(* waveview_gain_curve_function_t)(void *arg, double start, double end, float *vector, gint64 veclen)
void gnome_canvas_waveview_cache_destroy(GnomeCanvasWaveViewCache *cache)
static void gnome_canvas_waveview_update(GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
static void gnome_canvas_waveview_render(GnomeCanvasItem *item, GnomeCanvasBuf *buf)
static GnomeCanvasItemClass * parent_class
#define PAINT_VERTA_GR(inbuf, colr, colg, colb, cola, ptx, pty0, pty1, origin_y, obj_top)
Definition: rgb_macros.h:242
waveview_peak_function_t peak_function
tuple f
Definition: signals.py:35
static void gnome_canvas_waveview_destroy(GtkObject *object)
LIBARDOUR_API PBD::PropertyDescriptor< bool > gain
Definition: route_group.cc:44
#define UINT_TO_RGBA(u, r, g, b, a)
Definition: fastmeter.cc:35
GnomeCanvasWaveViewCacheEntry * data
#define origin
gulong(* waveview_length_function_t)(void *)
waveview_length_function_t length_function
static void gnome_canvas_waveview_init(GnomeCanvasWaveView *waveview)
static void gnome_canvas_waveview_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
#define PAINT_HORIZA(inbuf, colr, colg, colb, cola, ptx0, ptx1, pty)
Definition: rgb_macros.h:167
static int _gradient_rendering
#define GNOME_CANVAS_WAVEVIEW(obj)
struct _GnomeCanvasWaveViewClass GnomeCanvasWaveViewClass
void gnome_canvas_waveview_set_gradient_waveforms(int yn)
#define GNOME_IS_CANVAS_WAVEVIEW(obj)
static void gnome_canvas_waveview_reset_bounds(GnomeCanvasItem *item)
static float alt_log_meter(float power)
Definition: logmeter.h:31
static void gnome_canvas_waveview_set_channel(GnomeCanvasWaveView *, guint32)
#define PAINT_VERTA(inbuf, colr, colg, colb, cola, ptx, pty0, pty1)
Definition: rgb_macros.h:222
static void gnome_canvas_waveview_flat_render(GnomeCanvasItem *item, GnomeCanvasBuf *buf)
static guint32 gnome_canvas_waveview_ensure_cache(GnomeCanvasWaveView *waveview, gulong start_sample, gulong end_sample)
gulong(* waveview_sourcefile_length_function_t)(void *, double)
static void gnome_canvas_waveview_gradient_render(GnomeCanvasItem *item, GnomeCanvasBuf *buf)
waveview_sourcefile_length_function_t sourcefile_length_function
static void gnome_canvas_waveview_bounds(GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
#define MIN(a, b)
Definition: session_ltc.cc:45
void(* waveview_peak_function_t)(void *, gulong, gulong, gulong, gpointer, guint32, double)
GnomeCanvasWaveViewCache * cache
#define PAINT_DOTA(inbuf, colr, colg, colb, cola, ptx, pty)
Definition: rgb_macros.h:115
waveview_gain_curve_function_t gain_curve_function
static void gnome_canvas_waveview_class_init(GnomeCanvasWaveViewClass *class)
static void gnome_canvas_waveview_draw(GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int w, int h)
static void gnome_canvas_waveview_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)