GTK+ Forums

Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
It is currently Fri Oct 31, 2014 10:58 pm

All times are UTC




Post new topic Reply to topic  [ 15 posts ] 
Author Message
 Post subject: Simple animations?
PostPosted: Sat Jun 01, 2013 4:21 am 
Offline
Familiar Face

Joined: Thu May 30, 2013 5:26 am
Posts: 9
I'd like to do not mpeg or avi etc. animation but fast real-time data plotting. For practice an audio oscilloscope, what I'm working toward is plotting real time FFTs from fftw for a SDR. I'm a newbie and so far I've been able to plot into a pixbuf and load it to an image. I find I can update the image by writing to the pixbuf after it's been shown. Another application would be an audio strip-chart recorder like Radio Skypipe, which is much slower but it needs infinite scrolling of data off the screen to oblivion.

How do I clear the pixbuf? How can I get a GDK window from a GTK window?

Is it feasible to update an image say 10 times per second and still do reasonably cpu-intensive work elsewhere? I'd like to write something that works like hdsdr or sdr# (both Windows) but for unix. The math in them is possibly over my head but I have source code to sdr# and winrad to study. I could probably live with a memory-mapped screen, but I've got layers and layers of software to slow everything down.

If you look at what hdsdr or winrad do, they display 2 FFTs, 2 waterfalls and demodulate a 2 megasample per second I/Q stream into audio all in real time, and optionally record a wav file at the same time. Can that be done using GTK/GDK for a GUI? I'm writing in plain GCC C. I've done graphics in Delphi and Turbo Pascal before that, but not real time.

Thanks for your patience,

Alan, AB1JX


Top
 Profile  
 
 Post subject: Re: Simple animations?
PostPosted: Sat Jun 01, 2013 3:50 pm 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 768
Location: UK
Hello,

ab1jx can you tell us which version of GTK+ you are using, there is small differences between v2 and v3. If all you want to do is fill a GdkPixbuf you can use the function
Code:
void                gdk_pixbuf_fill                     (GdkPixbuf *pixbuf,
                                                         guint32 pixel);


How are you rendering your GdkPixbuf? Are you using GtkImage or GtkDrawingArea? GtkImage is easy to use though not really suitable for quick drawing. GtkDrawingArea is a bit more complex to use, but more flexible faster and you have the option to do some optimisation for example double buffering.

An image update of 10 frames per second is easy to achieve. In your case I would advise to have all the GUI stuff in your main thread and have audio processing and other complex stuff in other threads. As a note never ever have calls to the GTK+ API called from more than one thread, other wise with out care on Linux things could go wrong and on other systems will not work.

_________________
E.


Top
 Profile  
 
 Post subject: Re: Simple animations?
PostPosted: Sun Jun 02, 2013 3:19 am 
Offline
Familiar Face

Joined: Thu May 30, 2013 5:26 am
Posts: 9
I'm using gtk 3.4.4 on one box and 3.0.12 on another, under OpenBSD 5.2 and 5.0.

I was using GtkImage but I'll try DrawingArea. DrawingArea is one of the undocumented widgets in the Gtk 2 tutorial but I see it's in the reference for 3.

By the documentation I have gtk_image_new_from_pixbuf gives a GtkWidget but gtk_image_set_from_pixbuf works on a GtkWindow. Seems wacky to me. Can I cast one to the other?

OK, so I can use gdk_pixbuf_fill to fill it with black, then plot the next frame onto it. Do I have to draw/plot with Cairo or can I just calculate and set pixels to certain values? I like having double buffering: is there bit blit?

I'll play around and get back tomorrow night.

Alan


Top
 Profile  
 
 Post subject: Re: Simple animations?
PostPosted: Sun Jun 02, 2013 3:25 pm 
Offline
Familiar Face

Joined: Thu May 30, 2013 5:26 am
Posts: 9
Well, it's early but I'm not getting far. I'm not sure how to get a pixbuf to the drawingarea.

It seems like GTK as a whole needs to declare a moratorium on writing new code and deprecating everything and spend a year reviewing and rewriting documentation. I've never seen such a mess. Probably multiple languages are an issue, but I think multiple people working on it is possibly worse. It's like there's no continuity from one section to another. No one's in charge. It seems like with all the documentation that exists it shouldn't be necessary to read header files to figure out what's really happening. All the Doxygen-generated stuff doesn't take the place of managed writers.

