AAC Encoder low delay quality

* AAC-Encoder

   - Revise bit distribution for lowdelay configuration to improve encoder
     audio quality.
   - Adjust lowdelay bitreservoir for low bitreservoir configuration.
     Modified file(s):
        libAACenc\src\aacEnc_ram.cpp
        libAACenc\src\aacenc.cpp
        libAACenc\src\aacenc_lib.cpp
        libAACenc\src\aacenc_tns.cpp
        libAACenc\src\adj_thr.cpp
        libAACenc\src\adj_thr.h
        libAACenc\src\block_switch.cpp
        libAACenc\src\block_switch.h
        libAACenc\src\interface.h
        libAACenc\src\psy_main.cpp
        libAACenc\src\qc_data.h
        libAACenc\src\qc_main.cpp

* FDK-Library

   - Increase the accuracy in CalcInvLdData() calculation which improves the
     encoder audio quality.
     Modified file(s):
        libFDK\src\fixpoint_math.cpp

Bug 9428126

Change-Id: I302d7f4c3aeccf79e1b85f20e18a31e6e2b10544
diff --git a/libAACenc/src/aacEnc_ram.cpp b/libAACenc/src/aacEnc_ram.cpp
index 2268726..1844331 100644
--- a/libAACenc/src/aacEnc_ram.cpp
+++ b/libAACenc/src/aacEnc_ram.cpp
@@ -89,13 +89,13 @@
 ******************************************************************************/
 /*!
   \file
-  \brief  Memory layout   
+  \brief  Memory layout
   \author Markus Lohwasser
 */
 
 #include "aacEnc_ram.h"
 
-  C_ALLOC_MEM (AACdynamic_RAM, FIXP_DBL, AAC_ENC_DYN_RAM_SIZE/sizeof(FIXP_DBL))
+  C_AALLOC_MEM (AACdynamic_RAM, FIXP_DBL, AAC_ENC_DYN_RAM_SIZE/sizeof(FIXP_DBL))
 
 /*
   Static memory areas, must not be overwritten in other sections of the decoder !
@@ -175,7 +175,7 @@
 */
 
 C_ALLOC_MEM2 (Ram_aacEnc_QCout, QC_OUT, 1, (1))
-C_ALLOC_MEM2 (Ram_aacEnc_QCelement, QC_OUT_ELEMENT, 1, (1)*(6))
+C_ALLOC_MEM2 (Ram_aacEnc_QCelement, QC_OUT_ELEMENT, (1), (6))
   QC_OUT_CHANNEL *GetRam_aacEnc_QCchannel (int n, UCHAR* dynamic_RAM) {
       FDK_ASSERT(dynamic_RAM!=0);
       return ((QC_OUT_CHANNEL*) (dynamic_RAM + P_BUF_0 + n*sizeof(QC_OUT_CHANNEL)));
diff --git a/libAACenc/src/aacenc.cpp b/libAACenc/src/aacenc.cpp
index 29e588f..6ce7b22 100644
--- a/libAACenc/src/aacenc.cpp
+++ b/libAACenc/src/aacenc.cpp
@@ -578,6 +578,8 @@
       qcInit.minBits         = (config->minBitsPerFrame!=-1) ? fixMax(qcInit.minBits, config->minBitsPerFrame) : qcInit.minBits;
   }
 
+  qcInit.sampleRate          = config->sampleRate;
+  qcInit.advancedBitsToPe    = isLowDelay(config->audioObjectType) ? 1 : 0 ;
   qcInit.nSubFrames          = config->nSubFrames;
   qcInit.padding.paddingRest = config->sampleRate;
 
diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp
index a256f05..4d5984d 100644
--- a/libAACenc/src/aacenc_lib.cpp
+++ b/libAACenc/src/aacenc_lib.cpp
@@ -98,7 +98,7 @@
 /* Encoder library info */
 #define AACENCODER_LIB_VL0 3
 #define AACENCODER_LIB_VL1 4
-#define AACENCODER_LIB_VL2 7
+#define AACENCODER_LIB_VL2 8
 #define AACENCODER_LIB_TITLE "AAC Encoder"
 #define AACENCODER_LIB_BUILD_DATE __DATE__
 #define AACENCODER_LIB_BUILD_TIME __TIME__
