/* * */ package xplayer.dsp; /** * The Class KJFFT. * * @author Kris Fudalewski */ public class KJFFT { /** The xre. */ private float[] xre; /** The xim. */ private float[] xim; /** The mag. */ private float[] mag; /** The fft sin. */ private float[] fftSin; /** The fft cos. */ private float[] fftCos; /** The fft br. */ private int[] fftBr; /** The nu. */ private int ss, ss2, nu;// , nu1; /** * Instantiates a new kjfft. * * @param pSampleSize the sample size */ public KJFFT(int pSampleSize) { ss = pSampleSize; ss2 = ss >> 1; xre = new float[ss]; xim = new float[ss]; mag = new float[ss2]; nu = (int) (Math.log(ss) / Math.log(2)); // nu1 = nu - 1; prepareFFTTables(); } /** * Bitrev. * * @param j the j * @param nu the nu * @return the int */ private int bitrev(int j, int nu) { int j1 = j; int j2; int k = 0; for (int i = 1; i <= nu; i++) { j2 = j1 >> 1; k = (k << 1) + j1 - (j2 << 1); j1 = j2; } return k; } /** * Calculate. * * @param pSample The sample to compute FFT values on. * @return The results of the calculation, normalized between 0.0 and 1.0. */ public float[] calculate(float[] pSample) { int n2 = ss2; // int nu1 = nu - 1; int wAps = pSample.length / ss; // -- FIXME: This affects the calculation accuracy, because // is compresses the digital signal. Looks nice on // the spectrum analyser, as it chops off most of // sound we cannot hear anyway. for (int a = 0, b = 0; a < pSample.length; a += wAps, b++) { xre[b] = pSample[a]; xim[b] = 0.0f; } float tr, ti, c, s; int k, kn2, x = 0; for (int l = 1; l <= nu; l++) { k = 0; while (k < ss) { for (int i = 1; i <= n2; i++) { // -- Tabled sin/cos c = fftCos[x]; s = fftSin[x]; kn2 = k + n2; tr = xre[kn2] * c + xim[kn2] * s; ti = xim[kn2] * c - xre[kn2] * s; xre[kn2] = xre[k] - tr; xim[kn2] = xim[k] - ti; xre[k] += tr; xim[k] += ti; k++; x++; } k += n2; } // nu1--; n2 >>= 1; } int r; // -- Reorder output. for (k = 0; k < ss; k++) { // -- Use tabled BR values. r = fftBr[k]; if (r > k) { tr = xre[k]; ti = xim[k]; xre[k] = xre[r]; xim[k] = xim[r]; xre[r] = tr; xim[r] = ti; } } // -- Calculate magnitude. mag[0] = (float) (Math.sqrt(xre[0] * xre[0] + xim[0] * xim[0])) / ss; for (int i = 1; i < ss2; i++) { mag[i] = 2 * (float) (Math.sqrt(xre[i] * xre[i] + xim[i] * xim[i])) / ss; } return mag; } /** * Prepare FFT tables. */ private void prepareFFTTables() { int n2 = ss2; int nu1 = nu - 1; // -- Allocate FFT SIN/COS tables. fftSin = new float[nu * n2]; fftCos = new float[nu * n2]; float p, arg; int k = 0, x = 0; // -- Prepare SIN/COS tables. for (int l = 1; l <= nu; l++) { while (k < ss) { for (int i = 1; i <= n2; i++) { p = bitrev(k >> nu1, nu); arg = 2 * (float) Math.PI * p / ss; fftSin[x] = (float) Math.sin(arg); fftCos[x] = (float) Math.cos(arg); k++; x++; } k += n2; } k = 0; nu1--; n2 >>= 1; } // -- Prepare bitrev table. fftBr = new int[ss]; for (k = 0; k < ss; k++) { fftBr[k] = bitrev(k, nu); } } }