diff options
Diffstat (limited to '')
-rw-r--r-- | prog/baozveza/vis.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/prog/baozveza/vis.c b/prog/baozveza/vis.c new file mode 100644 index 0000000..02a4e99 --- /dev/null +++ b/prog/baozveza/vis.c @@ -0,0 +1,165 @@ +#include <X11/Xlib.h> +#include <X11/keysym.h> +#include <X11/Xutil.h> +#include <assert.h> +#include <unistd.h> +#include <poll.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include "dsp.c" +#include <error.h> +#include <stdlib.h> +#include <errno.h> +enum whattodraw { + whattodraw_abs, + whattodraw_re, + whattodraw_im +}; +int main (int argc, char ** argv) { + if (argc != 3) + error(1, 0, "argv[1] must be set. fft length will then be 2**argv[1]\nargv[2] must be set. peak value will then be argv[2] -- use a floating point."); + double peak = strtod(argv[2], NULL); + Display *dpy = XOpenDisplay(NULL); + assert(dpy); + int blackColor = BlackPixel(dpy, DefaultScreen(dpy)); + int width = 200; + int height = 400; + Window w = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, width, height, 0, blackColor, blackColor); + // We want to get MapNotify events + XSelectInput(dpy, w, StructureNotifyMask | KeyPressMask | ExposureMask | VisibilityChangeMask); + // "Map" the window (that is, make it appear on the screen) + XMapWindow(dpy, w); + // Create a "Graphics Context" + GC gc = XCreateGC(dpy, w, 0, NULL); + // Tell the GC we draw using the white color + XSetForeground(dpy, gc, 0xff0000); + // Wait for the MapNotify event + struct pollfd pollfd[2] = { + { + .fd = XConnectionNumber(dpy), + .events = POLLIN | POLLHUP + }, + { + .fd = STDIN_FILENO, + .events = POLLIN + } + }; + int flags = fcntl(XConnectionNumber(dpy), F_GETFL, 0); + assert(flags != -1); + flags |= O_NONBLOCK; + assert(fcntl(XConnectionNumber(dpy), F_SETFL, flags) == 0); + bool flush = false; + int spectrumheight = 100; + void draw_ui () { + XSetForeground(dpy, gc, 0xff0000); + XDrawLine(dpy, w, gc, 0, spectrumheight+1, width, spectrumheight+1); + } + int capturesize = 1 << atoi(argv[1]); + unsigned received_bytes = 0; + double samples[capturesize]; + enum whattodraw whattodraw = whattodraw_abs; + unsigned block = 0; + while (XPending(dpy) || poll(pollfd, 2, -1) > 0) { + if (pollfd[0].revents & POLLIN || XPending(dpy)) { + while (XPending(dpy)) { + XEvent e; + XNextEvent(dpy, &e); + switch (e.type) { + case ConfigureNotify: + width = e.xconfigure.width; + height = e.xconfigure.height; + break; + case MapNotify: + case Expose: + case VisibilityChangeMask: + draw_ui(); + flush = true; + break; + case DestroyNotify: + goto end; + case KeyPress: + switch (XLookupKeysym(&e.xkey, 0)) { + case XK_Up: + spectrumheight--; + break; + case XK_Down: + spectrumheight++; + break; + case XK_a: + case XK_A: + whattodraw = whattodraw_abs; + break; + case XK_r: + case XK_R: + whattodraw = whattodraw_re; + break; + case XK_i: + case XK_I: + whattodraw = whattodraw_im; + break; + } + draw_ui(); + flush = true; + break; + case MappingNotify: + XRefreshKeyboardMapping(&e.xmapping); + break; + } + } + } + if (pollfd[1].revents & POLLIN) { + int rr = read(STDIN_FILENO, ((void *) samples)+received_bytes, sizeof samples-received_bytes); + if (rr == 0) { // EOF + pollfd[1].events = 0; + continue; + } + if (rr < 0) + error(1, errno, "stdin read"); + received_bytes += rr; + if (received_bytes == capturesize*sizeof(samples[0])) { + double complex complex_samples[capturesize]; + for (int i = 0; i < capturesize; i++) + complex_samples[i] = samples[i]; + double complex spectrum[capturesize]; + fft(spectrum, complex_samples, capturesize, false, 1); + XSetForeground(dpy, gc, blackColor); + XFillRectangle(dpy, w, gc, 0, 0, width, spectrumheight+1); + XSetForeground(dpy, gc, 0x00ff00); + for (int i = 0; i < capturesize; i++) { + double frequency; + switch (whattodraw) { + case whattodraw_abs: + frequency = cabs(spectrum[i]); + break; + case whattodraw_re: + frequency = creal(spectrum[i]); + break; + case whattodraw_im: + frequency = cimag(spectrum[i]); + break; + } + if (frequency > peak) + frequency = peak; + XSetForeground(dpy, gc, 0x00ff00); + XDrawLine(dpy, w, gc, i, spectrumheight, i, spectrumheight-(frequency/peak)*spectrumheight); + XSetForeground(dpy, gc, (frequency/peak)*0x00ff00+(frequency/peak)*0x0000ff); + XDrawPoint(dpy, w, gc, i, spectrumheight+2+block%(height-spectrumheight-2)); + } + int scanner = spectrumheight+2+block%(height-spectrumheight-2); + XSetForeground(dpy, gc, 0xabcdef); + XFillRectangle(dpy, w, gc, 0, scanner+1, capturesize, 3); + flush = true; + received_bytes = 0; + block++; + } + } + if (flush) { + XFlush(dpy); + flush = false; + } + } + end: + XCloseDisplay(dpy); +} + |