Skip to content

Commit 9c0c414

Browse files
committed
added config option: x-axis scale (frequency) karlstav#289
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.
1 parent 1a75b17 commit 9c0c414

File tree

8 files changed

+170
-47
lines changed

8 files changed

+170
-47
lines changed

cava.c

Lines changed: 116 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,9 @@ int main(int argc, char **argv) {
230230
pthread_t p_thread;
231231
int thr_id GCC_UNUSED;
232232
float cut_off_frequency[256];
233+
float upper_cut_off_frequency[256];
233234
float relative_cut_off[256];
235+
double center_frequencies[256];
234236
int bars[256], FFTbuffer_lower_cut_off[256], FFTbuffer_upper_cut_off[256];
235237
int *bars_left, *bars_right, *bars_mono;
236238
int bars_mem[256];
@@ -553,18 +555,28 @@ as of 0.4.0 all options are specified in config file, see in '/home/username/.co
553555
bars[n] = 0;
554556
}
555557

558+
// frequencies on x axis require a bar width of four or more
559+
if (p.xaxis == FREQUENCY && p.bar_width < 4)
560+
p.bar_width = 4;
561+
556562
switch (output_mode) {
557563
#ifdef NCURSES
558564
// output: start ncurses mode
559565
case OUTPUT_NCURSES:
560566
init_terminal_ncurses(p.color, p.bcolor, p.col, p.bgcol, p.gradient,
561567
p.gradient_count, p.gradient_colors, &width, &lines);
568+
if (p.xaxis != NONE)
569+
lines--;
562570
// we have 8 times as much height due to using 1/8 block characters
563571
height = lines * 8;
564572
break;
565573
#endif
566574
case OUTPUT_NONCURSES:
567575
get_terminal_dim_noncurses(&width, &lines);
576+
577+
if (p.xaxis != NONE)
578+
lines--;
579+
568580
init_terminal_noncurses(inAtty, p.col, p.bgcol, width, lines, p.bar_width);
569581
height = lines * 8;
570582
break;
@@ -612,6 +624,7 @@ as of 0.4.0 all options are specified in config file, see in '/home/username/.co
612624
exit(EXIT_FAILURE); // Can't happen.
613625
}
614626

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