I started reading GTK tutorials 2- 3 years ago but gave up several times because nothing made sense. In between I've looked through several of the O'Reilly X books which are nicely done. Fltk is nice, but as far as I can tell it only works with C++.

If I work with a gdk_pixbuf, fetch the width, rowstride, etc. I can do this:
pixels = gdk_pixbuf_get_pixels (pbuf);
for (x=0; x<width; x++) { // diagonal line
y = x;
p = pixels + y * rowstride + x * n_channels;
p[1] = 255; // green only
}

Which was the beginning I was looking for as a test. I can do gtk_image_new_from_pixbuf to load it, but that's the only thing I've had work so far. There's plenty of documentation about themes, icons, that sort of thing, but not much about plotting pixels probably because of lack of interest. I want to plot data from my soundcard for starters. I don't want high level stuff. I've worked with Borland graphics, UCSD Pascal graphics, HPGL, Turtlegraphics, even gwbasic graphics, but here I'm having trouble getting pixels to the screen and replacing them.

Alan


Top
 Profile  
 
 Post subject: Re: Simple animations?
PostPosted: Mon Jun 03, 2013 2:22 am 
Offline
Familiar Face

Joined: Thu May 30, 2013 5:26 am
Posts: 9
Well, I finally found this: "GTK+ does all of its drawing using cairo." Which has nothing for fast drawing of pixels. Soundcards take 8000 - 192000 samples per second (so far) and it would be nice to plot pixels that fast. I think nobody had doing that in mind.

I'm looking at GdkPixbufSimpleAnim now. If I can make those on the fly and show them that seems the best way I've found yet. For the oscilloscope application at least a few missed frames won't matter that much.

Alan


Top
 Profile  
 
 Post subject: Re: Simple animations?
PostPosted: Mon Jun 03, 2013 5:48 am 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 768
Location: UK
We must be in two very different time zones and that you are trying to work on this problem every moment of the day. The way that you are demanding answers to your questions is not very help full as you are not giving enough information. Everyone here who contributes back does so in their own free time. We do have jobs (we need to make a living) and family life. No one here who give out help gets paid.

The API documentation is pretty good if a bit dry, which is probably why you find it hard. There is a tutorial series being produced, but this does depend on volunteers to write this. As with all software projects programmers like to write code and not documentation and those who are good at writing documentation do not think they can write for computer software. Have you written any documentation for your code yet?


There is no pixel plotting function for GdkPixbuf, you just need to write directly to the memory area.
Quote:
It is not included in the gdk-pixbuf library for performance reasons; rather than making several function calls for each pixel, your own code can take shortcuts.
For example why would you need to plot red, blue, green and alpha when all you need to plot is green. Or say do 10 function calls to plot 10 pixels when all you need to do is 10 memory accesses.

You can still use GdkPixbuf to generate your image. No matter what, Cairo is still used to render this to the screen.

Have you given any thought to what your application will be doing and what it will show to the user. For example doing some simple maths. If we have a higher frame rate of say 60 frames per second (no point going any higher as most monitors do not refresh any higher) using your highest sample rate of 192000 samples per second. If you want to plot every sample as a pixel you would need a screen at least 3200 wide. Yes I do have a nice wide monitor and it cost a lot but it is not that high a resolution. In cases like this the user would be more than happy to see a representation of the signal and not the exact sample by sample plot, especially if it is a stable, clear and slow enough for the human eye/brain.

For example the tape display used in nearly every audio editor does not show every sample.

An example of some thought in what to show - With my application where it can playback multiple audio tracks to multiple destinations plus MIDI plus doing audio mixing and processing all under a cue list controlled by the user I had to do some thinking about what needs to be displayed to the user. I could have had time displayed to a resolution of 0.001S, this would have been of no use to the user when a track is playing as it would be going too fast for them to see what it was doing. In this case I showed to 0.1S as this gave a good compromise between resolution and what the human eye/brain can determine.

GdkPixbufSimpleAnim is probably not what you want. It is more akin to GIF animation.

