123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931 |
- #include <GL/glut.h>
- #include <GL/gl.h>
- #include <alsa/asoundlib.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- #include <pthread.h>
- #include <sys/time.h>
- #include <math.h>
- #include <fftw3.h>
- #define PI 3.14159265358979323846
- class audioInput;
- void computespecslice(audioInput *ai);
- int chooseTics(float lo, float range, float fac, float *tics);
- static int verb;
- struct Param {
- int devicenumber;
- int windowtype;
- int twowinsize;
- float freqline[100];
- bool drawline = false;
- int nfreqlines = 0;
- bool drawcentroid = false;
- };
- Param param;
- const char *notenames[] = { "C","C#","D","Eb","E","F","F#","G","G#","A","Bb","B"};
- float timeDiff(timeval a, timeval b) {
- return (float)(b.tv_sec - a.tv_sec) + (float)(b.tv_usec - a.tv_usec) * 0.000001F;
- }
- void drawText(float x, float y, char *string) {
- int len, i;
- glRasterPos2f(x, y);
- len = (int) strlen(string);
- for (i = 0; i < len; i++)
- {
- glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, string[i]);
- }
- }
- void smallText(float x, float y, char *string) {
- int len, i;
- glRasterPos2f(x, y);
- len = (int) strlen(string);
- for (i = 0; i < len; i++)
- {
- glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, string[i]);
- }
- }
- class audioInput {
- public:
- char *chunk;
- float *b, *specslice, *bwin, *winf, *sg, *centroids;
- char *sgb;
- int b_ind, b_size, n_f, n_tw, sg_size, win_size;
- float dt, t_memory, Hz_per_pixel;
-
- bool quit, pause;
- pthread_t capture_thread;
- fftwf_plan fftw_p;
-
- int bytes_per_frame, frames_per_period, nperiods, channels;
- int req_rate, rate;
- int dir;
-
-
- snd_pcm_uframes_t period_size;
- snd_pcm_uframes_t req_size, size;
- snd_pcm_t *pcm_handle;
- snd_pcm_stream_t stream;
-
-
-
- snd_pcm_hw_params_t *hwparams;
-
-
-
- char *pcm_name;
- void setupWindowFunc(float *w, int N) {
- float W;
- int i;
- if (verb) printf("windowtype=%d\n", param.windowtype);
- switch (param.windowtype) {
- case 0:
- for( i=0; i<N; ++i)
- w[i] = 1.0F;
- break;
- case 1:
- W = N/2.0F;
- for( i=0; i<N; ++i)
- w[i] = (1.0F + cos(PI*(i-W)/W))/2;
- break;
- case 2:
- W = N/5.0F;
- for( i=0; i<N; ++i) w[i] = exp(-(i-N/2)*(i-N/2)/(2*W*W));
- break;
- default:
- fprintf(stderr, "unknown windowtype!\n");
- }
- }
- audioInput() {
- quit = false;
- pause = false;
- channels = 2;
- bytes_per_frame = 2 * channels;
- req_rate = 44100;
- frames_per_period = (int)(req_rate/60.0);
- nperiods = 2;
- t_memory = 20.0;
- period_size = frames_per_period * bytes_per_frame;
- chunk = new char[period_size];
- req_size = frames_per_period * nperiods;
- b_ind = 0;
- if( initDevice() < 0 )
- exit(1);
- dt = 1.0 / (float)rate;
- b_size = (int)(t_memory * rate);
- if (verb) printf("memory buffer size %d samples\n", b_size);
- b = new float[b_size];
-
- win_size = 1<<param.twowinsize;
- bwin = new float[win_size];
- winf = new float[win_size];
- setupWindowFunc(winf, win_size);
-
- fftw_p = fftwf_plan_r2r_1d(win_size, bwin, bwin, FFTW_R2HC, FFTW_MEASURE);
- n_f = 560;
- specslice = new float[n_f];
- n_tw = 940;
- centroids = new float[n_tw];
- for (int i=0; i<n_tw; ++i)
- centroids[i]=0;
- sg_size = n_f * n_tw;
- sg = new float[sg_size];
- sgb = new char[sg_size];
-
-
-
-
- Hz_per_pixel = 1.0F / (win_size*dt);
- if (verb) printf("Hz per pixel = %.3f\n", Hz_per_pixel);
-
-
- pthread_create(&capture_thread, NULL, audioCapture, (void*)this);
- }
- ~audioInput() {
- snd_pcm_close (pcm_handle);
- fftwf_destroy_plan(fftw_p);
- }
-
- int initDevice() {
-
-
- stream = SND_PCM_STREAM_CAPTURE;
-
- char pcm_devnum[21];
- snprintf(pcm_devnum, 21, "%d", param.devicenumber);
- pcm_name = strdup("plughw:");
- strcat(pcm_name, pcm_devnum);
- strcat(pcm_name, ",0");
-
- snd_pcm_hw_params_alloca(&hwparams);
-
-
-
-
-
-
-
- if (snd_pcm_open(&pcm_handle, pcm_name, stream, 0) < 0) {
- fprintf(stderr, "Error opening PCM device %s\n", pcm_name);
- return(-1);
- }
-
- if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
- fprintf(stderr, "Can not configure this PCM device.\n");
- return(-1);
- }
-
-
-
-
-
-
- if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
- fprintf(stderr, "Error setting access.\n");
- return(-1);
- }
-
-
- if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0) {
- fprintf(stderr, "Error setting format.\n");
- return(-1);
- }
-
-
-
- rate = req_rate;
- if (snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, (uint*)&rate, 0) < 0) {
- fprintf(stderr, "Error setting rate.\n");
- return(-1);
- }
- if (rate != req_rate) {
- fprintf(stderr, "The rate %d Hz is not supported by your hardware.\n \
- ==> Using %d Hz instead.\n", req_rate, rate);
- }
-
-
- if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels) < 0) {
- fprintf(stderr, "Error setting channels.\n");
- return(-1);
- }
-
-
- if (snd_pcm_hw_params_set_periods(pcm_handle, hwparams, nperiods, 0) < 0) {
- fprintf(stderr, "Error setting number of periods.\n");
- return(-1);
- }
-
-
- size = req_size;
- if (snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &size) < 0) {
- fprintf(stderr, "Error setting buffersize.\n");
- return(-1);
- }
- if( size != req_size ) {
- fprintf(stderr, "Buffer size %d is not supported, using %d instead.\n", (int)req_size, (int)size);
- }
-
-
- if (snd_pcm_hw_params(pcm_handle, hwparams) < 0) {
- fprintf(stderr, "Error setting HW params.\n");
- return(-1);
- }
- return 1;
- }
-
- void quitNow() {
- quit = true;
-
- snd_pcm_close (pcm_handle);
- }
-
- union byte {
- unsigned char uchar_val;
- char char_val;
- };
-
- int mod( int i ) {
-
- int r = i % b_size;
- if (r<0)
- r += b_size;
- return r;
- }
-
- static void* audioCapture(void* a) {
-
-
- fprintf(stderr, "audioCapture thread started...\n");
- audioInput* ai = (audioInput*) a;
-
- float inv256 = 1.0 / 256.0;
- float inv256_2 = inv256*inv256;
-
- while( ! ai->quit ) {
- int n;
- if( ! ai->pause ) {
-
- while((n = snd_pcm_readi(ai->pcm_handle, ai->chunk, ai->frames_per_period)) < 0 ) {
-
- fprintf(stderr, "Error occured while recording: %s\n", snd_strerror(n));
-
-
- snd_pcm_prepare(ai->pcm_handle);
-
- }
- if (verb>1) printf("snd_pcm_readi got n=%d frames\n", n);
- byte by;
- int write_ptr, read_ptr;
- for( int i = 0; i < n; i++ ) {
- read_ptr = i * ai->bytes_per_frame;
- write_ptr = ai->mod(ai->b_ind + i);
- by.char_val = ai->chunk[read_ptr];
-
- ai->b[write_ptr] = (float)ai->chunk[read_ptr+1]*inv256 + (float)by.uchar_val*inv256_2;
- }
- ai->b_ind = ai->mod(ai->b_ind+n);
- computespecslice(ai);
- }
- else {
- usleep(10000);
- }
- }
- fprintf(stderr, "audioCapture thread exiting.\n");
- }
- };
- class scene
- {
- public:
- float viewport_size[2];
- float mouse[3];
- bool pause;
- audioInput* ai;
- float color_scale[2];
- bool diagnose;
- char diagnosis[1000];
- time_t fps_tic;
- int frameCount, fps;
- int scroll_fac, scroll_count, colormode;
- float run_time;
- timeval start_time;
- int freqind;
- scene() { }
- ~scene() { }
-
- void init() {
-
- pause = false;
- color_scale[0] = 100.0+40;
- color_scale[1] = 255/120.0/1.5;
- ai = new audioInput();
- fps_tic = time(NULL); frameCount = fps = 0;
- colormode = 2;
- scroll_count = 0;
- gettimeofday(&start_time, NULL);
- run_time = 0.0;
- freqind = 0;
- diagnose = 0;
- strcpy(diagnosis, "no diagnosis ...");
- }
-
- void graph()
- {
- float tshow = 0.1;
- glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH); glLineWidth(2);
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glTranslatef(0.97,0.1,0);
- glScalef(4.0,1.0,1.0);
- char xlab[] = "t(s)", ylab[] = "";
-
- glColor4f(0.4, 1.0, 0.6, 1);
- glBegin(GL_LINE_STRIP);
- float x = -tshow;
- int ilo = ai->b_ind-(int)(tshow*ai->rate);
- int ihi = ai->b_ind;
- for( int i=ilo; i<ihi; i++ ) {
- glVertex2f(x, ai->b[ai->mod(i)]);
- x += ai->dt;
- }
- glEnd();
- glPopMatrix();
- }
- void slice()
- {
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glTranslatef(0.15,0.11,0);
- float max_Hz = ai->Hz_per_pixel*ai->n_f;
- glScalef(0.3/max_Hz,0.0015,1.0);
- glLineWidth(1);
- glColor4f(0.5, 0.4, 0.2, 1);
- glBegin(GL_LINES);
- float dB_min = -color_scale[0]/color_scale[1];
- float dB_max = (255.0-color_scale[0])/color_scale[1];
- glVertex2f(0,dB_min);glVertex2f(max_Hz,dB_min);
- glVertex2f(0,dB_max);glVertex2f(max_Hz,dB_max);
- glEnd();
- glColor4f(1.0, 0.8, 0.3, 1);
- glBegin(GL_LINE_STRIP);
- for( int i=0; i<ai->n_f; i++ )
- glVertex2f(i*ai->Hz_per_pixel, 20*log10(ai->specslice[i]));
- glEnd();
- char xlab[] = "f(Hz)", ylab[] = "I(dB)";
- drawAxes(0-1e-7, max_Hz, -50, 50, 1.0, 1.0, 1, 0, xlab, ylab);
- glPopMatrix();
- }
- void drawAxes(float x0, float x1, float y0, float y1, float xf, float yf, bool box, bool grid, char* xlab, char* ylab)
-
-
-
- {
- int n_tics, i, len;
- char label[20];
- float tics[100];
- float x_pix_size = 2.0*(x1-x0)/(viewport_size[0]*xf);
- float y_pix_size = 2.0*(y1-y0)/(viewport_size[1]*yf);
- glColor4f(0.7, 1.0, 1.0, 1);
- glDisable(GL_LINE_SMOOTH); glLineWidth(1);
- if (box) { glBegin(GL_LINE_STRIP);
- glVertex2f(x0,y1); glVertex2f(x0,y0); glVertex2f(x1,y0);
- if (box>1) { glVertex2f(x1,y1); glVertex2f(x0,y1); }
- glEnd();
- } else { glBegin(GL_LINES);
- glVertex2f(0,y0); glVertex2f(0,y1); glVertex2f(x0,0); glVertex2f(x1,0);
- glEnd(); }
- smallText(x1+8*x_pix_size,y0-8*y_pix_size,xlab);
- smallText(x0-8*x_pix_size,y1+8*y_pix_size,ylab);
-
- n_tics = chooseTics(x0,x1-x0,xf,tics);
- float xtic_top = (box==0) ? 0.0 : y0;
- float xtic_bot = xtic_top - 0.02*(y1-y0)/yf;
- glBegin(GL_LINES);
- for (i=0;i<n_tics;++i) {
- glVertex2d(tics[i], xtic_bot); glVertex2d(tics[i], xtic_top);
- }
- glEnd();
- for (i=0;i<n_tics;++i) {
- sprintf(label,"%.6g",tics[i]);
- smallText((float)(tics[i] - 4*strlen(label)*x_pix_size), \
- (float)(xtic_bot - 12*y_pix_size), label);
- }
- n_tics = chooseTics(y0,y1-y0,yf,tics);
- float ytic_top = (box==0) ? 0.0 : x0;
- float ytic_bot = ytic_top - 0.02*(x1-x0)/xf;
- glBegin(GL_LINES);
- for (i=0;i<n_tics;++i) {
- glVertex2d(ytic_bot, tics[i]); glVertex2d(ytic_top, tics[i]);
- }
- glEnd();
- for (i=0;i<n_tics;++i) {
- sprintf(label,"%.6g",tics[i]);
- smallText((float)(ytic_bot - 8*strlen(label)*x_pix_size), \
- (float)(tics[i] - 4*y_pix_size), label);
- }
- }
- void drawLines(float x0, float x1)
- {
- glColor4f(0.7, 1.0, 1.0, 1);
- glDisable(GL_LINE_SMOOTH); glLineWidth(1);
- glBegin(GL_LINES);
- if(param.drawline) {
- for (int n=0; n<param.nfreqlines; ++n) {
- glVertex2d(x0,param.freqline[n]); glVertex2d(x1,param.freqline[n]);
- }
- }
- glEnd();
- }
- void drawCentroids(float x0, float x1)
- {
- glColor4f(0.7, 1.0, 1.0, 1);
- glDisable(GL_LINE_SMOOTH); glLineWidth(1);
- glBegin(GL_LINES);
- float dt = (x1-x0)/ai->n_tw;
- for (int i=0; i < ai->n_tw; ++i) {
- glVertex2d(x0+i*dt, ai->centroids[i]);
- glVertex2d(x0+(i+1)*dt, ai->centroids[i+1]);
- }
- glEnd();
- }
- void spectrogram()
- {
- float x0=0.05, y0=0.22;
- float currfreq, linefreq; char str[50];
- int nummults, i, notenum, octave;
- glRasterPos2f(x0,y0);
- glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND);
-
-
-
- if (colormode<2)
- glDrawPixels(ai->n_tw, ai->n_f, GL_LUMINANCE, GL_UNSIGNED_BYTE, ai->sgb);
- else
- glDrawPixels(ai->n_tw, ai->n_f, GL_RGB, GL_UNSIGNED_BYTE_3_3_2, ai->sgb);
-
-
-
-
-
-
-
-
-
-
-
-
- glMatrixMode(GL_MODELVIEW); glPushMatrix();
- float secs_per_pixel = scroll_fac / 60.0;
- float max_Hz = ai->Hz_per_pixel*ai->n_f;
- float max_t = secs_per_pixel*ai->n_tw;
- glTranslatef(x0 + (ai->n_tw-run_time/secs_per_pixel)/(float)viewport_size[0], y0, 0);
- glScalef(1.0F/(viewport_size[0]*secs_per_pixel),1.0F/(viewport_size[1]*ai->Hz_per_pixel),1);
-
- char xlab[] = "t(s)", ylab[] = "f(Hz)";
- drawAxes(run_time-max_t, run_time, 0 - 1e-7, max_Hz, 2.0, 2.0, 2, 0, xlab, ylab);
- drawLines(run_time-max_t, run_time);
- if(param.drawcentroid)
- drawCentroids(run_time-max_t, run_time);
-
- if (freqind) {
-
- currfreq = ai->Hz_per_pixel*(viewport_size[1]*(1-y0)-mouse[1]);
- if (currfreq>0.0) {
- nummults = (freqind>1) ? 10 : 1;
- for (i=1;i<=nummults;++i) {
- linefreq = i*currfreq;
- if (i==1)
- glColor4f(0.8, 0.5, 0.0, 1);
- else
- glColor4f(0.8, 0.5, 0.0, 1);
- glDisable(GL_LINE_SMOOTH); glLineWidth(1);
- glBegin(GL_LINES);
- glVertex2f(run_time-max_t, linefreq);
- glVertex2f(run_time, linefreq);
- glEnd();
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- notenum = (int)roundf(12 * logf(linefreq/261.626)/logf(2.0));
- octave = 4 + notenum/12;
- if (octave<0) octave = (int)NAN;
- sprintf(str, " %.d %s%d",(int)roundf(linefreq),notenames[(notenum+1200) % 12],octave);
- smallText(run_time-max_t,linefreq+3.0*ai->Hz_per_pixel,str);
- }
- }
- }
- glPopMatrix();
- }
- char color_byte(float x)
-
- {
- float fac = 20.0 * color_scale[1];
- int k = (int)(color_scale[0] + fac*log10(x));
- if (k>255) k=255; else if (k<0) k=0;
- if (colormode==0)
- return (char)k;
- else if (colormode==1)
- return (char)(255-k);
- else if (colormode==2) {
- float a = k/255.0f;
- float r = 5*(a-0.2); if (r<0) r=0.0; else if (r>=1) r=.955;
- float g = 5*(a-0.6); if (g<0) g=0.0; else if (g>=1) g=.995;
- float b = 5*a;
- if (a>0.8) b = 5*(a-0.8); else if (a>0.4) b = 5*(0.6-a);
- if (b<0) b=0.0; else if (b>=1) b=.995;
- return (char)(b*4 + 4*((int)(g*8)) + 32*((int)(r*8)));
- }
- }
- void regen_sgb()
-
- {
- int i, j, n = ai->n_tw;
- for ( i=0; i<n; ++i)
- for ( j=0; j<ai->n_f; ++j)
- ai->sgb[j*n + i] = color_byte(ai->sg[j*n + i]);
- }
- };
- static scene scn;
- int chooseTics(float lo, float range, float fac, float *tics)
- {
- int i, n_tics, tic_start;
- float exponent, logr, spacing;
- if (fac==0.0) fac = 1.0;
-
- logr = log10(range * 0.4 / fac);
- exponent = floor(logr);
- spacing = pow(10.0, exponent);
- if (logr-exponent > log10(5.0))
- spacing *= 5.0;
- else if (logr-exponent > log10(2.0))
- spacing *= 2.0;
-
-
- tic_start = (int)(copysign(0.5,lo) + 1.0 + floor(lo / spacing));
-
- n_tics = (int)(1.0 + (lo + range - tic_start*spacing)/spacing);
- for (i=0;i<n_tics;++i) {
- tics[i] = spacing * (tic_start + i);
- }
- return n_tics;
- }
- void drawText()
- {
- glEnable (GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- glColor4f(1, .4, .4, 1.0);
- char str[50]; sprintf(str, "%d FPS",scn.fps); smallText(0.92,0.96,str);
- sprintf(str, "gain offset %.0f dB",scn.color_scale[0]);
- smallText(0.02,0.04,str);
- sprintf(str, "dyn range %.1f dB",255.0/scn.color_scale[1]);
- smallText(0.02,0.02,str);
- if (scn.diagnose) {
- glColor4f(.2, .2, .2, 0.8);
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glTranslatef(0.5,0.5,0); glScalef(0.5,0.4,1); glTranslatef(-0.5,-0.5,0);
- glBegin(GL_POLYGON);
- glVertex2f(0,0); glVertex2f(1,0); glVertex2f(1,1); glVertex2f(0,1); glVertex2f(0,0);
- glEnd();
- glColor4f(1, 1, 1, 1);
- drawText(0.2, 0.5, scn.diagnosis);
- glPopMatrix();
- }
- }
-
- void display()
- {
- glClear(GL_COLOR_BUFFER_BIT);
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(0, 1, 0, 1, -1, 1);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- scn.graph();
- scn.slice();
- scn.spectrogram();
- drawText();
-
- glutSwapBuffers();
- }
- void computespecslice(audioInput *ai)
- {
- int N = ai->win_size;
- int nf = ai->n_f;
-
- if (0)
- for ( int i=0; i<nf; ++i )
- ai->specslice[i] = 100.0 * ai->b[ai->mod(ai->b_ind - nf + i)];
- else {
- for ( int i=0; i<N; ++i )
- ai->bwin[i] = ai->winf[i] * ai->b[ai->mod(ai->b_ind - N + i)];
- fftwf_execute(ai->fftw_p);
- if (nf>N/2) {fprintf(stderr,"window too short cf n_f!\n"); return;}
- ai->specslice[0] = ai->bwin[0]*ai->bwin[0];
- for ( int i=1; i<nf; ++i )
- ai->specslice[i] = ai->bwin[i]*ai->bwin[i] + ai->bwin[N-i]*ai->bwin[N-i];
- }
- }
- void scroll_sg(audioInput *ai, float *newcol, float *centroids)
- {
- int i, j, n = ai->n_tw;
- for ( i=0; i<n; ++i)
- for ( j=0; j<ai->n_f; ++j)
- ai->sg[j*n + i] = ai->sg[j*n + i + 1];
- for ( i=0; i<n; ++i)
- for ( j=0; j<ai->n_f; ++j)
- ai->sgb[j*n + i] = ai->sgb[j*n + i + 1];
- for ( i=0; i<n; ++i)
- centroids[i] = centroids[i+1];
-
- float num = 0;
- float denom = 0;
- float curr_freq;
- for (j=0; j<ai->n_f; ++j) {
- curr_freq = ai->Hz_per_pixel * j;
- denom += newcol[j];
- num += newcol[j] * curr_freq;
- }
- float centroid = num / denom;
- centroids[n] = centroid;
- for ( j=0; j<ai->n_f; ++j) {
- ai->sg[j*n + n - 1] = newcol[j];
- }
- for ( j=0; j<ai->n_f; ++j) {
- ai->sgb[j*n + n - 1] = scn.color_byte(newcol[j]);
- }
- }
- void idle(void)
- {
- ++scn.frameCount;
- time_t now = time(NULL);
- if (now>scn.fps_tic) {
- scn.fps = scn.frameCount;
- scn.frameCount = 0;
- scn.fps_tic = now;
- }
- if (!scn.ai->pause) {
- timeval nowe;
- gettimeofday(&nowe, NULL);
-
- scn.run_time += 1/60.0;
- scn.run_time = fmod(scn.run_time, 100.0);
- ++scn.scroll_count;
- if (scn.scroll_count==scn.scroll_fac) {
- scroll_sg(scn.ai, scn.ai->specslice, scn.ai->centroids);
- scn.scroll_count = 0;
- }
- }
- glutPostRedisplay();
- }
- void keyboard(unsigned char key, int xPos, int yPos)
- {
- if( key == 27 || key == 'q') {
- scn.ai->quitNow();
- exit(0);
- } else if( key == ' ' ) {
- scn.pause = ! scn.pause;
- scn.ai->pause = ! scn.ai->pause;
- } else if( key == 'd' ) {
- scn.diagnose = ! scn.diagnose;
- } else if( key == ']' ) {
- if (scn.scroll_fac>1) {scn.scroll_fac--; scn.scroll_count=0; }
- } else if( key == '[' ) {
- if (scn.scroll_fac<50) scn.scroll_fac++;
- } else if( key == 'i' ) {
- scn.colormode = (scn.colormode + 1) % 3;
- scn.regen_sgb();
- } else {
- fprintf(stderr, "pressed key %d\n", (int)key);
- }
- }
- void special(int key, int xPos, int yPos) {
- if( key == 102 ) {
- scn.color_scale[1] *= 1.5; scn.regen_sgb();
- } else if( key == 100 ) {
- scn.color_scale[1] /= 1.5; scn.regen_sgb();
- } else if( key == 103 ) {
- scn.color_scale[0] -= 20; scn.regen_sgb();
- } else if( key == 101 ) {
- scn.color_scale[0] += 20; scn.regen_sgb();
- } else {
- fprintf(stderr, "pressed special key %d\n", key);
- }
- }
- void reshape(int w, int h)
- {
- scn.viewport_size[0] = w;
- scn.viewport_size[1] = h;
- if (verb) fprintf(stderr, "Setting w=%d, h=%d\n", w, h);
- glViewport(0, 0, w, h);
- }
- void mouse(int button, int state, int x, int y)
- {
- scn.mouse[0] = x;
- scn.mouse[1] = y;
- scn.mouse[2] = button;
- if (verb) printf("Mouse event: button: %d state: %d pos: %d, %d\n", button, state, x, y);
- if (button==GLUT_LEFT_BUTTON && state==GLUT_DOWN) scn.freqind = 1;
- if (button==GLUT_LEFT_BUTTON && state==GLUT_UP) scn.freqind = 0;
- if (button==GLUT_RIGHT_BUTTON && state==GLUT_DOWN) scn.freqind = 2;
- if (button==GLUT_RIGHT_BUTTON && state==GLUT_UP) scn.freqind = 0;
- if (button==GLUT_MIDDLE_BUTTON && state==GLUT_UP) scn.regen_sgb();
- }
- void motion(int x, int y)
- {
- int dx = (int)(x-scn.mouse[0]);
- int dy = (int)(y-scn.mouse[1]);
- if( scn.mouse[2] == GLUT_MIDDLE_BUTTON ) {
- scn.color_scale[0] += dx/5.0;
- scn.color_scale[1] *= exp(-dy/200.0);
- }
- scn.mouse[0] = x;
- scn.mouse[1] = y;
- }
- const char *helptext[] = {
- " Simple Spectrogram: real-time OpenGL spectrogram.\n",
- " (based on Alex Barnett glSpect, Dec 2010 and Luke Campagnola glScope)\n\n",
- "Usage: sspect [-f] [-v] [-d <device_number>] [-sf <scroll_factor>] [-w <windowtype>] [-t twowinsize] [-fl freqline] [-c]\n\n",
- "Command line arguments:\n",
- "-f fullscreen\n",
- "-v verbose mode\n",
- "device_number = 0,1,... the ALSA input device number (default 0)\n",
- "windowtype = \t0 (no window)\n\t\t1 (Hann)\n\t\t2 (Gaussian trunc at +-4sigma) (default)\n",
- "scroll_factor = 1,2,... # vSyncs (60Hz) to wait per scroll pixel (default 1)\n",
- "twowinsize = 11,12,...,16 is power of 2 giving FFT win_size N (default 12)\n\t(Note: this controls the vertical frequency resolution and range)\n",
- "freqline draws at line at frequency freqline. Several -fl options can be used to draw several lines\n",
- "-c draws the centroid line\n\n",
- "Keys & mouse: \tarrows or middle button drag - brightness/contrast\n",
- "\t\tleft button shows horizontal frequency readoff line\n",
- "\t\tright button shows horizontal frequency readoff with multiples\n",
- "\t\ti - cycles through color maps (B/W, inverse B/W, color)\n",
- "\t\tq or Esc - quit\n",
- "\t\t[ and ] - control horizontal scroll factor (rate)\n",
- NULL };
- int main(int argc, char** argv)
- {
- int scrnmode = 0;
- verb = 0;
- scn.scroll_fac = 2;
- param.devicenumber = 0;
- param.windowtype = 2;
- param.twowinsize = 12;
- param.drawcentroid = false;
- for (int i=1; i<argc; ++i) {
- if (!strcmp(argv[i], "-f"))
- scrnmode = 1;
- else if (!strcmp(argv[i], "-v"))
- verb = 1;
- else if (!strcmp(argv[i], "-sf")) {
- sscanf(argv[++i], "%d", &scn.scroll_fac);
- if (scn.scroll_fac<1) scn.scroll_fac=1;
- } else if (!strcmp(argv[i], "-t")) {
- sscanf(argv[++i], "%d", ¶m.twowinsize);
- if (param.twowinsize<10) param.twowinsize=10;
- if (param.twowinsize>18) param.twowinsize=18;
- } else if (!strcmp(argv[i], "-w")) {
- sscanf(argv[++i], "%d", ¶m.windowtype);
- if (param.windowtype<0) param.windowtype=0;
- } else if (!strcmp(argv[i], "-d")) {
- sscanf(argv[++i], "%d", ¶m.devicenumber);
- if (param.devicenumber<0) param.devicenumber=0;
- } else if (!strcmp(argv[i], "-fl")) {
- sscanf(argv[++i], "%f", ¶m.freqline[param.nfreqlines]);
- param.drawline = true;
- param.nfreqlines++;
- } else if (!strcmp(argv[i], "-c")) {
- param.drawcentroid = true;
- } else {
- fprintf(stderr, "bad command line option %s\n\n", argv[i]);
- for (int i=0; helptext[i]; i++) fprintf(stderr, "%s", helptext[i]);
- exit(1);
- }
- }
- scn.init();
- glutInit(&argc, argv);
- glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
- if (scrnmode==1) {
-
- glutGameModeString( "1024x768:24@60" );
- glutEnterGameMode();
- } else {
- glutInitWindowSize(1024, 768);
- int mainWindow = glutCreateWindow("sspect");
-
- }
- glutDisplayFunc(display);
- glutReshapeFunc(reshape);
- glutKeyboardFunc(keyboard);
- glutSpecialFunc(special);
- glutMouseFunc(mouse);
- glutMotionFunc(motion);
- glutIdleFunc(idle);
- glutMainLoop();
- return 0;
- }
|