Chris@226: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@226: Chris@226: /* Chris@226: Sonic Visualiser Chris@226: An audio file viewer and annotation editor. Chris@226: Centre for Digital Music, Queen Mary, University of London. Chris@226: This file copyright 2006 Chris Cannam and QMUL. Chris@226: FFT code from Don Cross's public domain FFT implementation. Chris@226: Chris@226: This program is free software; you can redistribute it and/or Chris@226: modify it under the terms of the GNU General Public License as Chris@226: published by the Free Software Foundation; either version 2 of the Chris@226: License, or (at your option) any later version. See the file Chris@226: COPYING included with this distribution for more information. Chris@226: */ Chris@226: Chris@226: #include "FFTapi.h" Chris@226: Chris@226: #ifndef HAVE_FFTW3F Chris@226: Chris@226: #include Chris@227: #include Chris@226: Chris@226: void Chris@226: fft(unsigned int n, bool inverse, double *ri, double *ii, double *ro, double *io) Chris@226: { Chris@226: if (!ri || !ro || !io) return; Chris@226: Chris@226: unsigned int bits; Chris@226: unsigned int i, j, k, m; Chris@226: unsigned int blockSize, blockEnd; Chris@226: Chris@226: double tr, ti; Chris@226: Chris@226: if (n < 2) return; Chris@226: if (n & (n-1)) return; Chris@226: Chris@226: double angle = 2.0 * M_PI; Chris@226: if (inverse) angle = -angle; Chris@226: Chris@226: for (i = 0; ; ++i) { Chris@226: if (n & (1 << i)) { Chris@226: bits = i; Chris@226: break; Chris@226: } Chris@226: } Chris@226: Chris@227: int *table = new int[n]; Chris@226: Chris@227: for (i = 0; i < n; ++i) { Chris@226: Chris@227: m = i; Chris@227: Chris@227: for (j = k = 0; j < bits; ++j) { Chris@227: k = (k << 1) | (m & 1); Chris@227: m >>= 1; Chris@227: } Chris@227: Chris@227: table[i] = k; Chris@226: } Chris@226: Chris@226: if (ii) { Chris@226: for (i = 0; i < n; ++i) { Chris@226: ro[table[i]] = ri[i]; Chris@226: io[table[i]] = ii[i]; Chris@226: } Chris@226: } else { Chris@226: for (i = 0; i < n; ++i) { Chris@226: ro[table[i]] = ri[i]; Chris@226: io[table[i]] = 0.0; Chris@226: } Chris@226: } Chris@226: Chris@226: blockEnd = 1; Chris@226: Chris@226: for (blockSize = 2; blockSize <= n; blockSize <<= 1) { Chris@226: Chris@226: double delta = angle / (double)blockSize; Chris@226: double sm2 = -sin(-2 * delta); Chris@226: double sm1 = -sin(-delta); Chris@226: double cm2 = cos(-2 * delta); Chris@226: double cm1 = cos(-delta); Chris@226: double w = 2 * cm1; Chris@226: double ar[3], ai[3]; Chris@226: Chris@226: for (i = 0; i < n; i += blockSize) { Chris@226: Chris@226: ar[2] = cm2; Chris@226: ar[1] = cm1; Chris@226: Chris@226: ai[2] = sm2; Chris@226: ai[1] = sm1; Chris@226: Chris@226: for (j = i, m = 0; m < blockEnd; j++, m++) { Chris@226: Chris@226: ar[0] = w * ar[1] - ar[2]; Chris@226: ar[2] = ar[1]; Chris@226: ar[1] = ar[0]; Chris@226: Chris@226: ai[0] = w * ai[1] - ai[2]; Chris@226: ai[2] = ai[1]; Chris@226: ai[1] = ai[0]; Chris@226: Chris@226: k = j + blockEnd; Chris@226: tr = ar[0] * ro[k] - ai[0] * io[k]; Chris@226: ti = ar[0] * io[k] + ai[0] * ro[k]; Chris@226: Chris@226: ro[k] = ro[j] - tr; Chris@226: io[k] = io[j] - ti; Chris@226: Chris@226: ro[j] += tr; Chris@226: io[j] += ti; Chris@226: } Chris@226: } Chris@226: Chris@226: blockEnd = blockSize; Chris@226: } Chris@226: Chris@227: /* fftw doesn't normalise, so nor will we Chris@227: Chris@226: if (inverse) { Chris@226: Chris@226: double denom = (double)n; Chris@226: Chris@226: for (i = 0; i < n; i++) { Chris@226: ro[i] /= denom; Chris@226: io[i] /= denom; Chris@226: } Chris@226: } Chris@227: */ Chris@227: delete[] table; Chris@226: } Chris@226: Chris@226: struct fftf_plan_ { Chris@226: int size; Chris@226: int inverse; Chris@226: float *real; Chris@226: fftf_complex *cplx; Chris@226: }; Chris@226: Chris@226: fftf_plan Chris@226: fftf_plan_dft_r2c_1d(int n, float *in, fftf_complex *out, unsigned) Chris@226: { Chris@226: if (n < 2) return 0; Chris@226: if (n & (n-1)) return 0; Chris@226: Chris@226: fftf_plan_ *plan = new fftf_plan_; Chris@226: plan->size = n; Chris@226: plan->inverse = 0; Chris@226: plan->real = in; Chris@226: plan->cplx = out; Chris@226: return plan; Chris@226: } Chris@226: Chris@226: fftf_plan Chris@226: fftf_plan_dft_c2r_1d(int n, fftf_complex *in, float *out, unsigned) Chris@226: { Chris@226: if (n < 2) return 0; Chris@226: if (n & (n-1)) return 0; Chris@226: Chris@226: fftf_plan_ *plan = new fftf_plan_; Chris@226: plan->size = n; Chris@226: plan->inverse = 1; Chris@226: plan->real = out; Chris@226: plan->cplx = in; Chris@226: return plan; Chris@226: } Chris@226: Chris@226: void Chris@226: fftf_destroy_plan(fftf_plan p) Chris@226: { Chris@226: delete p; Chris@226: } Chris@226: Chris@226: void Chris@226: fftf_execute(const fftf_plan p) Chris@226: { Chris@226: float *real = p->real; Chris@226: fftf_complex *cplx = p->cplx; Chris@226: int n = p->size; Chris@227: int forward = !p->inverse; Chris@226: Chris@226: double *ri = new double[n]; Chris@226: double *ro = new double[n]; Chris@226: double *io = new double[n]; Chris@226: Chris@226: double *ii = 0; Chris@227: if (!forward) ii = new double[n]; Chris@226: Chris@227: if (forward) { Chris@226: for (int i = 0; i < n; ++i) { Chris@226: ri[i] = real[i]; Chris@226: } Chris@226: } else { Chris@226: for (int i = 0; i < n/2+1; ++i) { Chris@226: ri[i] = cplx[i][0]; Chris@226: ii[i] = cplx[i][1]; Chris@226: if (i > 0) { Chris@226: ri[n-i] = ri[i]; Chris@226: ii[n-i] = -ii[i]; Chris@226: } Chris@226: } Chris@226: } Chris@226: Chris@227: fft(n, !forward, ri, ii, ro, io); Chris@226: Chris@227: if (forward) { Chris@226: for (int i = 0; i < n/2+1; ++i) { Chris@226: cplx[i][0] = ro[i]; Chris@226: cplx[i][1] = io[i]; Chris@226: } Chris@226: } else { Chris@226: for (int i = 0; i < n; ++i) { Chris@226: real[i] = ro[i]; Chris@226: } Chris@226: } Chris@226: Chris@226: delete[] ri; Chris@226: delete[] ro; Chris@226: delete[] io; Chris@227: if (ii) delete[] ii; Chris@226: } Chris@226: Chris@226: #endif