_________________
E.


Top
 Profile  
 
 Post subject: Re: Simple animations?
PostPosted: Tue Jun 04, 2013 3:54 am 
Offline
Familiar Face

Joined: Thu May 30, 2013 5:26 am
Posts: 9
Sorry, I was feeling lost, going around in circles and getting nowhere. I'm retired, so I work on what I want when I want, and we've just had several rainy days so I have an excuse to stay indoors. I mostly only get online (dial up) at night. I wasn't getting any response, then it occurred to me it was a weekend for normal people.

The problem I'm having isn't writing to a GdkPixbuf, it's writing that to anything else. I seem to find a lot of structs with only private properties and methods. I discovered that in the HTML pages for the documentation when there are 2 links on a line in an index, they mostly go different places. I was assuming they were the same. And if I find a link that's not local and I'm not on the internet it's a dead end.

But how, for example, do I draw a GdkPixbuf to a DrawingArea? I guess I've gotten a little used to the Delphi help format for oop, where they give a list of all the properties of an object and another list of all the methods. I don't see how to do anything with a DrawingArea other than one example of writing a cairo_t to it. Are there general things I should know, like all widgets have certain properties and methods even when they aren't mentioned under that specific widget?

I was trying a little acquisition of live audio today and plotting, but I don't have threads set up yet. I can get a few hundred samples then I think GTK is grabbing the CPU and interrupting. I've only done 2 other programs that dealt with audio but I didn't see the same thing happening. I need to use threads anyway, I was just playing around without them. I got farther than I expected to, but I'm still using GtkImage.

I'm not intending to use a high frame rate beyond about 10 per second, but I'd like to plot all the audio samples that come along in that 1/10 second (as dots). The oscilloscope program presents some special challenges because with most oscilloscopes the user can select a time interval per grid interval, same for vertical scaling. Also there's triggered sweep, which is the norm really, in which every time a certain voltage is reached with the right (positive or negative) slope it triggers acquisition (plotting in this case) of a frame. Once that trace is done everything waits for the next trigger. It's mostly used for repetitive waveforms.

As far as planning the user interface, I'm not really inventing anything new, I'm just trying to do under Unix and GTK what other programs already do under Windows. For examples: Christian Zeitnitz's sound card oscilloscope program, HDSDR, Radio Skypipe.

I've just tried to attach a 6k gif screenshot. It's 1/10 second of audio at a 32000 sample rate, a weather fax transmission over shortwave. The 0 voltage line at the left side I think is because I'm not doing the acquisition in a different thread.

Alan


Attachments:
File comment: One frame, window title's wrong, clear button doesn't work.
snap.gif
snap.gif [ 5.5 KiB | Viewed 1705 times ]
Top
 Profile  
 
 Post subject: Re: Simple animations?
PostPosted: Wed Jun 05, 2013 2:33 am 
Offline
Familiar Face

Joined: Thu May 30, 2013 5:26 am
Posts: 9
I made an important discovery regarding offline documentation. The documentation I have was installed as parts of several OpenBSD packages. They don't know about each other so they aren't cross-linked. Most of the links that try to access the internet, if I look at the filename and then do a locate I find I've already got the file in a different directory. I think I can run a link checker while I'm offline and then fix up the HTML. Finding this fills in a lot of holes anyway.

So what I'm going to try next is to create a drawingarea, put it in a grid. Create a new pixbuf, draw axes, a grid, etc. onto it and keep it as master. Make a copy, plot live data onto it, then use cairo-set-source-pixbuf to assign it to the drawing area. Make a new copy of the master pixbuf, plot new data onto it, then use gdk_pixbuf_copy_area to copy it onto the one that's showing. cairo-set-source-pixbuf was the link I was missing. (Maybe, I think)

Alan


Attachments:
File comment: 192k samples/second, 1000 samples
wx_aud_192k.gif
wx_aud_192k.gif [ 6.31 KiB | Viewed 1688 times ]
Top
 Profile  
 
 Post subject: Re: Simple animations?
PostPosted: Wed Jun 05, 2013 7:27 am 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 768
Location: UK
Hi,
I have made a code example that shows TV static in a window using GTK+ v3, GdkPixbuf to create the image which is then rendered into a GtkDrawingArea (using Cairo)

