diff --git a/README.md b/README.md index 3758b42..628aebb 100644 --- a/README.md +++ b/README.md @@ -39,15 +39,18 @@ Build requirements * [ALSA dev files](http://alsa-project.org/) * [FFTW](http://www.fftw.org/) +* ncursesw dev files Debian/Raspbian users can install this with: - apt-get install libfftw3-dev libasound2-dev + apt-get install libfftw3-dev libasound2-dev libncursesw5-dev ArchLinux users can install this with: pacman -S base-devel fftw +Unfortunately I don't know how to install ncursesw in arch, will figure it out soon! + Getting started --------------- diff --git a/cava.c b/cava.c index 53e02db..60fd42f 100644 --- a/cava.c +++ b/cava.c @@ -1,6 +1,8 @@ +#define _XOPEN_SOURCE_EXTENDED #include #include #include +#include #include #include #include @@ -19,6 +21,9 @@ #include #include #include +#include "ncursesw/curses.h" +#include + #ifdef __GNUC__ // curses.h or other sources may already define @@ -41,11 +46,11 @@ int rc; // general: cleanup void cleanup() { - printf("\033[0m\n"); system("setfont /usr/share/consolefonts/Lat2-Fixed16.psf.gz >/dev/null 2>&1"); system("setterm -cursor on"); system("setterm -blank 10"); system("clear"); + endwin(); rc = tcsetattr(0, TCSAFLUSH, &oldtio); } @@ -250,28 +255,25 @@ int main(int argc, char **argv) float fc[200]; float fr[200]; int lcf[200], hcf[200]; - float f[200]; - float fmem[200]; + int f[200]; + int fmem[200]; int flast[200]; + int flastd[200]; float peak[201]; int y[M / 2 + 1]; long int lpeak, hpeak; int bands = 25; int sleep = 0; - int i, n, o, bw, width, height, c, rest, virt, fixedbands; + int i, n, o, bw, width, height, h, w, hs, ws, c, rest, virt, fixedbands, q; int autoband = 1; float temp; - struct winsize w; double in[2 * (M / 2 + 1)]; fftw_complex out[M / 2 + 1][2]; fftw_plan p; char *color; - int col = 36; + int col = 6; int bgcol = 0; int sens = 100; - #ifndef DEBUG - int move = 0; - #endif int fall[200]; float fpeak[200]; float k[200]; @@ -280,6 +282,7 @@ int main(int argc, char **argv) float smooth[64] = {5, 4.5, 4, 3, 2, 1.5, 1.25, 1.5, 1.5, 1.25, 1.25, 1.5, 1.25, 1.25, 1.5, 2, 2, 1.75, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.75, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; float sm = 1.25; //min val from the above array struct timespec req = { .tv_sec = 0, .tv_nsec = 0 }; + const wchar_t* bars[] = {L"\u2581", L"\u2582", L"\u2583", L"\u2584", L"\u2585", L"\u2586", L"\u2587", L"\u2588"}; char *usage = "\n\ Usage : " PACKAGE " [options]\n\ Visualize audio input in terminal. \n\ @@ -302,12 +305,7 @@ Options:\n\ setlocale(LC_ALL, ""); - for (i = 0; i < 200; i++) { - flast[i] = 0; - fall[i] = 0; - fpeak[i] = 0; - fmem[i] = 0; - } + for (i = 0; i < M; i++)shared[i] = 0; // general: handle command-line arguments @@ -358,14 +356,14 @@ Options:\n\ case 'c': // argument: foreground color col = 0; color = optarg; - if (strcmp(color, "black") == 0) col = 30; - if (strcmp(color, "red") == 0) col = 31; - if (strcmp(color, "green") == 0) col = 32; - if (strcmp(color, "yellow") == 0) col = 33; - if (strcmp(color, "blue") == 0) col = 34; - if (strcmp(color, "magenta") == 0) col = 35; - if (strcmp(color, "cyan") == 0) col = 36; - if (strcmp(color, "white") == 0) col = 37; + if (strcmp(color, "black") == 0) col = 0; + if (strcmp(color, "red") == 0) col = 1; + if (strcmp(color, "green") == 0) col = 2; + if (strcmp(color, "yellow") == 0) col = 3; + if (strcmp(color, "blue") == 0) col = 4; + if (strcmp(color, "magenta") == 0) col = 5; + if (strcmp(color, "cyan") == 0) col = 6; + if (strcmp(color, "white") == 0) col = 7; if (col == 0) { cleanup(); fprintf(stderr, "color %s not supported\n", color); @@ -375,14 +373,14 @@ Options:\n\ case 'C': // argument: background color bgcol = 0; color = optarg; - if (strcmp(color, "black") == 0) bgcol = 40; - if (strcmp(color, "red") == 0) bgcol = 41; - if (strcmp(color, "green") == 0) bgcol = 42; - if (strcmp(color, "yellow") == 0) bgcol = 43; - if (strcmp(color, "blue") == 0) bgcol = 44; - if (strcmp(color, "magenta") == 0) bgcol = 45; - if (strcmp(color, "cyan") == 0) bgcol = 46; - if (strcmp(color, "white") == 0) bgcol = 47; + if (strcmp(color, "black") == 0) bgcol = 0; + if (strcmp(color, "red") == 0) bgcol = 1; + if (strcmp(color, "green") == 0) bgcol = 2; + if (strcmp(color, "yellow") == 0) bgcol = 3; + if (strcmp(color, "blue") == 0) bgcol = 4; + if (strcmp(color, "magenta") == 0) bgcol = 5; + if (strcmp(color, "cyan") == 0) bgcol = 6; + if (strcmp(color, "white") == 0) bgcol = 7; if (bgcol == 0) { cleanup(); fprintf(stderr, "color %s not supported\n", color); @@ -454,45 +452,54 @@ Options:\n\ p = fftw_plan_dft_r2c_1d(M, in, *out, FFTW_MEASURE); //planning to rock // output: get terminal's geometry - ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + initscr(); + timeout(0); + while (1) {//jumbing back to this loop means that you resized the screen + for (i = 0; i < 200; i++) { + flast[i] = 0; + flastd[i] = 0; + fall[i] = 0; + fpeak[i] = 0; + fmem[i] = 0; + } + + clear(); + //getting orignial numbers of bands incase of resize if (autoband == 1) { bands = 25; } else bands = fixedbands; + + getmaxyx(stdscr,hs,ws); + - if (bands > (int)w.ws_col / 2 - 1)bands = (int)w.ws_col / 2 - - 1; //handle for user setting to many bars - height = (int)w.ws_row - 1; - width = (int)w.ws_col - bands - 1; - #ifndef DEBUG - int matrix[width][height]; - for (i = 0; i < width; i++) { - for (n = 0; n < height; n++) { - matrix[i][n] = 0; - } - } - #endif + if (bands > ws / 2 - 1)bands = ws / 2 - + 1; //handle for user setting to many bars + height = hs - 1; + width = ws - bands - 1; bw = width / bands; // process [smoothing]: calculate gravity - g = ((float)height / 1000) * pow((60 / (float)framerate), 2.5); + g = ((float)height / 400) * pow((60 / (float)framerate), 2.5); //if no bands are selected it tries to padd the default 20 if there is extra room - if (autoband == 1) bands = bands + (((w.ws_col) - (bw * bands + bands - 1)) / + if (autoband == 1) bands = bands + ((ws - (bw * bands + bands - 1)) / (bw + 1)); - width = (int)w.ws_col - bands - 1; + + width = width - bands - 1; + //checks if there is stil extra room, will use this to center - rest = (((w.ws_col) - (bw * bands + bands - 1))); + rest = (((ws) - (bw * bands + bands - 1)) / 2) - 1; if (rest < 0)rest = 0; #ifdef DEBUG printf("hoyde: %d bredde: %d bands:%d bandbredde: %d rest: %d\n", - (int)w.ws_row, - (int)w.ws_col, bands, bw, rest); + wh, + ws, bands, bw, rest); #endif // process: calculate cutoff frequencies @@ -521,7 +528,8 @@ Options:\n\ // process: weigh signal to frequencies for (n = 0; n < bands; - n++)k[n] = pow(fc[n],0.62) * (float)height/(M*2000); + n++)k[n] = pow(fc[n],0.62) * ((float)height/(M*2000)) * 8 * ((float)sens / + 100); // output: prepare screen virt = system("setfont cava.psf >/dev/null 2>&1"); @@ -529,26 +537,10 @@ Options:\n\ system("setterm -cursor off"); system("setterm -blank 0"); - // output: reset console - printf("\033[0m\n"); - system("clear"); - - printf("\033[%dm", col); //setting color - - printf("\033[1m"); //setting "bright" color mode, looks cooler... I think - if (bgcol != 0) - printf("\033[%dm", bgcol); - { - for (n = (height); n >= 0; n--) { - for (i = 0; i < width + bands; i++) { - - printf(" ");//setting backround color - - } - printf("\n"); - } - printf("\033[%dA", height); //moving cursor back up - } + start_color(); + init_pair(1, col, bgcol); + bkgd(COLOR_PAIR(1)); + attron(COLOR_PAIR(1)); #endif @@ -556,7 +548,7 @@ Options:\n\ while (1) { // general: keyboard controls - if ((ch = getchar()) != EOF) { + if ((ch = getch()) != EOF) { switch (ch) { case 's': scientificMode = !scientificMode; @@ -567,12 +559,13 @@ Options:\n\ } } + // output: check if terminal has been resized if (virt != 0) { - ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - if ( ((int)w.ws_row - 1) != height || ((int)w.ws_col - bands - 1) != width) { - break; - } + getmaxyx(stdscr,h,w); + if ( h != hs || w != ws) { + break; + } } #ifdef DEBUG @@ -609,38 +602,11 @@ Options:\n\ peak[o] += y[i]; //adding upp band } peak[o] = peak[o] / (hcf[o]-lcf[o]+1); //getting average - temp = peak[o] * k[o] * ((float)sens / - 100); //multiplying with k and adjusting to sens settings - if (temp > height)temp = height; //just in case + temp = peak[o] * k[o]; //multiplying with k and adjusting to sens settings + if (temp > height * 8)temp = height * 8; //just in case f[o] = temp; - //**falloff function**// - if (!scientificMode) { - if (temp < flast[o]) { - f[o] = fpeak[o] - (g * fall[o] * fall[o]); - fall[o]++; - } else if (temp >= flast[o]) { - f[o] = temp; - fpeak[o] = f[o]; - fall[o] = 0; - } - - // process [smoothing] - - fmem[o] += f[o]; - fmem[o] = fmem[o] * 0.55; - f[o] = fmem[o]; - - - flast[o] = f[o]; //memmory for falloff func - } - - if (f[o] < 0.125)f[o] = 0.125; - #ifdef DEBUG - printf("%d: f:%f->%f (%d->%d)peak:%f adjpeak: %f \n", o, fc[o], fc[o + 1], - lcf[o], hcf[o], peak[o], f[o]); - #endif } } else { //**if in sleep mode wait and continiue**// @@ -654,6 +620,7 @@ Options:\n\ continue; } + // process [smoothing] if (!scientificMode) { // process [smoothing]: monstercat-style "average" @@ -669,61 +636,73 @@ Options:\n\ f[m_y] = max(f[z] / pow(2, m_y - z), f[m_y]); } } + + for (o = 0; o < bands; o++) { + + + temp = f[o]; + + if (temp < flast[o]) { + f[o] = fpeak[o] - (g * fall[o] * fall[o]); + fall[o]++; + } else if (temp >= flast[o]) { + f[o] = temp; + fpeak[o] = f[o]; + fall[o] = 0; + } + + fmem[o] += f[o]; + fmem[o] = fmem[o] * 0.55; + f[o] = fmem[o]; + + if (f[o] < 1)f[o] = 1; + + flast[o] = f[o]; + #ifdef DEBUG + printf("%d: f:%f->%f (%d->%d)peak:%f adjpeak: %f \n", o, fc[o], fc[o + 1], + lcf[o], hcf[o], peak[o], f[o]); + #endif + } + + + + + } // output: draw processed input #ifndef DEBUG switch (om) { - case 1: - for (n = (height - 1); n >= 0; n--) { - o = 0; - move = rest / 2; //center adjustment - for (i = 0; i < width; i++) { - - // output: check if we're already at the next bar - if (i != 0 && i % bw == 0) { - o++; - if (o < bands)move++; + case 1: + + for (i = rest; i < bands; i++) { + + if(f[i] > flastd[i]){//higher then last one + for (n = flastd[i] / 8; n < f[i] / 8; n++) for (q = 0; q < bw; q++) mvaddwstr((height - n), (i * bw) + q + i, bars[7]); + if (f[i] % 8 != 0) { + if (virt == 0) for (q = 0; q < bw; q++) mvprintw( (height - n), (i*bw) + q + i, "%d",(f[i] % 8) ); + else for (q = 0; q < bw; q++) mvaddwstr( (height - n), (i*bw) + q + i, bars[(f[i] % 8) - 1]); } - - // output: draw and move to another one, check whether we're not too far - if (o < bands) { - if (f[o] - n < 0.125) { //blank - if (matrix[i][n] != 0) { //change? - if (move != 0)printf("\033[%dC", move); - move = 0; - printf(" "); - } else move++; //no change, moving along - matrix[i][n] = 0; - } else if (f[o] - n > 1) { //color - if (matrix[i][n] != 1) { //change? - if (move != 0)printf("\033[%dC", move); - move = 0; - printf("\u2588"); - } else move++; //no change, moving along - matrix[i][n] = 1; - } else { //top color, finding fraction - if (move != 0)printf("\033[%dC", move); - move = 0; - c = ((((f[o] - (float)n) - 0.125) / 0.875 * 7) + 1); - if (0 < c && c < 8) { - if (virt == 0)printf("%d", c); - else printf("%lc", L'\u2580' + c); - } else printf(" "); - matrix[i][n] = 2; - } + }else if(f[i] < flastd[i]){//lower then last one + for (n = f[i] / 8; n < flastd[i]/8 + 1; n++) for (q = 0; q < bw; q++) mvaddstr( (height - n), (i*bw) + q + i, " "); + if (f[i] % 8 != 0) { + if (virt == 0) for (q = 0; q < bw; q++) mvprintw((height - f[i] / 8), (i * bw) + q + i, "%d",(f[i] % 8) ); + else for (q = 0; q < bw; q++) mvaddwstr((height - f[i] / 8), (i * bw) + q + i, bars[(f[i] % 8) - 1]); } - } - - printf("\n"); + + flastd[i] = f[i]; //memmory for falloff func } - printf("\033[%dA", height); + + + + refresh(); break; } + req.tv_sec = 0; req.tv_nsec = (1 / (float)framerate) * 1000000000; //sleeping for set us nanosleep (&req, NULL); diff --git a/makefile b/makefile index 51a7784..a0d9bd4 100644 --- a/makefile +++ b/makefile @@ -5,7 +5,7 @@ CC = gcc CFLAGS = -std=c99 -Wall -Wextra CPPFLAGS = -DPACKAGE=\"$(PACKAGE)\" -DVERSION=\"$(VERSION)\" \ -D_POSIX_SOURCE -D _POSIX_C_SOURCE=200809L -LDLIBS = -lasound -lm -lfftw3 -lpthread +LDLIBS = -lasound -lm -lfftw3 -lpthread -lncursesw INSTALL = install INSTALL_BIN = $(INSTALL) -D -m 755