679693
for (n = 0; n < number_of_bars + 1; n++) {
680694
double bar_distribution_coefficient = frequency_constant * (-1);
681695
bar_distribution_coefficient +=
682696
((float)n + 1) / ((float)number_of_bars + 1) * frequency_constant;
683697
cut_off_frequency[n] = p.upper_cut_off * pow(10, bar_distribution_coefficient);
698+
699+
if (n > 0) {
700+
if (cut_off_frequency[n - 1] >= cut_off_frequency[n] &&
701+
cut_off_frequency[n - 1] > bass_cut_off)
702+
cut_off_frequency[n] =
703+
cut_off_frequency[n - 1] +
704+
(cut_off_frequency[n - 1] - cut_off_frequency[n - 2]);
705+
}
706+
684707
relative_cut_off[n] = cut_off_frequency[n] / (audio.rate / 2);
685708
// remember nyquist!, per my calculations this should be rate/2
686709
// and nyquist freq in M/2 but testing shows it is not...
@@ -690,7 +713,7 @@ as of 0.4.0 all options are specified in config file, see in '/home/username/.co
690713

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

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

700723
if (cut_off_frequency[n] < bass_cut_off) {
701724
// BASS
725+
bar_buffer[n] = 1;
702726
FFTbuffer_lower_cut_off[n] =
703-
relative_cut_off[n] * (audio.FFTbassbufferSize / 2) + 1;
727+
relative_cut_off[n] * (audio.FFTbassbufferSize / 2);
704728
bass_cut_off_bar++;
705729
treble_cut_off_bar++;
730+
if (bass_cut_off_bar > 0)
731+
first_bar = false;
706732

707733
eq[n] *= log2(audio.FFTbassbufferSize);
708734
} else if (cut_off_frequency[n] > bass_cut_off &&
709735
cut_off_frequency[n] < treble_cut_off) {
710736
// MID
711-
FFTbuffer_lower_cut_off[n] =
712-
relative_cut_off[n] * (audio.FFTmidbufferSize / 2) + 1;
737+
bar_buffer[n] = 2;
738+
FFTbuffer_lower_cut_off[n] = relative_cut_off[n] * (audio.FFTmidbufferSize / 2);
713739
treble_cut_off_bar++;
714740
if ((treble_cut_off_bar - bass_cut_off_bar) == 1) {
715741
first_bar = true;
716742
FFTbuffer_upper_cut_off[n - 1] =
717743
relative_cut_off[n] * (audio.FFTbassbufferSize / 2);
718-
if (FFTbuffer_upper_cut_off[n - 1] < FFTbuffer_lower_cut_off[n - 1])
719-
FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n - 1];
720744
} else {
721745
first_bar = false;
722746
}
723747

724748
eq[n] *= log2(audio.FFTmidbufferSize);
725749
} else {
726750
// TREBLE
751+
bar_buffer[n] = 3;
727752
FFTbuffer_lower_cut_off[n] =
728-
relative_cut_off[n] * (audio.FFTtreblebufferSize / 2) + 1;
753+
relative_cut_off[n] * (audio.FFTtreblebufferSize / 2);
729754
first_treble_bar++;
730755
if (first_treble_bar == 1) {
731756
first_bar = true;
732757
FFTbuffer_upper_cut_off[n - 1] =
733758
relative_cut_off[n] * (audio.FFTmidbufferSize / 2);
734-
if (FFTbuffer_upper_cut_off[n - 1] < FFTbuffer_lower_cut_off[n - 1])
735-
FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n - 1];
736759
} else {
737760
first_bar = false;
738761
}
739762

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

743-
if (n != 0 && !first_bar) {
744-
FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n] - 1;
766+
if (n > 0) {
767+
if (!first_bar) {
768+
FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n] - 1;
769+
770+
// pushing the spectrum up if the exponential function gets "clumped" in the
771+
// bass and caluclating new cut off frequencies
772+
if (FFTbuffer_lower_cut_off[n] <= FFTbuffer_lower_cut_off[n - 1]) {
773+
774+
FFTbuffer_lower_cut_off[n] = FFTbuffer_lower_cut_off[n - 1] + 1;
775+
FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n] - 1;
776+
777+
if (bar_buffer[n] == 1)
778+
relative_cut_off[n] = (float)(FFTbuffer_lower_cut_off[n]) /
779+
((float)audio.FFTbassbufferSize / 2);
780+
else if (bar_buffer[n] == 2)
781+
relative_cut_off[n] = (float)(FFTbuffer_lower_cut_off[n]) /
782+
((float)audio.FFTmidbufferSize / 2);
783+
else if (bar_buffer[n] == 3)
784+
relative_cut_off[n] = (float)(FFTbuffer_lower_cut_off[n]) /
785+
((float)audio.FFTtreblebufferSize / 2);
745786

746-
// pushing the spectrum up if the exponential function gets "clumped" in the
747-
// bass
748-
if (FFTbuffer_lower_cut_off[n] <= FFTbuffer_lower_cut_off[n - 1])
749-
FFTbuffer_lower_cut_off[n] = FFTbuffer_lower_cut_off[n - 1] + 1;
750-
FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n] - 1;
787+
cut_off_frequency[n] = relative_cut_off[n] * ((float)audio.rate / 2);
788+
}
789+
} else {
790+
if (FFTbuffer_upper_cut_off[n - 1] <= FFTbuffer_lower_cut_off[n - 1])
791+
FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n - 1] + 1;
792+
}
793+
upper_cut_off_frequency[n - 1] =
794+
cut_off_frequency[n]; // high_relative_cut_off * ((float)audio.rate / 2);
795+
center_frequencies[n - 1] =
796+
pow((cut_off_frequency[n - 1] * upper_cut_off_frequency[n - 1]), 0.5);
751797
}
752798

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

