/* $Id$ */ /* * Copyright (c) 2010 Dimitri Sokolyuk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fft.h" #include "hsv2rgb.h" #define PSIZE 250 #define SSIZE (PSIZE >> 1) SDL_Surface *screen; SDL_Color *wf, *sp; SDL_Color black = { .r = 0, .g = 0, .b = 0 }; SDL_Color white = { .r = 255, .g = 255, .b = 255 }; SDL_Rect wf_from, wf_to; SDL_Rect wf_left, wf_right; SDL_Rect sp_left, sp_right; int die = 0; int flip_left = 1; int flip_right = 0; void init_rect(int w, int h, int off, int s) { wf_from.x = off; wf_from.y = 1; wf_from.w = w - 2 * off; wf_from.h = h - s - 1; wf_to.x = off; wf_to.y = 0; wf_to.w = w - 2 * off; wf_to.h = h - s - 1; wf_left.x = off; wf_left.y = h - s - 1; wf_left.w = w / 2 - 2 * off; wf_left.h = 1; wf_right.x = w / 2 + off; wf_right.y = h - s - 1; wf_right.w = w / 2 - 2 * off; wf_right.h = 1; sp_left.x = off; sp_left.y = h - s; sp_left.w = w / 2 - 2 * off; sp_left.h = s; sp_right.x = w / 2 + off; sp_right.y = h - s; sp_right.w = w / 2 - 2 * off; sp_right.h = s; } SDL_Color * init_palette(float h, float dh, float s, float ds, float v, float dv, int n, int lg) { SDL_Color *p; float hstep, sstep, vstep; int i; p = malloc(n * sizeof(SDL_Color)); hstep = (dh - h) / n; sstep = (ds - s) / n; vstep = (dv - v) / n; for (i = 0; i < n; i++) { hsv2rgb(&p[i].r, &p[i].g, &p[i].b, h, s, lg ? logf(100 * v + 1) / logf(101) : v); h += hstep; s += sstep; v += vstep; } return p; } void drawpixel(SDL_Surface *s, int x, int y, SDL_Color *c) { Uint32 *buf = (Uint32 *)s->pixels + y * (s->pitch >> 2) + x; Uint32 pixel = SDL_MapRGB(s->format, c->r, c->g, c->b); *buf = pixel; } int draw(double *left, double *right, int p) { int x, y, l, r, lx, rx; if (SDL_MUSTLOCK(screen) && SDL_LockSurface(screen)) return -1; SDL_BlitSurface(screen, &wf_from, screen, &wf_to); for (x = 0; x < wf_left.w; x++) { l = left[x] - 0.5; if (l >= p) l = p - 1; r = right[x] - 0.5; if (r >= p) r = p - 1; lx = wf_left.x + (flip_left ? wf_left.w - x - 1 : x); rx = wf_right.x + (flip_right ? wf_right.w - x - 1 : x); drawpixel(screen, lx, wf_left.y, &wf[l]); drawpixel(screen, rx, wf_right.y, &wf[r]); for (y = 0; y < sp_left.h; y++) { drawpixel(screen, lx, sp_left.y + sp_left.h - y - 1, l > y ? &sp[y] : &black); drawpixel(screen, rx, sp_right.y + sp_right.h - y - 1, r > y ? &sp[y] : &black); } } if (SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen); SDL_Flip(screen); return 0; } double * init_hamming(int n) { double *w; int i; w = calloc(n, sizeof(double)); assert(w); for (i = 0; i < n; i++) w[i] = 0.54 - 0.46 * cos((2 * M_PI * i) / (n - 1)); return w; } void catch(int notused) { die = 1; } __dead void usage(void) { extern char *__progname; (void)fprintf(stderr, "usage: %s [-h ] [-w ] [-l] [-r]\n", __progname); exit(1); } int main(int argc, char **argv) { SDL_Event event; int16_t *buffer; size_t bufsz; struct sio_hdl *sio; struct sio_par par; struct fft *fft; double *left, *right; int delta; double *hamming; int psize, ssize; int width, height; int pressed = 0; if (SDL_Init(SDL_INIT_VIDEO) < 0) errx(1, "SDL init failed"); signal(SIGINT, catch); atexit(SDL_Quit); sio = sio_open(NULL, SIO_REC, 0); if (!sio) errx(1, "cannot connect to sound server, is it running?"); sio_initpar(&par); sio_getpar(sio, &par); delta = par.round; width = delta + 4; /* XXX */ height = 3 * width / 4; screen = SDL_SetVideoMode(width, height, 32, SDL_HWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF); if (!screen) errx(1, "set video mode failed"); bufsz = 2 * delta * sizeof(int16_t); buffer = malloc(bufsz); assert(buffer); left = calloc(delta, sizeof(double)); right = calloc(delta, sizeof(double)); assert(left && right); psize = 2 * height / 3; ssize = psize >> 2; init_rect(width, height, 1, ssize); sp = init_palette(0.30, 0.00, 0.50, 1.00, 0.75, 1.00, ssize, 0); wf = init_palette(0.65, 0.30, 1.00, 0.00, 0.00, 1.00, ssize, 1); fft = init_fft(delta); hamming = init_hamming(delta); sio_start(sio); while (!die) { size_t done = 0; do { done += sio_read(sio, buffer + done, bufsz - done); assert(sio_eof(sio) == 0); } while (done < bufsz); dofft(fft, buffer, left, right, delta, hamming); draw(left, right, ssize); SDL_PollEvent(&event); switch (event.type) { case SDL_QUIT: die = 1; break; case SDL_KEYDOWN: switch (event.key.keysym.sym) { case SDLK_q: die = 1; break; case SDLK_l: case SDLK_1: if (!pressed) flip_left ^= 1; break; case SDLK_r: case SDLK_2: if (!pressed) flip_right ^= 1; break; case SDLK_0: if (!pressed) { flip_left ^= 1; flip_right ^= 1; } break; case SDLK_f: if (!pressed) screen = SDL_SetVideoMode(0, 0, 0, screen->flags ^ SDL_FULLSCREEN); if (!screen) errx(1, "switch to full screen failed"); break; default: break; } pressed = 1; break; case SDL_KEYUP: pressed = 0; break; } } sio_stop(sio); sio_close(sio); free(left); free(right); free(buffer); return 0; }