ref: 6c5816ea84585ca897ac98755a66805383166cef
parent: f504ca3a0b8b4b500e709a0b79cf806714f1342f
author: Jean-Marc Valin <[email protected]>
date: Thu Jul 8 16:54:32 EDT 2010
Sharing of the twiddles across multiple FFTs
--- a/libcelt/_kiss_fft_guts.h
+++ b/libcelt/_kiss_fft_guts.h
@@ -35,9 +35,10 @@
#ifndef FIXED_POINT
kiss_fft_scalar scale;
#endif
+ int shift;
int factors[2*MAXFACTORS];
int *bitrev;
- kiss_twiddle_cpx twiddles[1];
+ kiss_twiddle_cpx *twiddles;
};
/*
--- a/libcelt/kfft_double.h
+++ b/libcelt/kfft_double.h
@@ -69,7 +69,8 @@
#include "kiss_fft.h"
#include "_kiss_fft_guts.h"
-#define cpx32_fft_alloc(length) kiss_fft_alloc(length, 0, 0);
+#define cpx32_fft_alloc_twiddles(length,from) kiss_fft_alloc_twiddles(length, 0, 0, from)
+#define cpx32_fft_alloc(length) kiss_fft_alloc(length, 0, 0)
#define cpx32_fft_free(state) kiss_fft_free(state)
#define cpx32_fft(state, X, Y, nx) kiss_fft(state,(const kiss_fft_cpx *)(X), (kiss_fft_cpx *)(Y))
#define cpx32_ifft(state, X, Y, nx) kiss_ifft(state,(const kiss_fft_cpx *)(X), (kiss_fft_cpx *)(Y))
--- a/libcelt/kiss_fft.c
+++ b/libcelt/kiss_fft.c
@@ -470,7 +470,7 @@
void kf_work(
kiss_fft_cpx * Fout,
const kiss_fft_cpx * f,
- const size_t fstride,
+ size_t fstride,
int in_stride,
int * factors,
const kiss_fft_cfg st,
@@ -485,6 +485,9 @@
if (m!=1)
kf_work( Fout , f, fstride*p, in_stride, factors,st, N*p, fstride*in_stride, m);
+ /* Compensate for longer twiddles table (when sharing) */
+ if (st->shift>0)
+ fstride <<= st->shift;
switch (p) {
case 2: kf_bfly2(Fout,fstride,st,m, N, m2); break;
case 4: kf_bfly4(Fout,fstride,st,m, N, m2); break;
@@ -501,7 +504,7 @@
void ki_work(
kiss_fft_cpx * Fout,
const kiss_fft_cpx * f,
- const size_t fstride,
+ size_t fstride,
int in_stride,
int * factors,
const kiss_fft_cfg st,
@@ -516,6 +519,9 @@
if (m!=1)
ki_work( Fout , f, fstride*p, in_stride, factors,st, N*p, fstride*in_stride, m);
+ /* Compensate for longer twiddles table (when sharing) */
+ if (st->shift>0)
+ fstride <<= st->shift;
switch (p) {
case 2: ki_bfly2(Fout,fstride,st,m, N, m2); break;
case 4: ki_bfly4(Fout,fstride,st,m, N, m2); break;
@@ -559,6 +565,25 @@
} while (n > 1);
return 1;
}
+
+static void compute_twiddles(kiss_twiddle_cpx *twiddles, int nfft)
+{
+ int i;
+#if defined(FIXED_POINT) && (!defined(DOUBLE_PRECISION) || defined(MIXED_PRECISION))
+ for (i=0;i<nfft;++i) {
+ celt_word32 phase = -i;
+ kf_cexp2(twiddles+i, DIV32(SHL32(phase,17),nfft));
+ }
+#else
+ for (i=0;i<nfft;++i) {
+ const double pi=3.14159265358979323846264338327;
+ double phase = ( -2*pi /nfft ) * i;
+ kf_cexp(twiddles+i, phase );
+ }
+#endif
+}
+
+
/*
*
* User-callable function to allocate all necessary storage space for the fft.
@@ -566,11 +591,10 @@
* The return value is a contiguous block of memory, allocated with malloc. As such,
* It can be freed with free(), rather than a kiss_fft-specific function.
* */
-kiss_fft_cfg kiss_fft_alloc(int nfft,void * mem,size_t * lenmem )
+kiss_fft_cfg kiss_fft_alloc_twiddles(int nfft,void * mem,size_t * lenmem, kiss_fft_cfg base)
{
kiss_fft_cfg st=NULL;
- size_t memneeded = sizeof(struct kiss_fft_state)
- + sizeof(kiss_twiddle_cpx)*(nfft-1) + sizeof(int)*nfft; /* twiddle factors*/
+ size_t memneeded = sizeof(struct kiss_fft_state); /* twiddle factors*/
if ( lenmem==NULL ) {
st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded );
@@ -580,23 +604,24 @@
*lenmem = memneeded;
}
if (st) {
- int i;
st->nfft=nfft;
#ifndef FIXED_POINT
st->scale = 1./nfft;
#endif
-#if defined(FIXED_POINT) && (!defined(DOUBLE_PRECISION) || defined(MIXED_PRECISION))
- for (i=0;i<nfft;++i) {
- celt_word32 phase = -i;
- kf_cexp2(st->twiddles+i, DIV32(SHL32(phase,17),nfft));
+ if (base != NULL)
+ {
+ st->twiddles = base->twiddles;
+ st->shift = 0;
+ while (nfft<<st->shift != base->nfft && st->shift < 32)
+ st->shift++;
+ /* FIXME: Report error and do proper cleanup */
+ if (st->shift>=32)
+ return NULL;
+ } else {
+ st->twiddles = (kiss_twiddle_cpx*)KISS_FFT_MALLOC(sizeof(kiss_twiddle_cpx)*nfft);
+ compute_twiddles(st->twiddles, nfft);
+ st->shift = -1;
}
-#else
- for (i=0;i<nfft;++i) {
- const double pi=3.14159265358979323846264338327;
- double phase = ( -2*pi /nfft ) * i;
- kf_cexp(st->twiddles+i, phase );
- }
-#endif
if (!kf_factor(nfft,st->factors))
{
kiss_fft_free(st);
@@ -604,14 +629,17 @@
}
/* bitrev */
- st->bitrev = (int*)((char*)st + memneeded - sizeof(int)*nfft);
+ st->bitrev = (int*)KISS_FFT_MALLOC(sizeof(int)*nfft);
compute_bitrev_table(0, st->bitrev, 1,1, st->factors,st);
}
return st;
}
+kiss_fft_cfg kiss_fft_alloc(int nfft,void * mem,size_t * lenmem )
+{
+ return kiss_fft_alloc_twiddles(nfft, mem, lenmem, NULL);
+}
-
void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride)
{
@@ -657,3 +685,10 @@
kiss_ifft_stride(cfg,fin,fout,1);
}
+void kiss_fft_free(kiss_fft_cfg cfg)
+{
+ celt_free(cfg->bitrev);
+ if (cfg->shift < 0)
+ celt_free(cfg->twiddles);
+ celt_free(cfg);
+}
--- a/libcelt/kiss_fft.h
+++ b/libcelt/kiss_fft.h
@@ -75,6 +75,7 @@
#define CAT_SUFFIX(a,b) a ## b
#define SUF(a,b) CAT_SUFFIX(a, b)
+#define kiss_fft_alloc_twiddles SUF(kiss_fft_alloc_twiddles,KF_SUFFIX)
#define kiss_fft_alloc SUF(kiss_fft_alloc,KF_SUFFIX)
#define kf_work SUF(kf_work,KF_SUFFIX)
#define ki_work SUF(ki_work,KF_SUFFIX)
@@ -82,6 +83,7 @@
#define kiss_ifft SUF(kiss_ifft,KF_SUFFIX)
#define kiss_fft_stride SUF(kiss_fft_stride,KF_SUFFIX)
#define kiss_ifft_stride SUF(kiss_ifft_stride,KF_SUFFIX)
+#define kiss_fft_free SUF(kiss_fft_free,KF_SUFFIX)
typedef struct {
@@ -119,13 +121,15 @@
* buffer size in *lenmem.
* */
+kiss_fft_cfg kiss_fft_alloc_twiddles(int nfft,void * mem,size_t * lenmem, kiss_fft_cfg base);
+
kiss_fft_cfg kiss_fft_alloc(int nfft,void * mem,size_t * lenmem);
-void kf_work(kiss_fft_cpx * Fout,const kiss_fft_cpx * f,const size_t fstride,
+void kf_work(kiss_fft_cpx * Fout,const kiss_fft_cpx * f,size_t fstride,
int in_stride,int * factors,const kiss_fft_cfg st,int N,int s2,int m2);
/** Internal function. Can be useful when you want to do the bit-reversing yourself */
-void ki_work(kiss_fft_cpx * Fout, const kiss_fft_cpx * f, const size_t fstride,
+void ki_work(kiss_fft_cpx * Fout, const kiss_fft_cpx * f, size_t fstride,
int in_stride,int * factors,const kiss_fft_cfg st,int N,int s2,int m2);
/**
@@ -147,9 +151,7 @@
void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride);
void kiss_ifft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride);
-/** If kiss_fft_alloc allocated a buffer, it is one contiguous
- buffer and can be simply free()d when no longer needed*/
-#define kiss_fft_free celt_free
+void kiss_fft_free(kiss_fft_cfg cfg);
#ifdef __cplusplus
--- a/libcelt/mdct.c
+++ b/libcelt/mdct.c
@@ -69,7 +69,10 @@
l->maxshift = maxshift;
for (i=0;i<=maxshift;i++)
{
- l->kfft[i] = cpx32_fft_alloc(N>>2>>i);
+ if (i==0)
+ l->kfft[i] = cpx32_fft_alloc(N>>2>>i);
+ else
+ l->kfft[i] = cpx32_fft_alloc_twiddles(N>>2>>i, l->kfft[0]);
#ifndef ENABLE_TI_DSPLIB55
if (l->kfft[i]==NULL)
return;