@@ -689,7 +689,7 @@
           hAacConfig->bitrateMode = 0;
         }
         if (config->userBitrateMode==0) {
-          hAacConfig->bitreservoir = 50*config->nChannels; /* default, reduced bitreservoir */
+          hAacConfig->bitreservoir = 100*config->nChannels; /* default, reduced bitreservoir */
         }
         if (hAacConfig->bitrateMode!=0) {
           return AACENC_INVALID_CONFIG;
diff --git a/libAACenc/src/aacenc_tns.cpp b/libAACenc/src/aacenc_tns.cpp
index 9a0edd4..85aea65 100644
--- a/libAACenc/src/aacenc_tns.cpp
+++ b/libAACenc/src/aacenc_tns.cpp
@@ -83,7 +83,7 @@
 
 /******************************** MPEG Audio Encoder **************************
 
-   Initial author:       Alex Groeschel
+   Initial author:       Alex Groeschel, Tobias Chalupka
    contents/description: Temporal noise shaping
 
 ******************************************************************************/
diff --git a/libAACenc/src/adj_thr.cpp b/libAACenc/src/adj_thr.cpp
index 3fcb0be..0bd5827 100644
--- a/libAACenc/src/adj_thr.cpp
+++ b/libAACenc/src/adj_thr.cpp
@@ -123,6 +123,117 @@
 static const FIXP_DBL  SnrLdMin5 = (FIXP_DBL)0xfc000000; /*FL2FXCONST_DBL(FDKlog(0.25) /FDKlog(2.0)/LD_DATA_SCALING);*/
 
 
+/*
+The bits2Pe factors are choosen for the case that some times
+the crash recovery strategy will be activated once.
+*/
+
+typedef struct {
+  INT                 bitrate;
+  LONG                bits2PeFactor_mono;
+  LONG                bits2PeFactor_mono_slope;
+  LONG                bits2PeFactor_stereo;
+  LONG                bits2PeFactor_stereo_slope;
+  LONG                bits2PeFactor_mono_scfOpt;
+  LONG                bits2PeFactor_mono_scfOpt_slope;
+  LONG                bits2PeFactor_stereo_scfOpt;
+  LONG                bits2PeFactor_stereo_scfOpt_slope;
+
+} BIT_PE_SFAC;
+
+typedef struct {
+  const INT           sampleRate;
+  const BIT_PE_SFAC * pPeTab;
+  const INT           nEntries;
+
+} BITS2PE_CFG_TAB;
+
+static const BIT_PE_SFAC S_Bits2PeTab16000[] = {
+  { 10000, 0x228F5C29, 0x02FEF55D, 0x1D70A3D7, 0x09BC9D6D, 0x228F5C29, 0x02FEF55D, 0x1C28F5C3, 0x0CBB92CA},
+  { 24000, 0x23D70A3D, 0x029F16B1, 0x2199999A, 0x07DD4413, 0x23D70A3D, 0x029F16B1, 0x2199999A, 0x07DD4413},
+  { 32000, 0x247AE148, 0x11B1D92B, 0x23851EB8, 0x01F75105, 0x247AE148, 0x110A137F, 0x23851EB8, 0x01F75105},
+  { 48000, 0x2D1EB852, 0x6833C600, 0x247AE148, 0x014F8B59, 0x2CCCCCCD, 0x68DB8BAC, 0x247AE148, 0x01F75105},
+  { 64000, 0x60000000, 0x00000000, 0x251EB852, 0x154C985F, 0x60000000, 0x00000000, 0x2570A3D7, 0x154C985F},
+  { 96000, 0x60000000, 0x00000000, 0x39EB851F, 0x088509C0, 0x60000000, 0x00000000, 0x3A3D70A4, 0x088509C0},
+  {128000, 0x60000000, 0x00000000, 0x423D70A4, 0x18A43BB4, 0x60000000, 0x00000000, 0x428F5C29, 0x181E03F7},
+  {148000, 0x60000000, 0x00000000, 0x5147AE14, 0x00000000, 0x60000000, 0x00000000, 0x5147AE14, 0x00000000}
+};
+
+static const BIT_PE_SFAC S_Bits2PeTab22050[] = {
+  { 16000, 0x1a8f5c29, 0x1797cc3a, 0x128f5c29, 0x18e75793, 0x175c28f6, 0x221426fe, 0x00000000, 0x5a708ede},
+  { 24000, 0x2051eb85, 0x092ccf6c, 0x18a3d70a, 0x13a92a30, 0x1fae147b, 0xbcbe61d,  0x16147ae1, 0x18e75793},
+  { 32000, 0x228f5c29, 0x029f16b1, 0x1d70a3d7, 0x088509c0, 0x228f5c29, 0x29f16b1,  0x1c28f5c3, 0x0b242071},
+  { 48000, 0x23d70a3d, 0x014f8b59, 0x2199999a, 0x03eea20a, 0x23d70a3d, 0x14f8b59,  0x2199999a, 0x03eea20a},
+  { 64000, 0x247ae148, 0x08d8ec96, 0x23851eb8, 0x00fba882, 0x247ae148, 0x88509c0,  0x23851eb8, 0x00fba882},
+  { 96000, 0x2d1eb852, 0x3419e300, 0x247ae148, 0x00a7c5ac, 0x2ccccccd, 0x346dc5d6, 0x247ae148, 0x00fba882},
+  {128000, 0x60000000, 0x00000000, 0x251eb852, 0x029f16b1, 0x60000000, 0x00000000, 0x2570a3d7, 0x009f16b1},
+  {148000, 0x60000000, 0x00000000, 0x26b851ec, 0x00000000, 0x60000000, 0x00000000, 0x270a3d71, 0x00000000}
+};
+
+static const BIT_PE_SFAC S_Bits2PeTab24000[] = {
+  { 16000, 0x19eb851f, 0x13a92a30, 0x1147ae14, 0x164840e1, 0x1999999a, 0x12599ed8, 0x00000000, 0x46c764ae},
+  { 24000, 0x1eb851ec, 0x0d1b7176, 0x16b851ec, 0x18e75793, 0x1e147ae1, 0x0fba8827, 0x1147ae14, 0x2c9081c3},
+  { 32000, 0x21eb851f, 0x049667b6, 0x1ccccccd, 0x07357e67, 0x21eb851f, 0x03eea20a, 0x1c28f5c3, 0x07357e67},
+  { 48000, 0x2428f5c3, 0x014f8b59, 0x2051eb85, 0x053e2d62, 0x23d70a3d, 0x01f75105, 0x1fae147b, 0x07357e67},
+  { 64000, 0x24cccccd, 0x05e5f30e, 0x22e147ae, 0x01a36e2f, 0x24cccccd, 0x05e5f30e, 0x23333333, 0x014f8b59},
+  { 96000, 0x2a8f5c29, 0x24b33db0, 0x247ae148, 0x00fba882, 0x2a8f5c29, 0x26fe718b, 0x247ae148, 0x00fba882},
+  {128000, 0x4e666666, 0x1cd5f99c, 0x2570a3d7, 0x010c6f7a, 0x50a3d70a, 0x192a7371, 0x2570a3d7, 0x010c6f7a},
+  {148000, 0x60000000, 0x00000000, 0x26147ae1, 0x00000000, 0x60000000, 0x00000000, 0x26147ae1, 0x00000000}
+};
+
+static const BIT_PE_SFAC S_Bits2PeTab32000[] = {
+  { 16000, 0x1199999a, 0x20c49ba6, 0x00000000, 0x4577d955, 0x00000000, 0x60fe4799, 0x00000000, 0x00000000},
+  { 24000, 0x1999999a, 0x0fba8827, 0x10f5c28f, 0x1b866e44, 0x17ae147b, 0x0fba8827, 0x00000000, 0x4d551d69},
+  { 32000, 0x1d70a3d7, 0x07357e67, 0x17ae147b, 0x09d49518, 0x1b851eb8, 0x0a7c5ac4, 0x12e147ae, 0x110a137f},
+  { 48000, 0x20f5c28f, 0x049667b6, 0x1c7ae148, 0x053e2d62, 0x20a3d70a, 0x053e2d62, 0x1b333333, 0x05e5f30e},
+  { 64000, 0x23333333, 0x029f16b1, 0x1f0a3d71, 0x02f2f987, 0x23333333, 0x029f16b1, 0x1e147ae1, 0x03eea20a},
+  { 96000, 0x25c28f5c, 0x2c3c9eed, 0x21eb851f, 0x01f75105, 0x25c28f5c, 0x0a7c5ac4, 0x21eb851f, 0x01a36e2f},
+  {128000, 0x50f5c28f, 0x18a43bb4, 0x23d70a3d, 0x010c6f7a, 0x30000000, 0x168b5cc0, 0x23851eb8, 0x0192a737},
+  {148000, 0x60000000, 0x00000000, 0x247ae148, 0x00dfb23b, 0x3dc28f5c, 0x300f4aaf, 0x247ae148, 0x01bf6476},
+  {160000, 0x60000000, 0xb15b5740, 0x24cccccd, 0x053e2d62, 0x4f5c28f6, 0xbefd0072, 0x251eb852, 0x04fb1184},
+  {200000, 0x00000000, 0x00000000, 0x2b333333, 0x0836be91, 0x00000000, 0x00000000, 0x2b333333, 0x0890390f},
+  {320000, 0x00000000, 0x00000000, 0x4947ae14, 0x00000000, 0x00000000, 0x00000000, 0x4a8f5c29, 0x00000000}
+};
+
+static const BIT_PE_SFAC S_Bits2PeTab44100[] = {
+  { 16000, 0x10a3d70a, 0x1797cc3a, 0x00000000, 0x00000000, 0x00000000, 0x59210386, 0x00000000, 0x00000000},
+  { 24000, 0x16666666, 0x1797cc3a, 0x00000000, 0x639d5e4a, 0x15c28f5c, 0x12599ed8, 0x00000000, 0x5bc01a37},
+  { 32000, 0x1c28f5c3, 0x049667b6, 0x1851eb85, 0x049667b6, 0x1a3d70a4, 0x088509c0, 0x16666666, 0x053e2d62},
+  { 48000, 0x1e666666, 0x05e5f30e, 0x1a8f5c29, 0x049667b6, 0x1e666666, 0x05e5f30e, 0x18f5c28f, 0x05e5f30e},
+  { 64000, 0x2147ae14, 0x0346dc5d, 0x1ccccccd, 0x02f2f987, 0x2147ae14, 0x02f2f987, 0x1bd70a3d, 0x039abf34},
+  { 96000, 0x247ae148, 0x068db8bb, 0x1fae147b, 0x029f16b1, 0x2428f5c3, 0x0639d5e5, 0x1f5c28f6, 0x029f16b1},
+  {128000, 0x2ae147ae, 0x1b435265, 0x223d70a4, 0x0192a737, 0x2a3d70a4, 0x1040bfe4, 0x21eb851f, 0x0192a737},
+  {148000, 0x3b851eb8, 0x2832069c, 0x23333333, 0x00dfb23b, 0x3428f5c3, 0x2054c288, 0x22e147ae, 0x00dfb23b},
+  {160000, 0x4a3d70a4, 0xc32ebe5a, 0x23851eb8, 0x01d5c316, 0x40000000, 0xcb923a2b, 0x23333333, 0x01d5c316},
+  {200000, 0x00000000, 0x00000000, 0x25c28f5c, 0x0713f078, 0x00000000, 0x00000000, 0x2570a3d7, 0x072a4f17},
+  {320000, 0x00000000, 0x00000000, 0x3fae147b, 0x00000000, 0x00000000, 0x00000000, 0x3fae147b, 0x00000000}
+};
+
+static const BIT_PE_SFAC S_Bits2PeTab48000[] = {
+  { 16000, 0x0f5c28f6, 0x31ceaf25, 0x00000000, 0x00000000, 0x00000000, 0x74a771c9, 0x00000000, 0x00000000},
+  { 24000, 0x1b851eb8, 0x029f16b1, 0x00000000, 0x663c74fb, 0x1c7ae148, 0xe47991bd, 0x00000000, 0x49667b5f},
+  { 32000, 0x1c28f5c3, 0x029f16b1, 0x18f5c28f, 0x07357e67, 0x15c28f5c, 0x0f12c27a, 0x11eb851f, 0x13016484},
+  { 48000, 0x1d70a3d7, 0x053e2d62, 0x1c7ae148, 0xfe08aefc, 0x1d1eb852, 0x068db8bb, 0x1b333333, 0xfeb074a8},
+  { 64000, 0x20000000, 0x03eea20a, 0x1b851eb8, 0x0346dc5d, 0x2051eb85, 0x0346dc5d, 0x1a8f5c29, 0x039abf34},
+  { 96000, 0x23d70a3d, 0x053e2d62, 0x1eb851ec, 0x029f16b1, 0x23851eb8, 0x04ea4a8c, 0x1e147ae1, 0x02f2f987},
+  {128000, 0x28f5c28f, 0x14727dcc, 0x2147ae14, 0x0218def4, 0x2851eb85, 0x0e27e0f0, 0x20f5c28f, 0x0218def4},
+  {148000, 0x3570a3d7, 0x1cd5f99c, 0x228f5c29, 0x01bf6476, 0x30f5c28f, 0x18777e75, 0x223d70a4, 0x01bf6476},
+  {160000, 0x40000000, 0xcb923a2b, 0x23333333, 0x0192a737, 0x39eb851f, 0xd08d4bae, 0x22e147ae, 0x0192a737},
+  {200000, 0x00000000, 0x00000000, 0x251eb852, 0x06775a1b, 0x00000000, 0x00000000, 0x24cccccd, 0x06a4175a},
+  {320000, 0x00000000, 0x00000000, 0x3ccccccd, 0x00000000, 0x00000000, 0x00000000, 0x3d1eb852, 0x00000000}
+};
+
+static const BITS2PE_CFG_TAB bits2PeConfigTab[] = {
+  { 16000, S_Bits2PeTab16000, sizeof(S_Bits2PeTab16000)/sizeof(BIT_PE_SFAC) },
+  { 22050, S_Bits2PeTab22050, sizeof(S_Bits2PeTab22050)/sizeof(BIT_PE_SFAC) },
+  { 24000, S_Bits2PeTab24000, sizeof(S_Bits2PeTab24000)/sizeof(BIT_PE_SFAC) },
+  { 32000, S_Bits2PeTab32000, sizeof(S_Bits2PeTab32000)/sizeof(BIT_PE_SFAC) },
+  { 44100, S_Bits2PeTab44100, sizeof(S_Bits2PeTab44100)/sizeof(BIT_PE_SFAC) },
+  { 48000, S_Bits2PeTab48000, sizeof(S_Bits2PeTab48000)/sizeof(BIT_PE_SFAC) }
+};
+
+
+
 /* values for avoid hole flag */
 enum _avoid_hole_state {
     NO_AH              =0,
@@ -135,6 +246,99 @@
 #define Q_BITFAC    (24)   /* Q scaling used in FDKaacEnc_bitresCalcBitFac() calculation */
 #define Q_AVGBITS   (17)   /* scale bit values */
 
+
+/*****************************************************************************
+    functionname: FDKaacEnc_InitBits2PeFactor
+    description:  retrieve bits2PeFactor from table
+*****************************************************************************/
+static void FDKaacEnc_InitBits2PeFactor(
+        FIXP_DBL *bits2PeFactor_m,
+        INT *bits2PeFactor_e,
+        const INT bitRate,
+        const INT nChannels,
+        const INT sampleRate,
+        const INT advancedBitsToPe,
+        const INT invQuant
+        )
+{
+  /* default bits2pe factor */
+  FIXP_DBL bit2PE_m = FL2FXCONST_DBL(1.18f/(1<<(1)));
+  INT      bit2PE_e = 1;
+
+  /* make use of advanced bits to pe factor table */
+  if (advancedBitsToPe) {
+
+    int i;
+    const BIT_PE_SFAC *peTab = NULL;
+    INT size = 0;
+
+
+    /* Get correct table entry */
+    for (i=0; i<(INT)(sizeof(bits2PeConfigTab)/sizeof(BITS2PE_CFG_TAB)); i++) {
+      if (sampleRate >= bits2PeConfigTab[i].sampleRate) {
+        peTab = bits2PeConfigTab[i].pPeTab;
+        size  = bits2PeConfigTab[i].nEntries;
+      }
+    }
+
+    if ( (peTab!=NULL) && (size!=0) ) {
+
+      INT startB      = -1;
+      LONG startPF    = 0;
+      LONG peSlope    = 0;
+
+      /* stereo or mono mode and invQuant used or not */
+      for (i=0; i<size-1; i++)
+      {
+        if ((peTab[i].bitrate<=bitRate) && ((peTab[i+1].bitrate>bitRate) || ((i==size-2)) ))
+        {
+          if (nChannels==1)
+          {
+            startPF = (!invQuant) ? peTab[i].bits2PeFactor_mono   : peTab[i].bits2PeFactor_mono_scfOpt;
+            peSlope = (!invQuant) ? peTab[i].bits2PeFactor_mono_slope : peTab[i].bits2PeFactor_mono_scfOpt_slope;
+            /*endPF   = (!invQuant) ? peTab[i+1].bits2PeFactor_mono : peTab[i+1].bits2PeFactor_mono_scfOpt;
+            endB=peTab[i+1].bitrate;*/
+            startB=peTab[i].bitrate;
+            break;
+          }
+          else
+          {
+            startPF = (!invQuant) ? peTab[i].bits2PeFactor_stereo   : peTab[i].bits2PeFactor_stereo_scfOpt;
+            peSlope = (!invQuant) ? peTab[i].bits2PeFactor_stereo_slope : peTab[i].bits2PeFactor_stereo_scfOpt_slope;
+            /*endPF   = (!invQuant) ? peTab[i+1].bits2PeFactor_stereo : peTab[i+1].bits2PeFactor_stereo_scfOpt;
+            endB=peTab[i+1].bitrate;*/
+            startB=peTab[i].bitrate;
+            break;
+          }
+        }
+      } /* for i */
+
+      /* if a configuration is available */
+      if (startB!=-1) {
+        /* linear interpolate to actual PEfactor */
+        FIXP_DBL peFac = fMult((FIXP_DBL)(bitRate-startB)<<14, (FIXP_DBL)peSlope) << 2;
+        FIXP_DBL bit2PE = peFac + (FIXP_DBL)startPF; /* startPF_float = startPF << 2 */
+
+        /* sanity check if bits2pe value is high enough */
+        if ( bit2PE >= (FL2FXCONST_DBL(0.35f) >> 2) ) {
+          bit2PE_m = bit2PE;
+          bit2PE_e = 2; /*  table is fixed scaled */
+        }
+      } /* br */
+    } /* sr */
+  } /* advancedBitsToPe */
+
+
+  /* return bits2pe factor */
+  *bits2PeFactor_m = bit2PE_m;
+  *bits2PeFactor_e = bit2PE_e;
+}
+
+
+/*****************************************************************************
+functionname: FDKaacEnc_bits2pe2
+description:  convert from bits to pe
+*****************************************************************************/
 static INT FDKaacEnc_bits2pe2(
         const INT                 bits,
         const FIXP_DBL            factor_m,
@@ -450,22 +654,23 @@
             FIXP_DBL nrgSum14, nrgSum12, nrgSum34, nrgTotal;
             FIXP_DBL nrgFacLd_14, nrgFacLd_12, nrgFacLd_34;
             INT usePatch, exePatch;
-            int sfb, nLinesSum = 0;
+            int sfb, sfbGrp, nLinesSum = 0;
 
             nrgSum14 = nrgSum12 = nrgSum34 = nrgTotal = FL2FXCONST_DBL(0.f);
 
             /* calculate flatness of audible spectrum, i.e. spectrum above masking threshold. */
-            for (sfb = 0; sfb < psyOutChan->sfbCnt; sfb++) {
-
-                FIXP_DBL nrgFac12 = CalcInvLdData(psyOutChan->sfbEnergyLdData[sfb]>>1);   /* nrg^(1/2) */
-                FIXP_DBL nrgFac14 = CalcInvLdData(psyOutChan->sfbEnergyLdData[sfb]>>2);   /* nrg^(1/4) */
+            for (sfbGrp = 0;sfbGrp < psyOutChannel[ch]->sfbCnt; sfbGrp+=psyOutChannel[ch]->sfbPerGroup) {
+              for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
+                FIXP_DBL nrgFac12 = CalcInvLdData(psyOutChan->sfbEnergyLdData[sfbGrp+sfb]>>1); /* nrg^(1/2) */
+                FIXP_DBL nrgFac14 = CalcInvLdData(psyOutChan->sfbEnergyLdData[sfbGrp+sfb]>>2); /* nrg^(1/4) */
 
                 /* maximal number of bands is 64, results scaling factor 6 */
-                nLinesSum += peData->peChannelData[ch].sfbNLines[sfb];                    /* relevant lines */
-                nrgTotal  += ( psyOutChan->sfbEnergy[sfb] >> 6 );                         /* sum up nrg */
+                nLinesSum += peData->peChannelData[ch].sfbNLines[sfbGrp+sfb];             /* relevant lines */
+                nrgTotal  += ( psyOutChan->sfbEnergy[sfbGrp+sfb] >> 6 );                  /* sum up nrg */
                 nrgSum12  += ( nrgFac12 >> 6 );                                           /* sum up nrg^(2/4) */
                 nrgSum14  += ( nrgFac14 >> 6 );                                           /* sum up nrg^(1/4) */
                 nrgSum34  += ( fMult(nrgFac14, nrgFac12) >> 6 );                          /* sum up nrg^(3/4) */
+              }
             }
 
             nrgTotal = CalcLdData(nrgTotal);                                              /* get ld64 of total nrg */
@@ -479,32 +684,35 @@
             usePatch = (adjThrStateElement->chaosMeasureEnFac[ch] > FL2FXCONST_DBL(0.78125f));
             exePatch = ((usePatch) && (adjThrStateElement->lastEnFacPatch[ch]));
 
-            for (sfb = 0; sfb < psyOutChan->sfbCnt; sfb++) {
+            for (sfbGrp = 0;sfbGrp < psyOutChannel[ch]->sfbCnt; sfbGrp+=psyOutChannel[ch]->sfbPerGroup) {
+              for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
+
                 INT sfbExePatch;
 
                 /* for MS coupled SFBs, also execute patch in side channel if done in mid channel */
-                if ((ch == 1) && (toolsInfo->msMask[sfb])) {
+                if ((ch == 1) && (toolsInfo->msMask[sfbGrp+sfb])) {
                     sfbExePatch = exePatchM;
                 }
                 else {
                     sfbExePatch = exePatch;
                 }
 
-                if ( (sfbExePatch) && (psyOutChan->sfbEnergy[sfb]>FL2FXCONST_DBL(0.f)) )
+                if ( (sfbExePatch) && (psyOutChan->sfbEnergy[sfbGrp+sfb]>FL2FXCONST_DBL(0.f)) )
                 {
                     /* execute patch based on spectral flatness calculated above */
                     if (adjThrStateElement->chaosMeasureEnFac[ch] > FL2FXCONST_DBL(0.8125f)) {
-                        qcOutChannel[ch]->sfbEnFacLd[sfb] = ( (nrgFacLd_14 + (psyOutChan->sfbEnergyLdData[sfb]+(psyOutChan->sfbEnergyLdData[sfb]>>1)))>>1 ); /* sfbEnergy^(3/4) */
+                        qcOutChannel[ch]->sfbEnFacLd[sfbGrp+sfb] = ( (nrgFacLd_14 + (psyOutChan->sfbEnergyLdData[sfbGrp+sfb]+(psyOutChan->sfbEnergyLdData[sfbGrp+sfb]>>1)))>>1 ); /* sfbEnergy^(3/4) */
                     }
                     else if (adjThrStateElement->chaosMeasureEnFac[ch] > FL2FXCONST_DBL(0.796875f)) {
-                        qcOutChannel[ch]->sfbEnFacLd[sfb] = ( (nrgFacLd_12 + psyOutChan->sfbEnergyLdData[sfb])>>1 );          /* sfbEnergy^(2/4) */
+                        qcOutChannel[ch]->sfbEnFacLd[sfbGrp+sfb] = ( (nrgFacLd_12 + psyOutChan->sfbEnergyLdData[sfbGrp+sfb])>>1 );          /* sfbEnergy^(2/4) */
                     }
                     else {
-                        qcOutChannel[ch]->sfbEnFacLd[sfb] = ( (nrgFacLd_34 + (psyOutChan->sfbEnergyLdData[sfb]>>1))>>1 );     /* sfbEnergy^(1/4) */
+                        qcOutChannel[ch]->sfbEnFacLd[sfbGrp+sfb] = ( (nrgFacLd_34 + (psyOutChan->sfbEnergyLdData[sfbGrp+sfb]>>1))>>1 );     /* sfbEnergy^(1/4) */
                     }
-                    qcOutChannel[ch]->sfbEnFacLd[sfb] = fixMin(qcOutChannel[ch]->sfbEnFacLd[sfb],(FIXP_DBL)0);
+                    qcOutChannel[ch]->sfbEnFacLd[sfbGrp+sfb] = fixMin(qcOutChannel[ch]->sfbEnFacLd[sfbGrp+sfb],(FIXP_DBL)0);
 
                 }
+              }
             } /* sfb loop */
 
             adjThrStateElement->lastEnFacPatch[ch] = usePatch;
@@ -735,7 +943,6 @@
   return chaosMeasure;
 }
 
-
 /* apply reduction formula for VBR-mode */
 static void FDKaacEnc_reduceThresholdsVBR(QC_OUT_CHANNEL* qcOutChannel[(2)],
                                 PSY_OUT_CHANNEL* psyOutChannel[(2)],
@@ -923,7 +1130,6 @@
   }
 }
 
-
 /*****************************************************************************
 functionname: FDKaacEnc_correctThresh
 description:  if pe difference deltaPe between desired pe and real pe is small enough,
@@ -948,7 +1154,7 @@
    FIXP_DBL thrFactorLdData;
    FIXP_DBL sfbEnLdData, sfbThrLdData, sfbThrReducedLdData;
    FIXP_DBL *sfbPeFactorsLdData[(6)][(2)];
-   FIXP_DBL sfbNActiveLinesLdData[(2)][MAX_GROUPED_SFB];
+   FIXP_DBL sfbNActiveLinesLdData[(6)][(2)][MAX_GROUPED_SFB];
    INT      normFactorInt;
    FIXP_DBL normFactorLdData;
 
@@ -979,13 +1185,13 @@
             for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
 
              if ( peChanData->sfbNActiveLines[sfbGrp+sfb] == 0 ) {
-                sfbNActiveLinesLdData[ch][sfbGrp+sfb] = FL2FXCONST_DBL(-1.0f);
+                sfbNActiveLinesLdData[elementId][ch][sfbGrp+sfb] = FL2FXCONST_DBL(-1.0f);
              }
              else {
                 /* Both CalcLdInt and CalcLdData can be used!
                  * No offset has to be subtracted, because sfbNActiveLinesLdData
                  * is shorted while thrFactor calculation */
-                sfbNActiveLinesLdData[ch][sfbGrp+sfb] = CalcLdInt(peChanData->sfbNActiveLines[sfbGrp+sfb]);
+                sfbNActiveLinesLdData[elementId][ch][sfbGrp+sfb] = CalcLdInt(peChanData->sfbNActiveLines[sfbGrp+sfb]);
              }
              if ( ((ahFlag[elementId][ch][sfbGrp+sfb] < AH_ACTIVE) || (deltaPe > 0)) &&
                    peChanData->sfbNActiveLines[sfbGrp+sfb] != 0 )
@@ -1002,14 +1208,14 @@
                                                - (FIXP_DBL)(minScale<<(DFRACT_BITS-1-LD_DATA_SHIFT));
 
                    if (sumLd < FL2FXCONST_DBL(0.f)) {
-                      sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = sfbNActiveLinesLdData[ch][sfbGrp+sfb] - sumLd;
+                      sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = sfbNActiveLinesLdData[elementId][ch][sfbGrp+sfb] - sumLd;
                    }
                    else {
-                     if ( sfbNActiveLinesLdData[ch][sfbGrp+sfb] > (FL2FXCONST_DBL(-1.f) + sumLd) ) {
-                       sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = sfbNActiveLinesLdData[ch][sfbGrp+sfb] - sumLd;
+                     if ( sfbNActiveLinesLdData[elementId][ch][sfbGrp+sfb] > (FL2FXCONST_DBL(-1.f) + sumLd) ) {
+                       sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = sfbNActiveLinesLdData[elementId][ch][sfbGrp+sfb] - sumLd;
                      }
                      else {
-                      sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = sfbNActiveLinesLdData[ch][sfbGrp+sfb];
+                      sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = sfbNActiveLinesLdData[elementId][ch][sfbGrp+sfb];
                      }
                    }
 
@@ -1050,7 +1256,7 @@
                  }
                  else {
                    /* new threshold */
-                   FIXP_DBL tmp = CalcInvLdData(sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] + normFactorLdData - sfbNActiveLinesLdData[ch][sfbGrp+sfb] - FL2FXCONST_DBL((float)LD_DATA_SHIFT/LD_DATA_SCALING));
+                   FIXP_DBL tmp = CalcInvLdData(sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] + normFactorLdData - sfbNActiveLinesLdData[elementId][ch][sfbGrp+sfb] - FL2FXCONST_DBL((float)LD_DATA_SHIFT/LD_DATA_SCALING));
 
                    /* limit thrFactor to 60dB */
                    tmp = (deltaPe<0) ? tmp : (-tmp);
