Making the MDCT produce interleaved data
[opus.git] / libcelt / mdct.c
index 4e153b3..1e310ad 100644 (file)
-/********************************************************************
- *                                                                  *
- * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
- * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
- * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
- * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
- *                                                                  *
- * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002             *
- * by the XIPHOPHORUS Company http://www.xiph.org/                  *
- *                                                                  *
- ********************************************************************
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2008 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* This is a simple MDCT implementation that uses a N/4 complex FFT
+   to do most of the work. It should be relatively straightforward to
+   plug in pretty much and FFT here.
+
+   This replaces the Vorbis FFT (and uses the exact same API), which
+   was a bit too messy and that was ending up duplicating code
+   (might as well use the same FFT everywhere).
+
+   The algorithm is similar to (and inspired from) Fabrice Bellard's
+   MDCT implementation in FFMPEG, but has differences in signs, ordering
+   and scaling in many places.
+*/
+
+#ifndef SKIP_CONFIG_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#endif
 
- function: normalized modified discrete cosine transform
-           power of two length transform only [64 <= n ]
- last mod: $Id: mdct.c 7187 2004-07-20 07:24:27Z xiphmont $
-
- Original algorithm adapted long ago from _The use of multirate filter
- banks for coding of high quality digital audio_, by T. Sporer,
- K. Brandenburg and B. Edler, collection of the European Signal
- Processing Conference (EUSIPCO), Amsterdam, June 1992, Vol.1, pp
- 211-214
-
- The below code implements an algorithm that no longer looks much like
- that presented in the paper, but the basic structure remains if you
- dig deep enough to see it.
-
- This module DOES NOT INCLUDE code to generate/apply the window
- function.  Everybody has their own weird favorite including me... I
- happen to like the properties of y=sin(.5PI*sin^2(x)), but others may
- vehemently disagree.
-
- ********************************************************************/
-
-/* this can also be run as an integer transform by uncommenting a
-   define in mdct.h; the integerization is a first pass and although
-   it's likely stable for Vorbis, the dynamic range is constrained and
-   roundoff isn't done (so it's noisy).  Consider it functional, but
-   only a starting point.  There's no point on a machine with an FPU */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include "vorbis/codec.h"
 #include "mdct.h"
