shithub: aacdec

Download patch

ref: 62336dee445b3938cb71600d19efe96aa96f121e
parent: c095b2fdc5c1dc599dcfe9e2b93d23c2224617c7
author: menno <menno>
date: Mon Apr 12 14:17:42 EDT 2004

- PS fixed point
- Minor updates in SBR
- AUTHORS updated

--- a/AUTHORS
+++ b/AUTHORS
@@ -11,3 +11,7 @@
  - DRM code
  - lot's of bug fixes
 
+Gian-Carlo Pascutto (gpascutto(at)nero.com)
+ - DRM PS code
+ - bugfixes
+ 
\ No newline at end of file
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,6 @@
+12 april 2004   mbakker(at)nero.com
+    - common.h, ps_dec.c: Updates for PS fixed point, should completely work now
 
-- 30 mar 2004: Updated mpeg4ip libraries to version 1.0
-- xx mar 2004: First PS (Parametric Stereo) checkin
+12 april 2004   gpascutto(at)nero.com
+    - drm_dec.c, drm_dec.h: eliminated sqrt and SA mapping/dequantization from DRM PS decoder                
 
-- 26 feb 2004: Added downsampled SBR support
-- 26 feb 2004: Optimised Low Power QMF filterbank
--- a/common/mp4ff/drms.c
+++ b/common/mp4ff/drms.c
@@ -2,7 +2,7 @@
  * drms.c: DRMS
  *****************************************************************************
  * Copyright (C) 2004 VideoLAN
- * $Id: drms.c,v 1.5 2004/03/31 17:39:57 menno Exp $
+ * $Id: drms.c,v 1.6 2004/04/12 18:17:41 menno Exp $
  *
  * Authors: Jon Lech Johansen <[email protected]>
  *          Sam Hocevar <[email protected]>
--- a/common/mp4ff/drms.h
+++ b/common/mp4ff/drms.h
@@ -2,7 +2,7 @@
  * drms.h : DRMS
  *****************************************************************************
  * Copyright (C) 2004 VideoLAN
- * $Id: drms.h,v 1.5 2004/03/31 17:39:57 menno Exp $
+ * $Id: drms.h,v 1.6 2004/04/12 18:17:41 menno Exp $
  *
  * Author: Jon Lech Johansen <[email protected]>
  *
--- a/common/mp4ff/drmstables.h
+++ b/common/mp4ff/drmstables.h
@@ -2,7 +2,7 @@
  * drmstables.h : AES/Rijndael block cipher and miscellaneous tables
  *****************************************************************************
  * Copyright (C) 2004 VideoLAN
- * $Id: drmstables.h,v 1.4 2004/03/31 17:39:57 menno Exp $
+ * $Id: drmstables.h,v 1.6 2005/02/01 13:15:55 menno Exp $
  *
  * Author: Jon Lech Johansen <[email protected]>
  *
--- a/common/mp4ff/mp4atom.c
+++ b/common/mp4ff/mp4atom.c
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through [email protected].
 **
-** $Id: mp4atom.c,v 1.19 2004/03/31 17:39:57 menno Exp $
+** $Id: mp4atom.c,v 1.20 2004/04/12 18:17:42 menno Exp $
 **/
 
 #include <stdlib.h>
@@ -30,7 +30,9 @@
 #include "config.h"
 #else
 #include <tchar.h>
+#ifdef ITUNES_DRM
 #include <shlobj.h>
+#endif
 #include <windows.h>
 #endif
 #ifdef HAVE_GETPWUID
--- a/common/mp4ff/mp4ffint.h
+++ b/common/mp4ff/mp4ffint.h
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through [email protected].
 **
-** $Id: mp4ffint.h,v 1.17 2004/03/31 17:39:57 menno Exp $
+** $Id: mp4ffint.h,v 1.18 2004/04/12 18:17:42 menno Exp $
 **/
 
 #ifndef MP4FF_INTERNAL_H
@@ -37,7 +37,6 @@
 
 #if defined(_WIN32) && !defined(_WIN32_WCE)
 #define ITUNES_DRM
-#endif
 
 static __inline uint32_t GetDWLE( void const * _p )
 {
@@ -80,6 +79,8 @@
 #define FOURCC_iviv VLC_FOURCC( 'i', 'v', 'i', 'v' )
 #define FOURCC_name VLC_FOURCC( 'n', 'a', 'm', 'e' )
 #define FOURCC_priv VLC_FOURCC( 'p', 'r', 'i', 'v' )
+
+#endif
 
 #define MAX_TRACKS 1024
 #define TRACK_UNKNOWN 0
--- a/libfaad/common.h
+++ b/libfaad/common.h
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through [email protected].
 **
-** $Id: common.h,v 1.58 2004/04/03 10:49:14 menno Exp $
+** $Id: common.h,v 1.59 2004/04/12 18:17:42 menno Exp $
 **/
 
 #ifndef __COMMON_H__
@@ -92,7 +92,7 @@
 #define ALLOW_SMALL_FRAMELENGTH
 
 
-// Define LC_ONLY_DECODER if you want a pure AAC LC decoder (independant of SBR_DEC)
+// Define LC_ONLY_DECODER if you want a pure AAC LC decoder (independant of SBR_DEC and PS_DEC)
 //#define LC_ONLY_DECODER
 #ifdef LC_ONLY_DECODER
   #undef LTP_DEC
@@ -107,14 +107,11 @@
 //#define SBR_LOW_POWER
 #define PS_DEC
 
-/* FIXED POINT: No MAIN decoding, forced SBR Low Power decoder */
+/* FIXED POINT: No MAIN decoding */
 #ifdef FIXED_POINT
 # ifdef MAIN_DEC
 #  undef MAIN_DEC
 # endif
-# ifdef PS_DEC
-#  undef PS_DEC
-# endif
 #endif // FIXED_POINT
 
 #ifdef DRM
@@ -131,9 +128,11 @@
 #endif
 
 #ifdef FIXED_POINT
-#define SBR_DIV(A, B) (((int64_t)A << REAL_BITS)/B)
+#define DIV_R(A, B) (((int64_t)A << REAL_BITS)/B)
+#define DIV_C(A, B) (((int64_t)A << COEF_BITS)/B)
 #else
-#define SBR_DIV(A, B) ((A)/(B))
+#define DIV_R(A, B) ((A)/(B))
+#define DIV_C(A, B) ((A)/(B))
 #endif
 
 #ifndef SBR_LOW_POWER
--- a/libfaad/fixed.h
+++ b/libfaad/fixed.h
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through [email protected].
 **
-** $Id: fixed.h,v 1.21 2004/03/19 10:37:55 menno Exp $
+** $Id: fixed.h,v 1.22 2004/04/12 18:17:42 menno Exp $
 **/
 
 #ifndef __FIXED_H__
@@ -32,7 +32,7 @@
 extern "C" {
 #endif
 
-#ifdef _WIN32_WCE
+#if defined(_WIN32_WCE) && defined(_ARM_)
 #include <cmnintrin.h>
 #endif
 
@@ -213,15 +213,15 @@
   /* multiply with coef shift */
   #define MUL_C(A,B) (real_t)(((int64_t)(A)*(int64_t)(B)+(1 << (COEF_BITS-1))) >> COEF_BITS)
   /* multiply with fractional shift */
-#ifndef _WIN32_WCE
-  #define _MulHigh(A,B) (real_t)(((int64_t)(A)*(int64_t)(B)+(1 << (FRAC_SIZE-1))) >> FRAC_SIZE)
-  #define MUL_F(A,B) (real_t)(((int64_t)(A)*(int64_t)(B)+(1 << (FRAC_BITS-1))) >> FRAC_BITS)
-#else
+#if defined(_WIN32_WCE) && defined(_ARM_)
   /* eVC for PocketPC has an intrinsic function that returns only the high 32 bits of a 32x32 bit multiply */
   static INLINE real_t MUL_F(real_t A, real_t B)
   {
       return _MulHigh(A,B) << (32-FRAC_BITS);
   }
+#else
+  #define _MulHigh(A,B) (real_t)(((int64_t)(A)*(int64_t)(B)+(1 << (FRAC_SIZE-1))) >> FRAC_SIZE)
+  #define MUL_F(A,B) (real_t)(((int64_t)(A)*(int64_t)(B)+(1 << (FRAC_BITS-1))) >> FRAC_BITS)
 #endif
   #define MUL_Q2(A,B) (real_t)(((int64_t)(A)*(int64_t)(B)+(1 << (Q2_BITS-1))) >> Q2_BITS)
   #define MUL_SHIFT6(A,B) (real_t)(((int64_t)(A)*(int64_t)(B)+(1 << (6-1))) >> 6)
--- a/libfaad/ps_dec.c
+++ b/libfaad/ps_dec.c
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through [email protected].
 **
-** $Id: ps_dec.c,v 1.5 2004/04/03 19:08:38 menno Exp $
+** $Id: ps_dec.c,v 1.6 2004/04/12 18:17:42 menno Exp $
 **/
 
 #include "common.h"
@@ -926,7 +926,7 @@
 static void ps_decorrelate(ps_info *ps, qmf_t X_left[38][64], qmf_t X_right[38][64],
                            qmf_t X_hybrid_left[32][32], qmf_t X_hybrid_right[32][32])
 {
-    uint8_t gr, m, n, bk;
+    uint8_t gr, n, m, bk;
     uint8_t temp_delay;
     uint8_t sb, maxsb;
     const complex_t *Phi_Fract_SubQmf;
@@ -946,7 +946,6 @@
     }
 
     /* clear the energy values */
-#if 0
     for (n = 0; n < 32; n++)
     {
         for (bk = 0; bk < 34; bk++)
@@ -954,7 +953,6 @@
             P[n][bk] = 0;
         }
     }
-#endif
 
     /* calculate the energy in each parameter band b(k) */
     for (gr = 0; gr < ps->num_groups; gr++)
@@ -969,6 +967,10 @@
         {
             for (n = ps->border_position[0]; n < ps->border_position[ps->num_env]; n++)
             {
+#ifdef FIXED_POINT
+                uint32_t in_re, in_im;
+#endif
+
                 /* input from hybrid subbands or QMF subbands */
                 if (gr < ps->num_hybrid_groups)
                 {
@@ -980,11 +982,34 @@
                 }
 
                 /* accumulate energy */
+#ifdef FIXED_POINT
+                /* NOTE: all input is scaled by 2^(-5) because of fixed point QMF
+                 * meaning that P will be scaled by 2^(-10) compared to floating point version
+                 */
+                in_re = ((abs(RE(inputLeft))+(1<<(REAL_BITS-1)))>>REAL_BITS);
+                in_im = ((abs(IM(inputLeft))+(1<<(REAL_BITS-1)))>>REAL_BITS);
+                P[n][bk] += in_re*in_re + in_im*in_im;
+#else
                 P[n][bk] += MUL_R(RE(inputLeft),RE(inputLeft)) + MUL_R(IM(inputLeft),IM(inputLeft));
+#endif
             }
         }
     }
 
