Skip to content

Commit

Permalink
added config option: x-axis scale (frequency) karlstav#289
Browse files Browse the repository at this point in the history
only added frequency for now, will look at notes later

also fixed some bugs in the frequency calculation, the "push spectrum
if clumped" where causing too high frequencies to still use the bass
buffers. There was also a +1 too many causing bars to be one off
compared to the calculated frequency.
  • Loading branch information
karlstav committed Sep 7, 2020
1 parent 1a75b17 commit 9c0c414
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 47 deletions.
135 changes: 116 additions & 19 deletions cava.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,9 @@ int main(int argc, char **argv) {
pthread_t p_thread;
int thr_id GCC_UNUSED;
float cut_off_frequency[256];
float upper_cut_off_frequency[256];
float relative_cut_off[256];
double center_frequencies[256];
int bars[256], FFTbuffer_lower_cut_off[256], FFTbuffer_upper_cut_off[256];
int *bars_left, *bars_right, *bars_mono;
int bars_mem[256];
Expand Down Expand Up @@ -553,18 +555,28 @@ as of 0.4.0 all options are specified in config file, see in '/home/username/.co
bars[n] = 0;
}

// frequencies on x axis require a bar width of four or more
if (p.xaxis == FREQUENCY && p.bar_width < 4)
p.bar_width = 4;

switch (output_mode) {
#ifdef NCURSES
// output: start ncurses mode
case OUTPUT_NCURSES:
init_terminal_ncurses(p.color, p.bcolor, p.col, p.bgcol, p.gradient,
p.gradient_count, p.gradient_colors, &width, &lines);
if (p.xaxis != NONE)
lines--;
// we have 8 times as much height due to using 1/8 block characters
height = lines * 8;
break;
#endif
case OUTPUT_NONCURSES:
get_terminal_dim_noncurses(&width, &lines);

if (p.xaxis != NONE)
lines--;

init_terminal_noncurses(inAtty, p.col, p.bgcol, width, lines, p.bar_width);
height = lines * 8;
break;
Expand Down Expand Up @@ -612,6 +624,7 @@ as of 0.4.0 all options are specified in config file, see in '/home/username/.co
exit(EXIT_FAILURE); // Can't happen.
}


// handle for user setting too many bars
if (p.fixedbars) {
p.autobars = 0;
Expand Down Expand Up @@ -673,14 +686,24 @@ as of 0.4.0 all options are specified in config file, see in '/home/username/.co
// process: calculate cutoff frequencies and eq
int bass_cut_off_bar = -1;
int treble_cut_off_bar = -1;
bool first_bar = false;
bool first_bar = true;
int first_treble_bar = 0;
int bar_buffer[number_of_bars + 1];

for (n = 0; n < number_of_bars + 1; n++) {
double bar_distribution_coefficient = frequency_constant * (-1);
bar_distribution_coefficient +=
((float)n + 1) / ((float)number_of_bars + 1) * frequency_constant;
cut_off_frequency[n] = p.upper_cut_off * pow(10, bar_distribution_coefficient);

if (n > 0) {
if (cut_off_frequency[n - 1] >= cut_off_frequency[n] &&
cut_off_frequency[n - 1] > bass_cut_off)
cut_off_frequency[n] =
cut_off_frequency[n - 1] +
(cut_off_frequency[n - 1] - cut_off_frequency[n - 2]);
}

relative_cut_off[n] = cut_off_frequency[n] / (audio.rate / 2);
// remember nyquist!, per my calculations this should be rate/2
// and nyquist freq in M/2 but testing shows it is not...
Expand All @@ -690,7 +713,7 @@ as of 0.4.0 all options are specified in config file, see in '/home/username/.co

// the numbers that come out of the FFT are verry high
// the EQ is used to "normalize" them by dividing with this verry huge number
eq[n] *= (float)height / pow(2, 29);
eq[n] *= (float)height / pow(2, 28);

if (p.userEQ_enabled)
eq[n] *= p.userEQ[(int)floor(((double)n) * userEQ_keys_to_bars_ratio)];
Expand All @@ -699,55 +722,78 @@ as of 0.4.0 all options are specified in config file, see in '/home/username/.co

if (cut_off_frequency[n] < bass_cut_off) {
// BASS
bar_buffer[n] = 1;
FFTbuffer_lower_cut_off[n] =
relative_cut_off[n] * (audio.FFTbassbufferSize / 2) + 1;
relative_cut_off[n] * (audio.FFTbassbufferSize / 2);
bass_cut_off_bar++;
treble_cut_off_bar++;
if (bass_cut_off_bar > 0)
first_bar = false;

eq[n] *= log2(audio.FFTbassbufferSize);
} else if (cut_off_frequency[n] > bass_cut_off &&
cut_off_frequency[n] < treble_cut_off) {
// MID
FFTbuffer_lower_cut_off[n] =
relative_cut_off[n] * (audio.FFTmidbufferSize / 2) + 1;
bar_buffer[n] = 2;
FFTbuffer_lower_cut_off[n] = relative_cut_off[n] * (audio.FFTmidbufferSize / 2);
treble_cut_off_bar++;
if ((treble_cut_off_bar - bass_cut_off_bar) == 1) {
first_bar = true;
FFTbuffer_upper_cut_off[n - 1] =
relative_cut_off[n] * (audio.FFTbassbufferSize / 2);
if (FFTbuffer_upper_cut_off[n - 1] < FFTbuffer_lower_cut_off[n - 1])
FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n - 1];
} else {
first_bar = false;
}

eq[n] *= log2(audio.FFTmidbufferSize);
} else {
// TREBLE
bar_buffer[n] = 3;
FFTbuffer_lower_cut_off[n] =
relative_cut_off[n] * (audio.FFTtreblebufferSize / 2) + 1;
relative_cut_off[n] * (audio.FFTtreblebufferSize / 2);
first_treble_bar++;
if (first_treble_bar == 1) {
first_bar = true;
FFTbuffer_upper_cut_off[n - 1] =
relative_cut_off[n] * (audio.FFTmidbufferSize / 2);
if (FFTbuffer_upper_cut_off[n - 1] < FFTbuffer_lower_cut_off[n - 1])
FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n - 1];
} else {
first_bar = false;
}

eq[n] *= log2(audio.FFTtreblebufferSize);
}

