commit 552d6c5895108b409510da2b2fa3e1f5c13e3958
Author: sin <sin@2f30.org>
Date: Sun, 17 Nov 2013 16:07:35 +0000
Initial commit
Diffstat:
A | Makefile | | | 11 | +++++++++++ |
A | spectrum.c | | | 173 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 184 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -0,0 +1,11 @@
+# mpdvis
+
+CFLAGS = -I/usr/local/include
+LDFLAGS = -L/usr/local/lib
+LDLIBS = -lcurses -lfftw3
+
+BIN = spectrum
+all: $(BIN)
+
+clean:
+ rm -f $(BIN)
diff --git a/spectrum.c b/spectrum.c
@@ -0,0 +1,173 @@
+/* $Id: spectrum.c,v 1.1 2013/11/16 22:23:36 lostd Exp $ */
+
+/*
+ * ~/.mpdconf:
+ * audio_output {
+ * type "fifo"
+ * name "myfifo"
+ * path "~/.mpd/mpd.fifo"
+ * format "44100:16:1"
+ * }
+ */
+
+#include <err.h>
+#include <curses.h>
+#include <fcntl.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <fftw3.h>
+
+unsigned usec = 1000000 / 25; /* 25 fps */
+unsigned samples = 2048; /* mono */
+int samplerate = 44100;
+int bits = 16;
+int channels = 1;
+char symbol = '|';
+int die = 0;
+char *fname = NULL;
+
+struct frame {
+ int fd;
+ size_t width;
+ size_t height;
+ size_t nresult;
+ unsigned *res;
+ double *in;
+ fftw_complex *out;
+ fftw_plan plan;
+};
+
+void
+auvis_init(struct frame *fr)
+{
+ fr->fd = open(fname, O_RDONLY | O_NONBLOCK);
+ if (fr->fd == -1)
+ err(1, "open");
+
+ fr->nresult = samples / 2 + 1;
+ fr->res = malloc(fr->nresult * sizeof(unsigned));
+ fr->in = fftw_malloc(samples * sizeof(double));
+ fr->out = fftw_malloc(fr->nresult * sizeof(fftw_complex));
+ fr->plan = fftw_plan_dft_r2c_1d(samples, fr->in, fr->out, FFTW_ESTIMATE);
+}
+
+void
+auvis_done(struct frame *fr)
+{
+ fftw_destroy_plan(fr->plan);
+ fftw_free(fr->in);
+ fftw_free(fr->out);
+
+ free(fr->res);
+
+ close(fr->fd);
+}
+
+void
+auvis_update(struct frame *fr)
+{
+ int16_t buf[samples];
+ ssize_t n, nsamples;
+ unsigned i, j;
+
+ n = read(fr->fd, buf, sizeof(buf));
+ if (n == -1)
+ return;
+
+ nsamples = n / sizeof(int16_t);
+
+ for (i = 0, j = 0; i < samples; i++) {
+ if (j < nsamples)
+ fr->in[i] = buf[j++];
+ else
+ fr->in[i] = 0;
+ }
+
+ fftw_execute(fr->plan);
+}
+
+void
+auvis_draw(struct frame *fr)
+{
+ unsigned i, j;
+ unsigned freqs_per_col;
+
+ fr->width = COLS;
+ fr->height = LINES;
+
+ /* take most of the left part of the band */
+ freqs_per_col = fr->nresult / fr->width * 6 / 10;
+
+ /* scale each frequency to screen */
+ for (i = 0; i < fr->nresult; i++)
+ fr->res[i] = sqrt(fr->out[i][0] * fr->out[i][0] +
+ fr->out[i][1] * fr->out[i][1])
+ / 100000 * fr->height / 4;
+
+ clear();
+ attron(A_BOLD);
+ for (i = 0; i < fr->width; i++) {
+ size_t bar_height = 0;
+ size_t start_y;
+ size_t stop_y;
+
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+ for (j = 0; j < freqs_per_col; j++)
+ bar_height += fr->res[i * freqs_per_col + j];
+ bar_height = MIN(bar_height / freqs_per_col, fr->height);
+ start_y = fr->height - bar_height;
+ stop_y = MIN(bar_height + start_y, fr->height);
+
+ /* output symbols */
+ for (j = start_y; j < stop_y; j++) {
+ move(j, i);
+ printw("%c", symbol);
+ }
+ }
+ attroff(A_BOLD);
+ refresh();
+}
+
+int
+main(int argc, char *argv[])
+{
+ int c, i;
+ struct frame fr;
+
+ if (argc != 2)
+ errx(1, "usage: %s mpdfifo", argv[0]);
+ fname = argv[1];
+
+ /* init fftw3 */
+ memset(&fr, 0, sizeof(fr));
+ auvis_init(&fr);
+
+ /* init curses */
+ initscr();
+ cbreak();
+ noecho();
+ nonl();
+ intrflush(stdscr, FALSE);
+ keypad(stdscr, TRUE);
+ curs_set(FALSE); /* hide cursor */
+ //nodelay(stdscr, TRUE);
+
+ while (!die) {
+ //if (getch() == 'q')
+ // die = 1;
+
+ auvis_update(&fr);
+ auvis_draw(&fr);
+ usleep(usec);
+ }
+
+ endwin(); /* restore terminal */
+
+ auvis_done(&fr); /* destroy context */
+
+ return (0);
+}