// Simple meteor detector using Processing.org version 1.5.1

// AGW -20121128

// modified from

/**

* LiveSpectrogram_window

* Takes successive FFTs and renders them onto the screen as grayscale, scrolling left.

* This version includes variable window length.  Drag the mouse left and right to change the

* length of the Hanning window applied before the FFT is taken.

*

* Dan Ellis dpwe@ee.columbia.edu 2010-01-15

*/

import ddf.minim.analysis.*;

import ddf.minim.*;

Minim minim;

AudioInput in;

FFT fft;

// Configuration: spectrogram size (pixels)

int colmax = 256;

int rowmax = 256;

// Sample rate

float sampleRate = 22050;

// buffer size (= FFT size, must be power of 2)

int bufferSize = 2048;

// Variables

int[][] sgram = new int[rowmax][colmax];

int col;

int leftedge;

int window_len = bufferSize;

//

int flsum = 0;

int flhsum =0;

int[][] lstflhsum = new int[256][11];

int trig = 2000;

int ss = 128;

int tscl = -70;

int tlvl = 15000 ;

//

void setup()

{

 size(600, 256, P3D);

 textMode(SCREEN);

 textFont(createFont("SanSerif", 12));

 minim = new Minim(this);

 // setup audio input

 in = minim.getLineIn(Minim.MONO, bufferSize, sampleRate);

 fft = new FFT(in.bufferSize(), in.sampleRate());

 // suppress windowing inside FFT - we'll do it ourselves

 fft.window(FFT.NONE);

}

void draw()

{

 background(0);

 //

 stroke(255);

 // grab the input samples

 float[] samples = in.mix.toArray();

 // apply windowing

 for (int i = 0; i < samples.length/2; ++i) {

   // Calculate & apply window symmetrically around center point

   // Hanning (raised cosine) window

   float winval = (float)(0.5+0.5*Math.cos(Math.PI*(float)i/(float)(window_len/2)));

   if (i > window_len/2)  winval = 0;

   samples[samples.length/2 + i] *= winval;

   samples[samples.length/2 - i] *= winval;

 }

 // zero out first point (not touched by odd-length window)

 samples[0] = 0;

 // perform a forward FFT on the samples in the input buffer

 fft.forward(samples);

 // fill in the new column of spectral values

 for(int i = 0; i < rowmax /* fft.specSize() */; i++) {

   sgram[i][col] = (int)Math.round(Math.max(0,2*20*Math.log10(1000*fft.getBand(i))));

 

   flsum = flsum+sgram[i][col];

   flhsum = flsum ;

 

  //

 }

 // next time will be the next column

 col = col + 1;

 flsum =0 ;

//

 // wrap back to the first column when we get to the end

 if (col == colmax) { col = 0; }

 // Draw points.

 // leftedge is the column in the ring-filled array that is drawn at the extreme left

 // start from there, and draw to the end of the array

 for (int i = 0; i < colmax-leftedge; i++) {

   for (int j = 0; j < rowmax; j++) {

     stroke(sgram[j][i+leftedge]);

     point(i,height-j);

   

   }

 }

 // Draw the rest of the image as the beginning of the array (up to leftedge)

 for (int i = 0; i < leftedge; i++) {

   for (int j = 0; j < rowmax; j++) {

     stroke(sgram[j][i]);

     point(i+colmax-leftedge,height-j);

     //

   }

 }

 

 // draw trace of signal levels

 for (int g = 0; g < 256; g++) {

   //

    stroke(255);

   //

   line(colmax+80+256-g-1, ss+(tlvl-lstflhsum[g][0])/tscl, colmax+80+256-g, ss+(tlvl-(lstflhsum[g][0]+(flhsum))/2)/tscl);

   

   // this is the trigger check point

   if ( lstflhsum[g][0]-flhsum >= trig ) {

   print("\n"+trig+" Trigger "+(lstflhsum[g][0]-flhsum));

   text(flhsum+" [Trig: "+trig+" ]"+" Trigger "+(lstflhsum[g][0]-flhsum), colmax+80+5, 10);

    lstflhsum[255-leftedge][0] = (flhsum)*(15/10) ; // scale by 150% the triggering values

      }  

    else {  //

       lstflhsum[255-leftedge][0] = (flhsum) ;}

   }

   

   

 // Next time around, we move the left edge over by one, to have the whole thing

 // scroll left

 leftedge = leftedge + 1;

 

 // Make sure it wraps around

 if (leftedge == colmax) { leftedge = 0; }

   

     

 // Add frequency axis labels

 int x = colmax + 2; // to right of spectrogram display

 stroke(255);

 

 line(x,0,x,height); // vertical line

 // Make text appear centered relative to specified x,y point

 textAlign(LEFT,CENTER);

 for (float freq = 0.0; freq < in.sampleRate()/2; freq += 500.0) {

   int y = height - fft.freqToIndex(freq); // which bin holds this frequency?

   line(x,y,x+3,y); // add tick mark

   text(Math.round(freq)+" Hz", x+5, y); // add text label

 }

//

 

   

 // Report window size

 text(flhsum+" [Trig: "+trig+" ]", colmax+80+5, 10);

 //

// Draw ends here

}

void keyPressed() {

  //

   if (key =='x') { exit();}

   if (key =='c') { background(0); }

   if (key =='k') { trig-=50 ; print("\n trig "+trig);}

   if (key =='l') { trig+=50 ; print("\n trig "+trig);}

   if (key =='-') { tscl-=5 ; print("\n tscl "+tscl+" "+(flhsum));}

   if (key =='=') { tscl+=5 ; print("\n tscl "+tscl+" "+(flhsum));}

   if (key ==',') { tlvl-=100 ; print("\n tlvl "+tlvl+" "+(flhsum));}

   if (key =='.') { tlvl+=100 ; print("\n tlvl "+tlvl+" "+(flhsum));}

 }

void stop()

{

 // always close Minim audio classes when you finish with them

 in.close();

 minim.stop();

 super.stop();

}