Update cava.c

Moved audio capture to own pthread, added falloff and framerate limiter, looks much much nicer now.
master
karlstav 12 years ago
parent 8a7f928d0e
commit bc3aebe3de
  1. 431
      cava.c

431
cava.c

@ -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];
int 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="\nUsage : ./cava [options]\n\nOptions:\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\tsuported 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 ("\nUsage : ./cava [options]\n\nOptions:\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\tsuported 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
}
//

Loading…
Cancel
Save