-#include "os.h"
-#include "misc.h"
-
-/* build lookups for trig functions; also pre-figure scaling and
-   some window function algebra. */
-
-void mdct_init(mdct_lookup *lookup,int n){
-  int   *bitrev=_ogg_malloc(sizeof(*bitrev)*(n/4));
-  DATA_TYPE *T=_ogg_malloc(sizeof(*T)*(n+n/4));
-  
-  int i;
-  int n2=n>>1;
-  int log2n=lookup->log2n=rint(log((float)n)/log(2.f));
-  lookup->n=n;
-  lookup->trig=T;
-  lookup->bitrev=bitrev;
-
-/* trig lookups... */
-
-  for(i=0;i<n/4;i++){
-    T[i*2]=FLOAT_CONV(cos((M_PI/n)*(4*i)));
-    T[i*2+1]=FLOAT_CONV(-sin((M_PI/n)*(4*i)));
-    T[n2+i*2]=FLOAT_CONV(cos((M_PI/(2*n))*(2*i+1)));
-    T[n2+i*2+1]=FLOAT_CONV(sin((M_PI/(2*n))*(2*i+1)));
-  }
-  for(i=0;i<n/8;i++){
-    T[n+i*2]=FLOAT_CONV(cos((M_PI/n)*(4*i+2))*.5);
-    T[n+i*2+1]=FLOAT_CONV(-sin((M_PI/n)*(4*i+2))*.5);
-  }
-
-  /* bitreverse lookup... */
-
-  {
-    int mask=(1<<(log2n-1))-1,i,j;
-    int msb=1<<(log2n-2);
-    for(i=0;i<n/8;i++){
-      int acc=0;
-      for(j=0;msb>>j;j++)
-       if((msb>>j)&i)acc|=1<<j;
-      bitrev[i*2]=((~acc)&mask)-1;
-      bitrev[i*2+1]=acc;
-
-    }
-  }
-  lookup->scale=FLOAT_CONV(4.f/n);
-}
-
-/* 8 point butterfly (in place, 4 register) */
-STIN void mdct_butterfly_8(DATA_TYPE *x){
-  REG_TYPE r0   = x[6] + x[2];
-  REG_TYPE r1   = x[6] - x[2];
-  REG_TYPE r2   = x[4] + x[0];
-  REG_TYPE r3   = x[4] - x[0];
-
-          x[6] = r0   + r2;
-          x[4] = r0   - r2;
-          
-          r0   = x[5] - x[1];
-          r2   = x[7] - x[3];
-          x[0] = r1   + r0;
-          x[2] = r1   - r0;
-          
-          r0   = x[5] + x[1];
-          r1   = x[7] + x[3];
-          x[3] = r2   + r3;
-          x[1] = r2   - r3;
-          x[7] = r1   + r0;
-          x[5] = r1   - r0;
-          
-}
-
-/* 16 point butterfly (in place, 4 register) */
-STIN void mdct_butterfly_16(DATA_TYPE *x){
-  REG_TYPE r0     = x[1]  - x[9];
-  REG_TYPE r1     = x[0]  - x[8];
-
-           x[8]  += x[0];
-           x[9]  += x[1];
-           x[0]   = MULT_NORM((r0   + r1) * cPI2_8);
-           x[1]   = MULT_NORM((r0   - r1) * cPI2_8);
-
-           r0     = x[3]  - x[11];
-           r1     = x[10] - x[2];
-           x[10] += x[2];
-           x[11] += x[3];
-           x[2]   = r0;
-           x[3]   = r1;
-
-           r0     = x[12] - x[4];
-           r1     = x[13] - x[5];
-           x[12] += x[4];
-           x[13] += x[5];
-           x[4]   = MULT_NORM((r0   - r1) * cPI2_8);
-           x[5]   = MULT_NORM((r0   + r1) * cPI2_8);
-
-           r0     = x[14] - x[6];
-           r1     = x[15] - x[7];
-           x[14] += x[6];
-           x[15] += x[7];
-           x[6]  = r0;
-           x[7]  = r1;
-
-          mdct_butterfly_8(x);
-          mdct_butterfly_8(x+8);
-}
-
-/* 32 point butterfly (in place, 4 register) */
-STIN void mdct_butterfly_32(DATA_TYPE *x){
-  REG_TYPE r0     = x[30] - x[14];
-  REG_TYPE r1     = x[31] - x[15];
-
-           x[30] +=         x[14];           
-          x[31] +=         x[15];
-           x[14]  =         r0;              
-          x[15]  =         r1;
-
-           r0     = x[28] - x[12];   
-          r1     = x[29] - x[13];
-           x[28] +=         x[12];           
-          x[29] +=         x[13];
-           x[12]  = MULT_NORM( r0 * cPI1_8  -  r1 * cPI3_8 );
-          x[13]  = MULT_NORM( r0 * cPI3_8  +  r1 * cPI1_8 );
-
-           r0     = x[26] - x[10];
-          r1     = x[27] - x[11];
-          x[26] +=         x[10];
-          x[27] +=         x[11];
-          x[10]  = MULT_NORM(( r0  - r1 ) * cPI2_8);
-          x[11]  = MULT_NORM(( r0  + r1 ) * cPI2_8);
-
-          r0     = x[24] - x[8];
-          r1     = x[25] - x[9];
-          x[24] += x[8];
-          x[25] += x[9];
-          x[8]   = MULT_NORM( r0 * cPI3_8  -  r1 * cPI1_8 );
-          x[9]   = MULT_NORM( r1 * cPI3_8  +  r0 * cPI1_8 );
-
-          r0     = x[22] - x[6];
-          r1     = x[7]  - x[23];
-          x[22] += x[6];
-          x[23] += x[7];
-          x[6]   = r1;
-          x[7]   = r0;
-
-          r0     = x[4]  - x[20];
-          r1     = x[5]  - x[21];
-          x[20] += x[4];
-          x[21] += x[5];
-          x[4]   = MULT_NORM( r1 * cPI1_8  +  r0 * cPI3_8 );
-          x[5]   = MULT_NORM( r1 * cPI3_8  -  r0 * cPI1_8 );
-
-          r0     = x[2]  - x[18];
-          r1     = x[3]  - x[19];
-          x[18] += x[2];
-          x[19] += x[3];
-          x[2]   = MULT_NORM(( r1  + r0 ) * cPI2_8);
-          x[3]   = MULT_NORM(( r1  - r0 ) * cPI2_8);
-
-          r0     = x[0]  - x[16];
-          r1     = x[1]  - x[17];
-          x[16] += x[0];
-          x[17] += x[1];
-          x[0]   = MULT_NORM( r1 * cPI3_8  +  r0 * cPI1_8 );
-          x[1]   = MULT_NORM( r1 * cPI1_8  -  r0 * cPI3_8 );
-
-          mdct_butterfly_16(x);
-          mdct_butterfly_16(x+16);
-
-}
-
-/* N point first stage butterfly (in place, 2 register) */
-STIN void mdct_butterfly_first(DATA_TYPE *T,
-                                       DATA_TYPE *x,
-                                       int points){
-  
-  DATA_TYPE *x1        = x          + points      - 8;
-  DATA_TYPE *x2        = x          + (points>>1) - 8;
-  REG_TYPE   r0;
-  REG_TYPE   r1;
-
-  do{
-    
-               r0      = x1[6]      -  x2[6];
-              r1      = x1[7]      -  x2[7];
-              x1[6]  += x2[6];
-              x1[7]  += x2[7];
-              x2[6]   = MULT_NORM(r1 * T[1]  +  r0 * T[0]);
-              x2[7]   = MULT_NORM(r1 * T[0]  -  r0 * T[1]);
-              
-              r0      = x1[4]      -  x2[4];
-              r1      = x1[5]      -  x2[5];
-              x1[4]  += x2[4];
-              x1[5]  += x2[5];
-              x2[4]   = MULT_NORM(r1 * T[5]  +  r0 * T[4]);
-              x2[5]   = MULT_NORM(r1 * T[4]  -  r0 * T[5]);
-              
-              r0      = x1[2]      -  x2[2];
-              r1      = x1[3]      -  x2[3];
-              x1[2]  += x2[2];
-              x1[3]  += x2[3];
-              x2[2]   = MULT_NORM(r1 * T[9]  +  r0 * T[8]);
-              x2[3]   = MULT_NORM(r1 * T[8]  -  r0 * T[9]);
-              
-              r0      = x1[0]      -  x2[0];
-              r1      = x1[1]      -  x2[1];
-              x1[0]  += x2[0];
-              x1[1]  += x2[1];
-              x2[0]   = MULT_NORM(r1 * T[13] +  r0 * T[12]);
-              x2[1]   = MULT_NORM(r1 * T[12] -  r0 * T[13]);
-              
-    x1-=8;
-    x2-=8;
-    T+=16;
-
-  }while(x2>=x);
-}
-
-/* N/stage point generic N stage butterfly (in place, 2 register) */
-STIN void mdct_butterfly_generic(DATA_TYPE *T,
-                                         DATA_TYPE *x,
-                                         int points,
-                                         int trigint){
-  
-  DATA_TYPE *x1        = x          + points      - 8;
-  DATA_TYPE *x2        = x          + (points>>1) - 8;
-  REG_TYPE   r0;
-  REG_TYPE   r1;
-
-  do{
-    
-               r0      = x1[6]      -  x2[6];
-              r1      = x1[7]      -  x2[7];
-              x1[6]  += x2[6];
-              x1[7]  += x2[7];
-              x2[6]   = MULT_NORM(r1 * T[1]  +  r0 * T[0]);
-              x2[7]   = MULT_NORM(r1 * T[0]  -  r0 * T[1]);
-              
-              T+=trigint;
-              
-              r0      = x1[4]      -  x2[4];
-              r1      = x1[5]      -  x2[5];
-              x1[4]  += x2[4];
-              x1[5]  += x2[5];
-              x2[4]   = MULT_NORM(r1 * T[1]  +  r0 * T[0]);
-              x2[5]   = MULT_NORM(r1 * T[0]  -  r0 * T[1]);
-              
-              T+=trigint;
-              
-              r0      = x1[2]      -  x2[2];
-              r1      = x1[3]      -  x2[3];
-              x1[2]  += x2[2];
-              x1[3]  += x2[3];
-              x2[2]   = MULT_NORM(r1 * T[1]  +  r0 * T[0]);
-              x2[3]   = MULT_NORM(r1 * T[0]  -  r0 * T[1]);
-              
-              T+=trigint;
-              
-              r0      = x1[0]      -  x2[0];
-              r1      = x1[1]      -  x2[1];
-              x1[0]  += x2[0];
-              x1[1]  += x2[1];
-              x2[0]   = MULT_NORM(r1 * T[1]  +  r0 * T[0]);
-              x2[1]   = MULT_NORM(r1 * T[0]  -  r0 * T[1]);
-
-              T+=trigint;
-    x1-=8;
-    x2-=8;
-
-  }while(x2>=x);
+#include "kiss_fft.h"
+#include "_kiss_fft_guts.h"
+#include <math.h>
+#include "os_support.h"
+#include "mathops.h"
+#include "stack_alloc.h"
+
+#ifdef CUSTOM_MODES
+
+int clt_mdct_init(mdct_lookup *l,int N, int maxshift)
+{
+   int i;
+   int N4, N2;
+   kiss_twiddle_scalar *trig;
+   l->n = N;
+   N2 = N>>1;
+   N4 = N>>2;
+   l->maxshift = maxshift;
+   for (i=0;i<=maxshift;i++)
+   {
+      if (i==0)
+         l->kfft[i] = opus_fft_alloc(N>>2>>i, 0, 0);
+      else
+         l->kfft[i] = opus_fft_alloc_twiddles(N>>2>>i, 0, 0, l->kfft[0]);
+#ifndef ENABLE_TI_DSPLIB55
+      if (l->kfft[i]==NULL)
+         return 0;
+#endif
+   }
+   l->trig = trig = (kiss_twiddle_scalar*)celt_alloc((N4+1)*sizeof(kiss_twiddle_scalar));
+   if (l->trig==NULL)
+     return 0;
+   /* We have enough points that sine isn't necessary */
+#if defined(FIXED_POINT)
+   for (i=0;i<=N4;i++)
+      trig[i] = TRIG_UPSCALE*celt_cos_norm(DIV32(ADD32(SHL32(EXTEND32(i),17),N2),N));
+#else
+   for (i=0;i<=N4;i++)
+      trig[i] = (kiss_twiddle_scalar)cos(2*PI*i/N);
+#endif
+   return 1;
 }
 
-STIN void mdct_butterflies(mdct_lookup *init,
-                            DATA_TYPE *x,
-                            int points){
-  
-  DATA_TYPE *T=init->trig;
-  int stages=init->log2n-5;
-  int i,j;
-  
-  if(--stages>0){
-    mdct_butterfly_first(T,x,points);
-  }
-
-  for(i=1;--stages>0;i++){
-    for(j=0;j<(1<<i);j++)
-      mdct_butterfly_generic(T,x+(points>>i)*j,points>>i,4<<i);
-  }
-
-  for(j=0;j<points;j+=32)
-    mdct_butterfly_32(x+j);
-
+void clt_mdct_clear(mdct_lookup *l)
+{
+   int i;
+   for (i=0;i<=l->maxshift;i++)
+      opus_fft_free(l->kfft[i]);
+   celt_free((kiss_twiddle_scalar*)l->trig);
 }
 
-void mdct_clear(mdct_lookup *l){
-  if(l){
-    if(l->trig)_ogg_free(l->trig);
-    if(l->bitrev)_ogg_free(l->bitrev);
-    memset(l,0,sizeof(*l));
-  }
+#endif /* CUSTOM_MODES */
+
+void clt_mdct_forward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * restrict out,
+      const opus_val16 *window, int overlap, int shift, int stride)
+{
+   int i;
+   int N, N2, N4;
+   kiss_twiddle_scalar sine;
+   VARDECL(kiss_fft_scalar, f);
+   SAVE_STACK;
+   N = l->n;
+   N >>= shift;
+   N2 = N>>1;
+   N4 = N>>2;
+   ALLOC(f, N2, kiss_fft_scalar);
+   /* sin(x) ~= x here */
+#ifdef FIXED_POINT
+   sine = TRIG_UPSCALE*(QCONST16(0.7853981f, 15)+N2)/N;
+#else
+   sine = (kiss_twiddle_scalar)2*PI*(.125f)/N;
+#endif
+
+   /* Consider the input to be composed of four blocks: [a, b, c, d] */
+   /* Window, shuffle, fold */
+   {
+      /* Temp pointers to make it really clear to the compiler what we're doing */
+      const kiss_fft_scalar * restrict xp1 = in+(overlap>>1);
+      const kiss_fft_scalar * restrict xp2 = in+N2-1+(overlap>>1);
+      kiss_fft_scalar * restrict yp = f;
+      const opus_val16 * restrict wp1 = window+(overlap>>1);
+      const opus_val16 * restrict wp2 = window+(overlap>>1)-1;
+      for(i=0;i<(overlap>>2);i++)
+      {
+         /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/
+         *yp++ = MULT16_32_Q15(*wp2, xp1[N2]) + MULT16_32_Q15(*wp1,*xp2);
+         *yp++ = MULT16_32_Q15(*wp1, *xp1)    - MULT16_32_Q15(*wp2, xp2[-N2]);
+         xp1+=2;
+         xp2-=2;
+         wp1+=2;
+         wp2-=2;
+      }
+      wp1 = window;
+      wp2 = window+overlap-1;
+      for(;i<N4-(overlap>>2);i++)
+      {
+         /* Real part arranged as a-bR, Imag part arranged as -c-dR */
+         *yp++ = *xp2;
+         *yp++ = *xp1;
+         xp1+=2;
+         xp2-=2;
+      }
+      for(;i<N4;i++)
+      {
+         /* Real part arranged as a-bR, Imag part arranged as -c-dR */
+         *yp++ =  -MULT16_32_Q15(*wp1, xp1[-N2]) + MULT16_32_Q15(*wp2, *xp2);
+         *yp++ = MULT16_32_Q15(*wp2, *xp1)     + MULT16_32_Q15(*wp1, xp2[N2]);
+         xp1+=2;
+         xp2-=2;
+         wp1+=2;
+         wp2-=2;
+      }
+   }
+   /* Pre-rotation */
+   {
+      kiss_fft_scalar * restrict yp = f;
+      const kiss_twiddle_scalar *t = &l->trig[0];
+      for(i=0;i<N4;i++)
+      {
+         kiss_fft_scalar re, im, yr, yi;
+         re = yp[0];
+         im = yp[1];
+         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);
+      }
+   }
+
+   /* N/4 complex FFT, down-scales by 4/N */
+   opus_fft(l->kfft[shift], (kiss_fft_cpx *)f, (kiss_fft_cpx *)in);
+
+   /* Post-rotate */
+   {
+      /* Temp pointers to make it really clear to the compiler what we're doing */
+      const kiss_fft_scalar * restrict fp = in;
+      kiss_fft_scalar * restrict yp1 = out;
+      kiss_fft_scalar * restrict yp2 = out+stride*(N2-1);
+      const kiss_twiddle_scalar *t = &l->trig[0];
+      /* Temp pointers to make it really clear to the compiler what we're doing */
+      for(i=0;i<N4;i++)
+      {
+         kiss_fft_scalar yr, yi;
+         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);;
+         fp += 2;
+         yp1 += 2*stride;
+         yp2 -= 2*stride;
+      }
+   }
+   RESTORE_STACK;
 }
 