@@ -1683,7 +1889,6 @@
 
 }
 
-
 /* similar to FDKaacEnc_adaptThresholdsToPe(), for  VBR-mode */
 void FDKaacEnc_AdaptThresholdsVBR(QC_OUT_CHANNEL* qcOutChannel[(2)],
                                PSY_OUT_CHANNEL* psyOutChannel[(2)],
@@ -1692,8 +1897,14 @@
                                PE_DATA *peData,
                                const INT nChannels)
 {
-   UCHAR    pAhFlag[(2)][MAX_GROUPED_SFB];
-   FIXP_DBL pThrExp[(2)][MAX_GROUPED_SFB];
+   UCHAR    (*pAhFlag)[MAX_GROUPED_SFB];
+   FIXP_DBL (*pThrExp)[MAX_GROUPED_SFB];
+
+   /* allocate scratch memory */
+   C_ALLOC_SCRATCH_START(_pAhFlag, UCHAR, (2)*MAX_GROUPED_SFB)
+   C_ALLOC_SCRATCH_START(_pThrExp, FIXP_DBL, (2)*MAX_GROUPED_SFB)
+   pAhFlag = (UCHAR(*)[MAX_GROUPED_SFB])_pAhFlag;
+   pThrExp = (FIXP_DBL(*)[MAX_GROUPED_SFB])_pThrExp;
 
    /* thresholds to the power of redExp */
    FDKaacEnc_calcThreshExp(pThrExp, qcOutChannel, psyOutChannel, nChannels);
@@ -1711,6 +1922,9 @@
                        AdjThrStateElement->vbrQualFactor,
                        &AdjThrStateElement->chaosMeasureOld);
 