Compile using :-
Code:
gcc `pkg-config --cflags --libs gtk+-3.0 gdk-pixbuf-2.0` test.c

Code:
#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <stdlib.h>

/* the global pixmap that will serve as our buffer */
static GdkPixbuf *frame = NULL;

/* This is called when our window is re-sized
* Here we change the size of the GdkPixbuf by
* Allocating a new one, and scaling the old one into the new one.
* The old one is then de allocated
*/
gboolean on_window_configure_event(GtkWidget * da, GdkEventConfigure * event, gpointer user_data)
{
    static int oldw = 0;
    static int oldh = 0;
    //make our selves a properly sized pixmap if our window has been resized
    if (oldw != event->width || oldh != event->height){
        //create our new pixmap with the correct size.
        GdkPixbuf *tmppixmap = gdk_pixbuf_scale_simple (frame, event->width, event->height, GDK_INTERP_NEAREST);
        g_object_unref(frame);
        frame = tmppixmap;
    }
    oldw = event->width;
    oldh = event->height;
    return TRUE;
}

/* Draw callback for the drawing area
* This is called when we tell it via our timer call-back function
* and by the window system such as another window moving over this one
*/
static gboolean
draw_cb (GtkWidget *widget, cairo_t *cr, gpointer data)
{
    gdk_cairo_set_source_pixbuf (cr, frame, 0, 0);
    cairo_paint (cr);

    return TRUE;
}

/* A timer call back that is called every 33ms (roughly) */
static gboolean
timerer_cb (gpointer user_data)
{
    int width, height;
    int x, y;
    int rowstride;
    guchar *pixels, *p;
    int n_channels;

/* Get information on the pixbuf */
    width = gdk_pixbuf_get_width (frame);
    height = gdk_pixbuf_get_height (frame);
    rowstride = gdk_pixbuf_get_rowstride (frame);
    pixels = gdk_pixbuf_get_pixels (frame);
    n_channels = gdk_pixbuf_get_n_channels (frame);

/* Here we create our TV static image
   In your application this would be done in another thread using double buffering
   and locking
*/
    for (y = 0; y < height; ++y) {
        for (x = 0; x < width; ++x) {
            p = pixels + y * rowstride + x * n_channels;
            if (rand() > RAND_MAX / 2) {
                p[0] = p[1] = p[2] = 255;
            } else {
                p[0] = p[1] = p[2] = 0;
            }
        }
    }

/* Tell GTK to queue a redraw of our drawing area */
    gtk_widget_queue_draw_area ((GtkWidget *)user_data, 0, 0, width, height);

/* Lets do it again */
    return TRUE;
}

int
main (int argc, char *argv[])
{
    GtkWidget *window;
    GtkWidget *drawing_area;

    gtk_init(&argc, & argv);

    /* Create a window */
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_container_set_border_width (GTK_CONTAINER(window), 8);
    g_signal_connect (window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    /* Create the drawing area with an initial size of 100 x 100 */
    drawing_area = gtk_drawing_area_new ();
    gtk_widget_set_size_request (drawing_area, 100, 100);

    /* The initial frame to draw into */
    frame = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, 100, 100);

    /* because we will be painting our pixmap manually during draw events
       we can turn off gtk's automatic painting and double buffering routines. */
    gtk_widget_set_app_paintable (drawing_area, TRUE);
    gtk_widget_set_double_buffered (drawing_area, FALSE);

    /* Connect the "draw" and "configure_event" signals */
    g_signal_connect (drawing_area, "draw", G_CALLBACK (draw_cb), NULL);
    g_signal_connect (drawing_area, "configure_event", G_CALLBACK(on_window_configure_event), NULL);

    /* Place the drawing area in the window */
    gtk_container_add (GTK_CONTAINER (window), drawing_area);

    /* Our timer */
    g_timeout_add(33, timerer_cb, drawing_area);

    gtk_widget_show_all(window);
   
    gtk_main ();
   
    return 0;
}


