package com.sun.media.sound;
public final class FFT {
private final double[] w;
private final int fftFrameSize;
private final int sign;
private final int[] bitm_array;
private final int fftFrameSize2;
public FFT(int fftFrameSize, int sign) {
w = computeTwiddleFactors(fftFrameSize, sign);
this.fftFrameSize = fftFrameSize;
this.sign = sign;
fftFrameSize2 = fftFrameSize << 1;
bitm_array = new int[fftFrameSize2];
for (int i = 2; i < fftFrameSize2; i += 2) {
int j;
int bitm;
for (bitm = 2, j = 0; bitm < fftFrameSize2; bitm <<= 1) {
if ((i & bitm) != 0)
j++;
j <<= 1;
}
bitm_array[i] = j;
}
}
public void transform(double[] data) {
bitreversal(data);
calc(fftFrameSize, data, sign, w);
}
private static double[] computeTwiddleFactors(int fftFrameSize,
int sign) {
int imax = (int) (Math.log(fftFrameSize) / Math.log(2.));
double[] warray = new double[(fftFrameSize - 1) * 4];
int w_index = 0;
for (int i = 0, nstep = 2; i < imax; i++) {
int jmax = nstep;
nstep <<= 1;
double wr = 1.0;
double wi = 0.0;
double arg = Math.PI / (jmax >> 1);
double wfr = Math.cos(arg);
double wfi = sign * Math.sin(arg);
for (int j = 0; j < jmax; j += 2) {
warray[w_index++] = wr;
warray[w_index++] = wi;
double tempr = wr;
wr = tempr * wfr - wi * wfi;
wi = tempr * wfi + wi * wfr;
}
}
{
w_index = 0;
int w_index2 = warray.length >> 1;
for (int i = 0, nstep = 2; i < (imax - 1); i++) {
int jmax = nstep;
nstep *= 2;
int ii = w_index + jmax;
for (int j = 0; j < jmax; j += 2) {
double wr = warray[w_index++];
double wi = warray[w_index++];
double wr1 = warray[ii++];
double wi1 = warray[ii++];
warray[w_index2++] = wr * wr1 - wi * wi1;
warray[w_index2++] = wr * wi1 + wi * wr1;
}
}
}
return warray;
}
private static void calc(int fftFrameSize, double[] data, int sign,
double[] w) {
final int fftFrameSize2 = fftFrameSize << 1;
int nstep = 2;
if (nstep >= fftFrameSize2)
return;
int i = nstep - 2;
if (sign == -1)
calcF4F(fftFrameSize, data, i, nstep, w);
else
calcF4I(fftFrameSize, data, i, nstep, w);
}
private static void calcF2E(int fftFrameSize, double[] data, int i,
int nstep, double[] w) {
int jmax = nstep;
for (int n = 0; n < jmax; n += 2) {
double wr = w[i++];
double wi = w[i++];
int m = n + jmax;
double datam_r = data[m];
double datam_i = data[m + 1];
double datan_r = data[n];
double datan_i = data[n + 1];
double tempr = datam_r * wr - datam_i * wi;
double tempi = datam_r * wi + datam_i * wr;
data[m] = datan_r - tempr;
data[m + 1] = datan_i - tempi;
data[n] = datan_r + tempr;
data[n + 1] = datan_i + tempi;
}
return;
}
private static void calcF4F(int fftFrameSize, double[] data, int i,
int nstep, double[] w) {
final int fftFrameSize2 = fftFrameSize << 1;
int w_len = w.length >> 1;
while (nstep < fftFrameSize2) {
if (nstep << 2 == fftFrameSize2) {
calcF4FE(fftFrameSize, data, i, nstep, w);
return;
}
int jmax = nstep;
int nnstep = nstep << 1;
if (nnstep == fftFrameSize2) {
calcF2E(fftFrameSize, data, i, nstep, w);
return;
}
nstep <<= 2;
int ii = i + jmax;
int iii = i + w_len;
{
i += 2;
ii += 2;
iii += 2;
for (int n = 0; n < fftFrameSize2; n += nstep) {
int m = n + jmax;
double datam1_r = data[m];
double datam1_i = data[m + 1];
double datan1_r = data[n];
double datan1_i = data[n + 1];
n += nnstep;
m += nnstep;
double datam2_r = data[m];
double datam2_i = data[m + 1];
double datan2_r = data[n];
double datan2_i = data[n + 1];
double tempr = datam1_r;
double tempi = datam1_i;
datam1_r = datan1_r - tempr;
datam1_i = datan1_i - tempi;
datan1_r = datan1_r + tempr;
datan1_i = datan1_i + tempi;
double n2w1r = datan2_r;
double n2w1i = datan2_i;
double m2ww1r = datam2_r;
double m2ww1i = datam2_i;
tempr = m2ww1r - n2w1r;
tempi = m2ww1i - n2w1i;
datam2_r = datam1_r + tempi;
datam2_i = datam1_i - tempr;
datam1_r = datam1_r - tempi;
datam1_i = datam1_i + tempr;
tempr = n2w1r + m2ww1r;
tempi = n2w1i + m2ww1i;
datan2_r = datan1_r - tempr;
datan2_i = datan1_i - tempi;
datan1_r = datan1_r + tempr;
datan1_i = datan1_i + tempi;
data[m] = datam2_r;
data[m + 1] = datam2_i;
data[n] = datan2_r;
data[n + 1] = datan2_i;
n -= nnstep;
m -= nnstep;
data[m] = datam1_r;
data[m + 1] = datam1_i;
data[n] = datan1_r;
data[n + 1] = datan1_i;
}
}
for (int j = 2; j < jmax; j += 2) {
double wr = w[i++];
double wi = w[i++];
double wr1 = w[ii++];
double wi1 = w[ii++];
double wwr1 = w[iii++];
double wwi1 = w[iii++];
for (int n = j; n < fftFrameSize2; n += nstep) {
int m = n + jmax;
double datam1_r = data[m];
double datam1_i = data[m + 1];
double datan1_r = data[n];
double datan1_i = data[n + 1];
n += nnstep;
m += nnstep;
double datam2_r = data[m];
double datam2_i = data[m + 1];
double datan2_r = data[n];
double datan2_i = data[n + 1];
double tempr = datam1_r * wr - datam1_i * wi;
double tempi = datam1_r * wi + datam1_i * wr;
datam1_r = datan1_r - tempr;
datam1_i = datan1_i - tempi;
datan1_r = datan1_r + tempr;
datan1_i = datan1_i + tempi;
double n2w1r = datan2_r * wr1 - datan2_i * wi1;
double n2w1i = datan2_r * wi1 + datan2_i * wr1;
double m2ww1r = datam2_r * wwr1 - datam2_i * wwi1;
double m2ww1i = datam2_r * wwi1 + datam2_i * wwr1;
tempr = m2ww1r - n2w1r;
tempi = m2ww1i - n2w1i;
datam2_r = datam1_r + tempi;
datam2_i = datam1_i - tempr;
datam1_r = datam1_r - tempi;
datam1_i = datam1_i + tempr;
tempr = n2w1r + m2ww1r;
tempi = n2w1i + m2ww1i;
datan2_r = datan1_r - tempr;
datan2_i = datan1_i - tempi;
datan1_r = datan1_r + tempr;
datan1_i = datan1_i + tempi;
data[m] = datam2_r;
data[m + 1] = datam2_i;
data[n] = datan2_r;
data[n + 1] = datan2_i;
n -= nnstep;
m -= nnstep;
data[m] = datam1_r;
data[m + 1] = datam1_i;
data[n] = datan1_r;
data[n + 1] = datan1_i;
}
}
i += jmax << 1;
}
calcF2E(fftFrameSize, data, i, nstep, w);
}
private static void calcF4I(int fftFrameSize, double[] data, int i,
int nstep, double[] w) {
final int fftFrameSize2 = fftFrameSize << 1;
int w_len = w.length >> 1;
while (nstep < fftFrameSize2) {
if (nstep << 2 == fftFrameSize2) {
calcF4IE(fftFrameSize, data, i, nstep, w);
return;
}
int jmax = nstep;
int nnstep = nstep << 1;
if (nnstep == fftFrameSize2) {
calcF2E(fftFrameSize, data, i, nstep, w);
return;
}
nstep <<= 2;
int ii = i + jmax;
int iii = i + w_len;
{
i += 2;
ii += 2;
iii += 2;
for (int n = 0; n < fftFrameSize2; n += nstep) {
int m = n + jmax;
double datam1_r = data[m];
double datam1_i = data[m + 1];
double datan1_r = data[n];
double datan1_i = data[n + 1];
n += nnstep;
m += nnstep;
double datam2_r = data[m];
double datam2_i = data[m + 1];
double datan2_r = data[n];
double datan2_i = data[n + 1];
double tempr = datam1_r;
double tempi = datam1_i;
datam1_r = datan1_r - tempr;
datam1_i = datan1_i - tempi;
datan1_r = datan1_r + tempr;
datan1_i = datan1_i + tempi;
double n2w1r = datan2_r;
double n2w1i = datan2_i;
double m2ww1r = datam2_r;
double m2ww1i = datam2_i;
tempr = n2w1r - m2ww1r;
tempi = n2w1i - m2ww1i;
datam2_r = datam1_r + tempi;
datam2_i = datam1_i - tempr;
datam1_r = datam1_r - tempi;
datam1_i = datam1_i + tempr;
tempr = n2w1r + m2ww1r;
tempi = n2w1i + m2ww1i;
datan2_r = datan1_r - tempr;
datan2_i = datan1_i - tempi;
datan1_r = datan1_r + tempr;
datan1_i = datan1_i + tempi;
data[m] = datam2_r;
data[m + 1] = datam2_i;
data[n] = datan2_r;
data[n + 1] = datan2_i;
n -= nnstep;
m -= nnstep;
data[m] = datam1_r;
data[m + 1] = datam1_i;
data[n] = datan1_r;
data[n + 1] = datan1_i;
}
}
for (int j = 2; j < jmax; j += 2) {
double wr = w[i++];
double wi = w[i++];
double wr1 = w[ii++];
double wi1 = w[ii++];
double wwr1 = w[iii++];
double wwi1 = w[iii++];
for (int n = j; n < fftFrameSize2; n += nstep) {
int m = n + jmax;
double datam1_r = data[m];
double datam1_i = data[m + 1];
double datan1_r = data[n];
double datan1_i = data[n + 1];
n += nnstep;
m += nnstep;
double datam2_r = data[m];
double datam2_i = data[m + 1];
double datan2_r = data[n];
double datan2_i = data[n + 1];
double tempr = datam1_r * wr - datam1_i * wi;
double tempi = datam1_r * wi + datam1_i * wr;
datam1_r = datan1_r - tempr;
datam1_i = datan1_i - tempi;
datan1_r = datan1_r + tempr;
datan1_i = datan1_i + tempi;
double n2w1r = datan2_r * wr1 - datan2_i * wi1;
double n2w1i = datan2_r * wi1 + datan2_i * wr1;
double m2ww1r = datam2_r * wwr1 - datam2_i * wwi1;
double m2ww1i = datam2_r * wwi1 + datam2_i * wwr1;
tempr = n2w1r - m2ww1r;
tempi = n2w1i - m2ww1i;
datam2_r = datam1_r + tempi;
datam2_i = datam1_i - tempr;
datam1_r = datam1_r - tempi;
datam1_i = datam1_i + tempr;
tempr = n2w1r + m2ww1r;
tempi = n2w1i + m2ww1i;
datan2_r = datan1_r - tempr;
datan2_i = datan1_i - tempi;
datan1_r = datan1_r + tempr;
datan1_i = datan1_i + tempi;
data[m] = datam2_r;
data[m + 1] = datam2_i;
data[n] = datan2_r;
data[n + 1] = datan2_i;
n -= nnstep;
m -= nnstep;
data[m] = datam1_r;
data[m + 1] = datam1_i;
data[n] = datan1_r;
data[n + 1] = datan1_i;
}
}
i += jmax << 1;
}
calcF2E(fftFrameSize, data, i, nstep, w);
}
private static void calcF4FE(int fftFrameSize, double[] data, int i,
int nstep, double[] w) {
final int fftFrameSize2 = fftFrameSize << 1;
int w_len = w.length >> 1;
while (nstep < fftFrameSize2) {
int jmax = nstep;
int nnstep = nstep << 1;
if (nnstep == fftFrameSize2) {
calcF2E(fftFrameSize, data, i, nstep, w);
return;
}
nstep <<= 2;
int ii = i + jmax;
int iii = i + w_len;
for (int n = 0; n < jmax; n += 2) {
double wr = w[i++];
double wi = w[i++];
double wr1 = w[ii++];
double wi1 = w[ii++];
double wwr1 = w[iii++];
double wwi1 = w[iii++];
int m = n + jmax;
double datam1_r = data[m];
double datam1_i = data[m + 1];
double datan1_r = data[n];
double datan1_i = data[n + 1];
n += nnstep;
m += nnstep;
double datam2_r = data[m];
double datam2_i = data[m + 1];
double datan2_r = data[n];
double datan2_i = data[n + 1];
double tempr = datam1_r * wr - datam1_i * wi;
double tempi = datam1_r * wi + datam1_i * wr;
datam1_r = datan1_r - tempr;
datam1_i = datan1_i - tempi;
datan1_r = datan1_r + tempr;
datan1_i = datan1_i + tempi;
double n2w1r = datan2_r * wr1 - datan2_i * wi1;
double n2w1i = datan2_r * wi1 + datan2_i * wr1;
double m2ww1r = datam2_r * wwr1 - datam2_i * wwi1;
double m2ww1i = datam2_r * wwi1 + datam2_i * wwr1;
tempr = m2ww1r - n2w1r;
tempi = m2ww1i - n2w1i;
datam2_r = datam1_r + tempi;
datam2_i = datam1_i - tempr;
datam1_r = datam1_r - tempi;
datam1_i = datam1_i + tempr;
tempr = n2w1r + m2ww1r;
tempi = n2w1i + m2ww1i;
datan2_r = datan1_r - tempr;
datan2_i = datan1_i - tempi;
datan1_r = datan1_r + tempr;
datan1_i = datan1_i + tempi;
data[m] = datam2_r;
data[m + 1] = datam2_i;
data[n] = datan2_r;
data[n + 1] = datan2_i;
n -= nnstep;
m -= nnstep;
data[m] = datam1_r;
data[m + 1] = datam1_i;
data[n] = datan1_r;
data[n + 1] = datan1_i;
}
i += jmax << 1;
}
}
private static void calcF4IE(int fftFrameSize, double[] data, int i,
int nstep, double[] w) {
final int fftFrameSize2 = fftFrameSize << 1;
int w_len = w.length >> 1;
while (nstep < fftFrameSize2) {
int jmax = nstep;
int nnstep = nstep << 1;
if (nnstep == fftFrameSize2) {
calcF2E(fftFrameSize, data, i, nstep, w);
return;
}
nstep <<= 2;
int ii = i + jmax;
int iii = i + w_len;
for (int n = 0; n < jmax; n += 2) {
double wr = w[i++];
double wi = w[i++];
double wr1 = w[ii++];
double wi1 = w[ii++];
double wwr1 = w[iii++];
double wwi1 = w[iii++];
int m = n + jmax;
double datam1_r = data[m];
double datam1_i = data[m + 1];
double datan1_r = data[n];
double datan1_i = data[n + 1];
n += nnstep;
m += nnstep;
double datam2_r = data[m];
double datam2_i = data[m + 1];
double datan2_r = data[n];
double datan2_i = data[n + 1];
double tempr = datam1_r * wr - datam1_i * wi;
double tempi = datam1_r * wi + datam1_i * wr;
datam1_r = datan1_r - tempr;
datam1_i = datan1_i - tempi;
datan1_r = datan1_r + tempr;
datan1_i = datan1_i + tempi;
double n2w1r = datan2_r * wr1 - datan2_i * wi1;
double n2w1i = datan2_r * wi1 + datan2_i * wr1;
double m2ww1r = datam2_r * wwr1 - datam2_i * wwi1;
double m2ww1i = datam2_r * wwi1 + datam2_i * wwr1;
tempr = n2w1r - m2ww1r;
tempi = n2w1i - m2ww1i;
datam2_r = datam1_r + tempi;
datam2_i = datam1_i - tempr;
datam1_r = datam1_r - tempi;
datam1_i = datam1_i + tempr;
tempr = n2w1r + m2ww1r;
tempi = n2w1i + m2ww1i;
datan2_r = datan1_r - tempr;
datan2_i = datan1_i - tempi;
datan1_r = datan1_r + tempr;
datan1_i = datan1_i + tempi;
data[m] = datam2_r;
data[m + 1] = datam2_i;
data[n] = datan2_r;
data[n + 1] = datan2_i;
n -= nnstep;
m -= nnstep;
data[m] = datam1_r;
data[m + 1] = datam1_i;
data[n] = datan1_r;
data[n + 1] = datan1_i;
}
i += jmax << 1;
}
}
private void bitreversal(double[] data) {
if (fftFrameSize < 4)
return;
int inverse = fftFrameSize2 - 2;
for (int i = 0; i < fftFrameSize; i += 4) {
int j = bitm_array[i];
if (i < j) {
int n = i;
int m = j;
double tempr = data[n];
data[n] = data[m];
data[m] = tempr;
n++;
m++;
double tempi = data[n];
data[n] = data[m];
data[m] = tempi;
n = inverse - i;
m = inverse - j;
tempr = data[n];
data[n] = data[m];
data[m] = tempr;
n++;
m++;
tempi = data[n];
data[n] = data[m];
data[m] = tempi;
}
int m = j + fftFrameSize;
int n = i + 2;
double tempr = data[n];
data[n] = data[m];
data[m] = tempr;
n++;
m++;
double tempi = data[n];
data[n] = data[m];
data[m] = tempi;
}
}
}