X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fcanvas-waveview.c;h=bf7dad04297eb8e788b39e5a30912b881be95132;hb=dde13d288e22ba5dd8e23802c47fac288b089c57;hp=193b3cd68a3bb26ee5923bd95e06f6e301dddb06;hpb=bb7dbe6d86e08ea0fedf12ce50ca3d395aa212a5;p=ardour.git diff --git a/gtk2_ardour/canvas-waveview.c b/gtk2_ardour/canvas-waveview.c index 193b3cd68a..bf7dad0429 100644 --- a/gtk2_ardour/canvas-waveview.c +++ b/gtk2_ardour/canvas-waveview.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "ardour/dB.h" @@ -34,11 +35,11 @@ /* POSIX guarantees casting between void* and function pointers, ISO C doesn't * We can work around warnings by going one step deeper in our casts */ -#ifdef _POSIX_VERSION +#if defined(_POSIX_VERSION) || defined(COMPILER_MINGW) #define POSIX_FUNC_PTR_CAST(type, object) *((type*) &(object)) #endif // _POSIX_VERSION -extern void c_stacktrace(); +extern void c_stacktrace(void); enum { PROP_0, @@ -120,6 +121,9 @@ static guint32 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview gulong start_sample, gulong end_sample); + +static int _gradient_rendering = 0; + static GnomeCanvasItemClass *parent_class; GType @@ -327,8 +331,14 @@ gnome_canvas_waveview_class_init (GnomeCanvasWaveViewClass *class) item_class->draw = gnome_canvas_waveview_draw; } +void +gnome_canvas_waveview_set_gradient_waveforms (int yn) +{ + _gradient_rendering = yn; +} + GnomeCanvasWaveViewCache* -gnome_canvas_waveview_cache_new () +gnome_canvas_waveview_cache_new (void) { GnomeCanvasWaveViewCache *c; @@ -384,13 +394,9 @@ gnome_canvas_waveview_init (GnomeCanvasWaveView *waveview) static void gnome_canvas_waveview_destroy (GtkObject *object) { - GnomeCanvasWaveView *waveview; - g_return_if_fail (object != NULL); g_return_if_fail (GNOME_IS_CANVAS_WAVEVIEW (object)); - waveview = GNOME_CANVAS_WAVEVIEW (object); - if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); } @@ -1097,8 +1103,8 @@ gnome_canvas_waveview_update (GnomeCanvasItem *item, double *affine, ArtSVP *cli } static void -gnome_canvas_waveview_render (GnomeCanvasItem *item, - GnomeCanvasBuf *buf) +gnome_canvas_waveview_gradient_render (GnomeCanvasItem *item, + GnomeCanvasBuf *buf) { GnomeCanvasWaveView *waveview; gulong s1, s2; @@ -1217,6 +1223,9 @@ gnome_canvas_waveview_render (GnomeCanvasItem *item, int next_clip_max = 0; int next_clip_min = 0; + int wave_middle = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit); + int wave_top = (int) rint ((item->y1) * item->canvas->pixels_per_unit); + if (s1 < waveview->samples_per_unit) { /* we haven't got a prev vars to compare with, so outline the whole line here */ prev_pymax = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit); @@ -1349,10 +1358,10 @@ gnome_canvas_waveview_render (GnomeCanvasItem *item, if(pymax == fill_max) { PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax); ++fill_max; + } else { + PAINT_VERTA_GR(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max, wave_middle, wave_top); } - else { - PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max); - } + } if((prev_pymin > pymin && next_pymin > pymin) || @@ -1366,12 +1375,12 @@ gnome_canvas_waveview_render (GnomeCanvasItem *item, PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin); } else { - PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, fill_min, pymin); + PAINT_VERTA_GR(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, fill_min, pymin, wave_middle, wave_top); } } if(fill_max < fill_min) { - PAINT_VERTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max, fill_min); + 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); } else if(fill_max == fill_min) { PAINT_DOTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max); @@ -1379,11 +1388,16 @@ gnome_canvas_waveview_render (GnomeCanvasItem *item, } if (clip_max) { - PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length); + PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax + clip_length); + PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x + 1, pymax, pymax + (clip_length -1)); + PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x - 1, pymax, pymax + (clip_length - 1)); + } if (clip_min) { - PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin); + PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a , x, pymin - clip_length, pymin); + PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x + 1, pymin - (clip_length - 1), pymin); + PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x - 1, pymin - (clip_length - 1), pymin); } prev_pymax = pymax; @@ -1399,6 +1413,9 @@ gnome_canvas_waveview_render (GnomeCanvasItem *item, int next_clip_max = 0; int next_clip_min = 0; + int wave_middle = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit); + int wave_top = (int) rint ((item->y1) * item->canvas->pixels_per_unit); + // for rectified, this stays constant throughout the loop pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit); @@ -1524,7 +1541,7 @@ gnome_canvas_waveview_render (GnomeCanvasItem *item, ++fill_max; } else { - PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max); + PAINT_VERTA_GR(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max, wave_middle, wave_top); } } @@ -1537,11 +1554,15 @@ gnome_canvas_waveview_render (GnomeCanvasItem *item, } if (clip_max) { - PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length); + PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax + clip_length); + PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x + 1, pymax, pymax + (clip_length -1)); + PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x - 1, pymax, pymax + (clip_length - 1)); } if (clip_min) { - PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin); + PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a , x, pymin - clip_length, pymin); + PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x + 1, pymin - (clip_length - 1), pymin); + PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a >> 1, x - 1, pymin - (clip_length - 1), pymin); } prev_pymax = pymax; @@ -1617,12 +1638,11 @@ gnome_canvas_waveview_render (GnomeCanvasItem *item, } } - if (!waveview->rectified && waveview->zero_line) { + if (!waveview->rectified && waveview->zero_line && waveview->height >= 100) { // Paint zeroline. - //PAINT_HORIZA(buf, waveview->zero_r, waveview->zero_g, waveview->zero_b, waveview->zero_a, begin, endi-1, origin ); unsigned char zero_r, zero_g, zero_b, zero_a; - UINT_TO_RGBA( waveview->zero_color, &zero_r, &zero_g, &zero_b, &zero_a ); + UINT_TO_RGBA( waveview->zero_color, &zero_r, &zero_g, &zero_b, &zero_a); int zeroline_y = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit); PAINT_HORIZA(buf, zero_r, zero_g, zero_b, zero_a, zbegin, zend, zeroline_y); } @@ -1631,84 +1651,624 @@ gnome_canvas_waveview_render (GnomeCanvasItem *item, } static void -gnome_canvas_waveview_draw (GnomeCanvasItem *item, - GdkDrawable *drawable, - int x, int y, - int width, int height) +gnome_canvas_waveview_flat_render (GnomeCanvasItem *item, + GnomeCanvasBuf *buf) { GnomeCanvasWaveView *waveview; - cairo_t* cr; gulong s1, s2; - int cache_index; - gboolean rectify; - double origin; - double clip_length; - double xoff; - double yoff = 0.0; - double ulx; - double uly; - double lrx; - double lry; + int clip_length = 0; + int pymin, pymax; + guint cache_index; + double half_height; + int x; + char rectify; waveview = GNOME_CANVAS_WAVEVIEW (item); - /* compute intersection of Drawable area and waveview, - in canvas coordinate space - */ +// check_cache (waveview, "start of render"); - if (x > waveview->bbox_ulx) { - ulx = x; - } else { - ulx = waveview->bbox_ulx; + if (parent_class->render) { + (*parent_class->render) (item, buf); } - if (y > waveview->bbox_uly) { - uly = y; - } else { - uly = waveview->bbox_uly; + if (buf->is_bg) { + gnome_canvas_buf_ensure_buf (buf); + buf->is_bg = FALSE; } - if (x + width > waveview->bbox_lrx) { - lrx = waveview->bbox_lrx; - } else { - lrx = x + width; - } + /* a "unit" means a pixel */ - if (y + height > waveview->bbox_lry) { - lry = waveview->bbox_lry; - } else { - lry = y + height; + /* begin: render start x (units) */ + int const begin = MAX (waveview->bbox_ulx, buf->rect.x0); + + /* zbegin: start x for zero line (units) */ + int const zbegin = (begin == waveview->bbox_ulx) ? (begin + 1) : begin; + + /* end: render end x (units) */ + int const end = (waveview->bbox_lrx >= 0) ? MIN (waveview->bbox_lrx,buf->rect.x1) : buf->rect.x1; + + /* zend: end x for zero-line (units) */ + int const zend = (end == waveview->bbox_lrx) ? (end - 1) : end; + + if (begin == end) { + return; } - /* figure out which samples we need for the resulting intersection */ + /* s1: start sample + s2: end sample + */ - s1 = floor ((ulx - waveview->bbox_ulx) * waveview->samples_per_unit) ; + s1 = floor ((begin - waveview->bbox_ulx) * waveview->samples_per_unit); - if (lrx == waveview->bbox_lrx) { + // fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit); + + if (end == waveview->bbox_lrx) { /* This avoids minor rounding errors when we have the entire region visible. */ s2 = waveview->samples; } else { - s2 = s1 + floor ((lrx - ulx) * waveview->samples_per_unit); + s2 = s1 + floor ((end - begin) * waveview->samples_per_unit); } - /* translate back to buffer coordinate space */ +#if 0 + printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)" + " b/e %d..%d s= %lu..%lu @ %f\n", + waveview, + buf->rect.x0, + buf->rect.x1, + buf->rect.y0, + buf->rect.y1, + waveview->bbox_ulx, + waveview->bbox_lrx, + waveview->bbox_uly, + waveview->bbox_lry, + begin, end, s1, s2, + waveview->samples_per_unit); +#endif - ulx -= x; - uly -= y; - lrx -= x; - lry -= y; + /* now ensure that the cache is full and properly + positioned. + */ + +// check_cache (waveview, "pre-ensure"); + + if (waveview->cache_updater && waveview->reload_cache_in_render) { + waveview->cache->start = 0; + waveview->cache->end = 0; + waveview->reload_cache_in_render = FALSE; + } + +// check_cache (waveview, "post-ensure"); /* don't rectify at single-sample zoom */ - if(waveview->rectified && waveview->samples_per_unit > 1.0) { + if (waveview->rectified && waveview->samples_per_unit > 1) { rectify = TRUE; - } else { + } + else { rectify = FALSE; } clip_length = MIN(5,(waveview->height/4)); + /* + Now draw each line, clipping it appropriately. The clipping + is done by the macros PAINT_FOO(). + */ + + half_height = waveview->half_height; + +/* this makes it slightly easier to comprehend whats going on */ +#define origin half_height + + if (waveview->filled && !rectify) { + int prev_pymin = 1; + int prev_pymax = 0; + int last_pymin = 1; + int last_pymax = 0; + int next_pymin, next_pymax; + double max, min; + int next_clip_max = 0; + int next_clip_min = 0; + + if (s1 < waveview->samples_per_unit) { + /* we haven't got a prev vars to compare with, so outline the whole line here */ + prev_pymax = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit); + prev_pymin = prev_pymax; + } + else { + s1 -= waveview->samples_per_unit; + } + + if(end == waveview->bbox_lrx) { + /* we don't have the NEXT vars for the last sample */ + last_pymax = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit); + last_pymin = last_pymax; + } + else { + s2 += waveview->samples_per_unit; + } + + cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2); + + /* + * Compute the variables outside the rendering rect + */ + if(prev_pymax != prev_pymin) { + + prev_pymax = (int) rint ((item->y1 + origin - MIN(waveview->cache->data[cache_index].max, 1.0) * half_height) * item->canvas->pixels_per_unit); + prev_pymin = (int) rint ((item->y1 + origin - MAX(waveview->cache->data[cache_index].min, -1.0) * half_height) * item->canvas->pixels_per_unit); + ++cache_index; + } + if(last_pymax != last_pymin) { + /* take the index of one sample right of what we render */ + guint index = cache_index + (end - begin); + + if (index >= waveview->cache->data_size) { + + /* the data we want is off the end of the cache, which must mean its beyond + the end of the region's source; hence the peak values are 0 */ + last_pymax = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit); + last_pymin = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit); + + } else { + + last_pymax = (int) rint ((item->y1 + origin - MIN(waveview->cache->data[index].max, 1.0) * half_height) * item->canvas->pixels_per_unit); + last_pymin = (int) rint ((item->y1 + origin - MAX(waveview->cache->data[index].min, -1.0) * half_height) * item->canvas->pixels_per_unit); + + } + + } + + /* + * initialize NEXT* variables for the first run, duplicated in the loop for speed + */ + max = waveview->cache->data[cache_index].max; + min = waveview->cache->data[cache_index].min; + + if (max >= 1.0) { + max = 1.0; + next_clip_max = 1; + } + + if (min <= -1.0) { + min = -1.0; + next_clip_min = 1; + } + + max *= half_height; + min *= half_height; + + next_pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit); + next_pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit); + + /* + * And now the loop + */ + for(x = begin; x < end; ++x) { + int clip_max = next_clip_max; + int clip_min = next_clip_min; + int fill_max, fill_min; + + pymax = next_pymax; + pymin = next_pymin; + + /* compute next */ + if(x == end - 1) { + /*next is now the last column, which is outside the rendering rect, and possibly outside the region*/ + next_pymax = last_pymax; + next_pymin = last_pymin; + } + else { + ++cache_index; + + if (cache_index < waveview->cache->data_size) { + max = waveview->cache->data[cache_index].max; + min = waveview->cache->data[cache_index].min; + } else { + max = min = 0; + } + + next_clip_max = 0; + next_clip_min = 0; + + if (max >= 1.0) { + max = 1.0; + next_clip_max = 1; + } + + if (min <= -1.0) { + min = -1.0; + next_clip_min = 1; + } + + max *= half_height; + min *= half_height; + + next_pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit); + next_pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit); + } + + /* render */ + if (pymax == pymin) { + PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin); + } else { + if((prev_pymax < pymax && next_pymax < pymax) || + (prev_pymax == pymax && next_pymax == pymax)) { + fill_max = pymax + 1; + PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax); + } + else { + fill_max = MAX(prev_pymax, next_pymax); + if(pymax == fill_max) { + PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax); + ++fill_max; + } + else { + PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max); + } + } + + if((prev_pymin > pymin && next_pymin > pymin) || + (prev_pymin == pymin && next_pymin == pymin)) { + fill_min = pymin - 1; + PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin-1); + } + else { + fill_min = MIN(prev_pymin, next_pymin); + if(pymin == fill_min) { + PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin); + } + else { + PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, fill_min, pymin); + } + } + + if(fill_max < fill_min) { + PAINT_VERTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max, fill_min); + } + else if(fill_max == fill_min) { + PAINT_DOTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max); + } + } + + if (clip_max) { + PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length); + } + + if (clip_min) { + PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin); + } + + prev_pymax = pymax; + prev_pymin = pymin; + } + + } else if (waveview->filled && rectify) { + + int prev_pymax = -1; + int last_pymax = -1; + int next_pymax; + double max, min; + int next_clip_max = 0; + int next_clip_min = 0; + + // for rectified, this stays constant throughout the loop + pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit); + + if(s1 < waveview->samples_per_unit) { + /* we haven't got a prev vars to compare with, so outline the whole line here */ + prev_pymax = pymin; + } + else { + s1 -= waveview->samples_per_unit; + } + + if(end == waveview->bbox_lrx) { + /* we don't have the NEXT vars for the last sample */ + last_pymax = pymin; + } + else { + s2 += waveview->samples_per_unit; + } + + cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2); + + /* + * Compute the variables outside the rendering rect + */ + if(prev_pymax < 0) { + max = MIN(waveview->cache->data[cache_index].max, 1.0); + min = MAX(waveview->cache->data[cache_index].min, -1.0); + + if (fabs (min) > fabs (max)) { + max = fabs (min); + } + + prev_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit); + ++cache_index; + } + if(last_pymax < 0) { + /* take the index of one sample right of what we render */ + int index = cache_index + (end - begin); + + max = MIN(waveview->cache->data[index].max, 1.0); + min = MAX(waveview->cache->data[index].min, -1.0); + + if (fabs (min) > fabs (max)) { + max = fabs (min); + } + + last_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit); + } + + /* + * initialize NEXT* variables for the first run, duplicated in the loop for speed + */ + max = waveview->cache->data[cache_index].max; + min = waveview->cache->data[cache_index].min; + + if (max >= 1.0) { + max = 1.0; + next_clip_max = 1; + } + + if (min <= -1.0) { + min = -1.0; + next_clip_min = 1; + } + + if (fabs (min) > fabs (max)) { + max = fabs (min); + } + + next_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit); + + /* + * And now the loop + */ + for(x = begin; x < end; ++x) { + int clip_max = next_clip_max; + int clip_min = next_clip_min; + int fill_max; + + pymax = next_pymax; + + /* compute next */ + if(x == end - 1) { + /*next is now the last column, which is outside the rendering rect, and possibly outside the region*/ + next_pymax = last_pymax; + } + else { + ++cache_index; + + max = waveview->cache->data[cache_index].max; + min = waveview->cache->data[cache_index].min; + + if (max >= 1.0) { + max = 1.0; + next_clip_max = 1; + } + + if (min <= -1.0) { + min = -1.0; + next_clip_min = 1; + } + + if (fabs (min) > fabs (max)) { + max = fabs (min); + } + + next_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit); + } + + /* render */ + if (pymax == pymin) { + PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin); + } else { + if((prev_pymax < pymax && next_pymax < pymax) || + (prev_pymax == pymax && next_pymax == pymax)) { + fill_max = pymax + 1; + PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax); + } + else { + fill_max = MAX(prev_pymax, next_pymax); + if(pymax == fill_max) { + PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax); + ++fill_max; + } + else { + PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max); + } + } + + if(fill_max < pymin) { + PAINT_VERTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max, pymin); + } + else if(fill_max == pymin) { + PAINT_DOTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, pymin); + } + } + + if (clip_max) { + PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length); + } + + if (clip_min) { + PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin); + } + + prev_pymax = pymax; + } + } + else { + cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2); + + for (x = begin; x < end; x++) { + + double max, min; + int clip_max, clip_min; + + clip_max = 0; + clip_min = 0; + + max = waveview->cache->data[cache_index].max; + min = waveview->cache->data[cache_index].min; + + if (max >= 1.0) { + max = 1.0; + clip_max = 1; + } + + if (min <= -1.0) { + min = -1.0; + clip_min = 1; + } + + if (rectify) { + + if (fabs (min) > fabs (max)) { + max = fabs (min); + } + + max = max * waveview->height; + + pymax = (int) rint ((item->y1 + waveview->height - max) * item->canvas->pixels_per_unit); + pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit); + + } else { + + max = max * half_height; + min = min * half_height; + + pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit); + pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit); + } + + /* OK, now fill the RGB buffer at x=i with a line between pymin and pymax, + or, if samples_per_unit == 1, then a dot at each location. + */ + + if (pymax == pymin) { + PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin); + } else { + PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, pymin); + } + + /* show clipped waveforms with small red lines */ + + if (clip_max) { + PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length); + } + + if (clip_min) { + PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin); + } + + /* presto, we're done */ + + cache_index++; + } + } + + if (!waveview->rectified && waveview->zero_line && waveview->height >= 100) { + // Paint zeroline. + + unsigned char zero_r, zero_g, zero_b, zero_a; + UINT_TO_RGBA( waveview->zero_color, &zero_r, &zero_g, &zero_b, &zero_a); + int zeroline_y = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit); + PAINT_HORIZA(buf, zero_r, zero_g, zero_b, zero_a, zbegin, zend, zeroline_y); + } +#undef origin +} + +static void +gnome_canvas_waveview_render (GnomeCanvasItem *item, + GnomeCanvasBuf *buf) +{ + if (_gradient_rendering) { + gnome_canvas_waveview_gradient_render (item, buf); + } else { + gnome_canvas_waveview_flat_render (item, buf); + } +} + +static void +gnome_canvas_waveview_draw (GnomeCanvasItem *item, + GdkDrawable *drawable, + int x, int y, + int width, int height) +{ + GnomeCanvasWaveView *waveview; + cairo_t* cr; + gulong s1, s2; + int cache_index; + gboolean rectify; + double origin; + double xoff; + double yoff = 0.0; + double ulx; + double uly; + double lrx; + double lry; + + waveview = GNOME_CANVAS_WAVEVIEW (item); + + /* compute intersection of Drawable area and waveview, + in canvas coordinate space + */ + + if (x > waveview->bbox_ulx) { + ulx = x; + } else { + ulx = waveview->bbox_ulx; + } + + if (y > waveview->bbox_uly) { + uly = y; + } else { + uly = waveview->bbox_uly; + } + + if (x + width > waveview->bbox_lrx) { + lrx = waveview->bbox_lrx; + } else { + lrx = x + width; + } + + if (y + height > waveview->bbox_lry) { + lry = waveview->bbox_lry; + } else { + lry = y + height; + } + + /* figure out which samples we need for the resulting intersection */ + + s1 = floor ((ulx - waveview->bbox_ulx) * waveview->samples_per_unit) ; + + if (lrx == waveview->bbox_lrx) { + /* This avoids minor rounding errors when we have the + entire region visible. + */ + s2 = waveview->samples; + } else { + s2 = s1 + floor ((lrx - ulx) * waveview->samples_per_unit); + } + + /* translate back to buffer coordinate space */ + + ulx -= x; + uly -= y; + lrx -= x; + lry -= y; + + /* don't rectify at single-sample zoom */ + if(waveview->rectified && waveview->samples_per_unit > 1.0) { + rectify = TRUE; + } else { + rectify = FALSE; + } + cr = gdk_cairo_create (drawable); cairo_set_line_width (cr, 0.5);