if (n != 0 && !first_bar) {
FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n] - 1;
if (n > 0) {
if (!first_bar) {
FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n] - 1;

// pushing the spectrum up if the exponential function gets "clumped" in the
// bass and caluclating new cut off frequencies
if (FFTbuffer_lower_cut_off[n] <= FFTbuffer_lower_cut_off[n - 1]) {

FFTbuffer_lower_cut_off[n] = FFTbuffer_lower_cut_off[n - 1] + 1;
FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n] - 1;

if (bar_buffer[n] == 1)
relative_cut_off[n] = (float)(FFTbuffer_lower_cut_off[n]) /
((float)audio.FFTbassbufferSize / 2);
else if (bar_buffer[n] == 2)
relative_cut_off[n] = (float)(FFTbuffer_lower_cut_off[n]) /
((float)audio.FFTmidbufferSize / 2);
else if (bar_buffer[n] == 3)
relative_cut_off[n] = (float)(FFTbuffer_lower_cut_off[n]) /
((float)audio.FFTtreblebufferSize / 2);

// pushing the spectrum up if the exponential function gets "clumped" in the
// bass
if (FFTbuffer_lower_cut_off[n] <= FFTbuffer_lower_cut_off[n - 1])
FFTbuffer_lower_cut_off[n] = FFTbuffer_lower_cut_off[n - 1] + 1;
FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n] - 1;
cut_off_frequency[n] = relative_cut_off[n] * ((float)audio.rate / 2);
}
} else {
if (FFTbuffer_upper_cut_off[n - 1] <= FFTbuffer_lower_cut_off[n - 1])
FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n - 1] + 1;
}
upper_cut_off_frequency[n - 1] =
cut_off_frequency[n]; // high_relative_cut_off * ((float)audio.rate / 2);
center_frequencies[n - 1] =
pow((cut_off_frequency[n - 1] * upper_cut_off_frequency[n - 1]), 0.5);
}

#ifndef NDEBUG
Expand All @@ -766,6 +812,56 @@ as of 0.4.0 all options are specified in config file, see in '/home/username/.co
if (p.stereo)
number_of_bars = number_of_bars * 2;

int x_axis_info = 0;

