/* * This file is part of the Advance project. * * Copyright (C) 2004 Andrea Mazzoleni * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * In addition, as a special exception, Andrea Mazzoleni * gives permission to link the code of this program with * the MAME library (or with modified versions of MAME that use the * same license as MAME), and distribute linked combinations including * the two. You must obey the GNU General Public License in all * respects for all of the code used other than MAME. If you modify * this file, you may extend this exception to your version of the * file, but you are not obligated to do so. If you do not wish to * do so, delete this exception statement from your version. */ #include "portable.h" #include "dft.h" static adv_error dft_init(struct adv_dft_stage_struct* context, unsigned n) { unsigned i, j; double konst, delta; double thi, early, late; double* p; unsigned* fbp; unsigned* bbp; unsigned k, halfk, kmin1; int log2n; /* check for legal size */ if (n == 0 || (n & (n-1))) { return -1; } /* compute log size */ for (i = 1, log2n = 0; i < n; i <<= 1, log2n++); context->n = n; context->log2n = log2n; /* allocate storage for new tables */ context->ss = malloc(n * sizeof(double)); if (!context->ss) return -1; context->brev = malloc(n * sizeof(unsigned)); if (!context->brev) return -1; /* compute sine table, using the recurrent relation */ /* x[n] = 2 * cos(d) * x[n-1] - x[n-2], where d = 2 * pi / n */ delta = 2. * M_PI / n; konst = 2. * cos(delta); p = context->ss; *p++ = late = 0.; *p++ = early = sin(delta); for(i=2;icc = context->ss + n / 4; /* compute bit-reversing table */ context->brev[0] = 0; for(k=2;k<=n;k<<=1) { halfk = k >> 1, kmin1 = k - 1; fbp = context->brev; for(j=0;jss); free(context->brev); } /** * SRFT (Split-radix fast Fourier transform). * A Duhamel-Hollman split-radix DIF FFT. * Ref.: Electronic Letters, Jan. 5, 1984. */ static void dft(const struct adv_dft_stage_struct* context, double* restrict yr, double* restrict yi, unsigned ratio) { unsigned n4, n2; int i, j, k; int i0, i1, i2, i3, is, id; double r1, r2, s1, s2, s3; double cc1, ss1, cc3, ss3; unsigned ue, ua, ua3; int log2n2; unsigned n = context->n >> ratio; const double* restrict ss = context->ss; const double* restrict cc = context->cc; const unsigned* restrict brev = context->brev; int log2n = context->log2n - ratio; n2 = n + n; log2n2 = log2n + 1; for(k=1;k>= 1, log2n2--; n4 = n2 >> 2; ue = n >> log2n2; /* e = TWOPI / n2; */ ua = ue; is = 0, id = n2 << 1; do { for (i0 = is; i0 < n; i0 += id) { i1 = i0 + n4, i2 = i1 + n4, i3 = i2 + n4; r1 = yr[i0] - yr[i2], yr[i0] += yr[i2]; r2 = yr[i1] - yr[i3], yr[i1] += yr[i3]; s1 = yi[i0] - yi[i2], yi[i0] += yi[i2]; s2 = yi[i1] - yi[i3], yi[i1] += yi[i3]; yr[i3] = r1 - s2, yr[i2] = r1 + s2; yi[i2] = s1 - r2, yi[i3] = r2 + s1; } is = (id << 1) - n2, id <<= 2; } while (is < n); for(j=1;j i) { double xt, yt; xt = yr[j]; yr[j] = yr[i]; yr[i] = xt; yt = yi[j]; yi[j] = yi[i]; yi[i] = yt; } } } static void dft_execute(adv_dft* context) { dft(&context->stage, context->xr, context->xi, 0); } /** * Initialize a DFT plan. * \paran DFT plan to initialize. * \param n Size of the DFT. */ adv_error adv_dft_init(adv_dft* context, unsigned n) { if (dft_init(&context->stage, n) != 0) return -1; context->n = n; context->xr = malloc(n * sizeof(double)); context->xi = malloc(n * sizeof(double)); context->execute = dft_execute; return 0; } static void idft_execute(adv_dft* context) { unsigned i; unsigned n = context->n; double* restrict xr = context->xr; double* restrict xi = context->xi; double dn = context->n; dft(&context->stage, xi, xr, 0); for(i=0;istage, n) != 0) return -1; context->n = n; context->xr = malloc(n * sizeof(double)); context->xi = malloc(n * sizeof(double)); context->execute = idft_execute; return 0; } static void dftr_execute(adv_dft* context) { unsigned i, j; unsigned n = context->n; double* xr = context->xr; double* xi = context->xi; unsigned n2 = n / 2; unsigned n4 = n2 / 2; double* Yr = xi; double* Yi = xi + n2; double* Xr = xr; double* Xi = xi; const double* restrict ss = context->stage.ss; const double* restrict cc = context->stage.cc; for(i=0;istage, Yr, Yi, 1); Xr[0] = Yr[0] + Yi[0]; Xr[n2] = Yr[0] - Yi[0]; Xi[0] = 0; Xi[n2] = 0; i = 1; j = n-1; for(i=1;istage, n) != 0) return -1; context->n = n; context->xr = malloc(n * sizeof(double)); context->xi = malloc(n * sizeof(double)); context->execute = dftr_execute; return 0; } /** * Deinitialize a DFT plan. */ void adv_dft_free(adv_dft* context) { dft_free(&context->stage); free(context->xr); free(context->xi); }