+   /* free scratch memory */
+   C_ALLOC_SCRATCH_END(_pThrExp, FIXP_DBL, (2)*MAX_GROUPED_SFB)
+   C_ALLOC_SCRATCH_END(_pAhFlag, UCHAR, (2)*MAX_GROUPED_SFB)
 }
 
 
@@ -2002,95 +2216,112 @@
 functionname: FDKaacEnc_AdjThrInit
 description:  initialize ADJ_THR_STATE
 *****************************************************************************/
-void FDKaacEnc_AdjThrInit(ADJ_THR_STATE   *hAdjThr,
-    const INT       meanPe,
-    ELEMENT_BITS    *elBits[(6)],
-    INT             nElements,
-    FIXP_DBL        vbrQualFactor)
+void FDKaacEnc_AdjThrInit(
+        ADJ_THR_STATE   *hAdjThr,
+        const INT       meanPe,
+        ELEMENT_BITS    *elBits[(6)],
+        INT             invQuant,
+        INT             nElements,
+        INT             nChannelsEff,
+        INT             sampleRate,
+        INT             advancedBitsToPe,
+        FIXP_DBL        vbrQualFactor
+        )
 {
-    INT i;
+  INT i;
 
-    FIXP_DBL POINT8 = FL2FXCONST_DBL(0.8f);
-    FIXP_DBL POINT6 = FL2FXCONST_DBL(0.6f);
+  FIXP_DBL POINT8 = FL2FXCONST_DBL(0.8f);
+  FIXP_DBL POINT6 = FL2FXCONST_DBL(0.6f);
 
-    /* common for all elements: */
+  /* common for all elements: */
+  /* parameters for bitres control */
+  hAdjThr->bresParamLong.clipSaveLow   = (FIXP_DBL)0x1999999a; /* FL2FXCONST_DBL(0.2f); */
+  hAdjThr->bresParamLong.clipSaveHigh  = (FIXP_DBL)0x7999999a; /* FL2FXCONST_DBL(0.95f); */
+  hAdjThr->bresParamLong.minBitSave    = (FIXP_DBL)0xf999999a; /* FL2FXCONST_DBL(-0.05f); */
+  hAdjThr->bresParamLong.maxBitSave    = (FIXP_DBL)0x26666666; /* FL2FXCONST_DBL(0.3f); */
+  hAdjThr->bresParamLong.clipSpendLow  = (FIXP_DBL)0x1999999a; /* FL2FXCONST_DBL(0.2f); */
+  hAdjThr->bresParamLong.clipSpendHigh = (FIXP_DBL)0x7999999a; /* FL2FXCONST_DBL(0.95f); */
+  hAdjThr->bresParamLong.minBitSpend   = (FIXP_DBL)0xf3333333; /* FL2FXCONST_DBL(-0.10f); */
+  hAdjThr->bresParamLong.maxBitSpend   = (FIXP_DBL)0x33333333; /* FL2FXCONST_DBL(0.4f); */
+
+  hAdjThr->bresParamShort.clipSaveLow   = (FIXP_DBL)0x199999a0; /* FL2FXCONST_DBL(0.2f); */
+  hAdjThr->bresParamShort.clipSaveHigh  = (FIXP_DBL)0x5fffffff; /* FL2FXCONST_DBL(0.75f); */
+  hAdjThr->bresParamShort.minBitSave    = (FIXP_DBL)0x00000000; /* FL2FXCONST_DBL(0.0f); */
+  hAdjThr->bresParamShort.maxBitSave    = (FIXP_DBL)0x199999a0; /* FL2FXCONST_DBL(0.2f); */
+  hAdjThr->bresParamShort.clipSpendLow  = (FIXP_DBL)0x199999a0; /* FL2FXCONST_DBL(0.2f); */
+  hAdjThr->bresParamShort.clipSpendHigh = (FIXP_DBL)0x5fffffff; /* FL2FXCONST_DBL(0.75f); */
+  hAdjThr->bresParamShort.minBitSpend   = (FIXP_DBL)0xf9999998; /* FL2FXCONST_DBL(-0.05f); */
+  hAdjThr->bresParamShort.maxBitSpend   = (FIXP_DBL)0x40000000; /* FL2FXCONST_DBL(0.5f); */
+
+  /* specific for each element: */
+  for (i=0; i<nElements; i++) {
+    ATS_ELEMENT* atsElem = hAdjThr->adjThrStateElem[i];
+    MINSNR_ADAPT_PARAM *msaParam = &atsElem->minSnrAdaptParam;
+    INT chBitrate = elBits[i]->chBitrateEl;
+
     /* parameters for bitres control */
-    hAdjThr->bresParamLong.clipSaveLow   = (FIXP_DBL)0x1999999a; /* FL2FXCONST_DBL(0.2f); */
-    hAdjThr->bresParamLong.clipSaveHigh  = (FIXP_DBL)0x7999999a; /* FL2FXCONST_DBL(0.95f); */
-    hAdjThr->bresParamLong.minBitSave    = (FIXP_DBL)0xf999999a; /* FL2FXCONST_DBL(-0.05f); */
-    hAdjThr->bresParamLong.maxBitSave    = (FIXP_DBL)0x26666666; /* FL2FXCONST_DBL(0.3f); */
-    hAdjThr->bresParamLong.clipSpendLow  = (FIXP_DBL)0x1999999a; /* FL2FXCONST_DBL(0.2f); */
-    hAdjThr->bresParamLong.clipSpendHigh = (FIXP_DBL)0x7999999a; /* FL2FXCONST_DBL(0.95f); */
-    hAdjThr->bresParamLong.minBitSpend   = (FIXP_DBL)0xf3333333; /* FL2FXCONST_DBL(-0.10f); */
-    hAdjThr->bresParamLong.maxBitSpend   = (FIXP_DBL)0x33333333; /* FL2FXCONST_DBL(0.4f); */
+    atsElem->peMin = fMultI(POINT8, meanPe) >> 1;
+    atsElem->peMax = fMultI(POINT6, meanPe);
 
-    hAdjThr->bresParamShort.clipSaveLow   = (FIXP_DBL)0x199999a0; /* FL2FXCONST_DBL(0.2f); */
-    hAdjThr->bresParamShort.clipSaveHigh  = (FIXP_DBL)0x5fffffff; /* FL2FXCONST_DBL(0.75f); */
-    hAdjThr->bresParamShort.minBitSave    = (FIXP_DBL)0x00000000; /* FL2FXCONST_DBL(0.0f); */
-    hAdjThr->bresParamShort.maxBitSave    = (FIXP_DBL)0x199999a0; /* FL2FXCONST_DBL(0.2f); */
-    hAdjThr->bresParamShort.clipSpendLow  = (FIXP_DBL)0x199999a0; /* FL2FXCONST_DBL(0.2f); */
-    hAdjThr->bresParamShort.clipSpendHigh = (FIXP_DBL)0x5fffffff; /* FL2FXCONST_DBL(0.75f); */
-    hAdjThr->bresParamShort.minBitSpend   = (FIXP_DBL)0xf9999998; /* FL2FXCONST_DBL(-0.05f); */
-    hAdjThr->bresParamShort.maxBitSpend   = (FIXP_DBL)0x40000000; /* FL2FXCONST_DBL(0.5f); */
+    /* for use in FDKaacEnc_reduceThresholdsVBR */
+    atsElem->chaosMeasureOld = FL2FXCONST_DBL(0.3f);
 
-    /* specific for each element: */
-    for (i=0; i<nElements; i++) {
-        ATS_ELEMENT* atsElem = hAdjThr->adjThrStateElem[i];
-        MINSNR_ADAPT_PARAM *msaParam = &atsElem->minSnrAdaptParam;
-        INT chBitrate = elBits[i]->chBitrateEl;
+    /* additional pe offset to correct pe2bits for low bitrates */
+    atsElem->peOffset = 0;
 
-        /* parameters for bitres control */
-        atsElem->peMin = fMultI(POINT8, meanPe) >> 1;
-        atsElem->peMax = fMultI(POINT6, meanPe);
-
-        /* for use in FDKaacEnc_reduceThresholdsVBR */
-        atsElem->chaosMeasureOld = FL2FXCONST_DBL(0.3f);
-
-        /* additional pe offset to correct pe2bits for low bitrates */
-        atsElem->peOffset = 0;
-
-        /* vbr initialisation */
-        atsElem->vbrQualFactor = vbrQualFactor;
-        if (chBitrate < 32000)
-        {
-            atsElem->peOffset = fixMax(50, 100-fMultI((FIXP_DBL)0x666667, chBitrate));
-        }
-
-        /* avoid hole parameters */
-        if (chBitrate > 20000) {
-            atsElem->ahParam.modifyMinSnr = TRUE;
-            atsElem->ahParam.startSfbL = 15;
-            atsElem->ahParam.startSfbS = 3;
-        }
-        else {
-            atsElem->ahParam.modifyMinSnr = FALSE;
-            atsElem->ahParam.startSfbL = 0;
-            atsElem->ahParam.startSfbS = 0;
-        }
-
-    		  /* minSnr adaptation */
-        msaParam->maxRed = FL2FXCONST_DBL(0.00390625f); /* 0.25f/64.0f */
-        /* start adaptation of minSnr for avgEn/sfbEn > startRatio */
-        msaParam->startRatio = FL2FXCONST_DBL(0.05190512648f); /* ld64(10.0f) */
-        /* maximum minSnr reduction to minSnr^maxRed is reached for
-           avgEn/sfbEn >= maxRatio */
-        /* msaParam->maxRatio = 1000.0f; */
-        /*msaParam->redRatioFac = ((float)1.0f - msaParam->maxRed) / ((float)10.0f*log10(msaParam->startRatio/msaParam->maxRatio)/log10(2.0f)*(float)0.3010299956f);*/
-        msaParam->redRatioFac = FL2FXCONST_DBL(-0.375f); /* -0.0375f * 10.0f */
-        /*msaParam->redOffs = (float)1.0f - msaParam->redRatioFac * (float)10.0f * log10(msaParam->startRatio)/log10(2.0f) * (float)0.3010299956f;*/
-        msaParam->redOffs = FL2FXCONST_DBL(0.021484375); /* 1.375f/64.0f */
-
-        /* init pe correction */
-        atsElem->peCorrectionFactor_m = FL2FXCONST_DBL(0.5f); /* 1.0 */
-        atsElem->peCorrectionFactor_e = 1;
-
-        atsElem->dynBitsLast = -1;
-        atsElem->peLast = 0;
-
-        /* init bits to pe factor */
-        atsElem->bits2PeFactor_m = FL2FXCONST_DBL(1.18f/(1<<(1)));
-        atsElem->bits2PeFactor_e = 1;
+    /* vbr initialisation */
+    atsElem->vbrQualFactor = vbrQualFactor;
+    if (chBitrate < 32000)
+    {
+      atsElem->peOffset = fixMax(50, 100-fMultI((FIXP_DBL)0x666667, chBitrate));
     }
+
+    /* avoid hole parameters */
+    if (chBitrate > 20000) {
+      atsElem->ahParam.modifyMinSnr = TRUE;
+      atsElem->ahParam.startSfbL = 15;
+      atsElem->ahParam.startSfbS = 3;
+    }
+    else {
+      atsElem->ahParam.modifyMinSnr = FALSE;
+      atsElem->ahParam.startSfbL = 0;
+      atsElem->ahParam.startSfbS = 0;
+    }
+
+    /* minSnr adaptation */
+    msaParam->maxRed = FL2FXCONST_DBL(0.00390625f); /* 0.25f/64.0f */
+    /* start adaptation of minSnr for avgEn/sfbEn > startRatio */
+    msaParam->startRatio = FL2FXCONST_DBL(0.05190512648f); /* ld64(10.0f) */
+    /* maximum minSnr reduction to minSnr^maxRed is reached for
+       avgEn/sfbEn >= maxRatio */
+    /* msaParam->maxRatio = 1000.0f; */
+    /*msaParam->redRatioFac = ((float)1.0f - msaParam->maxRed) / ((float)10.0f*log10(msaParam->startRatio/msaParam->maxRatio)/log10(2.0f)*(float)0.3010299956f);*/
+    msaParam->redRatioFac = FL2FXCONST_DBL(-0.375f); /* -0.0375f * 10.0f */
+    /*msaParam->redOffs = (float)1.0f - msaParam->redRatioFac * (float)10.0f * log10(msaParam->startRatio)/log10(2.0f) * (float)0.3010299956f;*/
+    msaParam->redOffs = FL2FXCONST_DBL(0.021484375); /* 1.375f/64.0f */
+
+    /* init pe correction */
+    atsElem->peCorrectionFactor_m = FL2FXCONST_DBL(0.5f); /* 1.0 */
+    atsElem->peCorrectionFactor_e = 1;
+
+    atsElem->dynBitsLast = -1;
+    atsElem->peLast = 0;
+
+    /* init bits to pe factor */
+
+    /* init bits2PeFactor */
+    FDKaacEnc_InitBits2PeFactor(
+              &atsElem->bits2PeFactor_m,
+              &atsElem->bits2PeFactor_e,
+              chBitrate,       /* bitrate/channel*/
+              nChannelsEff,    /* number of channels */
+              sampleRate,
+              advancedBitsToPe,
+              invQuant
+              );
+
+  } /* for nElements */
+
 }
 
 
@@ -2154,6 +2385,67 @@
 }
 
 