Good to see that you are now getting on top of the documentation. Have you got Gnome Devhelp installed. This is a useful help browser for developers which puts things into categorise and can search. Treat my example as a starting point. You could use Cairo for the drawing which is more flexible has many more features such as writing text, drawing lines and curves which may be useful if you want to put scales etc. on your display. The down side is that it would not be as fast as direct plotting.

_________________
E.


Top
 Profile  
 
 Post subject: Re: Simple animations?
PostPosted: Thu Jun 06, 2013 3:13 am 
Offline
Familiar Face

Joined: Thu May 30, 2013 5:26 am
Posts: 9
I'll look into Gnome Devhelp, I hadn't heard of it.

In both your example and example 99, what is it in the draw callback that's drawing cr onto widget? Or does the fact that it's a draw callback imply that the output should get rendered onto the first argument passed?

Your example compiles and runs fine by the way. I can probably just copy your draw callback. I think I've seen that somewhere before, but examples are good to have.

Below is my attempt at using cairo from today. I just didn't know what to put in the draw callback.

Alan

Code:
#include <gtk/gtk.h>
#include <sys/types.h>
#include <time.h>
#include <string.h>

// globals (lazy)
  GtkWidget *window;   // top level
  GtkWidget *drawbox;  // drawing area
  GtkWidget *grid;
  GtkWidget *quit_button;
  GtkWidget *button1;
  GdkPixbuf *pbuf[2];
  char title[50];  // window title(date)
  time_t now_t;
  cairo_t *context;
  // attributes for all pixbufs:
  int width = 1000;
  int height = 500;
  int rowstride;
  int n_channels;
  cairo_format_t format = CAIRO_FORMAT_RGB24;
  cairo_surface_t *surface;

// draw event handler, since we need one
// draw doesn't necessarily mean moving like scribble
gboolean draw1(GtkWidget *widget, cairo_t *cr, gpointer data) {
//  guint width, height;
//  GdkRGBA color;
/*
   I don't see how the example 99 is putting cr onto widget
*/   
 
}

// this needs black fill first
void axes(void) {  // set up template pixbuf
  int i;
  guchar *pixels;
  guchar *p;
  int y = 0;
  pixels = gdk_pixbuf_get_pixels(pbuf[0]);
  for (i=0; i < width; i++) {  // line along top
    p = pixels + y + i * n_channels;
    p[0] = 128; // gray graticule lines
    p[1] = 128;
    p[2] = 128;
  }
}

void setup(int argc, char *argv[]) { // some clutter can go here
  now_t = time(NULL);
  strncpy(title, ctime( &now_t),50);
  gtk_init(&argc, &argv);
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_widget_set_name(window, title);
  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
  grid = gtk_grid_new();
  gtk_container_add(GTK_CONTAINER(window), grid);
  gtk_container_set_border_width (GTK_CONTAINER (window), 5);
  pbuf[0] = gdk_pixbuf_new(GDK_COLORSPACE_RGB,0,8,1000,500);  // master
  pbuf[1] = gdk_pixbuf_new(GDK_COLORSPACE_RGB,0,8,1000,500);
  rowstride = gdk_pixbuf_get_rowstride(pbuf[0]);
  n_channels = gdk_pixbuf_get_n_channels(pbuf[0]);
  axes();
  // make a cairo_format_t (up top as declaration)
  // make a cairo_surface_t
  surface = cairo_image_surface_create(format, width, height);
  // make a cairo_t
  context = cairo_create(surface);
  gdk_cairo_set_source_pixbuf(context,pbuf[0],0,0);
  drawbox = gtk_drawing_area_new();
  gtk_widget_set_size_request(drawbox, width, height);
  g_signal_connect(G_OBJECT(drawbox),"draw",G_CALLBACK(draw1), NULL);
  gtk_grid_attach(GTK_GRID(grid), drawbox, 0,0,2,1);
  quit_button = gtk_button_new_with_label("Quit");
  g_signal_connect (quit_button, "clicked", G_CALLBACK (gtk_main_quit), NULL);
  gtk_grid_attach (GTK_GRID (grid), quit_button, 0, 1, 1, 1);
  button1 = gtk_button_new_with_label("Draw");
  // signal connect button 1 here
  g_signal_connect (button1, "clicked", G_CALLBACK (draw1), NULL);
  gtk_grid_attach (GTK_GRID (grid), button1, 1, 1, 1, 1);
}

