import ddf.minim.*; import ddf.minim.analysis.*; Minim minim; FFT fft; int bufferSize = 256; int bufferStart = 0; int sampleRate = 44100; PFont titleFont; PFont smallFont; float[] signal = new float[44100]; float frequency; WindowFunction window; int waveform; public final int SINEWAVE = 1; public final int SQUAREWAVE = 2; public final int SAWWAVE = 3; public final int TRIANGLEWAVE = 4; //String[] windowName = {"Rectangular", "Hamming", "Hann", "Cosine", "Lanczos", "Bartlett", "Triangular", "Bartlett-Hann", "Blackman"}; void setup() { size(800, 400); frameRate(10); minim = new Minim(this); fft = new FFT(bufferSize, 44100); frequency = 900; String[] fontList = PFont.list(); //println(fontList); titleFont = createFont("Arial", 14, true); smallFont = createFont("Arial", 12, true); window = FourierTransform.HAMMING; waveform = SINEWAVE; smooth(); } void draw() { background(0xEEEEEE); for(int i = 0; i < 44100; i++) { float step = i * (frequency / 44100) % 1; switch(waveform) { case SINEWAVE: signal[i] = (float)Math.sin(TWO_PI * step); break; case SQUAREWAVE: signal[i] = step < 0.5 ? 1 : -1; break; case SAWWAVE: signal[i] = 2 * ( step - (float)Math.round(step)); break; case TRIANGLEWAVE: signal[i] = 1 - 4 * Math.abs(Math.round(step) - step); break; } } for ( int i = 0; i < 1024 -1; i++ ) { stroke(180); strokeWeight(1.5); if ( i >= bufferStart && i <= bufferStart + bufferSize ) { stroke(60); strokeWeight(1.5); } line(i,(signal[i] * 20) + 50, i+1, (signal[i+1] * 20) + 50); if ( i == bufferStart || i == bufferStart + bufferSize ) { stroke(30); strokeWeight(2); line(i, 25, i, 75); } } float[] measuredSignal = new float[bufferSize]; // Draw FFT perceived waveform for ( int i = 0; i < 1024 -1; i++ ) { stroke(60); strokeWeight(1.5); int pos = (i + bufferSize - (bufferStart % bufferSize)) % bufferSize + bufferStart; line(i, (signal[pos] * 20) + 130, i + 1, (signal[pos+1] * 20) + 130); measuredSignal[pos - bufferStart] = signal[pos]; // draw discontinuities if ( pos == bufferStart + bufferSize - 1 ) { stroke(30); strokeWeight(2); line(i, (signal[pos] * 20) + 130, i, signal[bufferStart] * 20 + 130); } } float discontinuityAmplitude = Math.abs(measuredSignal[measuredSignal.length - 1] - measuredSignal[0]); fft.window(window); fft.forward(measuredSignal); float[] windowCurve = window.generateCurve(bufferSize); // Draw windowed waveform for ( int i = 0; i < 1024 -1; i++ ) { stroke(180); strokeWeight(1.5); int pos = (i + bufferSize - (bufferStart % bufferSize)) % bufferSize; if (pos == bufferSize - 1 ) { // draw discontinuity line(i, (measuredSignal[pos] * 20) + 210, i, measuredSignal[0] * 20 + 210); } else { // draw window curve and waveform stroke(180); line(i, windowCurve[pos] * 20 + 210, i + 1, windowCurve[pos+1] * 20 + 210); line(i, windowCurve[pos] * -1 * 20 + 210, i + 1, windowCurve[pos+1] * -1 * 20 + 210); stroke(60); line(i, measuredSignal[pos] * 20 + 210, i + 1, measuredSignal[pos+1] * 20 + 210); } } // draw fft bins for ( int i = 0; i < fft.specSize() - 1; i++ ) { stroke(200, 60, 40, 128); strokeWeight(2); line(i * 3, height - fft.getBand(i) * 5, (i+1) * 3, height - fft.getBand(i+1) * 5); } // anotations textFont(titleFont); fill(60); text("Signal", 10, 20); text("FFT perceived signal (no window)", 10, 100); text("FFT perceived signal with ", 10, 180); fill(100); text(window.getClass().getName(), 177, 180); textFont(smallFont); fill(100); text("Measured interval: " + bufferSize + " samples, Frequency: " + frequency + "Hz", 55, 20); text("discontinuity amplitude: " + discontinuityAmplitude, 230, 100); } void keyPressed() { if ( keyCode == LEFT ) { if (bufferStart > 0) { bufferStart--; } } if ( keyCode == RIGHT ) { bufferStart++; } if ( keyCode == UP ) { if (bufferSize <= 16384) { bufferSize *= 2; fft = new FFT(bufferSize, 44100); } } if ( keyCode == DOWN ) { if (bufferSize > 4 ) { bufferSize /= 2; fft = new FFT(bufferSize, 44100); } } if ( key == '0' ) { window = new RectangularWindow(); } if ( key == '1' ) { window = new HammingWindow(); } if ( key == '2' ) { window = new HannWindow(); } if ( key == '3' ) { window = new CosineWindow(); } if ( key == '4' ) { window = new LanczosWindow(); } if ( key == '5' ) { window = new BartlettWindow(); } if ( key == '6' ) { window = new TriangularWindow(); } if ( key == '7' ) { window = new BartlettHannWindow(); } if ( key == '8' ) { window = new BlackmanWindow(); } if ( key == '9' ) { window = new GaussWindow(); } if ( key == 'd' ) { frequency -= 10; } if ( key == 'f' ) { frequency += 10; } if ( key == 'w' ) { waveform += 1; switch(waveform) { case SINEWAVE: case SQUAREWAVE: case SAWWAVE: case TRIANGLEWAVE: break; default: waveform = SINEWAVE; break; } } }