// fft utils for amit // based on nullsoft VMS and stephan sprenger's FFT paper class FFTutils { int WINDOW_SIZE,WS2; int BIT_LEN; int[] _bitrevtable; float _normF; float[] _equalize; float[] _envelope; float[] _fft_result; float[][] _fftBuffer; float[] _cosLUT,_sinLUT; float[] _FIRCoeffs; boolean _isEqualized, _hasEnvelope; public FFTutils(int windowSize) { WINDOW_SIZE=WS2=windowSize; WS2>>=1; BIT_LEN = (int)(Math.log((double)WINDOW_SIZE)/0.693147180559945+0.5); _normF=2f/WINDOW_SIZE; _hasEnvelope=false; _isEqualized=false; initFFTtables(); } void initFFTtables() { _cosLUT=new float[BIT_LEN]; _sinLUT=new float[BIT_LEN]; _fftBuffer=new float[WINDOW_SIZE][2]; _fft_result=new float[WS2]; // only need to compute sin/cos at BIT_LEN angles float phi=PI; for(int i=0; i i) { temp = _bitrevtable[i]; _bitrevtable[i] = _bitrevtable[j]; _bitrevtable[j] = temp; } bitm = WS2; while (bitm >= 1 && j >= bitm) { j -= bitm; bitm >>= 1; } j += bitm; } } // taken from nullsoft VMS // reduces impact of bassy freqs and slightly amplifies top range void useEqualizer(boolean on) { _isEqualized=on; if (on) { int i; float scaling = -0.02f; float inv_half_nfreq = 1.0f/WS2; _equalize = new float[WS2]; for (i=0; i> 1; w_r = _cosLUT[phi]; w_i = _sinLUT[phi++]; u_r = 1f; u_i = 0f; for (j = 1; j <= le2; j++) { for (i = j; i <= WINDOW_SIZE; i += le) { ip = i + le2; ip1 = ip-1; ii = i-1; float[] currFFT=_fftBuffer[ip1]; t_r = currFFT[0] * u_r - u_i * currFFT[1]; t_i = currFFT[1] * u_r + u_i * currFFT[0]; currFFT[0] = _fftBuffer[ii][0] - t_r; currFFT[1] = _fftBuffer[ii][1] - t_i; _fftBuffer[ii][0] += t_r; _fftBuffer[ii][1] += t_i; } t_r = u_r * w_r - w_i * u_i; u_i = w_r * u_i + w_i * u_r; u_r = t_r; } le<<=1; } // normalize bands or apply EQ float[] currBin; if (_isEqualized) { for(i=0; i eps; k++) { p *= x2; fact *= k; t = sq(p / fact); s += t; } return s; } int computeOrder() { // estimate filter order order = 2 * (int) ((atten - 7.95) / (14.36*trband/fN) + 1.0f); // estimate Kaiser window parameter if (atten >= 50.0f) kaiserV = 0.1102f*(atten - 8.7f); else if (atten > 21.0f) kaiserV = 0.5842f*(float)Math.exp(0.4f*(float)Math.log(atten - 21.0f))+ 0.07886f*(atten - 21.0f); if (atten <= 21.0f) kaiserV = 0.0f; println("filter oder: "+order); return order; } void initialize() { computeOrder(); // window function values float I0alpha = 1f/I0(kaiserV); int m = order>>1; float[] win = new float[m+1]; for (int n=1; n <= m; n++) win[n] = I0(kaiserV*sqrt(1.0f - sq((float)n/m))) * I0alpha; float w0 = 0.0f; float w1 = 0.0f; switch (filterType) { case LOW_PASS: w0 = 0.0f; w1 = PI*(f2 + 0.5f*trband)/fN; break; case HIGH_PASS: w0 = PI; w1 = PI*(1.0f - (f1 - 0.5f*trband)/fN); break; case BAND_PASS: w0 = HALF_PI * (f1 + f2) / fN; w1 = HALF_PI * (f2 - f1 + trband) / fN; break; } // filter coefficients (NB not normalised to unit maximum gain) a = new float[order+1]; a[0] = w1 / PI; for (int n=1; n <= m; n++) a[n] = sin(n*w1)*cos(n*w0)*win[n]/(n*PI); // shift impulse response to make filter causal: for (int n=m+1; n<=order; n++) a[n] = a[n - m]; for (int n=0; n<=m-1; n++) a[n] = a[order - n]; a[m] = w1 / PI; } float[] apply(float[] ip) { float[] op = new float[ip.length]; x=new float[order]; float sum; for (int i=0; i0; k--) x[k] = x[k-1]; } return op; } } FFTutils fft; FIRFilter filter; float[] signal,filtered; float[] fft_result; void setup() { size(1024,256); fft=new FFTutils(width); fft.useEqualizer(true); fft.useEnvelope(true,1); // setup new lowpass filter to cut off after 18.6kHz filter=new FIRFilter(FIRFilter.LOW_PASS,44100f,0,18600,60,3400); signal=new float[width]; } void loop() { background(50); // synthesize some basic sine wave as test signal for(int i=0; i