ref: 72513f3cc75a2a4a5ab12c1d00acb1dbfb96ab73
parent: 268caad4e82685553a49a84e42a391a64be9861e
author: Jean-Marc Valin <[email protected]>
date: Wed Jul 7 17:26:38 EDT 2010
Sharing twiddle factors across all MDCTs
--- a/libcelt/celt.c
+++ b/libcelt/celt.c
@@ -317,11 +317,9 @@
const int C = CHANNELS(_C);
if (C==1 && !shortBlocks)
{
- const mdct_lookup *lookup = &mode->mdct[LM];
const int overlap = OVERLAP(mode);
- clt_mdct_forward(lookup, in, out, mode->window, overlap);
+ clt_mdct_forward(&mode->mdct, in, out, mode->window, overlap, mode->maxLM-LM);
} else {
- const mdct_lookup *lookup = &mode->mdct[LM];
const int overlap = OVERLAP(mode);
int N = mode->shortMdctSize<<LM;
int B = 1;
@@ -331,7 +329,7 @@
SAVE_STACK;
if (shortBlocks)
{
- lookup = &mode->mdct[0];
+ /*lookup = &mode->mdct[0];*/
N = mode->shortMdctSize;
B = shortBlocks;
}
@@ -344,7 +342,7 @@
int j;
for (j=0;j<N+overlap;j++)
x[j] = in[C*(b*N+j)+c];
- clt_mdct_forward(lookup, x, tmp, mode->window, overlap);
+ clt_mdct_forward(&mode->mdct, x, tmp, mode->window, overlap, shortBlocks ? mode->maxLM : mode->maxLM-LM);
/* Interleaving the sub-frames */
for (j=0;j<N;j++)
out[(j*B+b)+c*N*B] = tmp[j];
@@ -367,8 +365,7 @@
{
int j;
if (transient_shift==0 && C==1 && !shortBlocks) {
- const mdct_lookup *lookup = &mode->mdct[LM];
- clt_mdct_backward(lookup, X, out_mem+C*(MAX_PERIOD-N-N4), mode->window, overlap);
+ clt_mdct_backward(&mode->mdct, X, out_mem+C*(MAX_PERIOD-N-N4), mode->window, overlap, mode->maxLM-LM);
} else {
VARDECL(celt_word32, x);
VARDECL(celt_word32, tmp);
@@ -376,7 +373,6 @@
int N2 = N;
int B = 1;
int n4offset=0;
- const mdct_lookup *lookup = &mode->mdct[LM];
SAVE_STACK;
ALLOC(x, 2*N, celt_word32);
@@ -384,7 +380,7 @@
if (shortBlocks)
{
- lookup = &mode->mdct[0];
+ /*lookup = &mode->mdct[0];*/
N2 = mode->shortMdctSize;
B = shortBlocks;
n4offset = N4;
@@ -397,7 +393,7 @@
/* De-interleaving the sub-frames */
for (j=0;j<N2;j++)
tmp[j] = X[(j*B+b)+c*N2*B];
- clt_mdct_backward(lookup, tmp, x+n4offset+N2*b, mode->window, overlap);
+ clt_mdct_backward(&mode->mdct, tmp, x+n4offset+N2*b, mode->window, overlap, shortBlocks ? mode->maxLM : mode->maxLM-LM);
}
if (transient_shift > 0)
--- a/libcelt/mdct.c
+++ b/libcelt/mdct.c
@@ -58,7 +58,7 @@
#define M_PI 3.141592653
#endif
-void clt_mdct_init(mdct_lookup *l,int N)
+void clt_mdct_init(mdct_lookup *l,int N, int maxshift)
{
int i;
int N2, N4;
@@ -65,11 +65,16 @@
l->n = N;
N2 = N>>1;
N4 = N>>2;
- l->kfft = cpx32_fft_alloc(N>>2);
+ l->kfft = celt_alloc(sizeof(kiss_fft_cfg)*(maxshift+1));
+ l->maxshift = maxshift;
+ for (i=0;i<=maxshift;i++)
+ {
+ l->kfft[i] = cpx32_fft_alloc(N>>2>>i);
#ifndef ENABLE_TI_DSPLIB55
- if (l->kfft==NULL)
- return;
+ if (l->kfft[i]==NULL)
+ return;
#endif
+ }
l->trig = (kiss_twiddle_scalar*)celt_alloc((N4+1)*sizeof(kiss_twiddle_scalar));
if (l->trig==NULL)
return;
@@ -90,11 +95,14 @@
void clt_mdct_clear(mdct_lookup *l)
{
- cpx32_fft_free(l->kfft);
+ int i;
+ for (i=0;i<=l->maxshift;i++)
+ cpx32_fft_free(l->kfft[i]);
+ celt_free(l->kfft);
celt_free(l->trig);
}
-void clt_mdct_forward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * restrict out, const celt_word16 *window, int overlap)
+void clt_mdct_forward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * restrict out, const celt_word16 *window, int overlap, int shift)
{
int i;
int N, N2, N4;
@@ -102,6 +110,7 @@
VARDECL(kiss_fft_scalar, f);
SAVE_STACK;
N = l->n;
+ N >>= shift;
N2 = N>>1;
N4 = N>>2;
ALLOC(f, N2, kiss_fft_scalar);
@@ -161,8 +170,8 @@
kiss_fft_scalar re, im, yr, yi;
re = yp[0];
im = yp[1];
- yr = -S_MUL(re,t[i]) - S_MUL(im,t[N4-i]);
- yi = -S_MUL(im,t[i]) + S_MUL(re,t[N4-i]);
+ yr = -S_MUL(re,t[i<<shift]) - S_MUL(im,t[(N4-i)<<shift]);
+ yi = -S_MUL(im,t[i<<shift]) + S_MUL(re,t[(N4-i)<<shift]);
/* works because the cos is nearly one */
*yp++ = yr + S_MUL(yi,sine);
*yp++ = yi - S_MUL(yr,sine);
@@ -170,7 +179,7 @@
}
/* N/4 complex FFT, down-scales by 4/N */
- cpx32_fft(l->kfft, out, f, N4);
+ cpx32_fft(l->kfft[shift], out, f, N4);
/* Post-rotate */
{
@@ -183,8 +192,8 @@
for(i=0;i<N4;i++)
{
kiss_fft_scalar yr, yi;
- yr = S_MUL(fp[1],t[N4-i]) + S_MUL(fp[0],t[i]);
- yi = S_MUL(fp[0],t[N4-i]) - S_MUL(fp[1],t[i]);
+ yr = S_MUL(fp[1],t[(N4-i)<<shift]) + S_MUL(fp[0],t[i<<shift]);
+ yi = S_MUL(fp[0],t[(N4-i)<<shift]) - S_MUL(fp[1],t[i<<shift]);
/* works because the cos is nearly one */
*yp1 = yr - S_MUL(yi,sine);
*yp2 = yi + S_MUL(yr,sine);;
@@ -197,7 +206,7 @@
}
-void clt_mdct_backward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * restrict out, const celt_word16 * restrict window, int overlap)
+void clt_mdct_backward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * restrict out, const celt_word16 * restrict window, int overlap, int shift)
{
int i;
int N, N2, N4;
@@ -206,6 +215,7 @@
VARDECL(kiss_fft_scalar, f2);
SAVE_STACK;
N = l->n;
+ N >>= shift;
N2 = N>>1;
N4 = N>>2;
ALLOC(f, N2, kiss_fft_scalar);
@@ -227,8 +237,8 @@
for(i=0;i<N4;i++)
{
kiss_fft_scalar yr, yi;
- yr = -S_MUL(*xp2, t[i]) + S_MUL(*xp1,t[N4-i]);
- yi = -S_MUL(*xp2, t[N4-i]) - S_MUL(*xp1,t[i]);
+ yr = -S_MUL(*xp2, t[i<<shift]) + S_MUL(*xp1,t[(N4-i)<<shift]);
+ yi = -S_MUL(*xp2, t[(N4-i)<<shift]) - S_MUL(*xp1,t[i<<shift]);
/* works because the cos is nearly one */
*yp++ = yr - S_MUL(yi,sine);
*yp++ = yi + S_MUL(yr,sine);
@@ -238,7 +248,7 @@
}
/* Inverse N/4 complex FFT. This one should *not* downscale even in fixed-point */
- cpx32_ifft(l->kfft, f2, f, N4);
+ cpx32_ifft(l->kfft[shift], f2, f, N4);
/* Post-rotate */
{
@@ -251,8 +261,8 @@
re = fp[0];
im = fp[1];
/* We'd scale up by 2 here, but instead it's done when mixing the windows */
- yr = S_MUL(re,t[i]) - S_MUL(im,t[N4-i]);
- yi = S_MUL(im,t[i]) + S_MUL(re,t[N4-i]);
+ yr = S_MUL(re,t[i<<shift]) - S_MUL(im,t[(N4-i)<<shift]);
+ yi = S_MUL(im,t[i<<shift]) + S_MUL(re,t[(N4-i)<<shift]);
/* works because the cos is nearly one */
*fp++ = yr - S_MUL(yi,sine);
*fp++ = yi + S_MUL(yr,sine);
--- a/libcelt/mdct.h
+++ b/libcelt/mdct.h
@@ -51,18 +51,19 @@
typedef struct {
int n;
- kiss_fft_cfg kfft;
+ int maxshift;
+ kiss_fft_cfg *kfft;
kiss_twiddle_scalar * restrict trig;
} mdct_lookup;
-void clt_mdct_init(mdct_lookup *l,int N);
+void clt_mdct_init(mdct_lookup *l,int N, int maxshift);
void clt_mdct_clear(mdct_lookup *l);
/** Compute a forward MDCT and scale by 4/N */
-void clt_mdct_forward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar *out, const celt_word16 *window, int overlap);
+void clt_mdct_forward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar *out, const celt_word16 *window, int overlap, int shift);
/** Compute a backward MDCT (no scaling) and performs weighted overlap-add
(scales implicitly by 1/2) */
-void clt_mdct_backward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar *out, const celt_word16 * restrict window, int overlap);
+void clt_mdct_backward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar *out, const celt_word16 * restrict window, int overlap, int shift);
#endif
--- a/libcelt/modes.c
+++ b/libcelt/modes.c
@@ -261,6 +261,7 @@
CELTMode *celt_mode_create(celt_int32 Fs, int frame_size, int *error)
{
int i;
+ int LM;
#ifdef STDIN_TUNING
scanf("%d ", &MIN_BINS);
scanf("%d ", &BITALLOC_SIZE);
@@ -337,18 +338,20 @@
if (frame_size >= 640 && (frame_size%16)==0)
{
- mode->nbShortMdcts = 8;
+ LM = 3;
} else if (frame_size >= 320 && (frame_size%8)==0)
{
- mode->nbShortMdcts = 4;
+ LM = 2;
} else if (frame_size >= 160 && (frame_size%4)==0)
{
- mode->nbShortMdcts = 2;
+ LM = 1;
} else
{
- mode->nbShortMdcts = 1;
+ LM = 0;
}
+ mode->maxLM = LM;
+ mode->nbShortMdcts = 1<<LM;
mode->shortMdctSize = frame_size/mode->nbShortMdcts;
res = (mode->Fs+mode->shortMdctSize)/(2*mode->shortMdctSize);
@@ -402,16 +405,14 @@
mode->logN = logN;
#endif /* !STATIC_MODES */
- for (i=0;(1<<i)<=mode->nbShortMdcts;i++)
- {
- clt_mdct_init(&mode->mdct[i], 2*mode->shortMdctSize<<i);
- if ((mode->mdct[i].trig==NULL)
+ clt_mdct_init(&mode->mdct, 2*mode->shortMdctSize*mode->nbShortMdcts, LM);
+ if ((mode->mdct.trig==NULL)
#ifndef ENABLE_TI_DSPLIB55
- || (mode->mdct[i].kfft==NULL)
+ || (mode->mdct.kfft==NULL)
#endif
- )
- goto failure;
- }
+ )
+ goto failure;
+
mode->prob = quant_prob_alloc(mode);
if (mode->prob==NULL)
goto failure;
@@ -487,8 +488,7 @@
celt_free((celt_int16*)mode->logN);
#endif
- for (i=0;(1<<i)<=mode->nbShortMdcts;i++)
- clt_mdct_clear(&mode->mdct[i]);
+ clt_mdct_clear(&mode->mdct);
quant_prob_free(mode->prob);
mode->marker_end = MODEFREED;
--- a/libcelt/modes.h
+++ b/libcelt/modes.h
@@ -98,10 +98,11 @@
const celt_int16 * const *(_bits[MAX_CONFIG_SIZES]); /**< Cache for pulses->bits mapping in each band */
/* Stuff that could go in the {en,de}coder, but we save space this way */
- mdct_lookup mdct[MAX_CONFIG_SIZES];
+ mdct_lookup mdct;
const celt_word16 *window;
+ int maxLM;
int nbShortMdcts;
int shortMdctSize;
--- a/libcelt/os_support.h
+++ b/libcelt/os_support.h
@@ -45,7 +45,7 @@
/** CELT wrapper for calloc(). To do your own dynamic allocation, all you need to do is replace this function, celt_realloc and celt_free
NOTE: celt_alloc needs to CLEAR THE MEMORY */
#ifndef OVERRIDE_CELT_ALLOC
-static inline void *celt_alloc (int size)
+static void *celt_alloc (int size)
{
/* WARNING: this is not equivalent to malloc(). If you want to use malloc()
or your own allocator, YOU NEED TO CLEAR THE MEMORY ALLOCATED. Otherwise
--- a/tests/mdct-test.c
+++ b/tests/mdct-test.c
@@ -89,7 +89,7 @@
celt_word16 * window= (celt_word16*)malloc(sizeof(celt_word16)*nfft/2);
int k;
- clt_mdct_init(&cfg, nfft);
+ clt_mdct_init(&cfg, nfft, 0);
for (k=0;k<nfft;++k) {
in[k] = (rand() % 32768) - 16384;
}
@@ -116,10 +116,10 @@
{
for (k=0;k<nfft;++k)
out[k] = 0;
- clt_mdct_backward(&cfg,in,out, window, nfft/2);
+ clt_mdct_backward(&cfg,in,out, window, nfft/2, 0);
check_inv(in,out,nfft,isinverse);
} else {
- clt_mdct_forward(&cfg,in,out,window, nfft/2);
+ clt_mdct_forward(&cfg,in,out,window, nfft/2, 0);
check(in,out,nfft,isinverse);
}
/*for (k=0;k<nfft;++k) printf("%d %d ", out[k].r, out[k].i);printf("\n");*/