if (p.xaxis != NONE) {
x_axis_info = 1;
double center_frequency;
if (output_mode == OUTPUT_NONCURSES) {
printf("\r\033[%dB", lines + 1);
if (rest)
printf("\033[%dC", rest);
}
for (n = 0; n < number_of_bars; n++) {
if (p.stereo) {
if (n < number_of_bars / 2)
center_frequency = center_frequencies[number_of_bars / 2 - 1 - n];
else
center_frequency = center_frequencies[n - number_of_bars / 2];
} else {
center_frequency = center_frequencies[n];
}

float freq_kilohz = center_frequency / 1000;
int freq_floor = center_frequency;

if (output_mode == OUTPUT_NCURSES) {
#ifdef NCURSES
if (center_frequency < 1000)
mvprintw(lines, n * (p.bar_width + p.bar_spacing) + rest, "%-4d",
freq_floor);
else if (center_frequency > 1000 && center_frequency < 10000)
mvprintw(lines, n * (p.bar_width + p.bar_spacing) + rest, "%.2f",
freq_kilohz);
else
mvprintw(lines, n * (p.bar_width + p.bar_spacing) + rest, "%.1f",
freq_kilohz);
#endif
} else if (output_mode == OUTPUT_NONCURSES) {
if (center_frequency < 1000)
printf("%-4d", freq_floor);
else if (center_frequency > 1000 && center_frequency < 10000)
printf("%.2f", freq_kilohz);
else
printf("%.1f", freq_kilohz);

if (n < number_of_bars - 1)
printf("\033[%dC", p.bar_width + p.bar_spacing - 4);
}
}
printf("\r\033[%dA", lines + 1);
}

bool resizeTerminal = false;
// fcntl(0, F_SETFL, O_NONBLOCK);