int main(int argc, char *argv[]) {
  setup(argc, argv);
 
  gtk_widget_show_all(window);
  gtk_main();
 
  return 0;
}



Top
 Profile  
 
 Post subject: Re: Simple animations?
PostPosted: Fri Jun 07, 2013 3:07 am 
Offline
Familiar Face

Joined: Thu May 30, 2013 5:26 am
Posts: 9
One thing about the TV demo, on this OpenBSD box at least resizing is funky. Going bigger works fine, but going back to the original size it hangs (the animation keeps going) and it keeps the focus so I have to ssh in from another machine and kill it. Anything with a resize handle that doesn't have a good resize routine does that. I turned off the resize handle below, but I need to cast the window for gtk_window_set_has_resize_grip(). This works but gives an "incompatible pointer type" warning.

This does one frame (1000 samples) every time you click the Acquire button. A one-shot digital storage oscilloscope.

Alan

Code:
/*
  single frame simple audio scope  (for OpenBSD and maybe NetBSD only)
 
  compile with:
 
  gcc `pkg-config --cflags gtk+-3.0` -o 0606b 0606b.c \
  `pkg-config --libs gtk+-3.0`
 
  grabs 1000 samples at SAMPRATE

*/

#include <gtk/gtk.h>
#include <sys/types.h>
#include <time.h>
#include <string.h>
#include <sys/audioio.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <fcntl.h>

#define GRAY 64
#define SAMPRATE 192000  // even my old AudioPCI can do this

// globals (lazy)
  GtkWidget *window;   // top level
  GtkWidget *drawbox;  // drawing area
  GtkWidget *grid;
  GtkWidget *quit_button;
  GtkWidget *button1;
  GdkPixbuf *pbuf[2];
  char title[50];  // window title(date)
  time_t now_t;
  cairo_t *context;
  // for sound
  struct audio_info ainfo;
  int snd;  // file descriptor
  // attributes for all pixbufs:
  int width = 1000;
  int height = 500;
  int rowstride;
  int n_channels;
  cairo_format_t format = CAIRO_FORMAT_RGB24;
  cairo_surface_t *surface;
  gpointer user_data;
 
gboolean draw1(GtkWidget *widget, cairo_t *cr, gpointer data);
 
void aud_samp(void) {  // get 1000 samples, scale, plot
  int16_t adat[1000];
  ssize_t bytesread;
  guchar *pixels;
  int i;
  double scl;
  int x,y;
  guchar *p;
  int16_t mn, mx;  // min,max
  bytesread = read(snd, adat, 2000);  // 16 bit samples, read 2000 bytes
  if (bytesread < 0) {
    g_printf("audio read failed.\n");
    exit(1);
  } else
  // find min, max
  mn = 999;
  mx = -999;
  for (i=0; i<1000; i++) {
    if (adat[i] > mx)
      mx = adat[i];
    if (adat[i] < mn)
      mn = adat[i];
  }
  pixels = gdk_pixbuf_get_pixels (pbuf[1]);
  if (pixels == NULL) {
    g_printf("got null pointer for pixels\n");
    exit(1);
  }
  // scale:
  scl = ((mx - mn) * 1.0) / (height * 1.0);
  // divide each point by scl
  for (x=0; x<width; x++) {
    y = (int)(((adat[x])/scl) + 0.5) + (height/2);
    if ((y >= 0) && (y <= height)) {  // clip/mask
      p = pixels + y * rowstride + x * n_channels;
      p[1] = 255;  // green only
    }
  }
}
 
void acquire(void) {
  if (pbuf[1] != NULL)
    g_object_unref(pbuf[1]);// has memory leak without this
  pbuf[1] = gdk_pixbuf_copy(pbuf[0]);  // copy template, graticule
  aud_samp();
  gdk_cairo_set_source_pixbuf (context, pbuf[1], 0, 0);
  cairo_paint(context);
  gtk_widget_queue_draw_area ((GtkWidget *)window, 0, 0, width, height);
}

