Mercurial > hg > svcore
diff data/fft/FFTapi.cpp @ 226:a867be73b638
* Add non-fftw3 fft alternative
author | Chris Cannam |
---|---|
date | Fri, 09 Feb 2007 11:32:34 +0000 |
parents | |
children | e919a2b97c2a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/fft/FFTapi.cpp Fri Feb 09 11:32:34 2007 +0000 @@ -0,0 +1,231 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006 Chris Cannam and QMUL. + FFT code from Don Cross's public domain FFT implementation. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "FFTapi.h" + +#ifndef HAVE_FFTW3F + +#include <cmath> + +void +fft(unsigned int n, bool inverse, double *ri, double *ii, double *ro, double *io) +{ + if (!ri || !ro || !io) return; + + unsigned int bits; + unsigned int i, j, k, m; + unsigned int blockSize, blockEnd; + + double tr, ti; + + if (n < 2) return; + if (n & (n-1)) return; + + double angle = 2.0 * M_PI; + if (inverse) angle = -angle; + + for (i = 0; ; ++i) { + if (n & (1 << i)) { + bits = i; + break; + } + } + + static unsigned int tableSize = 0; + static int *table = 0; + + if (tableSize != n) { + + delete[] table; + + table = new int[n]; + + for (i = 0; i < n; ++i) { + + m = i; + + for (j = k = 0; j < bits; ++j) { + k = (k << 1) | (m & 1); + m >>= 1; + } + + table[i] = k; + } + + tableSize = n; + } + + if (ii) { + for (i = 0; i < n; ++i) { + ro[table[i]] = ri[i]; + io[table[i]] = ii[i]; + } + } else { + for (i = 0; i < n; ++i) { + ro[table[i]] = ri[i]; + io[table[i]] = 0.0; + } + } + + blockEnd = 1; + + for (blockSize = 2; blockSize <= n; blockSize <<= 1) { + + double delta = angle / (double)blockSize; + double sm2 = -sin(-2 * delta); + double sm1 = -sin(-delta); + double cm2 = cos(-2 * delta); + double cm1 = cos(-delta); + double w = 2 * cm1; + double ar[3], ai[3]; + + for (i = 0; i < n; i += blockSize) { + + ar[2] = cm2; + ar[1] = cm1; + + ai[2] = sm2; + ai[1] = sm1; + + for (j = i, m = 0; m < blockEnd; j++, m++) { + + ar[0] = w * ar[1] - ar[2]; + ar[2] = ar[1]; + ar[1] = ar[0]; + + ai[0] = w * ai[1] - ai[2]; + ai[2] = ai[1]; + ai[1] = ai[0]; + + k = j + blockEnd; + tr = ar[0] * ro[k] - ai[0] * io[k]; + ti = ar[0] * io[k] + ai[0] * ro[k]; + + ro[k] = ro[j] - tr; + io[k] = io[j] - ti; + + ro[j] += tr; + io[j] += ti; + } + } + + blockEnd = blockSize; + } + + if (inverse) { + + double denom = (double)n; + + for (i = 0; i < n; i++) { + ro[i] /= denom; + io[i] /= denom; + } + } +} + +struct fftf_plan_ { + int size; + int inverse; + float *real; + fftf_complex *cplx; +}; + +fftf_plan +fftf_plan_dft_r2c_1d(int n, float *in, fftf_complex *out, unsigned) +{ + if (n < 2) return 0; + if (n & (n-1)) return 0; + + fftf_plan_ *plan = new fftf_plan_; + plan->size = n; + plan->inverse = 0; + plan->real = in; + plan->cplx = out; + return plan; +} + +fftf_plan +fftf_plan_dft_c2r_1d(int n, fftf_complex *in, float *out, unsigned) +{ + if (n < 2) return 0; + if (n & (n-1)) return 0; + + fftf_plan_ *plan = new fftf_plan_; + plan->size = n; + plan->inverse = 1; + plan->real = out; + plan->cplx = in; + return plan; +} + +void +fftf_destroy_plan(fftf_plan p) +{ + delete p; +} + +void +fftf_execute(const fftf_plan p) +{ + //!!! doesn't work yet for inverse transforms + + float *real = p->real; + fftf_complex *cplx = p->cplx; + int n = p->size; + int inv = p->inverse; + + double *ri = new double[n]; + double *ro = new double[n]; + double *io = new double[n]; + + double *ii = 0; + if (inv) ii = new double[n]; + + if (!inv) { + for (int i = 0; i < n; ++i) { + ri[i] = real[i]; + } + } else { + for (int i = 0; i < n/2+1; ++i) { + ri[i] = cplx[i][0]; + ii[i] = cplx[i][1]; + if (i > 0) { + ri[n-i] = ri[i]; + ii[n-i] = -ii[i]; + } + } + } + + fft(n, inv, ri, ii, ro, io); + + if (!inv) { + for (int i = 0; i < n/2+1; ++i) { + cplx[i][0] = ro[i]; + cplx[i][1] = io[i]; + } + } else { + for (int i = 0; i < n; ++i) { + real[i] = ro[i]; + } + } + + delete[] ri; + delete[] ro; + delete[] io; + delete[] ii; +} + +#endif