Expand Down Expand Up @@ -1030,12 +1126,13 @@ as of 0.4.0 all options are specified in config file, see in '/home/username/.co
#ifdef NCURSES
rc = draw_terminal_ncurses(inAtty, lines, width, number_of_bars, p.bar_width,
p.bar_spacing, rest, bars, previous_frame,
p.gradient);
p.gradient, x_axis_info);
break;
#endif
case OUTPUT_NONCURSES:
rc = draw_terminal_noncurses(inAtty, lines, width, number_of_bars, p.bar_width,
p.bar_spacing, rest, bars, previous_frame);
p.bar_spacing, rest, bars, previous_frame,
x_axis_info);
break;
case OUTPUT_RAW:
rc = print_raw_out(number_of_bars, fp, p.is_bin, p.bit_format, p.ascii_range,
Expand Down
Binary file modified cava.psf
Binary file not shown.
14 changes: 13 additions & 1 deletion config.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ enum input_method default_methods[] = {
INPUT_PULSE,
};

char *outputMethod, *channels;
char *outputMethod, *channels, *xaxisScale;

const char *input_method_names[] = {
"fifo", "portaudio", "alsa", "pulse", "sndio", "shmem",
Expand Down Expand Up @@ -234,6 +234,17 @@ bool validate_config(struct config_params *p, struct error_s *error) {
#endif
}

p->xaxis = NONE;
if (strcmp(xaxisScale, "none") == 0) {
p->xaxis = NONE;
}
if (strcmp(xaxisScale, "frequency") == 0) {
p->xaxis = FREQUENCY;
}
if (strcmp(xaxisScale, "note") == 0) {
p->xaxis = NOTE;
}

// validate: output channels
p->stereo = -1;
if (strcmp(channels, "mono") == 0) {
Expand Down Expand Up @@ -426,6 +437,7 @@ bool load_config(char configPath[PATH_MAX], struct config_params *p, bool colors
outputMethod = (char *)iniparser_getstring(ini, "output:method", "noncurses");
#endif

xaxisScale = (char *)iniparser_getstring(ini, "output:xaxis", "none");
p->monstercat = 1.5 * iniparser_getdouble(ini, "smoothing:monstercat", 0);
p->waves = iniparser_getint(ini, "smoothing:waves", 0);
p->integral = iniparser_getdouble(ini, "smoothing:integral", 77);
Expand Down
3 changes: 3 additions & 0 deletions config.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ enum input_method {

enum output_method { OUTPUT_NCURSES, OUTPUT_NONCURSES, OUTPUT_RAW, OUTPUT_NOT_SUPORTED };

enum xaxis_scale { NONE, FREQUENCY, NOTE };

struct config_params {
char *color, *bcolor, *raw_target, *audio_source,
/**gradient_color_1, *gradient_color_2,*/ **gradient_colors, *data_format, *mono_option;
Expand All @@ -54,6 +56,7 @@ struct config_params {
double *userEQ;
enum input_method im;
enum output_method om;
enum xaxis_scale xaxis;
int userEQ_keys, userEQ_enabled, col, bgcol, autobars, stereo, is_bin, ascii_range, bit_format,
gradient, gradient_count, fixedbars, framerate, bar_width, bar_spacing, autosens, overshoot,
waves, FFTbufferSize, fifoSample, fifoSampleBits;
Expand Down
27 changes: 16 additions & 11 deletions output/terminal_ncurses.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ struct colors {

#define MAX_COLOR_REDEFINITION 256

const wchar_t *bar_heights[] = {L"\u2581", L"\u2582", L"\u2583", L"\u2584",
L"\u2585", L"\u2586", L"\u2587", L"\u2588"};
int num_bar_heights = (sizeof(bar_heights) / sizeof(bar_heights[0]));

// static struct colors the_color_redefinitions[MAX_COLOR_REDEFINITION];

static void parse_color(char *color_string, struct colors *color) {
Expand Down Expand Up @@ -188,24 +192,25 @@ void get_terminal_dim_ncurses(int *width, int *height) {
#define TERMINAL_RESIZED -1

int draw_terminal_ncurses(int is_tty, int terminal_height, int terminal_width, int bars_count,
int bar_width, int bar_spacing, int rest, const int f[200],
int flastd[200], int gradient) {
int bar_width, int bar_spacing, int rest, const int bars[256],
int previous_frame[200], int gradient, int x_axis_info) {
const int height = terminal_height - 1;
const wchar_t *bar_heights[] = {L"\u2581", L"\u2582", L"\u2583", L"\u2584",
L"\u2585", L"\u2586", L"\u2587", L"\u2588"};
int num_bar_heights = (sizeof(bar_heights) / sizeof(bar_heights[0]));

// output: check if terminal has been resized
if (!is_tty) {
if (x_axis_info)
terminal_height++;
if (LINES != terminal_height || COLS != terminal_width) {
return TERMINAL_RESIZED;
if (x_axis_info)
terminal_height--;
}
}

// Compute how much of the screen we possibly need to update ahead-of-time.
int max_update_y = 0;
for (int bar = 0; bar < bars_count; bar++) {
max_update_y = max(max_update_y, max(f[bar], flastd[bar]));
max_update_y = max(max_update_y, max(bars[bar], previous_frame[bar]));
}

max_update_y = (max_update_y + num_bar_heights) / num_bar_heights;
Expand All @@ -216,20 +221,20 @@ int draw_terminal_ncurses(int is_tty, int terminal_height, int terminal_width, i
}

for (int bar = 0; bar < bars_count; bar++) {
if (f[bar] == flastd[bar]) {
if (bars[bar] == previous_frame[bar]) {
continue;
}

int cur_col = bar * bar_width + bar * bar_spacing + rest;
int f_cell = (f[bar] - 1) / num_bar_heights;
int f_last_cell = (flastd[bar] - 1) / num_bar_heights;
int f_cell = (bars[bar] - 1) / num_bar_heights;
int f_last_cell = (previous_frame[bar] - 1) / num_bar_heights;

if (f_cell >= y) {
int bar_step;

if (f_cell == y) {
// The "cap" of the bar occurs at this [y].
bar_step = (f[bar] - 1) % num_bar_heights;
bar_step = (bars[bar] - 1) % num_bar_heights;
} else if (f_last_cell <= y) {
// The bar is full at this [y].
bar_step = num_bar_heights - 1;
Expand All @@ -240,7 +245,7 @@ int draw_terminal_ncurses(int is_tty, int terminal_height, int terminal_width, i

for (int col = cur_col, i = 0; i < bar_width; i++, col++) {
if (is_tty) {
mvaddch(height - y, col, '1' + bar_step);
mvaddch(height - y, col, 0x41 + bar_step);
} else {
mvaddwstr(height - y, col, bar_heights[bar_step]);
}
Expand Down
4 changes: 2 additions & 2 deletions output/terminal_ncurses.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ void init_terminal_ncurses(char *const fg_color_string, char *const bg_color_str
int gradient_count, char **gradient_colors, int *width, int *height);
void get_terminal_dim_ncurses(int *width, int *height);
int draw_terminal_ncurses(int is_tty, int terminal_height, int terminal_width, int bars_count,
int bar_width, int bar_spacing, int rest, const int f[200],
int flastd[200], int gradient);
int bar_width, int bar_spacing, int rest, const int bars[256],
int previous_frame[256], int gradient, int x_axis_info);
void cleanup_terminal_ncurses(void);
Loading

0 comments on commit 9c0c414

Please sign in to comment.