-STIN void mdct_bitreverse(mdct_lookup *init, 
-                           DATA_TYPE *x){
-  int        n       = init->n;
-  int       *bit     = init->bitrev;
-  DATA_TYPE *w0      = x;
-  DATA_TYPE *w1      = x = w0+(n>>1);
-  DATA_TYPE *T       = init->trig+n;
-
-  do{
-    DATA_TYPE *x0    = x+bit[0];
-    DATA_TYPE *x1    = x+bit[1];
-
-    REG_TYPE  r0     = x0[1]  - x1[1];
-    REG_TYPE  r1     = x0[0]  + x1[0];
-    REG_TYPE  r2     = MULT_NORM(r1     * T[0]   + r0 * T[1]);
-    REG_TYPE  r3     = MULT_NORM(r1     * T[1]   - r0 * T[0]);
-
-             w1    -= 4;
-
-              r0     = HALVE(x0[1] + x1[1]);
-              r1     = HALVE(x0[0] - x1[0]);
-      
-             w0[0]  = r0     + r2;
-             w1[2]  = r0     - r2;
-             w0[1]  = r1     + r3;
-             w1[3]  = r3     - r1;
-
-              x0     = x+bit[2];
-              x1     = x+bit[3];
-
-              r0     = x0[1]  - x1[1];
-              r1     = x0[0]  + x1[0];
-              r2     = MULT_NORM(r1     * T[2]   + r0 * T[3]);
-              r3     = MULT_NORM(r1     * T[3]   - r0 * T[2]);
-
-              r0     = HALVE(x0[1] + x1[1]);
-              r1     = HALVE(x0[0] - x1[0]);
-      
-             w0[2]  = r0     + r2;
-             w1[0]  = r0     - r2;
-             w0[3]  = r1     + r3;
-             w1[1]  = r3     - r1;
-
-             T     += 4;
-             bit   += 4;
-             w0    += 4;
-
-  }while(w0<w1);
+void clt_mdct_backward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * restrict out,
+      const opus_val16 * restrict window, int overlap, int shift, int stride)
+{
+   int i;
+   int N, N2, N4;
+   kiss_twiddle_scalar sine;
+   VARDECL(kiss_fft_scalar, f);
+   VARDECL(kiss_fft_scalar, f2);
+   SAVE_STACK;
+   N = l->n;
+   N >>= shift;
+   N2 = N>>1;
+   N4 = N>>2;
+   ALLOC(f, N2, kiss_fft_scalar);
+   ALLOC(f2, N2, kiss_fft_scalar);
+   /* sin(x) ~= x here */
+#ifdef FIXED_POINT
+   sine = TRIG_UPSCALE*(QCONST16(0.7853981f, 15)+N2)/N;
+#else
+   sine = (kiss_twiddle_scalar)2*PI*(.125f)/N;
+#endif
+
+   /* Pre-rotate */
+   {
+      /* Temp pointers to make it really clear to the compiler what we're doing */
+      const kiss_fft_scalar * restrict xp1 = in;
+      const kiss_fft_scalar * restrict xp2 = in+stride*(N2-1);
+      kiss_fft_scalar * restrict yp = f2;
+      const kiss_twiddle_scalar *t = &l->trig[0];
+      for(i=0;i<N4;i++)
+      {
+         kiss_fft_scalar yr, yi;
+         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);
+         xp1+=2*stride;
+         xp2-=2*stride;
+      }
+   }
+
+   /* Inverse N/4 complex FFT. This one should *not* downscale even in fixed-point */
+   opus_ifft(l->kfft[shift], (kiss_fft_cpx *)f2, (kiss_fft_cpx *)f);
+
+   /* Post-rotate */
+   {
+      kiss_fft_scalar * restrict fp = f;
+      const kiss_twiddle_scalar *t = &l->trig[0];
+
+      for(i=0;i<N4;i++)
+      {
+         kiss_fft_scalar re, im, yr, yi;
+         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<<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);
+      }
+   }
+   /* De-shuffle the components for the middle of the window only */
+   {
+      const kiss_fft_scalar * restrict fp1 = f;
+      const kiss_fft_scalar * restrict fp2 = f+N2-1;
+      kiss_fft_scalar * restrict yp = f2;
+      for(i = 0; i < N4; i++)
+      {
+         *yp++ =-*fp1;
+         *yp++ = *fp2;
+         fp1 += 2;
+         fp2 -= 2;
+      }
+   }
+   out -= (N2-overlap)>>1;
+   /* Mirror on both sides for TDAC */
+   {
+      kiss_fft_scalar * restrict fp1 = f2+N4-1;
+      kiss_fft_scalar * restrict xp1 = out+N2-1;
+      kiss_fft_scalar * restrict yp1 = out+N4-overlap/2;
+      const opus_val16 * restrict wp1 = window;
+      const opus_val16 * restrict wp2 = window+overlap-1;
+      for(i = 0; i< N4-overlap/2; i++)
+      {
+         *xp1 = *fp1;
+         xp1--;
+         fp1--;
+      }
+      for(; i < N4; i++)
+      {
+         kiss_fft_scalar x1;
+         x1 = *fp1--;
+         *yp1++ +=-MULT16_32_Q15(*wp1, x1);
+         *xp1-- += MULT16_32_Q15(*wp2, x1);
+         wp1++;
+         wp2--;
+      }
+   }
+   {
+      kiss_fft_scalar * restrict fp2 = f2+N4;
+      kiss_fft_scalar * restrict xp2 = out+N2;
+      kiss_fft_scalar * restrict yp2 = out+N-1-(N4-overlap/2);
+      const opus_val16 * restrict wp1 = window;
+      const opus_val16 * restrict wp2 = window+overlap-1;
+      for(i = 0; i< N4-overlap/2; i++)
+      {
+         *xp2 = *fp2;
+         xp2++;
+         fp2++;
+      }
+      for(; i < N4; i++)
+      {
+         kiss_fft_scalar x2;
+         x2 = *fp2++;
+         *yp2--  = MULT16_32_Q15(*wp1, x2);
+         *xp2++  = MULT16_32_Q15(*wp2, x2);
+         wp1++;
+         wp2--;
+      }
+   }
+   RESTORE_STACK;
 }