815+
int x_axis_info = 0;
816+
817+
if (p.xaxis != NONE) {
818+
x_axis_info = 1;
819+
double center_frequency;
820+
if (output_mode == OUTPUT_NONCURSES) {
821+
printf("\r\033[%dB", lines + 1);
822+
if (rest)
823+
printf("\033[%dC", rest);
824+
}
825+
for (n = 0; n < number_of_bars; n++) {
826+
if (p.stereo) {
827+
if (n < number_of_bars / 2)
828+
center_frequency = center_frequencies[number_of_bars / 2 - 1 - n];
829+
else
830+
center_frequency = center_frequencies[n - number_of_bars / 2];
831+
} else {
832+
center_frequency = center_frequencies[n];
833+
}
834+
835+
float freq_kilohz = center_frequency / 1000;
836+
int freq_floor = center_frequency;
837+
838+
if (output_mode == OUTPUT_NCURSES) {
839+
#ifdef NCURSES
840+
if (center_frequency < 1000)
841+
mvprintw(lines, n * (p.bar_width + p.bar_spacing) + rest, "%-4d",
842+
freq_floor);
843+
else if (center_frequency > 1000 && center_frequency < 10000)
844+
mvprintw(lines, n * (p.bar_width + p.bar_spacing) + rest, "%.2f",
845+
freq_kilohz);
846+
else
847+
mvprintw(lines, n * (p.bar_width + p.bar_spacing) + rest, "%.1f",
848+
freq_kilohz);
849+
#endif
850+
} else if (output_mode == OUTPUT_NONCURSES) {
851+
if (center_frequency < 1000)
852+
printf("%-4d", freq_floor);
853+
else if (center_frequency > 1000 && center_frequency < 10000)
854+
printf("%.2f", freq_kilohz);
855+
else
856+
printf("%.1f", freq_kilohz);
857+
858+
if (n < number_of_bars - 1)
859+
printf("\033[%dC", p.bar_width + p.bar_spacing - 4);
860+
}
861+
}
862+
printf("\r\033[%dA", lines + 1);
863+
}
864+
769865
bool resizeTerminal = false;
770866
// fcntl(0, F_SETFL, O_NONBLOCK);
771867

