GTK+ Forums

Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
It is currently Sat Aug 23, 2014 1:23 pm

All times are UTC




Post new topic Reply to topic  [ 3 posts ] 
Author Message
 Post subject: Creating an oscilloscope (continuously updated drawing)
PostPosted: Mon Apr 09, 2007 4:39 pm 
Offline

Joined: Mon Apr 09, 2007 4:21 pm
Posts: 3
Location: Pittsburgh, PA
I'm writing a GTK+ audio application, and I would like to draw an oscilloscope that updates in real-time to visualize the sound wave. I've been trying a drawing area and pix map approach where I plot points every frame, but it isn't working. If I clear the entire oscilloscope every frame, the image tears. Not only that, the slow speed makes the audio very choppy. Right now my code can only smear the wave form on top of what's been already drawn. I've also tried clearing the pixels I drew from the last frame -- but the update rectangle makes things a mess -- it didn't work.

What is the best way to draw a constantly updating set of monochrome pixels onto the screen with GTK? Speed is top priority. Should I try rendering an OpenGL visual onto a drawing area widget? Is the pixbuf a better choice than a pixmap? I wouldn't know because I'm unfamiliar with the API and the documentation does not have any practical advice for this type of situation (heck, the drawing area widget isn't even documented). Here is the code for my current method -- it's pretty straight-forward:

Code:
static GdkPixmap *pixmap = NULL;
GtkWidget *drawing_area = NULL;

static gboolean configure_event(GtkWidget *widget, GdkEventConfigure *event)
{
   if (pixmap)
      g_object_unref(pixmap);

   pixmap = gdk_pixmap_new(widget->window, widget->allocation.width, widget->allocation.height, -1);
   gdk_draw_rectangle(pixmap, widget->style->black_gc, TRUE, 0, 0, widget->allocation.width, widget->allocation.height);

   return TRUE;
}

static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event)
{
   gdk_draw_drawable(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], pixmap,
                     event->area.x, event->area.y,
                     event->area.x, event->area.y,
                     event->area.width, event->area.height);

   return FALSE;
}

/////////////////////////////// WIDGET INITIALIZATION CODE ////////////////////////////////////
   drawing_area = gtk_drawing_area_new();
   gtk_widget_set_size_request(GTK_WIDGET(drawing_area), 640, 480);
   gtk_table_attach_defaults(GTK_TABLE(table), drawing_area, 0, 2, 0, 1);

   g_signal_connect(G_OBJECT (drawing_area), "expose_event", G_CALLBACK (expose_event), NULL);
   g_signal_connect(G_OBJECT(drawing_area), "configure_event", G_CALLBACK (configure_event), NULL);

   gtk_widget_set_events(drawing_area, GDK_EXPOSURE_MASK);
   gtk_widget_show(drawing_area);
///////////////////////////////////////////////////////////////////////////////////////////////

int x_pos = 0;   // global because the low-latency audio doesn't all come in at once

void UpdateOscilloscope(short *audio, int len)
{
   GdkRectangle update_rect;

   int lower_x = -1, lower_y = -1, upper_x = -1, upper_y = -1;

   for (register int i=0; i < len / 2; i++)
   {
      // determine our point
      int pt_x = x_pos;
      int pt_y = 240 - audio[i] / 137;

      // adjust our boundary if necessary (should be minimum area needed to draw the oscilloscope wave)
      if (lower_x == -1 || pt_x <= lower_x) lower_x = pt_x;
      if (lower_y == -1 || pt_y <= lower_y) lower_y = pt_y;

      if (upper_x == -1 || pt_x >= upper_x) upper_x = pt_x;
      if (upper_y == -1 || pt_y >= upper_y) upper_y = pt_y;

      // plot the point
      gdk_draw_point(pixmap, drawing_area->style->white_gc, pt_x, pt_y);

      // increment our x position
      x_pos++;
      if (x_pos >= 640) { x_pos = 0; break; }
   }

   // adjust our update rectangle based on the oscilloscope wave boundary
   update_rect.x = lower_x;
   update_rect.y = lower_y;
   update_rect.width = upper_x - lower_x;
   update_rect.height = upper_y - lower_y;

   // queue a redraw
   gtk_widget_queue_draw_area(drawing_area, update_rect.x, update_rect.y, update_rect.width, update_rect.height);
}


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 09, 2007 6:13 pm 
Offline
Never Seen the Sunlight

Joined: Wed Sep 21, 2005 3:07 am
Posts: 384
Location: Fairfax, Virginia
What you can do is have two drawables ... one that is the GdkWindow of the GtkDrawingArea that is visible to the user. Then, have a buffer GdkDrawable that you make changes to and then use gdk_draw_drawable() to expose it. This will allow you to shift the drawable by making it wider than the GtkDrawingArea's GdkWindow.

_________________
Andrew Krause

Foundations of GTK+ Development: Buy now for only $31.49!


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 09, 2007 8:41 pm 
Offline

Joined: Mon Apr 09, 2007 4:21 pm
Posts: 3
Location: Pittsburgh, PA
This "oscilloscope" doesn't work by shifting... it just displays snapshots of the wave. I suppose your method would still work, though. You still think I should go with pixmap?


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group