#include #define WIDTH 256 #define HEIGHT 128 #define BPL (WIDTH + 2) #define STAGE_ROWSTRIDE (WIDTH * 3) #define GDK_SCRATCH_IMAGE_WIDTH 256 #define GDK_SCRATCH_IMAGE_HEIGHT 64 typedef struct _Cmap Cmap; struct _Cmap { guint32 colors[256]; gint n_colors; }; typedef struct _CBdata CBdata; struct _CBdata { void *data; guchar *buf1; guchar *buf2; }; static guchar rgb_buf[(WIDTH + 2) * (HEIGHT + 2)]; static gint16 audio_data[2][256]; static Cmap *cmap = NULL; static inline void draw_pixel_8 (guchar *buffer, gint x, gint y, guchar c) { buffer[((y + 1) * BPL) + (x + 1)] = c; } void bscope_blur_8 (guchar *ptr, gint w, gint h, gint bpl) { register guint i, sum; register guchar *iptr; iptr = ptr + bpl + 1; i = bpl * h; while (i--) { sum = (iptr[-bpl] + iptr[-1] + iptr[1] + iptr[bpl]) >> 2; if (sum > 2) sum -= 2; *(iptr++) = sum; } } static inline void draw_vert_line (guchar *buffer, gint x, gint y1, gint y2) { int y; if (y1 < y2) { for (y = y1; y <= y2; y++) draw_pixel_8 (buffer, x, y, 0xFF); } else if (y2 < y1) { for (y = y2; y <= y1; y++) draw_pixel_8 (buffer, x, y, 0xFF); } else draw_pixel_8 (buffer, x, y1, 0xFF); } Cmap * cmap_new (guint32 *colors, gint n_colors) { Cmap *_cmap; _cmap = g_new (Cmap, 1); _cmap->n_colors = n_colors; memcpy (_cmap->colors, colors, n_colors * sizeof (guint32)); return _cmap; } void generate_cmap (void) { guint32 colors[256], i, red, blue, green; if (cmap) return; red = (guint32) (0xFF3F7F / 0x10000); green = (guint32) ((0xFF3F7F % 0x10000) / 0x100); blue = (guint32) (0xFF3F7F % 0x100); for (i = 255; i > 0; i--) colors[i] = (((guint32) (i * red / 256) << 16) | ((guint32) (i * green / 256) << 8) | ((guint32) (i * blue / 256))); colors[0] = 0; cmap = cmap_new (colors, 256); } void release (cairo_pattern_t *pattern, void *data, cairo_surface_t *surface) { CBdata *cb = data; cairo_surface_destroy (surface); g_free (cb->buf1); g_free (cb->buf2); g_free (cb); } cairo_surface_t * acquire (cairo_pattern_t *pattern, void *data, cairo_surface_t *target, const cairo_rectangle_int_t *extents) { cairo_surface_t *surf; guchar *pi, *pi_start, *po, *po_start, *p, *bptr, *bp2, *obuf; gint x, y, rgb, w; CBdata *cb = data; pi_start = cb->data; po_start = cb->buf1 = g_malloc (512 * STAGE_ROWSTRIDE); for (y = 0; y < extents->height; y++) { pi = pi_start; po = po_start; for (x = 0; x < extents->width; x++) { rgb = cmap->colors[*pi++]; *po++ = rgb << 16; *po++ = (rgb << 8) & 0xff; *po++ = rgb & 0xff; } pi_start += 258; po_start += STAGE_ROWSTRIDE; } bptr = po; obuf = cb->buf2 = g_malloc (1024 * STAGE_ROWSTRIDE); for (y = 0; y < extents->height; y++) { bp2 = bptr; p = obuf; w = extents->width; while (w--) { p[0] = bp2[2]; p[1] = bp2[1]; p[2] = bp2[0]; p[3] = 0xff; bp2 += 3; p += 4; } bptr += 768; obuf += 6144; } surf = cairo_image_surface_create_for_data (p, CAIRO_FORMAT_RGB24, extents->width, extents->height, 1024); cairo_surface_set_device_offset (surf, extents->x, extents->y); return surf; } gboolean the_bscope (GtkWidget *widget, cairo_t *cr, gpointer data) { gint i, y, prev_y, width, height; cairo_pattern_t *pat; CBdata *cb; bscope_blur_8 (rgb_buf, WIDTH, HEIGHT, BPL); prev_y = y = (HEIGHT / 2) + (audio_data[0][0] >> 9) + (audio_data[1][0] >> 9) / 2; if (prev_y < 0) y = prev_y = 0; if (y >= HEIGHT) y = prev_y = HEIGHT - 1; for (i = 0; i < WIDTH; i++) { y = (HEIGHT / 2) + (audio_data[0][i >> 1] >> 9) + (audio_data[1][i >> 1] >> 9) / 2; if (y < 0) y = 0; if (y >= HEIGHT) y = HEIGHT - 1; draw_vert_line (rgb_buf, i, prev_y, y); prev_y = y; } width = gtk_widget_get_allocated_width (widget); height = gtk_widget_get_allocated_height (widget); cairo_paint (cr); /* Черен фон */ cb = g_new (CBdata, 1); cb->data = rgb_buf + BPL + 1; pat = cairo_pattern_create_raster_source (cb, CAIRO_CONTENT_COLOR, width, height); cairo_raster_source_pattern_set_acquire (pat, acquire, release); cairo_set_source (cr, pat); cairo_paint (cr); return FALSE; } static gboolean close_bscope_window (GtkWidget *widget, GdkEvent *event, gpointer data) { gtk_main_quit (); return TRUE; } void init (void) { GtkWidget *window; GtkWidget *area; window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Blurscope"); gtk_window_set_resizable (GTK_WINDOW (window), FALSE); gtk_widget_set_size_request (window, WIDTH, HEIGHT); gtk_widget_realize (window); g_signal_connect(G_OBJECT (window), "delete-event", G_CALLBACK (close_bscope_window), NULL); area = gtk_drawing_area_new (); gtk_container_add (GTK_CONTAINER (window), area); gtk_widget_realize (area); g_signal_connect (G_OBJECT (area), "draw", G_CALLBACK (the_bscope), NULL); generate_cmap (); memset (rgb_buf, 0, (WIDTH + 2) * (HEIGHT + 2)); gtk_widget_show_all (window); } int main (int argc, char **argv) { gtk_init (&argc, &argv); init (); gtk_main (); return 0; } /* Local Variables: compile-command: "make bazz CFLAGS=\"`pkg-config gtk+-3.0 --cflags` -g\" LDLIBS=\"`pkg-config gtk+-3.0 --libs`\"" End: */