+#if 0
+    for (n = 0; n < 32; n++)
+    {
+        for (bk = 0; bk < 34; bk++)
+        {
+#ifdef FIXED_POINT
+            printf("%d %d: %d\n", n, bk, P[n][bk] /*/(float)REAL_PRECISION*/);
+#else
+            printf("%d %d: %f\n", n, bk, P[n][bk]/1024.0);
+#endif
+        }
+    }
+#endif
+
     /* calculate transient reduction ratio for each parameter band b(k) */
     for (bk = 0; bk < ps->nr_par_bands; bk++)
     {
@@ -1011,11 +1036,25 @@
             {
                 G_TransientRatio[n][bk] = REAL_CONST(1.0);
             } else {
-                G_TransientRatio[n][bk] = SBR_DIV(nrg, (MUL_C(P_SmoothPeakDecayDiffNrg, gamma)));
+                G_TransientRatio[n][bk] = DIV_R(nrg, (MUL_C(P_SmoothPeakDecayDiffNrg, gamma)));
             }
         }
     }
 
+#if 0
+    for (n = 0; n < 32; n++)
+    {
+        for (bk = 0; bk < 34; bk++)
+        {
+#ifdef FIXED_POINT
+            printf("%d %d: %f\n", n, bk, G_TransientRatio[n][bk]/(float)REAL_PRECISION);
+#else
+            printf("%d %d: %f\n", n, bk, G_TransientRatio[n][bk]);
+#endif
+        }
+    }
+#endif
+
     /* apply stereo decorrelation filter to the signal */
     for (gr = 0; gr < ps->num_groups; gr++)
     {
@@ -1028,6 +1067,7 @@
         for (sb = ps->group_border[gr]; sb < maxsb; sb++)
         {
             real_t g_DecaySlope;
+            real_t g_DecaySlope_filt[NO_ALLPASS_LINKS];
 
             /* g_DecaySlope: [0..1] */
             if (gr < ps->num_hybrid_groups || sb <= ps->decay_cutoff)
@@ -1044,7 +1084,13 @@
                 }
             }
 
+            /* calculate g_DecaySlope_filt for every m multiplied by filter_a[m] */
+            for (m = 0; m < NO_ALLPASS_LINKS; m++)
+            {
+                g_DecaySlope_filt[m] = MUL_F(g_DecaySlope, filter_a[m]);
+            }
 
+
             /* set delay indices */
             temp_delay = ps->saved_delay;
             for (n = 0; n < NO_ALLPASS_LINKS; n++)
@@ -1110,7 +1156,7 @@
 
                     RE(R0) = RE(tmp);
                     IM(R0) = IM(tmp);
-                    for (m = 0; m < NO_ALLPASS_LINKS ; m++)
+                    for (m = 0; m < NO_ALLPASS_LINKS; m++)
                     {
                         complex_t Q_Fract_allpass, tmp2;
 
@@ -1143,12 +1189,12 @@
                         ComplexMult(&RE(tmp), &IM(tmp), RE(tmp0), IM(tmp0), RE(Q_Fract_allpass), IM(Q_Fract_allpass));
 
                         /* -a(m) * g_DecaySlope[k] */
-                        RE(tmp) += -MUL_F(g_DecaySlope, MUL_F(filter_a[m], RE(R0)));
-                        IM(tmp) += -MUL_F(g_DecaySlope, MUL_F(filter_a[m], IM(R0)));
+                        RE(tmp) += -MUL_F(g_DecaySlope_filt[m], RE(R0));
+                        IM(tmp) += -MUL_F(g_DecaySlope_filt[m], IM(R0));
 
                         /* -a(m) * g_DecaySlope[k] * Q_Fract_allpass[k,m] * z^(-d(m)) */
-                        RE(tmp2) = RE(R0) + MUL_F(g_DecaySlope, MUL_F(filter_a[m], RE(tmp)));
-                        IM(tmp2) = IM(R0) + MUL_F(g_DecaySlope, MUL_F(filter_a[m], IM(tmp)));
+                        RE(tmp2) = RE(R0) + MUL_F(g_DecaySlope_filt[m], RE(tmp));
+                        IM(tmp2) = IM(R0) + MUL_F(g_DecaySlope_filt[m], IM(tmp));
 
                         /* store sample */
                         if (gr < ps->num_hybrid_groups)
@@ -1160,6 +1206,7 @@
                             IM(ps->delay_Qmf_ser[m][temp_delay_ser[m]][sb]) = IM(tmp2);
                         }
 
+                        /* store for next iteration (or as output value if last iteration) */
                         RE(R0) = RE(tmp);
                         IM(R0) = IM(tmp);
                     }
