From fce59d949c0a4767009a9db94f0af0903ff31be1 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sat, 12 Mar 2011 01:53:00 +0000 Subject: sio spectrogram --- spectrogram.c | 438 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 438 insertions(+) create mode 100644 spectrogram.c (limited to 'spectrogram.c') diff --git a/spectrogram.c b/spectrogram.c new file mode 100644 index 0000000..063bbfb --- /dev/null +++ b/spectrogram.c @@ -0,0 +1,438 @@ +/* $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 + +#include "fifo.h" +#include "fft.h" +#include "hsv2rgb.h" + +#define PSIZE 250 +#define SSIZE (PSIZE >> 1) + +#define TIMING 0 + +struct buf { + int16_t left; + int16_t right; +}; + +SDL_Surface *screen; +SDL_Color *pane; +SDL_Color *pan2; +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; + +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_small(int n) +{ + SDL_Color *p; + int i; + float h, s, v; + float hstep, sstep, vstep; + + + p = malloc(n * sizeof(SDL_Color)); + + h = 0.3; + hstep = -0.3 / n; + + s = 0.5; + sstep = 0.5 / n; + + v = 0.75; + vstep = 0.25 / n; + + + for (i = 0; i < n; i++) { + hsv2rgb(&p[i].r, &p[i].g, &p[i].b, h, s, v); + h += hstep; + s += sstep; + v += vstep; + } + + return p; +} + +SDL_Color * +init_palette_big(int n) +{ + SDL_Color *p; + int i; + float h, s, v; + float hstep, sstep, vstep; + float k; + int f = 100; + + p = malloc(n * sizeof(SDL_Color)); + k = 1.0 / logf(f + 1); + + h = 0.65; + hstep = -0.4 / n; + + s = 1.0; + sstep = -1.0 / n; + + v = 0.0; + vstep = 1.0 / n; + + for (i = 0; i < n; i++) { + hsv2rgb(&p[i].r, &p[i].g, &p[i].b, h, s, + k * logf(f * v + 1)); + // hsv2rgb(&p[i].r, &p[i].g, &p[i].b, h, s, sqrtf(v)); + + h += hstep; + s += sstep; + v += vstep; + } + + return p; +} + +int * +init_scala(int n, int w) +{ + int *s, i; + float k; + + s = malloc(w * sizeof(int)); + + k = n / logf(w); + + for (i = 0; i < w; i++) + s[i] = n - k * logf(w - i); + + return s; +} + +int * +init_factor(int *scala, int w) +{ + int *s, k, i; + + s = malloc(w * sizeof(int)); + k = 0; + for (i = 0; i < w; i++) { + s[i] = scala[i] - k; + if (s[i] == 0) + s[i] = 1; + k = scala[i]; + } + + return s; +} + +#if 1 +void inline +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; +} +#else +#define drawpixel(s, x, y, c) do { \ + Uint32 *buf, pixel; \ + buf = (Uint32 *)(s)->pixels + (y) * ((s)->pitch >> 2) + (x); \ + pixel = SDL_MapRGB((s)->format, (c)->r, (c)->g, (c)->b); \ + *buf = pixel; \ + } while (0) +#endif + +int +draw(double *left, double *right, int n, int *scala, int *fact, int p) +{ + int x, y, l, r, i; + + 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 = 0; + r = 0; + + for (i = 0; i < fact[x]; i++) { + l += left[scala[x] - i] + 0.5; + r += right[scala[x] - i] + 0.5; + } + + l /= fact[x]; + r /= fact[x]; + + l >>= 1; + r >>= 1; + + if (l >= p) + l = p - 1; + if (r >= p) + r = p - 1; + + drawpixel(screen, wf_left.x + x, wf_left.y, &pane[l]); + drawpixel(screen, wf_right.x + x, wf_right.y, &pane[r]); + + /* *** */ + + l >>= 1; + r >>= 1; + + for (y = 0; y < sp_left.h; y++) { + drawpixel(screen, sp_left.x + x, + sp_left.y + sp_left.h - y - 1, + l > y ? &pan2[y] : &black); + drawpixel(screen, sp_right.x + x, + sp_right.y + sp_right.h - y - 1, + r > y ? &pan2[y] : &black); + } + } + + if (SDL_MUSTLOCK(screen)) + SDL_UnlockSurface(screen); + + SDL_Flip(screen); + + return 0; +} + +double * +init_wights(int n) +{ + double *w; + int i; + + w = calloc(n, sizeof(double)); + assert(w); + + for (i = 0; i < n; i++) + w[i] = (1 - cos((2 * M_PI * i) / (n - 1))) / 2; + + return w; +} + +void +catch(int notused) +{ + die = 1; +} + +int +main(int argc, char **argv) +{ + const SDL_VideoInfo *vi; + SDL_Event event; + + struct buf *buf; + size_t bufsz; + + struct sio_hdl *sio; + struct sio_par par; + struct fifo *ff; + struct fft *fft; + + double *left, *right; + int c, i, n, k, r, delta; + double *wights; + int *scala; + int *factor; + int psize, ssize; + int height = 0; + int width = 0; + int sdlargs; + + + #if TIMING + struct timeval ta, te; + #endif + + while ((c = getopt(argc, argv, "h:w:")) != -1) + switch (c) { + case 'h': + height = atoi(optarg); + break; + case 'w': + width = atoi(optarg); + break; + default: + break; + } + + if (SDL_Init(SDL_INIT_VIDEO) < 0) + return 1; + + signal(SIGINT, catch); + atexit(SDL_Quit); + + vi = SDL_GetVideoInfo(); + if (!vi) + return 1; + warnx("%dx%d", vi->current_w, vi->current_h); + + sdlargs = SDL_HWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF; + if (!height && !width) + sdlargs |= SDL_FULLSCREEN; + if (!height) + height = vi->current_h - 1; + if (!width) + width = vi->current_w - 1; + + screen = SDL_SetVideoMode(width, height, 32, sdlargs); + if (!screen) + return 1; + + SDL_ShowCursor(SDL_DISABLE); + + psize = 2 * vi->current_h / 3; + ssize = psize >> 2; + + init_rect(vi->current_w, vi->current_h, 1, ssize); + + pan2 = init_palette_small(ssize); + pane = init_palette_big(psize); + + sio = sio_open(NULL, SIO_REC, 0); + assert(sio); + + sio_initpar(&par); + sio_getpar(sio, &par); + + delta = par.round / 2; +// delta = 1024; /* XXX */ + n = 4 * delta; + warnx("delta: %d, n: %d", delta, n); + + bufsz = delta * sizeof(struct buf); + buf = malloc(bufsz); + assert(buf); + + left = calloc(n, sizeof(double)); + right = calloc(n, sizeof(double)); + assert(left && right); + + sio_start(sio); + + fft = init_fft(n); + wights = init_wights(n); + ff = init_fifo(10 * n); + scala = init_scala(n / 2, wf_left.w); + factor = init_factor(scala, wf_left.w); + + #if TIMING + gettimeofday(&ta, NULL); + #endif + + while (!die) { + k = sio_read(sio, buf, bufsz) / sizeof(struct buf); + for (i = 0; i < k; i++) { + left[i] = buf[i].left / (double)INT16_MAX; + right[i] = buf[i].right / (double)INT16_MAX; + } + r = wr_fifo(ff, left, right, k); + + if (r >= n) { + rd_fifo(ff, left, right, n, wights); + + dofft(fft, left); + dofft(fft, right); + + draw(left, right, n / 2, scala, factor, psize); + } + + SDL_PollEvent(&event); + switch (event.type) { + case SDL_QUIT: + die = 1; + break; + case SDL_KEYDOWN: + if (event.key.keysym.sym == SDLK_q) + die = 1; + break; + } + #if TIMING + gettimeofday(&te, NULL); + fprintf(stderr, "%8d time elapsed: %7.6lf sec\r", + r, te.tv_sec - ta.tv_sec + + (te.tv_usec - ta.tv_usec)/1000000.0); + memcpy(&ta, &te, sizeof(struct timeval)); + #endif + } + + + sio_stop(sio); + sio_close(sio); + + free(left); + free(right); + free(buf); + + return 0; +} -- cgit v1.2.3