@ -11,8 +11,14 @@
# include <signal.h>
# include <string.h>
# include <getopt.h>
# include <pthread.h>
struct sigaction old_action ;
int M = 2048 ;
int shared [ 2048 ] ;
int debug = 0 ;
int format = - 1 ;
int rate = - 1 ;
void sigint_handler ( int sig_no )
@ -27,54 +33,167 @@ void sigint_handler(int sig_no)
}
int main ( int argc , char * * argv )
void *
music ( void * data )
{
int M = 4096 ;
signed char * buffer ;
snd_pcm_t * handle ;
snd_pcm_hw_params_t * params ;
unsigned int val ;
snd_pcm_uframes_t frames ;
char * device = ( ( char * ) data ) ;
val = 44100 ;
int i , n , o , size , dir , err , lo ;
int tempr , templ ;
int radj , ladj ;
//**init sound device***//
if ( ( err = snd_pcm_open ( & handle , device , SND_PCM_STREAM_CAPTURE , 0 ) < 0 ) )
printf ( " error opening stream: %s \n " , snd_strerror ( err ) ) ;
else
if ( debug = = 1 ) { printf ( " open stream succes \n " ) ; }
snd_pcm_hw_params_alloca ( & params ) ;
snd_pcm_hw_params_any ( handle , params ) ;
snd_pcm_hw_params_set_access ( handle , params , SND_PCM_ACCESS_RW_INTERLEAVED ) ;
snd_pcm_hw_params_set_format ( handle , params , SND_PCM_FORMAT_S16_LE ) ;
snd_pcm_hw_params_set_channels ( handle , params , 2 ) ;
val = 44100 ;
snd_pcm_hw_params_set_rate_near ( handle , params , & val , & dir ) ;
frames = 32 ;
snd_pcm_hw_params_set_period_size_near ( handle , params , & frames , & dir ) ;
err = snd_pcm_hw_params ( handle , params ) ;
if ( err < 0 ) {
fprintf ( stderr ,
" unable to set hw parameters: %s \n " ,
snd_strerror ( err ) ) ;
exit ( 1 ) ;
}
snd_pcm_hw_params_get_format ( params , ( snd_pcm_format_t * ) & val ) ; //getting format
if ( val < 6 ) format = 16 ;
else if ( val > 5 & & val < 10 ) format = 24 ;
else if ( val > 9 ) format = 32 ;
snd_pcm_hw_params_get_rate ( params , & rate , & dir ) ; //getting rate
if ( debug = = 1 ) printf ( " detected rate: %d \n " , rate ) ;
snd_pcm_hw_params_get_period_size ( params , & frames , & dir ) ;
snd_pcm_hw_params_get_period_time ( params , & val , & dir ) ;
size = frames * ( format / 8 ) * 2 ; /* bytes/sample * 2 channels */
buffer = ( char * ) malloc ( size ) ;
radj = format / 4 ;
ladj = format / 8 ;
o = 0 ;
while ( 1 ) {
err = snd_pcm_readi ( handle , buffer , frames ) ;
if ( err = = - EPIPE ) {
/* EPIPE means overrun */
if ( debug = = 1 ) { fprintf ( stderr , " overrun occurred \n " ) ; }
snd_pcm_prepare ( handle ) ;
} else if ( err < 0 ) {
if ( debug = = 1 ) { fprintf ( stderr , " error from read: %s \n " ,
snd_strerror ( err ) ) ; }
} else if ( err ! = ( int ) frames ) {
if ( debug = = 1 ) { fprintf ( stderr , " short read, read %d %d frames \n " , err , ( int ) frames ) ; }
}
//sorting out one channel and only biggest octet
n = 0 ; //frame counter
for ( i = 0 ; i < size ; i = i + ( ladj ) * 2 )
{
// left right
//structuere [litte],[litte],[big],[big],[litte],[litte],[big],[big]...
//first channel
tempr = ( ( buffer [ i + ( radj ) - 1 ] < < 2 ) ) ; //using the 10 upper bits this whould give me a vert res of 1024, enough...
lo = ( ( buffer [ i + ( radj ) - 2 ] > > 6 ) ) ;
if ( lo < 0 ) lo = lo + 4 ;
if ( tempr > = 0 ) tempr = tempr + lo ;
if ( tempr < 0 ) tempr = tempr - lo ;
//other channel
templ = ( buffer [ i + ( ladj ) - 1 ] < < 2 ) ;
lo = ( buffer [ i + ( ladj ) - 2 ] > > 6 ) ;
if ( lo < 0 ) lo = lo + 4 ;
if ( templ > = 0 ) templ = templ + lo ;
else templ = templ - lo ;
//adding channels and storing it int the buffer
shared [ o ] = ( tempr + templ ) / 2 ;
o + + ;
if ( o = = M - 1 ) o = 0 ;
//shifing ringbuffer one to the left, this ended up sing to much cpu..
//for(o=0;o<M-1;o++) shared[o]=shared[o+1];
n + + ;
}
}
}
int main ( int argc , char * * argv )
{
pthread_t p_thread ;
int thr_id ;
char * device = " hw:1,1 " ;
float fc [ 200 ] ; //={150.223,297.972,689.062,1470,3150,5512.5,11025,18000};
float fr [ 200 ] ; //={0.00340905,0.0067567,0.015625,0.0333,0.07142857,0.125,0.25,0.4};
int lcf [ 200 ] , hcf [ 200 ] ;
double f [ 200 ] ;
double x [ M ] ;
double peak [ 201 ] ;
float y [ M / 2 + 1 ] ;
float f [ 200 ] ;
int flast [ 200 ] ;
float peak [ 201 ] ;
in t y [ M / 2 + 1 ] ;
long int lpeak , hpeak ;
int bands = 20 ;
int bands = 25 ;
int sleep = 0 ;
float h ;
int i , n , o , size , dir , err , xb , yb , bw , format , rate , width , height , c , rest , virt , lo ;
int i , n , o , size , dir , err , bw , width , height , c , rest , virt ;
int autoband = 1 ;
//long int peakhist[bands][400];
double temp ;
float temp ;
double sum = 0 ;
int16_t hi ;
int q = 0 ;
val = 44100 ;
int debug = 0 ;
struct winsize w ;
double in [ 2 * ( M / 2 + 1 ) ] ;
fftw_complex out [ M / 2 + 1 ] [ 2 ] ;
fftw_plan p ;
struct timespec start , stop ;
double accum ;
char * color ;
int col = 36 ;
int sens = 100 ;
int beat = 0 ;
int move = 0 ;
int fall [ 200 ] ;
float fpeak [ 200 ] ;
float k [ 200 ] ;
float g ;
int framerate = 60 ;
char * usage = " \n Usage : ./cava [options] \n \n Options: \n \t -b 1..(console columns/2-1) or 200) \t number of bars in the spectrum (default 25 + fills up the console), program wil auto adjust to maxsize if input is to high) \n \n \t -d 'alsa device' \t name of alsa capture device (default 'hw:1,1') \n \n \t -c color \t suported colors: red, green, yellow, magenta, cyan, white, blue (default: cyan) \n \n \t -s sensitivity % \t sensitivity in percent, 0 means no respons 100 is normal 50 half 200 double and so forth \n \n \t -f framerate \t max frames per second to be drawn, if you are experiencing high CPU usage, try redcing this (default: 60 \n \n " ;
//**END INIT
for ( i = 0 ; i < 200 ; i + + )
{
flast [ i ] = 0 ;
fall [ i ] = 0 ;
fpeak [ i ] = 0 ;
}
for ( i = 0 ; i < M ; i + + ) shared [ M ] = 0 ;
//**arg handler**//
while ( ( c = getopt ( argc , argv , " b:d:s:c: " ) ) ! = - 1 )
while ( ( c = getopt ( argc , argv , " b:d:s:f: c:h " ) ) ! = - 1 )
switch ( c )
{
case ' b ' :
@ -88,6 +207,9 @@ while ((c = getopt (argc, argv, "b:d:s:c:")) != -1)
case ' s ' :
sens = atoi ( optarg ) ;
break ;
case ' f ' :
framerate = atoi ( optarg ) ;
break ;
case ' c ' :
col = 0 ;
color = optarg ;
@ -104,8 +226,11 @@ while ((c = getopt (argc, argv, "b:d:s:c:")) != -1)
exit ( 1 ) ;
}
break ;
case ' h ' :
printf ( " %s " , usage ) ;
return 0 ;
case ' ? ' :
printf ( " \n Usage : ./cava [options] \n \n Options: \n \t -b 1..(console columns/2-1) or 200) \t number of bars in the spectrum (default 20 + fills up the console), program wil auto adjust to maxsize if input is to high) \n \n \t -d 'alsa device' \t name of alsa capture device (default 'hw:1,1') \n \n \t -c color \t suported colors: red, green, yellow, magenta, cyan, white, blue (default: cyan) \n \n \t -s sensitivity % \t sensitivity in percent, 0 means no respons 100 is normal 50 half 200 double and so forth \n \n " ) ;
printf ( " %s " , usage ) ;
return 1 ;
default :
abort ( ) ;
@ -120,21 +245,27 @@ action.sa_handler = &sigint_handler;
sigaction ( SIGINT , & action , & old_action ) ;
//**preparing screen**//
if ( debug = = 0 ) {
virt = system ( " setfont cava.psf " ) ;
system ( " setterm -cursor off " ) ;
}
//getting h*w of term
//**getting h*w of term**//
ioctl ( STDOUT_FILENO , TIOCGWINSZ , & w ) ;
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 ;
bool matrix [ width ] [ height ] ;
int matrix [ width ] [ height ] ;
for ( i = 0 ; i < width ; i + + )
{
for ( n = 0 ; n < height ; n + + )
{
matrix [ i ] [ n ] = 0 ;
}
}
bw = width / bands ;
g = ( ( float ) height / 1000 ) * pow ( ( 60 / ( float ) framerate ) , 2.5 ) ; //calculating gravity
//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 ) ) / ( bw + 1 ) ) ;
@ -145,135 +276,67 @@ if(rest<0)rest=0;
printf ( " hoyde: %d bredde: %d bands:%d bandbredde: %d rest: %d \n " , ( int ) w . ws_row , ( int ) w . ws_col , bands , bw , rest ) ;
//resetting console
printf ( " \033 [0m \n " ) ;
system ( " clear " ) ;
printf ( " \033 [%dm " , col ) ; //setting volor
printf ( " \033 [1m " ) ; //setting "bright" color mode, looks cooler...
//**init sound device***//
if ( ( err = snd_pcm_open ( & handle , device , SND_PCM_STREAM_CAPTURE , 0 ) < 0 ) )
printf ( " error opening stream: %s \n " , snd_strerror ( err ) ) ;
else
if ( debug = = 1 ) { printf ( " open stream succes \n " ) ; }
snd_pcm_hw_params_alloca ( & params ) ;
snd_pcm_hw_params_any ( handle , params ) ;
snd_pcm_hw_params_set_access ( handle , params , SND_PCM_ACCESS_RW_INTERLEAVED ) ;
snd_pcm_hw_params_set_format ( handle , params , SND_PCM_FORMAT_S16_LE ) ;
snd_pcm_hw_params_set_channels ( handle , params , 2 ) ;
val = 44100 ;
snd_pcm_hw_params_set_rate_near ( handle , params , & val , & dir ) ;
frames = 32 ;
snd_pcm_hw_params_set_period_size_near ( handle , params , & frames , & dir ) ;
err = snd_pcm_hw_params ( handle , params ) ;
if ( err < 0 ) {
fprintf ( stderr ,
" unable to set hw parameters: %s \n " ,
snd_strerror ( err ) ) ;
exit ( 1 ) ;
}
snd_pcm_hw_params_get_period_size ( params , & frames , & dir ) ;
snd_pcm_hw_params_get_period_time ( params , & val , & dir ) ;
snd_pcm_hw_params_get_format ( params , ( snd_pcm_format_t * ) & val ) ; //getting format
if ( val < 6 ) format = 16 ;
else if ( val > 5 & & val < 10 ) format = 24 ;
else if ( val > 9 ) format = 32 ;
size = frames * ( format / 8 ) * 2 ; /* bytes/sample * 2 channels */
buffer = ( char * ) malloc ( size ) ;
if ( debug = = 1 ) printf ( " detected format: %d \n " , format ) ;
snd_pcm_hw_params_get_rate ( params , & rate , & dir ) ; //getting rate
if ( debug = = 1 ) printf ( " detected rate: %d \n " , rate ) ;
//**watintg for audio to be ready**//
n = 0 ;
thr_id = pthread_create ( & p_thread , NULL , music , ( void * ) device ) ; //starting music listner
while ( format = = - 1 | | rate = = - 1 )
{
usleep ( 1000 ) ;
n + + ;
if ( n > 2000 )
{
printf ( " could not get rate and or format, problems with audoi thread? quiting... \n " ) ;
exit ( 1 ) ;
}
}
printf ( " got format: %d and rate %d \n " , format , rate ) ;
//**calculating cutof frequencies**/
for ( n = 0 ; n < bands + 1 ; n + + )
{
fc [ n ] = 8000 * pow ( 10 , - 2 + ( ( ( float ) n / ( float ) bands ) * 2 ) ) ; //decided to cut it at 10k, little interesting to hear above
fc [ n ] = 12000 * pow ( 10 , - 2.5 + ( ( ( float ) n / ( float ) bands ) * 2.5 ) ) ; //decided to cut it at 12k, little interesting to hear above
fr [ n ] = fc [ n ] / ( rate ) ; //remember nyquist
lcf [ n ] = fr [ n ] * ( M / 2 + 1 ) ;
if ( n ! = 0 ) hcf [ n - 1 ] = lcf [ n ] ;
if ( n ! = 0 )
{
hcf [ n - 1 ] = lcf [ n ] - 1 ;
if ( lcf [ n ] < = lcf [ n - 1 ] ) lcf [ n ] = lcf [ n - 1 ] + 1 ; //pushing the spectrum up if the expe function gets "clumped"
hcf [ n - 1 ] = lcf [ n ] - 1 ;
}
if ( debug = = 1 & & n ! = 0 ) { printf ( " %d: %f -> %f (%d -> %d) \n " , n , fc [ n - 1 ] , fc [ n ] , lcf [ n - 1 ] , hcf [ n - 1 ] ) ; }
}
//exit(1);
//constants to wigh signal to frequency
for ( n = 0 ; n < bands ; n + + ) k [ n ] = ( ( float ) height * log ( lcf [ n ] + 2 ) ) / ( 1024 * ( M / 4 ) ) ;
p = fftw_plan_dft_r2c_1d ( M , in , * out , FFTW_MEASURE ) ; //planning to rock
//**start main loop**//
while ( 1 )
{
/*
if ( clock_gettime ( CLOCK_REALTIME , & start ) = = - 1 ) {
perror ( " clock gettime " ) ;
exit ( EXIT_FAILURE ) ;
}
*/
//**filling of the buffer**//
for ( o = 0 ; o < M / 32 ; o + + )
{
err = snd_pcm_readi ( handle , buffer , frames ) ;
if ( err = = - EPIPE ) {
/* EPIPE means overrun */
if ( debug = = 1 ) { fprintf ( stderr , " overrun occurred \n " ) ; }
snd_pcm_prepare ( handle ) ;
} else if ( err < 0 ) {
if ( debug = = 1 ) { fprintf ( stderr , " error from read: %s \n " ,
snd_strerror ( err ) ) ; }
} else if ( err ! = ( int ) frames ) {
if ( debug = = 1 ) { fprintf ( stderr , " short read, read %d %d frames \n " , err , ( int ) frames ) ; }
}
//sorting out one channel and only biggest octet
n = 0 ; //frame counter
for ( i = 0 ; i < size ; i = i + ( format / 8 ) * 2 )
{
// left right
//structuere [litte],[litte],[big],[big],[litte],[litte],[big],[big]...
//first channel
x [ n + ( int ) frames * o ] = ( ( buffer [ i + ( format / 4 ) - 1 ] < < 8 ) ) ; //+(buffer[i+(format/8)-1] << 8))/2;//avg of left and right
lo = ( ( buffer [ i + ( format / 4 ) - 2 ] ) ) ; //+buffer[i+(format/8)-2])/2);
if ( lo < 0 ) lo = lo + 255 ;
if ( x [ n + ( int ) frames * o ] > = 0 ) x [ n + ( int ) frames * o ] = x [ n + ( int ) frames * o ] + lo ;
if ( x [ n + ( int ) frames * o ] < 0 ) x [ n + ( int ) frames * o ] = x [ n + ( int ) frames * o ] - lo ;
//**preparing screen**//
if ( debug = = 0 ) {
virt = system ( " setfont cava.psf " ) ;
system ( " setterm -cursor off " ) ;
//resetting console
printf ( " \033 [0m \n " ) ;
system ( " clear " ) ;
printf ( " \033 [%dm " , col ) ; //setting volor
printf ( " \033 [1m " ) ; //setting "bright" color mode, looks cooler...
//other channel
temp = ( buffer [ i + ( format / 8 ) - 1 ] < < 8 ) ;
lo = buffer [ i + ( format / 8 ) - 2 ] ;
if ( lo < 0 ) lo = lo + 255 ;
if ( temp > = 0 ) temp = temp + lo ;
else temp = temp - lo ;
//adding channels
x [ n + ( int ) frames * o ] = ( x [ n + ( int ) frames * o ] + temp ) / 2 ;
if ( x [ n + ( int ) frames * o ] > hpeak ) hpeak = x [ o ] ;
if ( x [ n + ( int ) frames * o ] < lpeak ) lpeak = x [ o ] ;
n + + ;
}
}
//**start main loop**//
while ( 1 )
{
if ( debug = = 1 ) { system ( " clear " ) ; }
@ -284,9 +347,9 @@ for(o=0;o<M/32;o++)
{
if ( i < M )
{
in [ i ] = x [ i ] ;
if ( x [ i ] > hpeak ) hpeak = x [ i ] ;
if ( x [ i ] < lpeak ) lpeak = x [ i ] ;
in [ i ] = shared [ i ] ;
if ( shared [ i ] > hpeak ) hpeak = shared [ i ] ;
if ( shared [ i ] < lpeak ) lpeak = shared [ i ] ;
}
else in [ i ] = 0 ;
// if(debug==1) printf("%d %f\n",i,in[i]);
@ -300,12 +363,6 @@ for(o=0;o<M/32;o++)
fftw_execute ( p ) ; //applying FFT to signal
//saving freq domian of input signal
for ( i = 0 ; i < M / 2 + 1 ; i + + )
{
y [ i ] = pow ( pow ( * out [ i ] [ 0 ] , 2 ) + pow ( * out [ i ] [ 1 ] , 2 ) , 0.5 ) ;
}
//seperating freq bands
for ( o = 0 ; o < bands ; o + + )
{
@ -314,25 +371,36 @@ for(o=0;o<M/32;o++)
//getting peaks
for ( i = lcf [ o ] ; i < = hcf [ o ] ; i + + )
{
y [ i ] = pow ( pow ( * out [ i ] [ 0 ] , 2 ) + pow ( * out [ i ] [ 1 ] , 2 ) , 0.5 ) ; //getting r of compex
if ( y [ i ] > peak [ o ] ) peak [ o ] = y [ i ] ;
}
//if (peak[o]>sum)sum=peak[o]; peakest values are ussaly around 50k but i have seen 113000
//divides on 200 because of complex mplification
//mulitplise by log of frequency probably because of eq master cd standard, riaa...?
temp = peak [ o ] * k [ o ] ; //weighing signal to height and frequency
f [ o ] = ( ( peak [ o ] * ( float ) height * log ( lcf [ o ] + hcf [ o ] + 10 ) * log ( lcf [ o ] + hcf [ o ] + 10 ) ) ) / ( 65536 * ( M / 8 ) * ( log ( hcf [ bands - 1 ] ) ) ) ; //weighing signal to height and frequency
//**falloff function**//
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 ;
}
f [ o ] = f [ o ] * ( ( float ) sens / 100 ) ;
flast [ o ] = f [ o ] ; //memmory for falloff func
f [ o ] = f [ o ] * ( ( float ) sens / 100 ) ; //adjusting sens
if ( f [ o ] > height ) f [ o ] = height ; //just in case
if ( debug = = 1 ) { 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 ] ) ; }
}
if ( debug = = 1 ) { printf ( " topp overall unfiltered:%f \n " , peak [ bands ] ) ;
// if(debug==1){ printf("topp overall unfiltered:%f \n",peak[bands]); }
}
//if(debug==1){ printf("topp overall alltime:%f \n",sum);}
}
else //**if no signal don't bother**//
@ -340,7 +408,8 @@ for(o=0;o<M/32;o++)
if ( sleep > ( rate * 5 ) / M ) //if no signal for 5 sec, go to sleep mode
{
if ( debug = = 1 ) printf ( " no sound detected for 5 sec, going to sleep mode \n " ) ;
usleep ( 1 * 1000000 ) ; //wait one sec, then check sound again. Maybe break, close and reopen?
for ( i = 0 ; i < 200 ; i + + ) flast [ i ] = 0 ; //zeroing memory
usleep ( 1 * 200000 ) ; //wait 200 msec, then check sound again.
continue ;
}
if ( debug = = 1 ) printf ( " no sound detected, trying again \n " ) ;
@ -351,33 +420,50 @@ for(o=0;o<M/32;o++)
//**DRAWING**// -- put in function file maybe?
if ( debug = = 0 )
{
/* //**BEAT detection, not yet implemented...
printf ( " \033 [0m " ) ;
printf ( " \033 [%dm " , col ) ;
if ( beat )
{
printf ( " \033 [47m " ) ;
beat = 0 ;
}
*/
for ( n = ( height - 1 ) ; n > = 0 ; n - - )
{
o = 0 ;
o = 0 ;
move = rest / 2 ; //center adjustment
//if(rest!=0)printf("\033[%dC",(rest/2));//center adjustment
for ( i = 0 ; i < width ; i + + )
{
//next bar? make a space
if ( i ! = 0 & & i % bw = = 0 ) {
o + + ;
if ( o < bands ) printf ( " " ) ;
if ( o < bands ) move + + ;
}
//draw color or blank
//draw color or blank or move+1
if ( o < bands ) { //watch so it doesnt draw to far
if ( f [ o ] - n < 0.125 ) printf ( " " ) ; //blank
else if ( f [ o ] - n > 1 ) printf ( " \u2588 " ) ; //color
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 ) ;
switch ( c )
{
@ -412,17 +498,20 @@ if (debug==0)
default :
printf ( " " ) ;
}
}
matrix [ i ] [ n ] = 2 ;
}
}
}
printf ( " \n " ) ; //next line
if ( rest ! = 0 ) printf ( " \033 [%dC " , ( rest / 2 ) ) ; //center adjustment
}
printf ( " \033 [%dA " , height ) ; //backup
usleep ( ( 1 / ( float ) framerate ) * 1000000 ) ; //sleeping for set us
}
//