gboolean draw1(GtkWidget *widget, cairo_t *cr, gpointer data) {
  if (pbuf[1] != NULL)
    gdk_cairo_set_source_pixbuf (cr, pbuf[1], 0, 0);
  else
    gdk_cairo_set_source_pixbuf (cr, pbuf[0], 0, 0);
  cairo_paint (cr);
  return TRUE;
}

/*
   Operating systems differ widely in their treatment of sound cards.  These
   sound card routines are for OpenBSD 5.0, might also work under NetBSD,
   Solaris is also possible.  Linux, FreeBSD, MS Windows, OS-X: no way.
*/

void clear_data(void) { // gets rid of turn-on click in sound card
  struct audio_info tmp_info;
  int16_t trash[50];
  if (ioctl(snd, AUDIO_FLUSH, &tmp_info) < 0) {
    printf("Error doing AUDIO_FLUSH to empty sound card.\n");
    perror("init ");
  }
  (void) read(snd,trash,40); // always reads junk 1st
}

void init_sound() {  // set the sound card
  snd = open("/dev/audio",O_RDONLY | O_NOCTTY, 0777);
  if (snd < 0) {
    printf("Error opening sound card.\n");
    perror("sound ");
    exit(1);
  }
  AUDIO_INITINFO(&ainfo);  // fills it with zeroes to start
  ainfo.record.sample_rate = SAMPRATE; // changeable up top
  ainfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE;
  ainfo.record.port = AUDIO_MICROPHONE;
  // ainfo.record.port = AUDIO_LINE_IN;  // alternate macro
  ainfo.record.channels = 1;
  ainfo.record.gain = 192;  // arbitrary choice
  ainfo.record.precision = 16;
  ainfo.record.pause = 0;  // this and next may not actually do anything
  ainfo.record.active = 1;
  ainfo.mode = AUMODE_RECORD;  // ie not play
  if (ioctl(snd, AUDIO_SETINFO, &ainfo) < 0) {  /* write struct to sound card */
    printf("Error doing AUDIO_SETINFO ioctl.\n");
    perror("sound ");
    exit(1); // make it fatal
  }
  clear_data();
}  // init_sound

void graticule(void) {
  int i, y;
  int xdiv, ydiv;
  xdiv = width/10;
  ydiv = height/10;
  guchar *pixels, *p;
  pixels = gdk_pixbuf_get_pixels(pbuf[0]);
  for (y=0; y<=height; y+= ydiv) {  // horizontal graticule lines
    for (i=0; i<= width; i++ ) {
      p = pixels + (y * rowstride) + (i * n_channels);
      p[0] = p[1] = p[2] = GRAY;
    }
  }
  for (i=xdiv; i<width; i+=xdiv) { // vertical lines
    for (y=0; y<height; y++) {
      p = pixels + (y * rowstride) + (i * n_channels);
      p[0] = p[1] = p[2] = GRAY;
    }
  }
}

void setup(int argc, char *argv[]) { // some clutter can go here
  now_t = time(NULL);
  strncpy(title, ctime( &now_t),50);
  gtk_init(&argc, &argv);
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_has_resize_grip(window, FALSE);
  gtk_widget_set_name(window, title);
  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
  grid = gtk_grid_new();
  gtk_container_add(GTK_CONTAINER(window), grid);
  gtk_container_set_border_width (GTK_CONTAINER (window), 5);
  pbuf[0] = gdk_pixbuf_new(GDK_COLORSPACE_RGB,0,8,width,height);  // master
  rowstride = gdk_pixbuf_get_rowstride(pbuf[0]);
  n_channels = gdk_pixbuf_get_n_channels(pbuf[0]);
  graticule();
  // some of this cairo stuff is probably not needed
  // make a cairo_format_t (up top as declaration)
  // make a cairo_surface_t
  surface = cairo_image_surface_create(format, width, height);
  // make a cairo_t
  context = cairo_create(surface);
  gdk_cairo_set_source_pixbuf(context,pbuf[0],0,0);
  drawbox = gtk_drawing_area_new();
  gtk_widget_set_size_request(drawbox, width, height);
  g_signal_connect(G_OBJECT(drawbox),"draw",G_CALLBACK(draw1), NULL);
  gtk_grid_attach(GTK_GRID(grid), drawbox, 0,0,2,1);
  quit_button = gtk_button_new_with_label("Quit");
  g_signal_connect (quit_button, "clicked", G_CALLBACK (gtk_main_quit), NULL);
  gtk_grid_attach (GTK_GRID (grid), quit_button, 0, 1, 1, 1);
  button1 = gtk_button_new_with_label("Acquire");
  g_signal_connect (button1, "clicked", G_CALLBACK (acquire), user_data);
  gtk_grid_attach (GTK_GRID (grid), button1, 1, 1, 1, 1);
}

