Mercurial > hg > dmlib
changeset 749:44138892c784
Add FFT routines.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sat, 04 May 2013 23:29:22 +0300 |
parents | 136d4ddc7438 |
children | e6d807ce715b |
files | Makefile.gen dmfft.c dmfft.h |
diffstat | 3 files changed, 175 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile.gen Sat May 04 19:08:01 2013 +0300 +++ b/Makefile.gen Sat May 04 23:29:22 2013 +0300 @@ -270,7 +270,7 @@ DMLIB_OBJS += \ dmfile.o dmbstr.o dmlib.o dmlerp.o dmstring.o \ dmargs.o dmvecmat.o dmperlin.o dmimage.o \ - dmwav.o dmengine.o dmq3d.o + dmwav.o dmengine.o dmq3d.o dmfft.o TESTS_TARGETS = $(addprefix $(TESTS_BINPATH),$(addsuffix $(EXEEXT),$(TESTS_BINARIES)))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmfft.c Sat May 04 23:29:22 2013 +0300 @@ -0,0 +1,151 @@ +/* + * Realfftf + * Originally (C) Copyright 1993 Philib Van Baren + * Cleaned up and refactored to be re-entrant by + * Matti 'ccr' Hamalainen <ccr@tnsp.org>, 2013 + * + * Note: Output is BIT-REVERSED! so you must use the BitReversed to + * get legible output, (i.e. Real_i = buffer[ BitReversed[i] ] + * Imag_i = buffer[ BitReversed[i]+1 ] ) + * Input is in normal order. + */ +#include "dmfft.h" +#include <math.h> + + +int dmInitializeFFT(DMFFTContext * ctx, const int fftlen) +{ + int i; + + if (ctx == NULL) + return DMERR_NULLPTR; + + if (fftlen <= 16) + return DMERR_INVALID_ARGS; + + // Allocate necessary tables + ctx->npoints = fftlen / 2; + ctx->sinTable = (DMFFTType *) dmMalloc(fftlen * sizeof(DMFFTType)); + if (ctx->sinTable == NULL) + return DMERR_MALLOC; + + // Bitreversion buffer + ctx->breversed = (int *) dmMalloc(ctx->npoints * sizeof(int)); + if (ctx->breversed == NULL) + { + dmFree(ctx->sinTable); + return DMERR_MALLOC; + } + + // Calculate data + for (i = 0; i < ctx->npoints; i++) + { + int mask, tmp; + for (tmp = 0, mask = ctx->npoints / 2; mask > 0; mask >>= 1) + { + tmp = (tmp >> 1) + ((i & mask) ? ctx->npoints : 0); + } + + ctx->breversed[i] = tmp; + } + + for (i = 0; i < ctx->npoints; i++) + { + ctx->sinTable[ctx->breversed[i]] = -sin((2.0f * M_PI * i) / fftlen); + ctx->sinTable[ctx->breversed[i] + 1] = + -cos((2.0f * M_PI * i) / fftlen); + } + + return DMERR_OK; +} + + +void dmEndFFT(DMFFTContext * ctx) +{ + if (ctx != NULL) + { + dmFree(ctx->breversed); + dmFree(ctx->sinTable); + memset(ctx, 0, sizeof(DMFFTContext)); + } +} + + +int dmRealFFT(DMFFTContext * ctx, DMFFTType * buffer) +{ + if (ctx == NULL || buffer == NULL) + return DMERR_NULLPTR; + + int rounds = ctx->npoints / 2; + DMFFTType *endptr1 = buffer + ctx->npoints * 2; + + while (rounds > 0) + { + DMFFTType *sptr = ctx->sinTable; + DMFFTType *A = buffer, + *B = buffer + rounds * 2; + + while (A < endptr1) + { + DMFFTType qsin = *sptr; + DMFFTType qcos = *(sptr + 1); + DMFFTType *endptr2 = B; + + while (A < endptr2) + { + DMFFTType v1 = (*B) * qcos + (*(B + 1)) * qsin; + DMFFTType v2 = (*B) * qsin - (*(B + 1)) * qcos; + *B = (*A + v1) * 0.5; + *(A++) = *(B++) - v1; + *B = (*A - v2) * 0.5; + *(A++) = *(B++) + v2; + } + A = B; + B += rounds * 2; + sptr += 2; + } + + rounds >>= 1; + } + + /* + * Massage output to get the output for a real input sequence. + */ + int *br1 = ctx->breversed + 1; + int *br2 = ctx->breversed + ctx->npoints - 1; + + while (br1 <= br2) + { + const DMFFTType vsin = ctx->sinTable[*br1]; + const DMFFTType vcos = ctx->sinTable[*br1 + 1]; + DMFFTType *A = buffer + *br1, + *B = buffer + *br2, + HRplus, HRminus, + HIplus, HIminus, + tmp1, tmp2; + + HRminus = *A - *B; + HRplus = HRminus + (*B * 2); + + HIminus = *(A + 1) - *(B + 1); + HIplus = HIminus + (*(B + 1) * 2); + + tmp1 = (vsin * HRminus) - (vcos * HIplus); + tmp2 = (vcos * HRminus) + (vsin * HIplus); + + *A = (HRplus + tmp1) * 0.5f; + *B = *A - tmp1; + + *(A + 1) = (HIminus + tmp2) * 0.5f; + *(B + 1) = (*(A + 1)) - HIminus; + + br1++; + br2--; + } + + // Handle DC bin separately + buffer[0] += buffer[1]; + buffer[1] = 0; + + return DMERR_OK; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmfft.h Sat May 04 23:29:22 2013 +0300 @@ -0,0 +1,23 @@ +#ifndef DMFFT_H +#define DMFFT_H 1 + +#include "dmlib.h" + + +typedef double DMFFTType; + + +typedef struct +{ + int npoints; + DMFFTType *sinTable; + int *breversed; +} DMFFTContext; + + +int dmInitializeFFT(DMFFTContext *, int); +void dmEndFFT(DMFFTContext *); +int dmRealFFT(DMFFTContext *, DMFFTType *); + + +#endif // DMFFT_H