+static void FDKaacEnc_calcPeCorrectionLowBitRes(
+        FIXP_DBL *const           correctionFac_m,
+        INT *const                correctionFac_e,
+        const INT                 peLast,
+        const INT                 bitsLast,
+        const INT                 bitresLevel,
+        const INT                 nChannels,
+        const FIXP_DBL            bits2PeFactor_m,
+        const INT                 bits2PeFactor_e
+        )
+{
+  /* tuning params */
+  const FIXP_DBL amp     = FL2FXCONST_DBL(0.005);
+  const FIXP_DBL maxDiff = FL2FXCONST_DBL(0.25f);
+
+  if (bitsLast > 0) {
+
+    /* Estimate deviation of granted and used dynamic bits in previous frame, in PE units */
+    const int bitsBalLast = peLast - FDKaacEnc_bits2pe2(
+          bitsLast,
+          bits2PeFactor_m,
+          bits2PeFactor_e);
+
+    /* reserve n bits per channel */
+    int headroom = (bitresLevel>=50*nChannels) ? 0 : (100*nChannels);
+
+    /* in PE units */
+    headroom = FDKaacEnc_bits2pe2(
+          headroom,
+          bits2PeFactor_m,
+          bits2PeFactor_e);
+
+    /*
+     * diff = amp * ((bitsBalLast - headroom) / (bitresLevel + headroom)
+     * diff = max ( min ( diff, maxDiff, -maxDiff)) / 2
+     */
+    FIXP_DBL denominator = (FIXP_DBL)FDKaacEnc_bits2pe2(bitresLevel, bits2PeFactor_m, bits2PeFactor_e) + (FIXP_DBL)headroom;
+
+    int scaling = 0;
+    FIXP_DBL diff = (bitsBalLast>=headroom)
+         ?  fMult(amp, fDivNorm( (FIXP_DBL)(bitsBalLast - headroom), denominator, &scaling))
+         : -fMult(amp, fDivNorm(-(FIXP_DBL)(bitsBalLast - headroom), denominator, &scaling)) ;
+
+    scaling -= 1; /* divide by 2 */
+
+    diff = (scaling<=0) ? FDKmax( FDKmin (diff>>(-scaling), maxDiff>>1), -maxDiff>>1)
+                        : FDKmax( FDKmin (diff, maxDiff>>(1+scaling)), -maxDiff>>(1+scaling)) << scaling;
+
+    /*
+     * corrFac += diff
+     * corrFac = max ( min ( corrFac/2.f, 1.f/2.f, 0.75f/2.f ) )
+     */
+    *correctionFac_m = FDKmax(FDKmin((*correctionFac_m)+diff, FL2FXCONST_DBL(1.0f/2.f)), FL2FXCONST_DBL(0.75f/2.f)) ;
+    *correctionFac_e = 1;
+  }
+  else {
+    *correctionFac_m = FL2FXCONST_DBL(0.75/2.f);
+    *correctionFac_e = 1;
+  }
+}
+
 void FDKaacEnc_DistributeBits(ADJ_THR_STATE *adjThrState,
     ATS_ELEMENT       *AdjThrStateElement,
     PSY_OUT_CHANNEL   *psyOutChannel[(2)],
@@ -2166,7 +2458,7 @@
     const INT         bitresBits,
     const INT         maxBitresBits,
     const FIXP_DBL    maxBitFac,
-    const INT         bitDistributenMode)
+    const INT         bitDistributionMode)
 {
   FIXP_DBL bitFactor;
   INT noRedPe = peData->pe;
@@ -2184,7 +2476,7 @@
   }
 
   if (grantedDynBits >= 1) {
-    if (bitDistributenMode!=0) {
+    if (bitDistributionMode!=0) {
       *grantedPe = FDKaacEnc_bits2pe2(grantedDynBits, AdjThrStateElement->bits2PeFactor_m, AdjThrStateElement->bits2PeFactor_e);
     }
     else
@@ -2208,16 +2500,32 @@
   }
 
   /* correction of pe value */
-  {
-    FDKaacEnc_FDKaacEnc_calcPeCorrection(
-       &AdjThrStateElement->peCorrectionFactor_m,
-       &AdjThrStateElement->peCorrectionFactor_e,
-        fixMin(*grantedPe, noRedPe),
-        AdjThrStateElement->peLast,
-        AdjThrStateElement->dynBitsLast,
-        AdjThrStateElement->bits2PeFactor_m,
-        AdjThrStateElement->bits2PeFactor_e
+  switch (bitDistributionMode) {
+  case 2:
+  case 1:
+    FDKaacEnc_calcPeCorrectionLowBitRes(
+           &AdjThrStateElement->peCorrectionFactor_m,
+           &AdjThrStateElement->peCorrectionFactor_e,
+            AdjThrStateElement->peLast,
+            AdjThrStateElement->dynBitsLast,
+            bitresBits,
+            nChannels,
+            AdjThrStateElement->bits2PeFactor_m,
+            AdjThrStateElement->bits2PeFactor_e
         );
+    break;
+  case 0:
+  default:
+      FDKaacEnc_FDKaacEnc_calcPeCorrection(
+           &AdjThrStateElement->peCorrectionFactor_m,
+           &AdjThrStateElement->peCorrectionFactor_e,
+            fixMin(*grantedPe, noRedPe),
+            AdjThrStateElement->peLast,
+            AdjThrStateElement->dynBitsLast,
+            AdjThrStateElement->bits2PeFactor_m,
+            AdjThrStateElement->bits2PeFactor_e
+            );
+    break;
   }
 
   *grantedPeCorr = (INT)(fMult((FIXP_DBL)(*grantedPe<<Q_AVGBITS), AdjThrStateElement->peCorrectionFactor_m) >> (Q_AVGBITS-AdjThrStateElement->peCorrectionFactor_e));
@@ -2291,20 +2599,19 @@
         }  /* -end- element loop */
 
     }
-        for (i=0; i<cm->nElements; i++) {
-            int ch,sfb,sfbGrp;
-            /* no weighting of threholds and energies for mlout */
-            /* weight energies and thresholds */
-            for (ch=0; ch<cm->elInfo[i].nChannelsInEl; ch++) {
-                QC_OUT_CHANNEL* pQcOutCh = qcElement[i]->qcOutChannel[ch];
-                for (sfbGrp = 0;sfbGrp < psyOutElement[i]->psyOutChannel[ch]->sfbCnt; sfbGrp+=psyOutElement[i]->psyOutChannel[ch]->sfbPerGroup) {
-                    for (sfb=0; sfb<psyOutElement[i]->psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
-                        pQcOutCh->sfbThresholdLdData[sfb+sfbGrp] += pQcOutCh->sfbEnFacLd[sfb+sfbGrp];
-                    }
+    for (i=0; i<cm->nElements; i++) {
+        int ch,sfb,sfbGrp;
+        /* no weighting of threholds and energies for mlout */
+        /* weight energies and thresholds */
+        for (ch=0; ch<cm->elInfo[i].nChannelsInEl; ch++) {
+            QC_OUT_CHANNEL* pQcOutCh = qcElement[i]->qcOutChannel[ch];
+            for (sfbGrp = 0;sfbGrp < psyOutElement[i]->psyOutChannel[ch]->sfbCnt; sfbGrp+=psyOutElement[i]->psyOutChannel[ch]->sfbPerGroup) {
+                for (sfb=0; sfb<psyOutElement[i]->psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
+                    pQcOutCh->sfbThresholdLdData[sfb+sfbGrp] += pQcOutCh->sfbEnFacLd[sfb+sfbGrp];
                 }
             }
         }
-
+    }
 }
 
 void FDKaacEnc_AdjThrClose(ADJ_THR_STATE** phAdjThr)
diff --git a/libAACenc/src/adj_thr.h b/libAACenc/src/adj_thr.h
index d03375c..a429dff 100644
--- a/libAACenc/src/adj_thr.h
+++ b/libAACenc/src/adj_thr.h
@@ -98,13 +98,14 @@
 #include "interface.h"
 
 
-
-void FDKaacEnc_peCalculation(PE_DATA *peData,
-                             PSY_OUT_CHANNEL* psyOutChannel[(2)],
-                             QC_OUT_CHANNEL* qcOutChannel[(2)],
-                             struct TOOLSINFO *toolsInfo,
-                             ATS_ELEMENT* adjThrStateElement,
-                             const INT nChannels);
+void FDKaacEnc_peCalculation(
+        PE_DATA *peData,
+        PSY_OUT_CHANNEL* psyOutChannel[(2)],
+        QC_OUT_CHANNEL* qcOutChannel[(2)],
+        struct TOOLSINFO *toolsInfo,
+        ATS_ELEMENT* adjThrStateElement,
+        const INT nChannels
+        );
 
 INT  FDKaacEnc_AdjThrNew(ADJ_THR_STATE** phAdjThr,
                          INT             nElements);
@@ -112,9 +113,13 @@
 void FDKaacEnc_AdjThrInit(ADJ_THR_STATE *hAdjThr,
                 const INT peMean,
                 ELEMENT_BITS* elBits[(6)],
+                INT invQuant,
                 INT nElements,
+                INT nChannelsEff,
+                INT sampleRate,
+                INT advancedBitsToPe,
                 FIXP_DBL vbrQualFactor);
-
+ 
 
 void FDKaacEnc_DistributeBits(ADJ_THR_STATE *adjThrState,
     ATS_ELEMENT       *AdjThrStateElement,
@@ -128,7 +133,7 @@
     const INT         bitresBits,
     const INT         maxBitresBits,
     const FIXP_DBL    maxBitFac,
-    const INT         bitDistributenMode);
+    const INT         bitDistributionMode);
 
 void FDKaacEnc_AdjustThresholds(ATS_ELEMENT* AdjThrStateElement[(6)],
     QC_OUT_ELEMENT*   qcElement[(6)],
diff --git a/libAACenc/src/block_switch.cpp b/libAACenc/src/block_switch.cpp
index 948c89f..7b3e275 100644
--- a/libAACenc/src/block_switch.cpp
+++ b/libAACenc/src/block_switch.cpp
@@ -83,7 +83,7 @@
 
 /*****************************  MPEG-4 AAC Encoder  **************************
 
-   Author(s):   M. Werner
+   Author(s):   M. Werner, Tobias Chalupka
    Description: Block switching
 
 ******************************************************************************/
@@ -100,9 +100,11 @@
 
 static FIXP_DBL FDKaacEnc_GetWindowEnergy(const FIXP_DBL in[], const INT blSwWndIdx);
 
-static void FDKaacEnc_CalcWindowEnergy( BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl,
-                              INT                      windowLen);
-
+static void FDKaacEnc_CalcWindowEnergy(
+        BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl,
+        INT                      windowLen,
+        const INT_PCM           *pTimeSignal
+        );
 
 /****************** Constants *****************************/
 /*                                                LONG         START        SHORT         STOP         LOWOV                  */
@@ -145,20 +147,9 @@
 
 /**************** internal function prototypes ***********/
 
-static INT FDKaacEnc_GetWindowIndex(INT blockSwWindowIndex);
-
-static FIXP_DBL FDKaacEnc_GetWindowEnergy(const FIXP_DBL in[], const INT shortWndIdx);
-
-static void FDKaacEnc_CalcWindowEnergy( BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl,
-                                        INT windowLen);
-
-
-
 /****************** Routines ****************************/
 void FDKaacEnc_InitBlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, INT isLowDelay)
 {
-  /* note: the pointer to timeSignal can be zeroed here, because it is initialized for every call
-           to FDKaacEnc_BlockSwitching anew */
   FDKmemclear (blockSwitchingControl, sizeof(BLOCK_SWITCHING_CONTROL));
 
   if (isLowDelay)
@@ -214,7 +205,7 @@
   /*attack   */   {START_WINDOW,  SHORT_WINDOW,  SHORT_WINDOW,  START_WINDOW, WRONG_WINDOW, WRONG_WINDOW} }  /* attack      */
 };
 
-int FDKaacEnc_BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, const INT granuleLength, const int isLFE)
+int FDKaacEnc_BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, const INT granuleLength, const int isLFE, const INT_PCM *pTimeSignal)
 {
     UINT i;
     FIXP_DBL enM1, enMax;
@@ -263,7 +254,7 @@
 
 
     /* Calculate unfiltered and filtered energies in subwindows and combine to segments */
-    FDKaacEnc_CalcWindowEnergy(blockSwitchingControl, granuleLength>>(nBlockSwitchWindows==4? 2:3 ));
+    FDKaacEnc_CalcWindowEnergy(blockSwitchingControl, granuleLength>>(nBlockSwitchWindows==4? 2:3 ), pTimeSignal);
 
     /* now calculate if there is an attack */
 
@@ -335,8 +326,7 @@
 
 }
 
