aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2013-06-13 21:46:58 +0000
committerDimitri Sokolyuk <demon@dim13.org>2013-06-13 21:46:58 +0000
commita6223a76f161033558b401935cf00cc28e877fda (patch)
treee8a8afd393ce1cb1d45f2d4ce838b875d9f650e7
parent298b3bf909c2aee84bb6514461af045ba6df4819 (diff)
split sndio
-rw-r--r--Makefile2
-rw-r--r--fft.c26
-rw-r--r--fft.h2
-rw-r--r--sio.c92
-rw-r--r--sio.h28
-rw-r--r--spectrogram.c145
6 files changed, 198 insertions, 97 deletions
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 <err.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -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 <demon@dim13.org>
+ *
+ * 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 <err.h>
+#include <stdlib.h>
+#include <sndio.h>
+
+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 <demon@dim13.org>
+ *
+ * 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 <sys/types.h>
#include <sys/time.h>
#include <err.h>
-#include <sndio.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
@@ -30,6 +29,7 @@
#include <math.h>
#include <signal.h>
+#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);