--- /dev/null
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include "Fft.h"
+
+#include <stdlib.h>
+#include <math.h>
+
+Fft::Fft(void) : mCosine(0), mSine(0), mFftSize(0), mFftTableSize(0) { }
+
+Fft::~Fft(void) {
+ fftCleanup();
+}
+
+/* Construct a FFT table suitable to perform a DFT of size 2^power. */
+void Fft::fftInit(int power) {
+ fftCleanup();
+ fftMakeTable(power);
+}
+
+void Fft::fftCleanup() {
+ delete [] mSine;
+ delete [] mCosine;
+ mSine = NULL;
+ mCosine = NULL;
+ mFftTableSize = 0;
+ mFftSize = 0;
+}
+
+/* z <- (10 * log10(x^2 + y^2)) for n elements */
+int Fft::fftLogMag(float *x, float *y, float *z, int n) {
+ float *xp, *yp, *zp, t1, t2, ssq;
+
+ if(x && y && z && n) {
+ for(xp=x+n, yp=y+n, zp=z+n; zp > z;) {
+ t1 = *--xp;
+ t2 = *--yp;
+ ssq = (t1*t1)+(t2*t2);
+ *--zp = (ssq > 0.0)? 10.0 * log10((double)ssq) : -200.0;
+ }
+ return 1; //true
+ } else {
+ return 0; // false/fail
+ }
+}
+
+int Fft::fftMakeTable(int pow2) {
+ int lmx, lm;
+ float *c, *s;
+ double scl, arg;
+
+ mFftSize = 1 << pow2;
+ mFftTableSize = lmx = mFftSize/2;
+ mSine = new float[lmx];
+ mCosine = new float[lmx];
+ scl = (M_PI*2.0)/mFftSize;
+ for (s=mSine, c=mCosine, lm=0; lm<lmx; lm++ ) {
+ arg = scl * lm;
+ *s++ = sin(arg);
+ *c++ = cos(arg);
+ }
+ mBase = (mFftTableSize * 2)/mFftSize;
+ mPower2 = pow2;
+ return(mFftTableSize);
+}
+
+
+/* Compute the discrete Fourier transform of the 2**l complex sequence
+ * in x (real) and y (imaginary). The DFT is computed in place and the
+ * Fourier coefficients are returned in x and y.
+ */
+void Fft::fft( float *x, float *y ) {
+ float c, s, t1, t2;
+ int j1, j2, li, lix, i;
+ int lmx, lo, lixnp, lm, j, nv2, k=mBase, im, jm, l = mPower2;
+
+ for (lmx=mFftSize, lo=0; lo < l; lo++, k *= 2) {
+ lix = lmx;
+ lmx /= 2;
+ lixnp = mFftSize - lix;
+ for (i=0, lm=0; lm<lmx; lm++, i += k ) {
+ c = mCosine[i];
+ s = mSine[i];
+ for ( li = lixnp+lm, j1 = lm, j2 = lm+lmx; j1<=li;
+ j1+=lix, j2+=lix ) {
+ t1 = x[j1] - x[j2];
+ t2 = y[j1] - y[j2];
+ x[j1] += x[j2];
+ y[j1] += y[j2];
+ x[j2] = (c * t1) + (s * t2);
+ y[j2] = (c * t2) - (s * t1);
+ }
+ }
+ }
+
+ /* Now perform the bit reversal. */
+ j = 1;
+ nv2 = mFftSize/2;
+ for ( i=1; i < mFftSize; i++ ) {
+ if ( j < i ) {
+ jm = j-1;
+ im = i-1;
+ t1 = x[jm];
+ t2 = y[jm];
+ x[jm] = x[im];
+ y[jm] = y[im];
+ x[im] = t1;
+ y[im] = t2;
+ }
+ k = nv2;
+ while ( j > k ) {
+ j -= k;
+ k /= 2;
+ }
+ j += k;
+ }
+}
+
+/* Compute the discrete inverse Fourier transform of the 2**l complex
+ * sequence in x (real) and y (imaginary). The DFT is computed in
+ * place and the Fourier coefficients are returned in x and y. Note
+ * that this DOES NOT scale the result by the inverse FFT size.
+ */
+void Fft::ifft(float *x, float *y ) {
+ float c, s, t1, t2;
+ int j1, j2, li, lix, i;
+ int lmx, lo, lixnp, lm, j, nv2, k=mBase, im, jm, l = mPower2;
+
+ for (lmx=mFftSize, lo=0; lo < l; lo++, k *= 2) {
+ lix = lmx;
+ lmx /= 2;
+ lixnp = mFftSize - lix;
+ for (i=0, lm=0; lm<lmx; lm++, i += k ) {
+ c = mCosine[i];
+ s = - mSine[i];
+ for ( li = lixnp+lm, j1 = lm, j2 = lm+lmx; j1<=li;
+ j1+=lix, j2+=lix ) {
+ t1 = x[j1] - x[j2];
+ t2 = y[j1] - y[j2];
+ x[j1] += x[j2];
+ y[j1] += y[j2];
+ x[j2] = (c * t1) + (s * t2);
+ y[j2] = (c * t2) - (s * t1);
+ }
+ }
+ }
+
+ /* Now perform the bit reversal. */
+ j = 1;
+ nv2 = mFftSize/2;
+ for ( i=1; i < mFftSize; i++ ) {
+ if ( j < i ) {
+ jm = j-1;
+ im = i-1;
+ t1 = x[jm];
+ t2 = y[jm];
+ x[jm] = x[im];
+ y[jm] = y[im];
+ x[im] = t1;
+ y[im] = t2;
+ }
+ k = nv2;
+ while ( j > k ) {
+ j -= k;
+ k /= 2;
+ }
+ j += k;
+ }
+}
+
+int Fft::fftGetSize(void) { return mFftSize; }
+
+int Fft::fftGetPower2(void) { return mPower2; }