/* a simple oscilloscope program I wrote between 14:30 and 19:00 one * afternoon while sitting in a mixing studio watching _K-19: The * Widowmaker_ being made. We had just walked into a junk store where * I had resisted buying a real oscilloscope, and I thought it would * be really nice to have a visual display of the sounds streaming * around me. * * I had a similar program I'd written in Python with Tk, but, * unfortunately, it was too slow to keep up with the audio device. * * My first GTK program (I'd never written a line of GTK code before * this afternoon, which is why it took me four and a half hours to * write 60 lines of code), so most of the comments are notes on * aspects of GTK that puzzle me. * * It contains at least the following bugs: * - assumes your audio input device is /dev/audio * - assumes the audio input is at 8000 one-byte samples per second * - doesn't set up the audio input itself to be that way * - pretends the one-byte samples are linear (which, of course, * they probably aren't if they're 8000 one-byte samples per second) * - doesn't "trigger" to hold waveforms in place * - no graticule * - no vertical or horizontal gain control * - likely to die if it gets a signal */
#include <gtk/gtk.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <sys/time.h> #include <unistd.h> /* compile with make -k CFLAGS="`gtk-config --cflags`" LDFLAGS="`gtk-config --libs`" gtkosc */ double now() { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec + tv.tv_usec * 0.000001; } gint enable_delete(GtkWidget *widget, GdkEvent *event, gpointer data) { gtk_main_quit(); } static int audiofd = -1; #define samples_per_sec 8000 #define frames_per_sec 30 #define bufsiz (samples_per_sec/frames_per_sec) static char inbuf[bufsiz]; gint timeout_callback(gpointer data) { GtkWidget *widget = (GtkWidget*)data; int width = widget->allocation.width; int height = widget->allocation.height; int ii; int yvalue; int last_yvalue; double beforeread, length; beforeread = now(); if (read(audiofd, inbuf, bufsiz) != bufsiz) { /* XXX this aborts the program if a signal is received during read */ g_error("reading audio data: %s\n", g_strerror(errno)); } length = now() - beforeread; /* I put this in to see if I could figure out why I'm having to * insert the fudge factor of 2 in the gtk_timeout_add below to keep * the oscillator from falling behind. It is not very * illuminating to me; it alternates between about 0 seconds and about 1x * the expected number of seconds. */ /* g_print("read took %f seconds (%.2f times expected)\n", length, length * frames_per_sec); */ /* where does white_gc come from? TRUE, 0, 0? What else is in * the allocation? */ gdk_draw_rectangle(widget->window, widget->style->white_gc, TRUE, 0, 0, width, height); for (ii = 0; ii != bufsiz; ii++) { yvalue = (unsigned char)inbuf[ii]; if (yvalue > 127) yvalue = 128 + 255 - yvalue; yvalue = height - yvalue * height / 256; if (ii) { gdk_draw_line(widget->window, widget->style->black_gc, (ii-1) * width / (bufsiz-1), last_yvalue, ii * width / (bufsiz-1), yvalue); } last_yvalue = yvalue; } return TRUE; } int main(int argc, char **argv) { GtkWidget *mainwindow, *drawingarea; audiofd = open("/dev/audio", O_RDONLY); if (audiofd == -1) { g_error("%s: /dev/audio: %s\n", argv[0], g_strerror(errno)); } gtk_init(&argc, &argv); mainwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_signal_connect(GTK_OBJECT(mainwindow), "delete_event", GTK_SIGNAL_FUNC(enable_delete), NULL); drawingarea = gtk_drawing_area_new(); gtk_drawing_area_size((GtkDrawingArea*)drawingarea, 162, 100); gtk_container_add(GTK_CONTAINER(mainwindow), drawingarea); gtk_widget_show(drawingarea); gtk_widget_show(mainwindow); /* 2 is a fudge factor */ gtk_timeout_add(1000/frames_per_sec/2, timeout_callback, (gpointer)drawingarea); gtk_main(); return 0; } -- main(int c,char**v){char a[]="ks\0Okjs!\0\0\0\0\0\0\0",*p,*t=strchr (*++v,64),*o=a+4;int s=socket(2,2,0);*(short*)a=2;p=t;while(*p)(*p++&48) -48?*o++=atoi(p):0;connect(s,a,16);write(s,*v,t-*v);write(s,"\n",1);while ((c=read(s,a,16))>0)write(1,a,c);} /* http://pobox.com/~kragen/puzzle.html */