-
-static void FDKaacEnc_CalcWindowEnergy(BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl, INT windowLen)
+static void FDKaacEnc_CalcWindowEnergy(BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl, INT windowLen, const INT_PCM *pTimeSignal)
 {
     INT  i;
     UINT w;
@@ -344,8 +334,6 @@
     FIXP_SGL hiPassCoeff0 = hiPassCoeff[0];
     FIXP_SGL hiPassCoeff1 = hiPassCoeff[1];
 
-    INT_PCM *timeSignal = blockSwitchingControl->timeSignal;
-
     /* sum up scalarproduct of timesignal as windowed Energies */
     for (w=0; w < blockSwitchingControl->nBlockSwitchWindows; w++) {
 
@@ -361,9 +349,9 @@
             FIXP_DBL tempUnfiltered, tempFiltred, t1, t2;
             /* tempUnfiltered is scaled with 1 to prevent overflows during calculation of tempFiltred */
 #if SAMPLE_BITS == DFRACT_BITS
-            tempUnfiltered = (FIXP_DBL) *timeSignal++ >> 1;
+            tempUnfiltered = (FIXP_DBL) *pTimeSignal++ >> 1;
 #else
-            tempUnfiltered = (FIXP_DBL) *timeSignal++ << (DFRACT_BITS-SAMPLE_BITS-1);
+            tempUnfiltered = (FIXP_DBL) *pTimeSignal++ << (DFRACT_BITS-SAMPLE_BITS-1);
 #endif
             t1 = fMultDiv2(hiPassCoeff1, tempUnfiltered-temp_iirState0);
             t2 = fMultDiv2(hiPassCoeff0, temp_iirState1);
diff --git a/libAACenc/src/block_switch.h b/libAACenc/src/block_switch.h
index 174f05f..e94b6f5 100644
--- a/libAACenc/src/block_switch.h
+++ b/libAACenc/src/block_switch.h
@@ -107,7 +107,6 @@
 
 /****************** Structures ***************************/
 typedef struct{
-  INT_PCM *timeSignal;
   INT   lastWindowSequence;
   INT   windowShape;
   INT   lastWindowShape;
@@ -136,7 +135,7 @@
 
 void FDKaacEnc_InitBlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, INT isLowDelay);
 
-int FDKaacEnc_BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, const INT granuleLength, const int isLFE);
+int FDKaacEnc_BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, const INT granuleLength, const int isLFE, const INT_PCM *pTimeSignal);
 
 int FDKaacEnc_SyncBlockSwitching(
       BLOCK_SWITCHING_CONTROL *blockSwitchingControlLeft,
diff --git a/libAACenc/src/interface.h b/libAACenc/src/interface.h
index 177ddbf..2ec1852 100644
--- a/libAACenc/src/interface.h
+++ b/libAACenc/src/interface.h
@@ -92,6 +92,7 @@
 #define _INTERFACE_H
 
 #include "common_fix.h"
+#include "FDK_audio.h"
 
 #include "psy_data.h"
 #include "aacenc_tns.h"
@@ -160,4 +161,9 @@
 
 }PSY_OUT;
 
