diff --git a/README.md b/README.md new file mode 100644 index 0000000..918cb09 --- /dev/null +++ b/README.md @@ -0,0 +1,43 @@ +# mvc + +An MPD music visualizer, based on curses. It works by reading the fifo output of an MPD instance. +At the moment it performs a Fast Fourier Transform of the raw PCM data provided by MPD, but a beat detection is going to be implemented to gain more precision. + +## Requirements + +The fifo output of MPD needs to be enabled. To do so, simply place this in your mpd.conf: + +``` +audio_output { + type "fifo" + name "my_fifo" + path "/tmp/mpd.fifo" + format "44100:16:1" +} +``` +This is allowing MPD to create a file (the location is hardcoded right now so it must be /tmp/mpd.fifo) and write it with raw PCM data in realtime. +Path and format variables MUST be the same displayed above. +By reading that, mvc is able to compute a frequency spectrum of the current track played. + +## Building + +Makefile-based. +``` +make all +``` + +To install: +``` +sudo make install +``` + +## Usage + +Simply run: + +``` +mvc +``` + +Note that an instance of MPD must be running for mvc to work, otherwise the fifo file doesn't exist. + diff --git a/fft.c b/fft.c new file mode 100644 index 0000000..dc6989d --- /dev/null +++ b/fft.c @@ -0,0 +1,136 @@ +#include "fft.h" +/* if flag is EVEN (0), it takes only the even elements + * otherwise if flag is ODD (1) it takes only the odd ones + */ +cplx *split_array(cplx *a, int len, int flag) +{ + int i, cnt = 0; + cplx *ret = malloc((len/2)*sizeof(cplx)); + + for(i=0+flag; i +#include // malloc +#include +#include +#include // uint16_t + +#define PI acos(-1.0) // even if it is defined as M_PI in math.h, this is more precise computationally +#define EVEN 0 +#define ODD 1 + +typedef double complex cplx; + +cplx *split_array(cplx *a, int len, int flag); +cplx *_fast_ft(cplx *compArray, int len); +void print_components(cplx *a, int len); +unsigned int amplitude(cplx c); +unsigned int* fast_fft(int inLen, uint16_t *sig); +unsigned int* average_signal(unsigned int *fftBuf, int inLen, int maxC, int *avgLen); diff --git a/makefile b/makefile new file mode 100644 index 0000000..cc33fd0 --- /dev/null +++ b/makefile @@ -0,0 +1,28 @@ +ALL = fft.c utils_curses.c music_visualizer.c +LOCPATH = ./bin +INSTALLPATH = /usr/local +LFLAGS = -lm -lcurses +DEBFLAGS = -g -Wall +NAME = mvc + +all: + mkdir -p $(LOCPATH) + gcc $(ALL) -o $(LOCPATH)/$(NAME) $(LFLAGS) +debug: + mkdir -p $(LOCPATH)/debug + gcc $(ALL) -o $(LOCPATH)/debug/$(NAME)_debug $(LFLAGS) $(DEBFLAGS) +asan: + gcc $(ALL) -o $(LOCPATH)/debug/$(NAME)_debug_asan $(LFLAGS) $(DEBFLAGS) -fsanitize=address +clean: + rm $(LOCPATH)/$(NAME) + rm $(LOCPATH)/debug/$(NAME)_debug +distclean: + rm -r $(LOCPATH) +install: + cp $(LOCPATH)/$(NAME) $(INSTALLPATH)/bin/$(NAME) +uninstall: + rm $(INSTALLPATH)/bin/$(NAME) + + + + diff --git a/music_visualizer.c b/music_visualizer.c new file mode 100644 index 0000000..2606c91 --- /dev/null +++ b/music_visualizer.c @@ -0,0 +1,51 @@ +#include +#include // exit +#include // read +#include // open +#include // open +#include // uint16_t +#include "fft.h" // fast fourier transform +#include "utils_curses.h" + +/*FREQ 44100*/ +#define N_SAMPLES 1024 +/*FPS FREQ/N_SAMPLES*/ + +int +main(int argc, char *argv[]) +{ + int fifo, i; + WINDOW *mainwin; + int maxR, maxC, avgLen; //curses + uint16_t buf[N_SAMPLES]; + unsigned int *fftBuf, *fftAvg; + + fifo = open("/tmp/mpd.fifo", O_RDONLY); + + if((mainwin = curses_init()) == NULL){ + exit(EXIT_FAILURE); + } + getmaxyx(stdscr, maxR, maxC); + color_set(2, NULL); + mvprintw(maxR/2, maxC/2, "%d %d\n", maxR, maxC); + refresh(); + + while(read(fifo, (uint16_t*)buf, 2*N_SAMPLES) != 0){ + + fftBuf = fast_fft(N_SAMPLES, (uint16_t*)buf); + fftAvg = average_signal(fftBuf, N_SAMPLES, maxC, &avgLen); + free(fftBuf); + + for(i=0; il; row--){ + mvaddch(row, col, SHARP); + } +} + diff --git a/utils_curses.h b/utils_curses.h new file mode 100644 index 0000000..d7ee544 --- /dev/null +++ b/utils_curses.h @@ -0,0 +1,7 @@ +#include + +#define SHARP '#' + +void init_color_pairs(); +WINDOW* curses_init(); +void print_col(int col, int length, int maxR);