From a6223a76f161033558b401935cf00cc28e877fda Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Thu, 13 Jun 2013 21:46:58 +0000 Subject: split sndio --- Makefile | 2 +- fft.c | 26 +++++++++-- fft.h | 2 +- sio.c | 92 +++++++++++++++++++++++++++++++++++++ sio.h | 28 ++++++++++++ spectrogram.c | 145 +++++++++++++++++++++------------------------------------- 6 files changed, 198 insertions(+), 97 deletions(-) create mode 100644 sio.c create mode 100644 sio.h diff --git a/Makefile b/Makefile index f243d96..5bcfce5 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # $Id$ PROG= spectrogram -SRCS= spectrogram.c fft.c hsv2rgb.c +SRCS= spectrogram.c sio.c fft.c hsv2rgb.c HEADERS=fft.h hsv2rgb.h LIBS= fftw3 x11 PCCF!= pkg-config --cflags ${LIBS} diff --git a/fft.c b/fft.c index f39fd2a..5d02291 100644 --- a/fft.c +++ b/fft.c @@ -15,6 +15,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include #include @@ -26,8 +27,25 @@ struct fft { double *in; double *out; int n; + double *window; }; +double * +hamming(int n) +{ + double *w; + int i; + + w = calloc(n, sizeof(double)); + if (!w) + errx(1, "malloc failed"); + + for (i = 0; i < n; i++) + w[i] = 0.54 - 0.46 * cos((2 * M_PI * i) / (n - 1)); + + return w; +} + struct fft * init_fft(int n) { @@ -47,17 +65,19 @@ init_fft(int n) p[1].plan = fftw_plan_r2r_1d(n, p[1].in, p[1].out, FFTW_R2HC, FFTW_MEASURE); + p->window = hamming(n); + return p; } int -dofft(struct fft *p, int16_t *data, double *left, double *right, int n, double *wight, float scala) +dofft(struct fft *p, int16_t *data, double *left, double *right, int n, float scala) { int i; for (i = 0; i < n; i++) { - p[0].in[i] = wight[i] * data[2 * i + 0] / (double)INT16_MAX; - p[1].in[i] = wight[i] * data[2 * i + 1] / (double)INT16_MAX; + p[0].in[i] = p->window[i] * data[2 * i + 0] / (double)INT16_MAX; + p[1].in[i] = p->window[i] * data[2 * i + 1] / (double)INT16_MAX; } fftw_execute(p[0].plan); diff --git a/fft.h b/fft.h index cf69e54..3feba73 100644 --- a/fft.h +++ b/fft.h @@ -21,6 +21,6 @@ struct fft; struct fft *init_fft(int); -int dofft(struct fft *, int16_t *, double *, double *, int, double *, float); +int dofft(struct fft *, int16_t *, double *, double *, int, float); #endif diff --git a/sio.c b/sio.c new file mode 100644 index 0000000..8776930 --- /dev/null +++ b/sio.c @@ -0,0 +1,92 @@ +/* $Id$ */ +/* + * Copyright (c) 2013 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 + +struct sio { + struct sio_hdl *sio; + struct sio_par par; +}; + +struct sio * +init_sio(int rchan, int bits, int sig) +{ + struct sio *sio; + + sio = malloc(sizeof(struct sio)); + if (!sio) + errx(1, "malloc failed"); + + sio->sio = sio_open(NULL, SIO_REC, 0); + + if (!sio->sio) + errx(1, "cannot connect to sound server, is it running?"); + + sio_initpar(&sio->par); + + sio->par.rchan = rchan; + sio->par.bits = bits; + sio->par.le = SIO_LE_NATIVE; + sio->par.sig = sig; + + if (!sio_setpar(sio->sio, &sio->par)) + errx(1, "SIO set params failed"); + if (!sio_getpar(sio->sio, &sio->par)) + errx(1, "SIO get params failed"); + + if (sio->par.rchan != rchan || + sio->par.bits != bits || + sio->par.le != SIO_LE_NATIVE || + sio->par.sig != sig) + errx(1, "unsupported audio params"); + + sio_start(sio->sio); + + return sio; +} + +unsigned int +get_round(struct sio *sio) +{ + return sio->par.round; +} + +int +read_sio(struct sio *sio, int16_t *buffer, size_t sz) +{ + int done = 0; + + do { + done += sio_read(sio->sio, buffer, sz); + if (sio_eof(sio->sio)) + errx(1, "SIO EOF"); + buffer += done; + sz -= done; + } while (sz); + + return done; +} + +void +del_sio(struct sio *sio) +{ + sio_stop(sio->sio); + sio_close(sio->sio); + free(sio); +} diff --git a/sio.h b/sio.h new file mode 100644 index 0000000..c771dd1 --- /dev/null +++ b/sio.h @@ -0,0 +1,28 @@ +/* $Id$ */ +/* + * Copyright (c) 2013 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. + */ + +#ifndef __SIO_H +#define __SIO_H + +struct sio; + +struct sio *init_sio(int, int, int); +unsigned int get_round(struct sio *); +int read_sio(struct sio *, int16_t *, size_t); +void del_sio(struct sio *); + +#endif diff --git a/spectrogram.c b/spectrogram.c index 7f3189f..1b514ba 100644 --- a/spectrogram.c +++ b/spectrogram.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -30,6 +29,7 @@ #include #include +#include "sio.h" #include "fft.h" #include "hsv2rgb.h" @@ -37,6 +37,10 @@ #define SSIZE (PSIZE >> 1) #define GAP 2 +#define RCHAN 2 +#define BITS 16 +#define SIGNED 1 + extern char *__progname; Display *dsp; @@ -46,7 +50,6 @@ GC gc; Pixmap pix, bg; int width, height; -unsigned long *wf, *sp, black, white; XRectangle wf_from, wf_to; /* waterfall blit */ XRectangle wf_left, wf_right; /* waterfall */ @@ -54,6 +57,18 @@ XRectangle sp_left, sp_right; /* spectrogram */ int die = 0; +struct data { + int16_t *buffer; + size_t bufsz; + double *left; + double *right; + int maxval; + unsigned long *wf; + unsigned long *sp; + unsigned long black; + unsigned long white; +}; + void init_rect(int w, int h, int ssz) { @@ -133,12 +148,12 @@ init_palette(float h, float dh, float s, float ds, float v, float dv, int n, int } void -createbg(void) +createbg(struct data *data) { int y; for (y = 0; y < sp_left.height; y++) { - XSetForeground(dsp, gc, sp[y]); + XSetForeground(dsp, gc, data->sp[y]); XDrawLine(dsp, bg, gc, sp_left.x, sp_left.y + sp_left.height - y - 1, sp_left.x + sp_left.width - 1, @@ -149,8 +164,10 @@ createbg(void) sp_right.x, sp_right.y); } +#define LIMIT(val, maxval) ((val) > (maxval) ? (maxval) : (val)) + int -draw(double *left, double *right, int p, int step) +draw(struct data *data) { int x, l, r, lx, rx; @@ -163,23 +180,22 @@ draw(double *left, double *right, int p, int step) XCopyArea(dsp, bg, pix, gc, sp_left.x, sp_left.y, width, sp_left.height, sp_left.x, sp_left.y); - for (x = 0; x < wf_left.width; x++) { - l = left[x] > p ? p : left[x]; - r = right[x] > p ? p : right[x]; + l = LIMIT(data->left[x], data->maxval); + r = LIMIT(data->right[x], data->maxval); lx = wf_left.x + wf_left.width - x - 1; rx = wf_right.x + x; /* waterfall */ - XSetForeground(dsp, gc, wf[l]); + XSetForeground(dsp, gc, data->wf[l]); XDrawPoint(dsp, pix, gc, lx, wf_left.y); - XSetForeground(dsp, gc, wf[r]); + XSetForeground(dsp, gc, data->wf[r]); XDrawPoint(dsp, pix, gc, rx, wf_right.y); /* spectrogram neg mask */ - XSetForeground(dsp, gc, black); + XSetForeground(dsp, gc, data->black); XDrawLine(dsp, pix, gc, lx, sp_left.y, lx, sp_left.y + sp_left.height - l - 1); @@ -194,22 +210,6 @@ draw(double *left, double *right, int p, int step) return 0; } -double * -init_hamming(int n) -{ - double *w; - int i; - - w = calloc(n, sizeof(double)); - if (!w) - errx(1, "malloc failed"); - - 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) { @@ -230,23 +230,17 @@ int main(int argc, char **argv) { - int scr; Atom delwin; + int scr; - struct sio_hdl *sio; - struct sio_par par; + struct sio *sio; struct fft *fft; + struct data data; - double *left, *right; - double *hamming; float scala = 2.0; - int16_t *buffer; - size_t bufsz; - size_t done; - int ch, dflag = 1; - int delta, resolution, fps; + int delta; int psize, ssize; while ((ch = getopt(argc, argv, "hd")) != -1) @@ -266,48 +260,25 @@ main(int argc, char **argv) if (!dsp) errx(1, "Cannot connect to X11 server"); scr = DefaultScreen(dsp); - black = BlackPixel(dsp, scr); - white = WhitePixel(dsp, scr); + data.black = BlackPixel(dsp, scr); + data.white = WhitePixel(dsp, scr); cmap = DefaultColormap(dsp, scr); signal(SIGINT, catch); - sio = sio_open(NULL, SIO_REC, 0); - if (!sio) - errx(1, "cannot connect to sound server, is it running?"); - - sio_initpar(&par); - - par.rchan = 2; - par.bits = 16; - par.le = SIO_LE_NATIVE; - par.sig = 1; - - if (!sio_setpar(sio, &par)) - errx(1, "SIO set params failed"); - if (!sio_getpar(sio, &par)) - errx(1, "SIO get params failed"); - - if (par.rchan != 2 || - par.bits != 16 || - par.le != SIO_LE_NATIVE || - par.sig != 1) - errx(1, "unsupported audio params"); + sio = init_sio(RCHAN, BITS, SIGNED); #if 0 if (dflag) daemon(0, 0); #endif - delta = par.round; - resolution = (par.rate / par.round) / par.rchan; - fps = (par.rate / par.round) * par.rchan; - + delta = get_round(sio); width = delta + 2 * GAP; height = 3 * width / 4; win = XCreateSimpleWindow(dsp, RootWindow(dsp, scr), 0, 0, - width, height, 2, white, black); + width, height, 2, data.white, data.black); XStoreName(dsp, win, __progname); delwin = XInternAtom(dsp, "WM_DELETE_WINDOW", 0); XSetWMProtocols(dsp, win, &delwin, 1); @@ -321,42 +292,33 @@ main(int argc, char **argv) XSelectInput(dsp, win, ExposureMask|KeyPressMask); XMapWindow(dsp, win); - bufsz = par.rchan * delta * sizeof(int16_t); - buffer = malloc(bufsz); - if (!buffer) + data.bufsz = RCHAN * delta * sizeof(int16_t); /* par.rchan */ + data.buffer = malloc(data.bufsz); + if (!data.buffer) errx(1, "malloc failed"); - left = calloc(delta, sizeof(double)); - right = calloc(delta, sizeof(double)); - if (!left || !right) + data.left = calloc(delta, sizeof(double)); + data.right = calloc(delta, sizeof(double)); + if (!data.left || !data.right) errx(1, "malloc failed"); psize = 2 * height / 3; ssize = psize >> 2; + data.maxval = ssize; init_rect(width, height, ssize); - sp = init_palette(0.30, 0.00, 0.50, 1.00, 0.75, 1.00, ssize, 0); - wf = init_palette(0.65, 0.35, 1.00, 0.00, 0.00, 1.00, ssize, 1); + data.sp = init_palette(0.30, 0.00, 0.50, 1.00, 0.75, 1.00, ssize, 0); + data.wf = init_palette(0.65, 0.35, 1.00, 0.00, 0.00, 1.00, ssize, 1); - createbg(); + createbg(&data); fft = init_fft(delta); - hamming = init_hamming(delta); - - sio_start(sio); - done = 0; while (!die) { - do { - done += sio_read(sio, buffer + done, bufsz - done); - if (sio_eof(sio)) - errx(1, "SIO EOF"); - } while (done < bufsz); - done -= bufsz; - - dofft(fft, buffer, left, right, delta, hamming, scala); - draw(left, right, ssize, resolution); + read_sio(sio, data.buffer, data.bufsz); + dofft(fft, data.buffer, data.left, data.right, delta, scala); + draw(&data); while (XPending(dsp)) { XEvent ev; @@ -390,12 +352,11 @@ main(int argc, char **argv) } } - sio_stop(sio); - sio_close(sio); + del_sio(sio); - free(left); - free(right); - free(buffer); + free(data.left); + free(data.right); + free(data.buffer); XCloseDisplay(dsp); -- cgit v1.2.3