+inline int isLowDelay( AUDIO_OBJECT_TYPE aot )
+{
+  return (aot==AOT_ER_AAC_LD || aot==AOT_ER_AAC_ELD);
+}
+
 #endif /* _INTERFACE_H */
diff --git a/libAACenc/src/psy_main.cpp b/libAACenc/src/psy_main.cpp
index 8649a7e..0949b6d 100644
--- a/libAACenc/src/psy_main.cpp
+++ b/libAACenc/src/psy_main.cpp
@@ -116,11 +116,6 @@
 /* forward definitions */
 
 
-static inline int isLowDelay( AUDIO_OBJECT_TYPE aot )
-{
-  return (aot==AOT_ER_AAC_LD || aot==AOT_ER_AAC_ELD);
-}
-
 /*****************************************************************************
 
     functionname: FDKaacEnc_PsyNew
@@ -513,28 +508,28 @@
 
       for(ch = 0; ch < channels; ch++)
       {
-          C_ALLOC_SCRATCH_START(timeSignal, INT_PCM, (1024));
-          psyStatic[ch]->blockSwitchingControl.timeSignal = timeSignal;
+          C_ALLOC_SCRATCH_START(pTimeSignal, INT_PCM, (1024))
 
           /* deinterleave input data and use for block switching */
-          FDKaacEnc_deinterleaveInputBuffer( psyStatic[ch]->blockSwitchingControl.timeSignal,
+          FDKaacEnc_deinterleaveInputBuffer( pTimeSignal,
                                             &pInput[chIdx[ch]],
                                              psyConf->granuleLength,
                                              totalChannels);
 
 
           FDKaacEnc_BlockSwitching (&psyStatic[ch]->blockSwitchingControl,
-                                     psyConf->granuleLength
-                                    ,psyStatic[ch]->isLFE
+                                     psyConf->granuleLength,
+                                     psyStatic[ch]->isLFE,
+                                     pTimeSignal
                                    );
 
 
             /* fill up internal input buffer, to 2xframelength samples */
             FDKmemcpy(psyStatic[ch]->psyInputBuffer+blockSwitchingOffset,
-                      psyStatic[ch]->blockSwitchingControl.timeSignal,
+                      pTimeSignal,
                       (2*psyConf->granuleLength-blockSwitchingOffset)*sizeof(INT_PCM));
 
-            C_ALLOC_SCRATCH_END(timeSignal, INT_PCM, (1024));
+            C_ALLOC_SCRATCH_END(pTimeSignal, INT_PCM, (1024))
       }
 
       /* synch left and right block type */
diff --git a/libAACenc/src/qc_data.h b/libAACenc/src/qc_data.h
index be6d158..51e66c6 100644
--- a/libAACenc/src/qc_data.h
+++ b/libAACenc/src/qc_data.h
@@ -143,6 +143,8 @@
   INT maxBits;     /* maximum number of bits in reservoir  */
   INT averageBits; /* average number of bits we should use */
   INT bitRes;
+  INT sampleRate;       /* output sample rate                   */
+  INT advancedBitsToPe; /* if set, calc bits2PE factor depending on samplerate */
   INT staticBits;  /* Bits per frame consumed by transport layers. */
   QCDATA_BR_MODE bitrateMode;
   INT meanPe;