@@ -1192,6 +1239,7 @@
                 /* update delay indices */
                 if (sb > ps->nr_allpass_bands && gr >= ps->num_hybrid_groups)
                 {
+                    /* delay_D depends on the samplerate, it can hold the values 14 and 1 */
                     if (++ps->delay_buf_index_delay[sb] >= ps->delay_D[sb])
                     {
                         ps->delay_buf_index_delay[sb] = 0;
@@ -1215,10 +1263,41 @@
         ps->delay_buf_index_ser[m] = temp_delay_ser[m];
 }
 
+#ifdef FIXED_POINT
+#define step(shift) \
+    if ((0x40000000l >> shift) + root <= value)       \
+    {                                                 \
+        value -= (0x40000000l >> shift) + root;       \
+        root = (root >> 1) | (0x40000000l >> shift);  \
+    } else {                                          \
+        root = root >> 1;                             \
+    }
+
+/* fixed point square root approximation */
+static real_t ps_sqrt(real_t value)
+{
+    real_t root = 0;
+
+    step( 0); step( 2); step( 4); step( 6);
+    step( 8); step(10); step(12); step(14);
+    step(16); step(18); step(20); step(22);
+    step(24); step(26); step(28); step(30);
+
+    if (root < value)
+        ++root;
+
+    root <<= (REAL_BITS/2);
+
+    return root;
+}
+#else
+#define ps_sqrt(A) sqrt(A)
+#endif
+
 static void ps_mix_phase(ps_info *ps, qmf_t X_left[38][64], qmf_t X_right[38][64],
                          qmf_t X_hybrid_left[32][32], qmf_t X_hybrid_right[32][32])
 {
-    uint8_t i;
+    uint8_t n;
     uint8_t gr;
     uint8_t bk = 0;
     uint8_t sb, maxsb;
@@ -1315,9 +1394,6 @@
                 RE(h12) = MUL_C(c_1, (ab1 + ab2));
                 RE(h21) = MUL_C(c_2, (ab3 + ab4));
                 RE(h22) = MUL_C(c_1, (ab3 - ab4));
-
-                //printf("%d %f %f %f %f\n", ps->iid_index[env][bin], scaleR, scaleL, alpha, beta);
-
             } else {
                 /* type 'B' mixing as described in 8.6.4.6.2.2 */
                 real_t sina, cosa;
@@ -1385,27 +1461,32 @@
              */
             if ((ps->enable_ipdopd) && (bk < nr_ipdopd_par))
             {
-                real_t ipd, opd;
+                int8_t i;
                 real_t xxyy, ppqq;
                 real_t yq, xp, xq, py, tmp;
 
-                ipd = (float)( M_PI/4.0f ) * ps->ipd_index[env][bk];
-                opd = (float)( M_PI/4.0f ) * ps->opd_index[env][bk];
-
                 /* ringbuffer index */
                 i = ps->phase_hist;
 
                 /* previous value */
+#ifdef FIXED_POINT
+                /* divide by 4, shift right 2 bits */
+                RE(tempLeft)  = RE(ps->ipd_prev[bk][i]) >> 2;
+                IM(tempLeft)  = IM(ps->ipd_prev[bk][i]) >> 2;
+                RE(tempRight) = RE(ps->opd_prev[bk][i]) >> 2;
+                IM(tempRight) = IM(ps->opd_prev[bk][i]) >> 2;
+#else
                 RE(tempLeft)  = MUL_F(RE(ps->ipd_prev[bk][i]), FRAC_CONST(0.25));
                 IM(tempLeft)  = MUL_F(IM(ps->ipd_prev[bk][i]), FRAC_CONST(0.25));
                 RE(tempRight) = MUL_F(RE(ps->opd_prev[bk][i]), FRAC_CONST(0.25));
                 IM(tempRight) = MUL_F(IM(ps->opd_prev[bk][i]), FRAC_CONST(0.25));
+#endif
 
                 /* save current value */
-                RE(ps->ipd_prev[bk][i]) = (float)cos(ipd);
-                IM(ps->ipd_prev[bk][i]) = (float)sin(ipd);
-                RE(ps->opd_prev[bk][i]) = (float)cos(opd);
-                IM(ps->opd_prev[bk][i]) = (float)sin(opd);
+                RE(ps->ipd_prev[bk][i]) = (float)cos((float)( M_PI/4.0f ) * ps->ipd_index[env][bk]);
+                IM(ps->ipd_prev[bk][i]) = (float)sin((float)( M_PI/4.0f ) * ps->ipd_index[env][bk]);
+                RE(ps->opd_prev[bk][i]) = (float)cos((float)( M_PI/4.0f ) * ps->opd_index[env][bk]);
+                IM(ps->opd_prev[bk][i]) = (float)sin((float)( M_PI/4.0f ) * ps->opd_index[env][bk]);
 
                 /* add current value */
                 RE(tempLeft)  += RE(ps->ipd_prev[bk][i]);
@@ -1421,12 +1502,20 @@
                 i--;
 
                 /* get value before previous */
+#ifdef FIXED_POINT
+                /* dividing by 2, shift right 1 bit */
+                RE(tempLeft)  += (RE(ps->ipd_prev[bk][i]) >> 1);
+                IM(tempLeft)  += (IM(ps->ipd_prev[bk][i]) >> 1);
+                RE(tempRight) += (RE(ps->opd_prev[bk][i]) >> 1);
+                IM(tempRight) += (IM(ps->opd_prev[bk][i]) >> 1);
+#else
                 RE(tempLeft)  += MUL_F(RE(ps->ipd_prev[bk][i]), FRAC_CONST(0.5));
                 IM(tempLeft)  += MUL_F(IM(ps->ipd_prev[bk][i]), FRAC_CONST(0.5));
                 RE(tempRight) += MUL_F(RE(ps->opd_prev[bk][i]), FRAC_CONST(0.5));
                 IM(tempRight) += MUL_F(IM(ps->opd_prev[bk][i]), FRAC_CONST(0.5));
+#endif
 
-#if 0
+#if 0 /* original code */
                 ipd = (float)atan2(IM(tempLeft), RE(tempLeft));
                 opd = (float)atan2(IM(tempRight), RE(tempRight));
 
@@ -1441,41 +1530,49 @@
                 // sin(atan2(x,y)) = x/(y*sqrt(1 + (x*x)/(y*y)))
                 // cos(atan2(x,y)-atan2(p,q)) = (y*q+x*p)/(y*q * sqrt(1 + (x*x)/(y*y)) * sqrt(1 + (p*p)/(q*q)));
                 // sin(atan2(x,y)-atan2(p,q)) = (x*q-p*y)/(y*q * sqrt(1 + (x*x)/(y*y)) * sqrt(1 + (p*p)/(q*q)));
-#define DIV_C(A,B) ((A)/(B))
-                xxyy = DIV_C(MUL_C(IM(tempLeft),IM(tempLeft)), MUL_C(RE(tempLeft),RE(tempLeft)));
-                ppqq = DIV_C(MUL_C(IM(tempRight),IM(tempRight)), MUL_C(RE(tempRight),RE(tempRight)));
 
-                xxyy += COEF_CONST(1);
-                ppqq += COEF_CONST(1);
+                /* (x*x)/(y*y)  (REAL > 0) */
+                xxyy = DIV_R(MUL_C(IM(tempLeft),IM(tempLeft)), MUL_C(RE(tempLeft),RE(tempLeft)));
+                ppqq = DIV_R(MUL_C(IM(tempRight),IM(tempRight)), MUL_C(RE(tempRight),RE(tempRight)));
 
-                xxyy = sqrt(xxyy);
-                ppqq = sqrt(ppqq);
+                /* 1 + (x*x)/(y*y)  (REAL > 1) */
+                xxyy += REAL_CONST(1);
+                ppqq += REAL_CONST(1);
 
+                /* 1 / sqrt(1 + (x*x)/(y*y))  (FRAC <= 1) */
+                xxyy = DIV_R(FRAC_CONST(1), ps_sqrt(xxyy));
+                ppqq = DIV_R(FRAC_CONST(1), ps_sqrt(ppqq));
+
+                /* COEF */
                 yq = MUL_C(RE(tempLeft), RE(tempRight));
                 xp = MUL_C(IM(tempLeft), IM(tempRight));
                 xq = MUL_C(IM(tempLeft), RE(tempRight));
-                py = MUL_C(IM(tempRight), RE(tempLeft));
+                py = MUL_C(RE(tempLeft), IM(tempRight));
 
-                RE(phaseLeft) = 1.f/xxyy;
-                IM(phaseLeft) = IM(tempLeft)/(RE(tempLeft)*xxyy);
+                RE(phaseLeft) = xxyy;
+                IM(phaseLeft) = MUL_R(xxyy, (DIV_R(IM(tempLeft), RE(tempLeft))));
 
-                tmp = 1.f / (yq * xxyy * ppqq);
-                RE(phaseRight) = (yq+xp) * tmp;
-                IM(phaseRight) = (xq-py) * tmp;
+                tmp = DIV_C(MUL_F(xxyy, ppqq), yq);
+
+                /* MUL_C(FRAC,COEF) = FRAC */
+                RE(phaseRight) = MUL_C(tmp, (yq+xp));
+                IM(phaseRight) = MUL_C(tmp, (xq-py));
 #endif
 
-                IM(h11) = RE(h11) * IM(phaseLeft);
-                IM(h12) = RE(h12) * IM(phaseRight);
-                IM(h21) = RE(h21) * IM(phaseLeft);
-                IM(h22) = RE(h22) * IM(phaseRight);
+                /* MUL_F(COEF, FRAC) = COEF */
+                IM(h11) = MUL_F(RE(h11), IM(phaseLeft));
+                IM(h12) = MUL_F(RE(h12), IM(phaseRight));
+                IM(h21) = MUL_F(RE(h21), IM(phaseLeft));
+                IM(h22) = MUL_F(RE(h22), IM(phaseRight));
 
-                RE(h11) *= RE(phaseLeft);
-                RE(h12) *= RE(phaseRight);
-                RE(h21) *= RE(phaseLeft);
-                RE(h22) *= RE(phaseRight);
+                RE(h11) = MUL_F(RE(h11), RE(phaseLeft));
+                RE(h12) = MUL_F(RE(h12), RE(phaseRight));
+                RE(h21) = MUL_F(RE(h21), RE(phaseLeft));
+                RE(h22) = MUL_F(RE(h22), RE(phaseRight));
             }
 
             /* length of the envelope n_e+1 - n_e (in time samples) */
+            /* 0 < L <= 32: integer */
             L = (real_t)(ps->border_position[env + 1] - ps->border_position[env]);
 
             /* obtain final H_xy by means of linear interpolation */
@@ -1528,9 +1625,9 @@
             }
 
             /* apply H_xy to the current envelope band of the decorrelated subband */
-            for (i = ps->border_position[env]; i < ps->border_position[env + 1]; i++)
+            for (n = ps->border_position[env]; n < ps->border_position[env + 1]; n++)
             {
-                /* addition finalises the interpolation */
+                /* addition finalises the interpolation over every n */
                 RE(H11) += RE(deltaH11);
                 RE(H12) += RE(deltaH12);
                 RE(H21) += RE(deltaH21);
@@ -1551,45 +1648,45 @@
                     /* load decorrelated samples */
                     if (gr < ps->num_hybrid_groups)
                     {
-                        RE(inLeft) =  RE(X_hybrid_left[i][sb]);
-                        IM(inLeft) =  IM(X_hybrid_left[i][sb]);
-                        RE(inRight) = RE(X_hybrid_right[i][sb]);
-                        IM(inRight) = IM(X_hybrid_right[i][sb]);
+                        RE(inLeft) =  RE(X_hybrid_left[n][sb]);
+                        IM(inLeft) =  IM(X_hybrid_left[n][sb]);
+                        RE(inRight) = RE(X_hybrid_right[n][sb]);
+                        IM(inRight) = IM(X_hybrid_right[n][sb]);
                     } else {
-                        RE(inLeft) =  RE(X_left[i][sb]);
-                        IM(inLeft) =  IM(X_left[i][sb]);
-                        RE(inRight) = RE(X_right[i][sb]);
-                        IM(inRight) = IM(X_right[i][sb]);
+                        RE(inLeft) =  RE(X_left[n][sb]);
+                        IM(inLeft) =  IM(X_left[n][sb]);
+                        RE(inRight) = RE(X_right[n][sb]);
+                        IM(inRight) = IM(X_right[n][sb]);
                     }
 
                     /* apply mixing */
-                    RE(tempLeft) =  RE(H11) * RE(inLeft) + RE(H21) * RE(inRight);
-                    IM(tempLeft) =  RE(H11) * IM(inLeft) + RE(H21) * IM(inRight);
-                    RE(tempRight) = RE(H12) * RE(inLeft) + RE(H22) * RE(inRight);
-                    IM(tempRight) = RE(H12) * IM(inLeft) + RE(H22) * IM(inRight);
+                    RE(tempLeft) =  MUL_C(RE(H11), RE(inLeft)) + MUL_C(RE(H21), RE(inRight));
+                    IM(tempLeft) =  MUL_C(RE(H11), IM(inLeft)) + MUL_C(RE(H21), IM(inRight));
+                    RE(tempRight) = MUL_C(RE(H12), RE(inLeft)) + MUL_C(RE(H22), RE(inRight));
+                    IM(tempRight) = MUL_C(RE(H12), IM(inLeft)) + MUL_C(RE(H22), IM(inRight));
 
                     /* only perform imaginary operations when needed */
                     if ((ps->enable_ipdopd) && (bk < nr_ipdopd_par))
                     {
                         /* apply rotation */
-                        RE(tempLeft)  -= IM(H11) * IM(inLeft) + IM(H21) * IM(inRight); 
-                        IM(tempLeft)  += IM(H11) * RE(inLeft) + IM(H21) * RE(inRight);
-                        RE(tempRight) -= IM(H12) * IM(inLeft) + IM(H22) * IM(inRight);
-                        IM(tempRight) += IM(H12) * RE(inLeft) + IM(H22) * RE(inRight);
+                        RE(tempLeft)  -= MUL_C(IM(H11), IM(inLeft)) + MUL_C(IM(H21), IM(inRight));
+                        IM(tempLeft)  += MUL_C(IM(H11), RE(inLeft)) + MUL_C(IM(H21), RE(inRight));
+                        RE(tempRight) -= MUL_C(IM(H12), IM(inLeft)) + MUL_C(IM(H22), IM(inRight));
+                        IM(tempRight) += MUL_C(IM(H12), RE(inLeft)) + MUL_C(IM(H22), RE(inRight));
                     }
 
                     /* store final samples */
                     if (gr < ps->num_hybrid_groups)
                     {
-                        RE(X_hybrid_left[i][sb]) =  RE(tempLeft);
-                        IM(X_hybrid_left[i][sb]) =  IM(tempLeft);
-                        RE(X_hybrid_right[i][sb]) = RE(tempRight);
-                        IM(X_hybrid_right[i][sb]) = IM(tempRight);
+                        RE(X_hybrid_left[n][sb])  = RE(tempLeft);
+                        IM(X_hybrid_left[n][sb])  = IM(tempLeft);
+                        RE(X_hybrid_right[n][sb]) = RE(tempRight);
+                        IM(X_hybrid_right[n][sb]) = IM(tempRight);
                     } else {
-                        RE(X_left[i][sb]) =  RE(tempLeft);
-                        IM(X_left[i][sb]) =  IM(tempLeft);
-                        RE(X_right[i][sb]) = RE(tempRight);
-                        IM(X_right[i][sb]) = IM(tempRight);
+                        RE(X_left[n][sb])  = RE(tempLeft);
+                        IM(X_left[n][sb])  = IM(tempLeft);
+                        RE(X_right[n][sb]) = RE(tempRight);
+                        IM(X_right[n][sb]) = IM(tempRight);
                     }
                 }
             }
