// 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();
}