int main(int argc, char *argv[]) {
  setup(argc, argv);
  init_sound();
 
  gtk_widget_show_all(window);
  gtk_main();
 
  return 0;
}



Attachments:
File comment: multiple psk31 signals
multi.gif
multi.gif [ 12.02 KiB | Viewed 1665 times ]
File comment: One morse code dit
dit.gif
dit.gif [ 12.03 KiB | Viewed 1665 times ]
Top
 Profile  
 
 Post subject: Re: Simple animations?
PostPosted: Fri Jun 07, 2013 5:47 am 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 768
Location: UK
It is looking good. I did my little demo very quickly so may have done a mistake on the resizing routine :)

The BSD sound system looks very similar to the OSS sound system that is sometimes still used on Linux. There is a library called PortAudio that may be of use if you want your code to work on many more types of machines. This includes Windows, MacOS X, Linux and other sound systems. It is used by Audacity an audio editing software and have heard that it works on BSD

_________________
E.


Top
 Profile  
 
 Post subject: Re: Simple animations?
PostPosted: Sat Jun 08, 2013 3:02 am 
Offline
Familiar Face

Joined: Thu May 30, 2013 5:26 am
Posts: 9
I have PortAudio installed, also Jack Audio, but those are glued-on compatibility layers. Both also seem to not work right at times so I was sticking with the native "Audio". Yes, it's a little like OSS, which I think FreeBSD also uses. I like the simplicity of opening the sound card like a file and reading from it. I also have OSS emulation so I could write for that. Maybe I should put it in ifdefs. I should be able to write interchangeable sound routines. I can boot the same box into Debian for testing, but I don't think I have GTK3 under this Debian.

There's a scope program called Xoscope which I have under Debian that I haven't gotten to work under OpenBSD so I was practicing. There's also Xanalyzer which does FFTs.

I goofed off today, but I think I'm going to add a spinner or drop down for setting the sound card sample rate next. Maybe the number of samples too, which is always 1000 now. Still no threads, no fancy timing, 1 frame per click.

Alan


Top
 Profile  
 
 Post subject: Re: Simple animations?
PostPosted: Sat Jun 08, 2013 8:09 am 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 768
Location: UK
I have never used PortAudio myself for coding though it is used in Audacity which is probably one of the best known FOSS audio editors out there. JackAudio I use, but you are stuck with the sampling rate at which the server is started with. Both libraries/software are very good.

Under Linux OSS is available but not always activated, with many systems using ALSA instead as it has many more features. The latest version of Debian Wheezy was released on the 4 May 2013 and this has GTK v3.4 in it.

I see that you have gone for the keep it simple approach. Always a good place to start and once you have got that working then you have have fun doing the hard parts.

_________________
E.


Top
 Profile  
 
 Post subject: Re: Simple animations?
PostPosted: Mon Jul 15, 2013 2:36 pm 
Offline
Familiar Face

Joined: Thu Aug 27, 2009 9:44 pm
Posts: 21
Hi ab1jx,

my comment is just related to the initial post.

I want to make similiar stuff to plot the step-response of some analog systems with gtk. I use the `gtkdatabox` widget for this [1]! I think it is not worth the effort to implement a new plotting widget unless you do it for educational purpose only. Especially with regard to those conceptual changes that are often done if you jump in such task over night without any detailled planning about the interface of your new plotting widget.

To get `gtkdatabox` running with gtk3 checkout the `cairo-alpha` branch of the repository.


[1]: http://sourceforge.net/projects/gtkdatabox/


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

All times are UTC


Who is online

Users browsing this forum: No registered users and 5 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