--- a/libfaad/ps_dec.h
+++ b/libfaad/ps_dec.h
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through [email protected].
 **
-** $Id: ps_dec.h,v 1.3 2004/04/03 19:08:38 menno Exp $
+** $Id: ps_dec.h,v 1.6 2004/07/31 15:48:56 menno Exp $
 **/
 
 #ifndef __PS_DEC_H__
@@ -104,10 +104,10 @@
     uint8_t delay_D[64];
     uint8_t delay_buf_index_delay[64];
 
-    complex_t delay_Qmf[14][64]; /* 14 samples delay, 64 QMF channels */
-    complex_t delay_SubQmf[14][32]; /* 14 samples delay */
-    complex_t delay_Qmf_ser[NO_ALLPASS_LINKS][14][64]; /* 14 samples delay, 64 QMF channels */
-    complex_t delay_SubQmf_ser[NO_ALLPASS_LINKS][14][32]; /* 14 samples delay */
+    complex_t delay_Qmf[14][64]; /* 14 samples delay max, 64 QMF channels */
+    complex_t delay_SubQmf[2][32]; /* 2 samples delay max (SubQmf is always allpass filtered) */
+    complex_t delay_Qmf_ser[NO_ALLPASS_LINKS][5][64]; /* 5 samples delay max (table 8.34), 64 QMF channels */
+    complex_t delay_SubQmf_ser[NO_ALLPASS_LINKS][5][32]; /* 5 samples delay max (table 8.34) */
 
     /* transients */
     real_t alpha_decay;
--- a/libfaad/sbr_dec.c
+++ b/libfaad/sbr_dec.c
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through [email protected].
 **
-** $Id: sbr_dec.c,v 1.34 2004/04/03 10:49:15 menno Exp $
+** $Id: sbr_dec.c,v 1.35 2004/04/12 18:17:42 menno Exp $
 **/
 
 
@@ -96,6 +96,9 @@
         sbr->numTimeSlotsRate = RATE * NO_TIME_SLOTS;
         sbr->numTimeSlots = NO_TIME_SLOTS;
     }