-
-void mdct_backward(mdct_lookup *init, DATA_TYPE *in, DATA_TYPE *out){
-  int n=init->n;
-  int n2=n>>1;
-  int n4=n>>2;
-
-  /* rotate */
-
-  DATA_TYPE *iX = in+n2-7;
-  DATA_TYPE *oX = out+n2+n4;
-  DATA_TYPE *T  = init->trig+n4;
-
-  do{
-    oX         -= 4;
-    oX[0]       = MULT_NORM(-iX[2] * T[3] - iX[0]  * T[2]);
-    oX[1]       = MULT_NORM (iX[0] * T[3] - iX[2]  * T[2]);
-    oX[2]       = MULT_NORM(-iX[6] * T[1] - iX[4]  * T[0]);
-    oX[3]       = MULT_NORM (iX[4] * T[1] - iX[6]  * T[0]);
-    iX         -= 8;
-    T          += 4;
-  }while(iX>=in);
-
-  iX            = in+n2-8;
-  oX            = out+n2+n4;
-  T             = init->trig+n4;
-
-  do{
-    T          -= 4;
-    oX[0]       =  MULT_NORM (iX[4] * T[3] + iX[6] * T[2]);
-    oX[1]       =  MULT_NORM (iX[4] * T[2] - iX[6] * T[3]);
-    oX[2]       =  MULT_NORM (iX[0] * T[1] + iX[2] * T[0]);
-    oX[3]       =  MULT_NORM (iX[0] * T[0] - iX[2] * T[1]);
-    iX         -= 8;
-    oX         += 4;
-  }while(iX>=in);
-
-  mdct_butterflies(init,out+n2,n2);
-  mdct_bitreverse(init,out);
-
-  /* roatate + window */
-
-  {
-    DATA_TYPE *oX1=out+n2+n4;
-    DATA_TYPE *oX2=out+n2+n4;
-    DATA_TYPE *iX =out;
-    T             =init->trig+n2;
-    
-    do{
-      oX1-=4;
-
-      oX1[3]  =  MULT_NORM (iX[0] * T[1] - iX[1] * T[0]);
-      oX2[0]  = -MULT_NORM (iX[0] * T[0] + iX[1] * T[1]);
-
-      oX1[2]  =  MULT_NORM (iX[2] * T[3] - iX[3] * T[2]);
-      oX2[1]  = -MULT_NORM (iX[2] * T[2] + iX[3] * T[3]);
-
-      oX1[1]  =  MULT_NORM (iX[4] * T[5] - iX[5] * T[4]);
-      oX2[2]  = -MULT_NORM (iX[4] * T[4] + iX[5] * T[5]);
-
-      oX1[0]  =  MULT_NORM (iX[6] * T[7] - iX[7] * T[6]);
-      oX2[3]  = -MULT_NORM (iX[6] * T[6] + iX[7] * T[7]);
-
-      oX2+=4;
-      iX    +=   8;
-      T     +=   8;
-    }while(iX<oX1);
-
-    iX=out+n2+n4;
-    oX1=out+n4;
-    oX2=oX1;
-
-    do{
-      oX1-=4;
-      iX-=4;
-
-      oX2[0] = -(oX1[3] = iX[3]);
-      oX2[1] = -(oX1[2] = iX[2]);
-      oX2[2] = -(oX1[1] = iX[1]);
-      oX2[3] = -(oX1[0] = iX[0]);
-
-      oX2+=4;
-    }while(oX2<iX);
-
-    iX=out+n2+n4;
-    oX1=out+n2+n4;
-    oX2=out+n2;
-    do{
-      oX1-=4;
-      oX1[0]= iX[3];
-      oX1[1]= iX[2];
-      oX1[2]= iX[1];
-      oX1[3]= iX[0];
-      iX+=4;
-    }while(oX1>oX2);
-  }
-}
-
-void mdct_forward(mdct_lookup *init, DATA_TYPE *in, DATA_TYPE *out){
-  int n=init->n;
-  int n2=n>>1;
-  int n4=n>>2;
-  int n8=n>>3;
-  DATA_TYPE *w=alloca(n*sizeof(*w)); /* forward needs working space */
-  DATA_TYPE *w2=w+n2;
-
-  /* rotate */
-
-  /* window + rotate + step 1 */
-  
-  REG_TYPE r0;
-  REG_TYPE r1;
-  DATA_TYPE *x0=in+n2+n4;
-  DATA_TYPE *x1=x0+1;
-  DATA_TYPE *T=init->trig+n2;
-  
-  int i=0;
-  
-  for(i=0;i<n8;i+=2){
-    x0 -=4;
-    T-=2;
-    r0= x0[2] + x1[0];
-    r1= x0[0] + x1[2];       
-    w2[i]=   MULT_NORM(r1*T[1] + r0*T[0]);
-    w2[i+1]= MULT_NORM(r1*T[0] - r0*T[1]);
-    x1 +=4;
-  }
-
-  x1=in+1;
-  
-  for(;i<n2-n8;i+=2){
-    T-=2;
-    x0 -=4;
-    r0= x0[2] - x1[0];
-    r1= x0[0] - x1[2];       
-    w2[i]=   MULT_NORM(r1*T[1] + r0*T[0]);
-    w2[i+1]= MULT_NORM(r1*T[0] - r0*T[1]);
-    x1 +=4;
-  }
-    
-  x0=in+n;
-
-  for(;i<n2;i+=2){
-    T-=2;
-    x0 -=4;
-    r0= -x0[2] - x1[0];
-    r1= -x0[0] - x1[2];       
-    w2[i]=   MULT_NORM(r1*T[1] + r0*T[0]);
-    w2[i+1]= MULT_NORM(r1*T[0] - r0*T[1]);
-    x1 +=4;
-  }
-
-
-  mdct_butterflies(init,w+n2,n2);
-  mdct_bitreverse(init,w);
-
-  /* roatate + window */
-
-  T=init->trig+n2;
-  x0=out+n2;
-
-  for(i=0;i<n4;i++){
-    x0--;
-    out[i] =MULT_NORM((w[0]*T[0]+w[1]*T[1])*init->scale);
-    x0[0]  =MULT_NORM((w[0]*T[1]-w[1]*T[0])*init->scale);
-    w+=2;
-    T+=2;
-  }
-}
-