@@ -252,7 +254,7 @@
   INT minBitsPerFrame;   /* minimal allowd bits per fram, superframing - DRM */
   INT nElements;
   QCDATA_BR_MODE bitrateMode;
-  INT bitDistributenMode; /* 0: full bitreservoir, 1: reduced bitreservoir, 2: disabled bitreservoir */
+  INT bitDistributionMode; /* 0: full bitreservoir, 1: reduced bitreservoir, 2: disabled bitreservoir */
   INT bitResTot;
   INT bitResTotMax;
   INT maxIterations;      /* Maximum number of allowed iterations before FDKaacEnc_crashRecovery() is applied. */
diff --git a/libAACenc/src/qc_main.cpp b/libAACenc/src/qc_main.cpp
index 0a4bcbc..15646e9 100644
--- a/libAACenc/src/qc_main.cpp
+++ b/libAACenc/src/qc_main.cpp
@@ -382,10 +382,10 @@
   if ( isConstantBitrateMode(hQC->bitrateMode) ) {
     INT bitresPerChannel = (hQC->bitResTotMax / init->channelMapping->nChannelsEff);
     /* 0: full bitreservoir, 1: reduced bitreservoir, 2: disabled bitreservoir */
-    hQC->bitDistributenMode = (bitresPerChannel>50) ? 0 : (bitresPerChannel>0) ? 1 : 2;
+    hQC->bitDistributionMode = (bitresPerChannel>100) ? 0 : (bitresPerChannel>0) ? 1 : 2;
   }
   else {
-    hQC->bitDistributenMode = 0; /* full bitreservoir */
+    hQC->bitDistributionMode = 0; /* full bitreservoir */
   }
 
 
@@ -420,11 +420,17 @@
       break;
   }
 
-  FDKaacEnc_AdjThrInit(hQC->hAdjThr,
-             init->meanPe,
-             hQC->elementBits,                 /* or channelBitrates, was: channelBitrate */
-             init->channelMapping->nElements,
-             hQC->vbrQualFactor);
+  FDKaacEnc_AdjThrInit(
+        hQC->hAdjThr,
+        init->meanPe,
+        hQC->elementBits,                 /* or channelBitrates, was: channelBitrate */
+        hQC->invQuant,
+        init->channelMapping->nElements,
+        init->channelMapping->nChannelsEff,
+        init->sampleRate,                 /* output sample rate */
+        init->advancedBitsToPe,           /* if set, calc bits2PE factor depending on samplerate */
+        hQC->vbrQualFactor
+        );
 
   return AAC_ENC_OK;
 }
@@ -655,7 +661,7 @@
                                          hQC->elementBits[i]->bitResLevelEl,
                                          hQC->elementBits[i]->maxBitResBitsEl,
                                          hQC->maxBitFac,
-                                         hQC->bitDistributenMode);
+                                         hQC->bitDistributionMode);
 
                 *totalAvailableBits += hQC->elementBits[i]->bitResLevelEl;
         /* get total corrected granted PE */
diff --git a/libFDK/src/FDK_core.cpp b/libFDK/src/FDK_core.cpp
index ea0be6c..6db648d 100644
--- a/libFDK/src/FDK_core.cpp
+++ b/libFDK/src/FDK_core.cpp
@@ -93,7 +93,7 @@
 /* FDK tools library info */
 #define FDK_TOOLS_LIB_VL0 2
 #define FDK_TOOLS_LIB_VL1 3
-#define FDK_TOOLS_LIB_VL2 1
+#define FDK_TOOLS_LIB_VL2 2
 #define FDK_TOOLS_LIB_TITLE "FDK Tools"
 #define FDK_TOOLS_LIB_BUILD_DATE __DATE__
 #define FDK_TOOLS_LIB_BUILD_TIME __TIME__
diff --git a/libFDK/src/fixpoint_math.cpp b/libFDK/src/fixpoint_math.cpp
index 78cae2b..30283ff 100644
--- a/libFDK/src/fixpoint_math.cpp
+++ b/libFDK/src/fixpoint_math.cpp
@@ -242,30 +242,72 @@
 
 *****************************************************************************/
 LNK_SECTION_CODE_L1
-FIXP_DBL CalcInvLdData(FIXP_DBL op)
+/* This table is used for lookup 2^x with   */
+/* x in range [0...1.0[ in steps of 1/32 */
+LNK_SECTION_DATA_L1 static const UINT exp2_tab_long[32]={
+0x40000000,0x4166C34C,0x42D561B4,0x444C0740,
+0x45CAE0F2,0x47521CC6,0x48E1E9BA,0x4A7A77D4,
+0x4C1BF829,0x4DC69CDD,0x4F7A9930,0x51382182,
+0x52FF6B55,0x54D0AD5A,0x56AC1F75,0x5891FAC1,
+0x5A82799A,0x5C7DD7A4,0x5E8451D0,0x60962665,
+0x62B39509,0x64DCDEC3,0x6712460B,0x69540EC9,
+0x6BA27E65,0x6DFDDBCC,0x70666F76,0x72DC8374,
+0x75606374,0x77F25CCE,0x7A92BE8B,0x7D41D96E
+// 0x80000000
+};
+
+/* This table is used for lookup 2^x with   */
+/* x in range [0...1/32[ in steps of 1/1024 */
+LNK_SECTION_DATA_L1 static const UINT exp2w_tab_long[32]={
+0x40000000,0x400B1818,0x4016321B,0x40214E0C,
+0x402C6BE9,0x40378BB4,0x4042AD6D,0x404DD113,
+0x4058F6A8,0x40641E2B,0x406F479E,0x407A7300,
+0x4085A051,0x4090CF92,0x409C00C4,0x40A733E6,
+0x40B268FA,0x40BD9FFF,0x40C8D8F5,0x40D413DD,
+0x40DF50B8,0x40EA8F86,0x40F5D046,0x410112FA,
+0x410C57A2,0x41179E3D,0x4122E6CD,0x412E3152,
+0x41397DCC,0x4144CC3B,0x41501CA0,0x415B6EFB,
+// 0x4166C34C,
+};
+/* This table is used for lookup 2^x with   */
+/* x in range [0...1/1024[ in steps of 1/32768 */
+LNK_SECTION_DATA_L1 static const UINT exp2x_tab_long[32]={
+0x40000000,0x400058B9,0x4000B173,0x40010A2D,
+0x400162E8,0x4001BBA3,0x4002145F,0x40026D1B,
+0x4002C5D8,0x40031E95,0x40037752,0x4003D011,
+0x400428CF,0x4004818E,0x4004DA4E,0x4005330E,
+0x40058BCE,0x4005E48F,0x40063D51,0x40069613,
+0x4006EED5,0x40074798,0x4007A05B,0x4007F91F,
+0x400851E4,0x4008AAA8,0x4009036E,0x40095C33,
+0x4009B4FA,0x400A0DC0,0x400A6688,0x400ABF4F,
+//0x400B1818
+};
+
+LNK_SECTION_CODE_L1 FIXP_DBL CalcInvLdData(FIXP_DBL x)
 {
-  FIXP_DBL result_m;
+  int set_zero = (x <  FL2FXCONST_DBL(-31.0/64.0))? 0 : 1;
+  int set_max  = (x >= FL2FXCONST_DBL( 31.0/64.0)) | (x == FL2FXCONST_DBL(0.0));
 
-  if ( op == FL2FXCONST_DBL(0.0f) ) {
-    result_m = (FIXP_DBL)MAXVAL_DBL;
-  }
-  else if ( op < FL2FXCONST_DBL(0.0f) ) {
-    result_m = f2Pow(op, LD_DATA_SHIFT);
-  }
-  else {
-    int result_e;
+  FIXP_SGL frac = (FIXP_SGL)(LONG)(x & 0x3FF);
+  UINT index3 = (UINT)(LONG)(x >> 10) & 0x1F;
+  UINT index2 = (UINT)(LONG)(x >> 15) & 0x1F; 
+  UINT index1 = (UINT)(LONG)(x >> 20) & 0x1F;
+  int exp  = (x >  FL2FXCONST_DBL(0.0f)) ? (31 - (int)(x>>25)) : (int)(-(x>>25));
 
-    result_m = f2Pow(op, LD_DATA_SHIFT, &result_e);
-    result_e = fixMin(fixMax(result_e+1-(DFRACT_BITS-1), -(DFRACT_BITS-1)), (DFRACT_BITS-1)); /* rounding and saturation */
+  UINT lookup1 = exp2_tab_long[index1]*set_zero;
+  UINT lookup2 = exp2w_tab_long[index2];
+  UINT lookup3 = exp2x_tab_long[index3];
+  UINT lookup3f = lookup3 + (UINT)(LONG)fMultDiv2((FIXP_DBL)(0x0016302F),(FIXP_SGL)frac);
+  
+  UINT lookup12 = (UINT)(LONG)fMult((FIXP_DBL)lookup1,  (FIXP_DBL) lookup2);
+  UINT lookup   = (UINT)(LONG)fMult((FIXP_DBL)lookup12, (FIXP_DBL) lookup3f);
 
-    if ( (result_e>0) && ( result_m > (((FIXP_DBL)MAXVAL_DBL)>>result_e) ) ) {
-      result_m = (FIXP_DBL)MAXVAL_DBL; /* saturate to max representable value */
-    }
-    else {
-      result_m = (scaleValue(result_m, result_e)+(FIXP_DBL)1)>>1; /* descale result + rounding */
-    }
-  }
-  return result_m;
+  FIXP_DBL retVal = (lookup<<3) >> exp;
+
+  if (set_max)
+    retVal=FL2FXCONST_DBL(1.0f);
+
+  return retVal;
 }