+
+    sbr->GQ_ringbuf_index[0] = 0;
+    sbr->GQ_ringbuf_index[1] = 0;
 
     if (id_aac == ID_CPE)
     {
--- a/libfaad/sbr_dec.h
+++ b/libfaad/sbr_dec.h
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through [email protected].
 **
-** $Id: sbr_dec.h,v 1.30 2004/04/03 10:49:15 menno Exp $
+** $Id: sbr_dec.h,v 1.31 2004/04/12 18:17:42 menno Exp $
 **/
 
 #ifndef __SBR_DEC_H__
@@ -43,6 +43,10 @@
 #define MAX_NTSRHFG 40
 #define MAX_NTSR    32 /* max number_time_slots * rate, ok for DRM and not DRM mode */
 
+/* MAX_M: maximum value for M */
+#define MAX_M       49
+/* MAX_L_E: maximum value for L_E */
+#define MAX_L_E      5
 
 typedef struct {
     real_t *x;
@@ -98,18 +102,19 @@
     uint8_t L_E_prev[2];
     uint8_t L_Q[2];
 
-    uint8_t t_E[2][6];
+    uint8_t t_E[2][MAX_L_E+1];
     uint8_t t_Q[2][3];
-    uint8_t f[2][6];
+    uint8_t f[2][MAX_L_E+1];
     uint8_t f_prev[2];
 
     real_t *G_temp_prev[2][5];
     real_t *Q_temp_prev[2][5];
+    int8_t GQ_ringbuf_index[2];
 
-    int16_t E[2][64][5];
+    int16_t E[2][64][MAX_L_E];
     int16_t E_prev[2][64];
-    real_t E_orig[2][64][5];
-    real_t E_curr[2][64][5];
+    real_t E_orig[2][64][MAX_L_E];
+    real_t E_curr[2][64][MAX_L_E];
     int32_t Q[2][64][2];
     real_t Q_div[2][64][2];
     real_t Q_div2[2][64][2];
@@ -118,8 +123,8 @@
     int8_t l_A[2];
     int8_t l_A_prev[2];
 
-    uint8_t bs_invf_mode[2][5];
-    uint8_t bs_invf_mode_prev[2][5];
+    uint8_t bs_invf_mode[2][MAX_L_E];
+    uint8_t bs_invf_mode_prev[2][MAX_L_E];
     real_t bwArray[2][64];
     real_t bwArray_prev[2][64];
 
--- a/libfaad/sbr_fbt.c
+++ b/libfaad/sbr_fbt.c
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through [email protected].
 **
-** $Id: sbr_fbt.c,v 1.12 2004/03/10 19:45:41 menno Exp $
+** $Id: sbr_fbt.c,v 1.13 2004/04/12 18:17:42 menno Exp $
 **/
 
 /* Calculate frequency band tables */
@@ -594,7 +594,7 @@
     printf("f_table_noise[%d]: ", sbr->N_Q);
     for (k = 0; k <= sbr->N_Q; k++)
     {
-        printf("%d ", sbr->f_table_noise[k]);
+        printf("%d ", sbr->f_table_noise[k] - sbr->kx);
     }
     printf("\n");
 #endif
@@ -626,6 +626,15 @@
     sbr->f_table_lim[0][1] = sbr->f_table_res[LO_RES][sbr->N_low] - sbr->kx;
     sbr->N_L[0] = 1;
 
+#if 0
+    printf("f_table_lim[%d][%d]: ", 0, sbr->N_L[0]);
+    for (k = 0; k <= sbr->N_L[0]; k++)
+    {
+        printf("%d ", sbr->f_table_lim[0][k]);
+    }
+    printf("\n");
+#endif
+
     for (s = 1; s < 4; s++)
     {
         int32_t limTable[100 /*TODO*/] = {0};
@@ -668,7 +677,7 @@
                 nOctaves = REAL_CONST(log((float)limTable[k]/(float)limTable[k-1])/log(2.0));
 #else
 #ifdef FIXED_POINT
-                nOctaves = SBR_DIV(REAL_CONST(limTable[k]),REAL_CONST(limTable[k-1]));
+                nOctaves = DIV_R(REAL_CONST(limTable[k]),REAL_CONST(limTable[k-1]));
 #else
                 nOctaves = (real_t)limTable[k]/(real_t)limTable[k-1];
 #endif
--- a/libfaad/sbr_hfadj.c
+++ b/libfaad/sbr_hfadj.c
@@ -1,19 +1,19 @@
 /*
 ** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
 ** Copyright (C) 2003-2004 M. Bakker, Ahead Software AG, http://www.nero.com
-**  
+**
 ** 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 
+** along with this program; if not, write to the Free Software
 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **
 ** Any non-GPL usage of this software or parts of this software is strictly
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through [email protected].
 **
-** $Id: sbr_hfadj.c,v 1.13 2004/03/19 10:37:55 menno Exp $
+** $Id: sbr_hfadj.c,v 1.14 2004/04/12 18:17:42 menno Exp $
 **/
 
 /* High Frequency adjustment */
@@ -77,28 +77,25 @@
 static void map_noise_data(sbr_info *sbr, sbr_hfadj_info *adj, uint8_t ch)
 {
     uint8_t l, i;
-    uint32_t m;
+    uint8_t m;
 
     for (l = 0; l < sbr->L_E[ch]; l++)
     {
-        for (i = 0; i < sbr->N_Q; i++)
+        uint8_t k;
+
+        /* select the noise time band k that completely holds the current envelope time band l */
+        for (k = 0; k < 2; k++)
         {
-            for (m = sbr->f_table_noise[i]; m < sbr->f_table_noise[i+1]; m++)
+            if ((sbr->t_E[ch][l] >= sbr->t_Q[ch][k]) && (sbr->t_E[ch][l+1] <= sbr->t_Q[ch][k+1]))
             {
-                uint8_t k;
-
-                adj->Q_div_mapped[m - sbr->kx][l] = 0;
-                adj->Q_div2_mapped[m - sbr->kx][l] = 0;
-
-                for (k = 0; k < 2; k++)
+                for (i = 0; i < sbr->N_Q; i++)
                 {
-                    if ((sbr->t_E[ch][l] >= sbr->t_Q[ch][k]) &&
-                        (sbr->t_E[ch][l+1] <= sbr->t_Q[ch][k+1]))
+                    for (m = sbr->f_table_noise[i]; m < sbr->f_table_noise[i+1]; m++)
                     {
-                        adj->Q_div_mapped[m - sbr->kx][l] =
+                        adj->Q_div_mapped[l][m - sbr->kx] =
                             sbr->Q_div[ch][i][k];
 
-                        adj->Q_div2_mapped[m - sbr->kx][l] =
+                        adj->Q_div2_mapped[l][m - sbr->kx] =
                             sbr->Q_div2[ch][i][k];
                     }
                 }
@@ -130,8 +127,8 @@
     {
         for (i = 0; i < 64; i++)
         {
-            adj->S_index_mapped[i][l] = 0;
-            adj->S_mapped[i][l] = 0;
+            adj->S_index_mapped[l][i] = 0;
+            adj->S_mapped[l][i] = 0;
         }
     }
 
@@ -139,22 +136,12 @@
     {
         for (i = 0; i < sbr->N_high; i++)
         {
-            for (m = sbr->f_table_res[HI_RES][i]; m < sbr->f_table_res[HI_RES][i+1]; m++)
+            if ((l >= sbr->l_A[ch]) ||
+                (sbr->bs_add_harmonic_prev[ch][i] && sbr->bs_add_harmonic_flag_prev[ch]))
             {
-                uint8_t delta_step = 0;
-                if ((l >= sbr->l_A[ch]) || ((sbr->bs_add_harmonic_prev[ch][i]) &&
-                    (sbr->bs_add_harmonic_flag_prev[ch])))
-                {
-                    delta_step = 1;
-                }
-
-                if (m == (int32_t)((real_t)(sbr->f_table_res[HI_RES][i+1]+sbr->f_table_res[HI_RES][i])/2.))
-                {
-                    adj->S_index_mapped[m - sbr->kx][l] =
-                        delta_step * sbr->bs_add_harmonic[ch][i];
-                } else {
-                    adj->S_index_mapped[m - sbr->kx][l] = 0;
-                }
+                /* find the middle subband of the frequency band */
+                m = (sbr->f_table_res[HI_RES][i+1] + sbr->f_table_res[HI_RES][i]) >> 1;
+                adj->S_index_mapped[l][m - sbr->kx] = /*delta_step **/ sbr->bs_add_harmonic[ch][i];
             }
         }
     }
@@ -163,7 +150,7 @@
     {
         for (i = 0; i < sbr->N_high; i++)
         {
-            if (sbr->f[ch][l] == 1)
+            if (sbr->f[ch][l] == HI_RES)
             {
                 k1 = i;
                 k2 = i + 1;
@@ -192,18 +179,59 @@
             delta_S = 0;
             for (k = l_i; k < u_i; k++)
             {
-                if (adj->S_index_mapped[k - sbr->kx][l] == 1)
+                if (adj->S_index_mapped[l][k - sbr->kx] == 1)
                     delta_S = 1;
             }
 
             for (m = l_i; m < u_i; m++)
             {
-                adj->S_mapped[m - sbr->kx][l] = delta_S;
+                adj->S_mapped[l][m - sbr->kx] = delta_S;
             }
         }
     }
 }
 
+static uint8_t get_S_mapped(sbr_info *sbr, uint8_t ch, uint8_t l, uint8_t current_band)
+{
+    if (sbr->f[ch][l] == HI_RES)
+    {
+        /* in case of using f_table_high we just have 1 to 1 mapping
+         * from bs_add_harmonic[l][k]
+         */
+        if ((l >= sbr->l_A[ch]) ||
+            (sbr->bs_add_harmonic_prev[ch][current_band] && sbr->bs_add_harmonic_flag_prev[ch]))
+        {
+            return sbr->bs_add_harmonic[ch][current_band];
+        }
+    } else {
+        uint8_t b, lb, ub;
+
+        /* in case of f_table_low we check if any of the HI_RES bands
+         * within this LO_RES band has bs_add_harmonic[l][k] turned on
+         * (note that borders in the LO_RES table are also present in
+         * the HI_RES table)
+         */
+
+        /* find first HI_RES band in current LO_RES band */
+        lb = 2*current_band - ((sbr->N_high & 1) ? 1 : 0);
+        /* find first HI_RES band in next LO_RES band */
+        ub = 2*(current_band+1) - ((sbr->N_high & 1) ? 1 : 0);
+
+        /* check all HI_RES bands in current LO_RES band for sinusoid */
+        for (b = lb; b < ub; b++)
+        {
+            if ((l >= sbr->l_A[ch]) ||
+                (sbr->bs_add_harmonic_prev[ch][b] && sbr->bs_add_harmonic_flag_prev[ch]))
+            {
+                if (sbr->bs_add_harmonic[ch][b] == 1)
+                    return 1;
+            }
+        }
+    }
+
+    return 0;
+}
+
 static void estimate_current_envelope(sbr_info *sbr, sbr_hfadj_info *adj,
                                       qmf_t Xsbr[MAX_NTSRHFG][64], uint8_t ch)
 {
@@ -445,13 +473,13 @@
 {
     uint8_t m, l, k, i;
 
-    ALIGN real_t Q_M_lim[64];
-    ALIGN real_t G_lim[64];
+    ALIGN real_t Q_M_lim[MAX_M];
+    ALIGN real_t G_lim[MAX_M];
     ALIGN real_t G_boost;
-    ALIGN real_t S_M[64];
-    ALIGN uint8_t table_map_res_to_m[64];
-    ALIGN uint8_t G_is_frac[64];
-    ALIGN uint8_t Q_M_is_real[64];
+    ALIGN real_t S_M[MAX_M];
+    ALIGN uint8_t table_map_res_to_m[MAX_M];
+    ALIGN uint8_t G_is_frac[MAX_M];
+    ALIGN uint8_t Q_M_is_real[MAX_M];
 
 
     for (l = 0; l < sbr->L_E[ch]; l++)
@@ -549,9 +577,9 @@
                 /* Q_mapped: fixed point */
 
                 /* Q_div1: [0..1] FRAC_CONST */
-                Q_div1 = adj->Q_div_mapped[m][l];
+                Q_div1 = adj->Q_div_mapped[l][m];
                 /* Q_div2: [0..1] FRAC_CONST */
-                Q_div2 = adj->Q_div2_mapped[m][l];
+                Q_div2 = adj->Q_div2_mapped[l][m];
 
                 /* E_orig: integer */
                 E_orig = sbr->E_orig[ch][table_map_res_to_m[m]][l];
@@ -564,18 +592,18 @@
                     Q_M = ((int64_t)(E_orig>>4) * Q_div2) >> FRAC_BITS;
                     Q_M_is_real[m] = 0;
 
-                    S_M[m] = adj->S_index_mapped[m][l] * MUL_F((E_orig>>4), Q_div1);
+                    S_M[m] = adj->S_index_mapped[l][m] * MUL_F((E_orig>>4), Q_div1);
                 } else if (E_orig > (1<<4)) {
                     Q_M = ((int64_t)(E_orig>>4) * Q_div2) >> (FRAC_BITS-REAL_BITS);
                     Q_M_is_real[m] = 1;
 
-                    S_M[m] = adj->S_index_mapped[m][l] * MUL_F((E_orig>>4), Q_div1);
+                    S_M[m] = adj->S_index_mapped[l][m] * MUL_F((E_orig>>4), Q_div1);
                 } else {
                     Q_M = ((int64_t)E_orig * Q_div2) >> (FRAC_BITS-REAL_BITS);
                     Q_M >>= 4;
                     Q_M_is_real[m] = 1;
 
-                    S_M[m] = adj->S_index_mapped[m][l] * MUL_F(E_orig, Q_div1);
+                    S_M[m] = adj->S_index_mapped[l][m] * MUL_F(E_orig, Q_div1);
                     S_M[m] >>= 4;
                 }
 
@@ -617,7 +645,7 @@
                     G_is_frac[m] = 0;
                 }
 
-                if (adj->S_mapped[m][l] == 1)
+                if (adj->S_mapped[l][m] == 1)
                 {
                     G = MUL_F(G, Q_div2);
                 } else if (delta == 1) {
@@ -668,7 +696,7 @@
                     den_int += MUL_F(sbr->E_curr[ch][m][l], G_lim[m]);
                 }
                 den_int += S_M[m];
-                if ((!adj->S_index_mapped[m][l]) && (l != sbr->l_A[ch]))
+                if ((!adj->S_index_mapped[l][m]) && (l != sbr->l_A[ch]))
                 {
                     if (Q_M_is_real[m] == 1)
                     {
@@ -727,7 +755,7 @@
                 }
 
                 /* S_M_boost: integer */
-                if (adj->S_index_mapped[m][l])
+                if (adj->S_index_mapped[l][m])
                 {
                     adj->S_M_boost[l][m] = SBR_SQRT_INT(MUL_R(S_M[m], G_boost));
                 } else {
@@ -742,24 +770,30 @@
 static void calculate_gain(sbr_info *sbr, sbr_hfadj_info *adj, uint8_t ch)
 {
     static real_t limGain[] = { 0.5, 1.0, 2.0, 1e10 };
-    uint8_t m, l, k, i;
+    uint8_t m, l, k;
 
-    ALIGN real_t Q_M_lim[64];
-    ALIGN real_t G_lim[64];
+    uint8_t current_t_noise_band = 0;
+    uint8_t S_mapped;
+
+    ALIGN real_t Q_M_lim[MAX_M];
+    ALIGN real_t G_lim[MAX_M];
     ALIGN real_t G_boost;
-    ALIGN real_t S_M[64];
-    ALIGN uint8_t table_map_res_to_m[64];
+    ALIGN real_t S_M[MAX_M];
 
     for (l = 0; l < sbr->L_E[ch]; l++)
     {
+        uint8_t current_f_noise_band = 0;
+        uint8_t current_res_band = 0;
+        uint8_t current_res_band2 = 0;
+        uint8_t current_hi_res_band = 0;
+
         real_t delta = (l == sbr->l_A[ch] || l == sbr->prevEnvIsShort[ch]) ? 0 : 1;
 
-        for (i = 0; i < sbr->n[sbr->f[ch][l]]; i++)
+        S_mapped = get_S_mapped(sbr, ch, l, current_res_band2);
+
+        if (sbr->t_E[ch][l+1] > sbr->t_Q[ch][current_t_noise_band+1])
         {
-            for (m = sbr->f_table_res[sbr->f[ch][l]][i]; m < sbr->f_table_res[sbr->f[ch][l]][i+1]; m++)
-            {
-                table_map_res_to_m[m - sbr->kx] = i;
-            }
+            current_t_noise_band++;
         }
 
         for (k = 0; k < sbr->N_L[sbr->bs_limiter_bands]; k++)
@@ -768,6 +802,7 @@
             real_t den = 0;
             real_t acc1 = 0;
             real_t acc2 = 0;
+            uint8_t current_res_band_size = 0;
 
             uint8_t ml1, ml2;
 
@@ -778,39 +813,110 @@
             /* calculate the accumulated E_orig and E_curr over the limiter band */
             for (m = ml1; m < ml2; m++)
             {
-                acc1 += sbr->E_orig[ch][table_map_res_to_m[m]][l];
+                if ((m + sbr->kx) == sbr->f_table_res[sbr->f[ch][l]][current_res_band+1])
+                {
+                    current_res_band++;
+                }
+                acc1 += sbr->E_orig[ch][current_res_band][l];
                 acc2 += sbr->E_curr[ch][m][l];
             }
 
-            G_max = ((EPS + acc1)/(EPS + acc2)) * limGain[sbr->bs_limiter_gains];
+
+            /* calculate the maximum gain */
+            /* ratio of the energy of the original signal and the energy
+             * of the HF generated signal
+             */
+            G_max = ((EPS + acc1) / (EPS + acc2)) * limGain[sbr->bs_limiter_gains];
             G_max = min(G_max, 1e10);
 
+
             for (m = ml1; m < ml2; m++)
             {
                 real_t Q_M, G;
                 real_t Q_div, Q_div2;
+                uint8_t S_index_mapped;
 
+
+                /* check if m is on a noise band border */
+                if ((m + sbr->kx) == sbr->f_table_noise[current_f_noise_band+1])
+                {
+                    /* step to next noise band */
+                    current_f_noise_band++;
+                }
+
+
+                /* check if m is on a resolution band border */
+                if ((m + sbr->kx) == sbr->f_table_res[sbr->f[ch][l]][current_res_band2+1])
+                {
+                    /* step to next resolution band */
+                    current_res_band2++;
+
+                    /* if we move to a new resolution band, we should check if we are
+                     * going to add a sinusoid in this band
+                     */
+                    S_mapped = get_S_mapped(sbr, ch, l, current_res_band2);
+                }
+
+
+                /* check if m is on a HI_RES band border */
+                if ((m + sbr->kx) == sbr->f_table_res[HI_RES][current_hi_res_band+1])
+                {
+                    /* step to next HI_RES band */
+                    current_hi_res_band++;
+                }
+
+
+                /* find S_index_mapped
+                 * S_index_mapped can only be 1 for the m in the middle of the
+                 * current HI_RES band
+                 */
+                S_index_mapped = 0;
+                if ((l >= sbr->l_A[ch]) ||
+                    (sbr->bs_add_harmonic_prev[ch][current_hi_res_band] && sbr->bs_add_harmonic_flag_prev[ch]))
+                {
+                    /* find the middle subband of the HI_RES frequency band */
+                    if ((m + sbr->kx) == (sbr->f_table_res[HI_RES][current_hi_res_band+1] + sbr->f_table_res[HI_RES][current_hi_res_band]) >> 1)
+                        S_index_mapped = sbr->bs_add_harmonic[ch][current_hi_res_band];
+                }
+
+
                 /* Q_div: [0..1] (1/(1+Q_mapped)) */
-                Q_div = adj->Q_div_mapped[m][l];
+                Q_div = sbr->Q_div[ch][current_f_noise_band][current_t_noise_band];
 
+
                 /* Q_div2: [0..1] (Q_mapped/(1+Q_mapped)) */
-                Q_div2 = adj->Q_div2_mapped[m][l];
+                Q_div2 = sbr->Q_div2[ch][current_f_noise_band][current_t_noise_band];
 
-                Q_M = sbr->E_orig[ch][table_map_res_to_m[m]][l] * Q_div2;
 
-                /* 12-Nov: Changed S_mapped to S_index_mapped */
-                if (adj->S_index_mapped[m][l] == 0)
+                /* Q_M only depends on E_orig and Q_div2:
+                 * since N_Q <= N_Low <= N_High we only need to recalculate Q_M on
+                 * a change of current noise band
+                 */
+                Q_M = sbr->E_orig[ch][current_res_band2][l] * Q_div2;
+
+
+                /* S_M only depends on E_orig, Q_div and S_index_mapped:
+                 * S_index_mapped can only be non-zero once per HI_RES band
+                 */
+                if (S_index_mapped == 0)
                 {
                     S_M[m] = 0;
                 } else {
-                    S_M[m] = sbr->E_orig[ch][table_map_res_to_m[m]][l] * Q_div;
+                    S_M[m] = sbr->E_orig[ch][current_res_band2][l] * Q_div;
+
+                    /* accumulate sinusoid part of the total energy */
+                    den += S_M[m];
                 }
 
-                G = sbr->E_orig[ch][table_map_res_to_m[m]][l] / (1.0 + sbr->E_curr[ch][m][l]);
 
-                if ((adj->S_mapped[m][l] == 0) && (delta == 1))
+                /* calculate gain */
+                /* ratio of the energy of the original signal and the energy
+                 * of the HF generated signal
+                 */
+                G = sbr->E_orig[ch][current_res_band2][l] / (1.0 + sbr->E_curr[ch][m][l]);
+                if ((S_mapped == 0) && (delta == 1))
                     G *= Q_div;
-                else if (adj->S_mapped[m][l] == 1)
+                else if (S_mapped == 1)
                     G *= Q_div2;
 
 
@@ -821,14 +927,14 @@
                     Q_M_lim[m] = Q_M;
                     G_lim[m] = G;
                 } else {
-                    Q_M_lim[m] = Q_M * G_max / G; /* equivalent to code below */
+                    Q_M_lim[m] = Q_M * G_max / G;
                     G_lim[m] = G_max;
                 }
 
+
+                /* accumulate the total energy */
                 den += sbr->E_curr[ch][m][l] * G_lim[m];
-                if (adj->S_index_mapped[m][l])
-                    den += S_M[m];
-                else if (l != sbr->l_A[ch])
+                if ((S_index_mapped == 0) && (l != sbr->l_A[ch]))
                     den += Q_M_lim[m];
             }
 
@@ -849,7 +955,7 @@
 #endif
                 adj->Q_M_lim_boost[l][m] = sqrt(Q_M_lim[m] * G_boost);
 
-                if (adj->S_index_mapped[m][l])
+                if (S_M[m] != 0)
                 {
                     adj->S_M_boost[l][m] = sqrt(S_M[m] * G_boost);
                 } else {
@@ -874,7 +980,7 @@
 
         for (k = sbr->kx; k < sbr->kx + sbr->M - 1; k++)
         {
-            if (deg[k + 1] && adj->S_mapped[k-sbr->kx][l] == 0)
+            if (deg[k + 1] && adj->S_mapped[l][k-sbr->kx] == 0)
             {
                 if (grouping == 0)
                 {
@@ -885,7 +991,7 @@
             } else {
                 if (grouping)
                 {
-                    if (adj->S_mapped[k-sbr->kx][l])
+                    if (adj->S_mapped[l][k-sbr->kx])
                     {
                         sbr->f_group[l][i] = k;
                     } else {
@@ -895,7 +1001,7 @@
                     i++;
                 }
             }
-        }        
+        }
 
         if (grouping)
         {
@@ -917,7 +1023,7 @@
         for (k = 0; k < sbr->N_G[l]; k++)
         {
             E_total_est = E_total = 0;
-            
+
             for (m = sbr->f_group[l][k<<1]; m < sbr->f_group[l][(k<<1) + 1]; m++)
             {
                 /* E_curr: integer */
@@ -1023,7 +1129,6 @@
     uint16_t fIndexNoise = 0;
     uint8_t fIndexSine = 0;
     uint8_t assembly_reset = 0;
-    real_t *temp;
 
     real_t G_filt, Q_filt;
 
@@ -1058,6 +1163,8 @@
                 memcpy(sbr->G_temp_prev[ch][n], adj->G_lim_boost[l], sbr->M*sizeof(real_t));
                 memcpy(sbr->Q_temp_prev[ch][n], adj->Q_M_lim_boost[l], sbr->M*sizeof(real_t));
             }
+            /* reset ringbuffer index */
+            sbr->GQ_ringbuf_index[ch] = 4;
             assembly_reset = 0;
         }
 
@@ -1068,8 +1175,9 @@
             uint8_t sinusoids = 0;
 #endif
 
-            memcpy(sbr->G_temp_prev[ch][4], adj->G_lim_boost[l], sbr->M*sizeof(real_t));
-            memcpy(sbr->Q_temp_prev[ch][4], adj->Q_M_lim_boost[l], sbr->M*sizeof(real_t));
+            /* load new values into ringbuffer */
+            memcpy(sbr->G_temp_prev[ch][sbr->GQ_ringbuf_index[ch]], adj->G_lim_boost[l], sbr->M*sizeof(real_t));
+            memcpy(sbr->Q_temp_prev[ch][sbr->GQ_ringbuf_index[ch]], adj->Q_M_lim_boost[l], sbr->M*sizeof(real_t));
 
             for (m = 0; m < sbr->M; m++)
             {
@@ -1083,13 +1191,16 @@
                 {
                     for (n = 0; n <= 4; n++)
                     {
-                        G_filt += MUL_F(sbr->G_temp_prev[ch][n][m], h_smooth[n]);
-                        Q_filt += MUL_F(sbr->Q_temp_prev[ch][n][m], h_smooth[n]);
+                        uint8_t ri = sbr->GQ_ringbuf_index[ch] + 1 + n;
+                        if (ri >= 5)
+                            ri -= 5;
+                        G_filt += MUL_F(sbr->G_temp_prev[ch][ri][m], h_smooth[n]);
+                        Q_filt += MUL_F(sbr->Q_temp_prev[ch][ri][m], h_smooth[n]);
                     }
                 } else {
 #endif
-                    G_filt = sbr->G_temp_prev[ch][4][m];
-                    Q_filt = sbr->Q_temp_prev[ch][4][m];
+                    G_filt = sbr->G_temp_prev[ch][sbr->GQ_ringbuf_index[ch]][m];
+                    Q_filt = sbr->Q_temp_prev[ch][sbr->GQ_ringbuf_index[ch]][m];
 #ifndef SBR_LOW_POWER
                 }
 #endif
@@ -1219,16 +1330,10 @@
 
             fIndexSine = (fIndexSine + 1) & 3;
 
-
-            temp = sbr->G_temp_prev[ch][0];
-            for (n = 0; n < 4; n++)
-                sbr->G_temp_prev[ch][n] = sbr->G_temp_prev[ch][n+1];
-            sbr->G_temp_prev[ch][4] = temp;
-
-            temp = sbr->Q_temp_prev[ch][0];
-            for (n = 0; n < 4; n++)
-                sbr->Q_temp_prev[ch][n] = sbr->Q_temp_prev[ch][n+1];
-            sbr->Q_temp_prev[ch][4] = temp;
+            /* update the ringbuffer index used for filtering G and Q with h_smooth */
+            sbr->GQ_ringbuf_index[ch]++;
+            if (sbr->GQ_ringbuf_index[ch] >= 5)
+                sbr->GQ_ringbuf_index[ch] = 0;
         }
     }
 
--- a/libfaad/sbr_hfadj.h
+++ b/libfaad/sbr_hfadj.h
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through [email protected].
 **
-** $Id: sbr_hfadj.h,v 1.11 2004/03/10 19:45:42 menno Exp $
+** $Id: sbr_hfadj.h,v 1.12 2004/04/12 18:17:42 menno Exp $
 **/
 
 #ifndef __SBR_HFADJ_H__
@@ -34,15 +34,15 @@
 
 typedef struct
 {
-    real_t Q_div_mapped[64][5];
-    real_t Q_div2_mapped[64][5];
+    real_t Q_div_mapped[MAX_L_E][MAX_M];
+    real_t Q_div2_mapped[MAX_L_E][MAX_M];
 
-    uint8_t S_index_mapped[64][5];
-    uint8_t S_mapped[64][5];
+    uint8_t S_index_mapped[MAX_L_E][MAX_M];
+    uint8_t S_mapped[MAX_L_E][MAX_M];
 
-    real_t G_lim_boost[5][64];
-    real_t Q_M_lim_boost[5][64];
-    real_t S_M_boost[5][64];
+    real_t G_lim_boost[MAX_L_E][MAX_M];
+    real_t Q_M_lim_boost[MAX_L_E][MAX_M];
+    real_t S_M_boost[MAX_L_E][MAX_M];
 
 } sbr_hfadj_info;
 
--- a/libfaad/sbr_hfgen.c
+++ b/libfaad/sbr_hfgen.c
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through [email protected].
 **
-** $Id: sbr_hfgen.c,v 1.16 2004/04/03 10:49:15 menno Exp $
+** $Id: sbr_hfgen.c,v 1.17 2004/04/12 18:17:42 menno Exp $
 **/
 
 /* High Frequency generation */
@@ -384,9 +384,9 @@
     } else {
 #ifdef FIXED_POINT
         tmp = (MUL_R(RE(ac.r01), RE(ac.r12)) - MUL_R(IM(ac.r01), IM(ac.r12)) - MUL_R(RE(ac.r02), RE(ac.r11)));
-        RE(alpha_1[k]) = SBR_DIV(tmp, ac.det);
+        RE(alpha_1[k]) = DIV_R(tmp, ac.det);
         tmp = (MUL_R(IM(ac.r01), RE(ac.r12)) + MUL_R(RE(ac.r01), IM(ac.r12)) - MUL_R(IM(ac.r02), RE(ac.r11)));
-        IM(alpha_1[k]) = SBR_DIV(tmp, ac.det);
+        IM(alpha_1[k]) = DIV_R(tmp, ac.det);
 #else
         tmp = REAL_CONST(1.0) / ac.det;
         RE(alpha_1[k]) = (MUL_R(RE(ac.r01), RE(ac.r12)) - MUL_R(IM(ac.r01), IM(ac.r12)) - MUL_R(RE(ac.r02), RE(ac.r11))) * tmp;
@@ -401,9 +401,9 @@
     } else {
 #ifdef FIXED_POINT
         tmp = -(RE(ac.r01) + MUL_R(RE(alpha_1[k]), RE(ac.r12)) + MUL_R(IM(alpha_1[k]), IM(ac.r12)));
-        RE(alpha_0[k]) = SBR_DIV(tmp, RE(ac.r11));
+        RE(alpha_0[k]) = DIV_R(tmp, RE(ac.r11));
         tmp = -(IM(ac.r01) + MUL_R(IM(alpha_1[k]), RE(ac.r12)) - MUL_R(RE(alpha_1[k]), IM(ac.r12)));
-        IM(alpha_0[k]) = SBR_DIV(tmp, RE(ac.r11));
+        IM(alpha_0[k]) = DIV_R(tmp, RE(ac.r11));
 #else
         tmp = 1.0f / RE(ac.r11);
         RE(alpha_0[k]) = -(RE(ac.r01) + MUL_R(RE(alpha_1[k]), RE(ac.r12)) + MUL_R(IM(alpha_1[k]), IM(ac.r12))) * tmp;
@@ -438,10 +438,10 @@
             RE(alpha_1[k]) = 0;
         } else {
             tmp = MUL_R(RE(ac.r01), RE(ac.r22)) - MUL_R(RE(ac.r12), RE(ac.r02));
-            RE(alpha_0[k]) = SBR_DIV(tmp, (-ac.det));
+            RE(alpha_0[k]) = DIV_R(tmp, (-ac.det));
 
             tmp = MUL_R(RE(ac.r01), RE(ac.r12)) - MUL_R(RE(ac.r02), RE(ac.r11));
-            RE(alpha_1[k]) = SBR_DIV(tmp, ac.det);
+            RE(alpha_1[k]) = DIV_R(tmp, ac.det);
         }
 
         if ((RE(alpha_0[k]) >= REAL_CONST(4)) || (RE(alpha_1[k]) >= REAL_CONST(4)))
@@ -455,11 +455,7 @@
         {
             rxx[k] = COEF_CONST(0.0);
         } else {
-#ifdef FIXED_POINT
-            rxx[k] = ((int64_t)RE(ac.r01) << COEF_BITS) / RE(ac.r11);
-#else
-            rxx[k] = RE(ac.r01) / RE(ac.r11);
-#endif
+            rxx[k] = DIV_C(RE(ac.r01), RE(ac.r11));
             rxx[k] = -rxx[k];
             if (rxx[k] > COEF_CONST(1.0)) rxx[k] = COEF_CONST(1.0);
             if (rxx[k] < COEF_CONST(-1.0)) rxx[k] = COEF_CONST(-1.0);