@@ -1030,12 +1126,13 @@ as of 0.4.0 all options are specified in config file, see in '/home/username/.co
10301126
#ifdef NCURSES
10311127
rc = draw_terminal_ncurses(inAtty, lines, width, number_of_bars, p.bar_width,
10321128
p.bar_spacing, rest, bars, previous_frame,
1033-
p.gradient);
1129+
p.gradient, x_axis_info);
10341130
break;
10351131
#endif
10361132
case OUTPUT_NONCURSES:
10371133
rc = draw_terminal_noncurses(inAtty, lines, width, number_of_bars, p.bar_width,
1038-
p.bar_spacing, rest, bars, previous_frame);
1134+
p.bar_spacing, rest, bars, previous_frame,
1135+
x_axis_info);
10391136
break;
10401137
case OUTPUT_RAW:
10411138
rc = print_raw_out(number_of_bars, fp, p.is_bin, p.bit_format, p.ascii_range,

cava.psf

-720 Bytes
Binary file not shown.

config.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ enum input_method default_methods[] = {
2222
INPUT_PULSE,
2323
};
2424

25-
char *outputMethod, *channels;
25+
char *outputMethod, *channels, *xaxisScale;
2626

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

237+
p->xaxis = NONE;
238+
if (strcmp(xaxisScale, "none") == 0) {
239+
p->xaxis = NONE;
240+
}
241+
if (strcmp(xaxisScale, "frequency") == 0) {
242+
p->xaxis = FREQUENCY;
243+
}
244+
if (strcmp(xaxisScale, "note") == 0) {
245+
p->xaxis = NOTE;
246+
}
247+
237248
// validate: output channels
238249
p->stereo = -1;
239250
if (strcmp(channels, "mono") == 0) {
@@ -426,6 +437,7 @@ bool load_config(char configPath[PATH_MAX], struct config_params *p, bool colors
426437
outputMethod = (char *)iniparser_getstring(ini, "output:method", "noncurses");
427438
#endif
428439

440+
xaxisScale = (char *)iniparser_getstring(ini, "output:xaxis", "none");
429441
p->monstercat = 1.5 * iniparser_getdouble(ini, "smoothing:monstercat", 0);
430442
p->waves = iniparser_getint(ini, "smoothing:waves", 0);
431443
p->integral = iniparser_getdouble(ini, "smoothing:integral", 77);

config.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ enum input_method {
4545

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

48+
enum xaxis_scale { NONE, FREQUENCY, NOTE };
49+
4850
struct config_params {
4951
char *color, *bcolor, *raw_target, *audio_source,
5052
/**gradient_color_1, *gradient_color_2,*/ **gradient_colors, *data_format, *mono_option;
@@ -54,6 +56,7 @@ struct config_params {
5456
double *userEQ;
5557
enum input_method im;
5658
enum output_method om;
59+
enum xaxis_scale xaxis;
5760
int userEQ_keys, userEQ_enabled, col, bgcol, autobars, stereo, is_bin, ascii_range, bit_format,
5861
gradient, gradient_count, fixedbars, framerate, bar_width, bar_spacing, autosens, overshoot,
5962
waves, FFTbufferSize, fifoSample, fifoSampleBits;

output/terminal_ncurses.c

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ struct colors {
2020

2121
#define MAX_COLOR_REDEFINITION 256
2222

23+
const wchar_t *bar_heights[] = {L"\u2581", L"\u2582", L"\u2583", L"\u2584",
24+
L"\u2585", L"\u2586", L"\u2587", L"\u2588"};
25+
int num_bar_heights = (sizeof(bar_heights) / sizeof(bar_heights[0]));
26+
2327
// static struct colors the_color_redefinitions[MAX_COLOR_REDEFINITION];
2428

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

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

198199
// output: check if terminal has been resized
199200
if (!is_tty) {
201+
if (x_axis_info)
202+
terminal_height++;
200203
if (LINES != terminal_height || COLS != terminal_width) {
201204
return TERMINAL_RESIZED;
205+
if (x_axis_info)
206+
terminal_height--;
202207
}
203208
}
204209

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

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

218223
for (int bar = 0; bar < bars_count; bar++) {
219-
if (f[bar] == flastd[bar]) {
224+
if (bars[bar] == previous_frame[bar]) {
220225
continue;
221226
}
222227

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

227232
if (f_cell >= y) {
228233
int bar_step;
229234

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

241246
for (int col = cur_col, i = 0; i < bar_width; i++, col++) {
242247
if (is_tty) {
243-
mvaddch(height - y, col, '1' + bar_step);
248+
mvaddch(height - y, col, 0x41 + bar_step);
244249
} else {
245250
mvaddwstr(height - y, col, bar_heights[bar_step]);
246251
}

output/terminal_ncurses.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ void init_terminal_ncurses(char *const fg_color_string, char *const bg_color_str
33
int gradient_count, char **gradient_colors, int *width, int *height);
44
void get_terminal_dim_ncurses(int *width, int *height);
55
int draw_terminal_ncurses(int is_tty, int terminal_height, int terminal_width, int bars_count,
6-
int bar_width, int bar_spacing, int rest, const int f[200],
7-
int flastd[200], int gradient);
6+
int bar_width, int bar_spacing, int rest, const int bars[256],
7+
int previous_frame[256], int gradient, int x_axis_info);
88
void cleanup_terminal_ncurses(void);

0 commit comments

Comments
 (0)