[automerger skipped] [DO NOT MERGE] Fix heap buffer overflow in sbrDecoder_AssignQmfChannels2SbrChannels(). am: 50aa5be388 am: 0468e02e5b am: d20df7ee14 -s ours am: 80ebc985fb -s ours am: 035cf671b8 am: ce38f54339 -s ours

am skip reason: subject contains skip directive

Original change: https://googleplex-android-review.googlesource.com/c/platform/external/aac/+/12088847

Change-Id: Ie337579b14a76c90016c6866d58422816d61ea0a
diff --git a/Android.bp b/Android.bp
index 80a0347..1cf54fd 100644
--- a/Android.bp
+++ b/Android.bp
@@ -51,4 +51,11 @@
         "libSACdec/include",
         "libSACenc/include",
     ],
+
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.bluetooth.updatable",
+        "com.android.media.swcodec",
+    ],
+    min_sdk_version: "29",
 }
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..ecf8b8e
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,2 @@
+[Hook Scripts]
+mainline_hook = ${REPO_ROOT}/frameworks/av/tools/mainline_hook_project.sh
diff --git a/documentation/aacDecoder.pdf b/documentation/aacDecoder.pdf
index eb2a75e..cc7cf41 100644
--- a/documentation/aacDecoder.pdf
+++ b/documentation/aacDecoder.pdf
Binary files differ
diff --git a/documentation/aacEncoder.pdf b/documentation/aacEncoder.pdf
index e438e27..77b8f4c 100644
--- a/documentation/aacEncoder.pdf
+++ b/documentation/aacEncoder.pdf
Binary files differ
diff --git a/libAACdec/include/aacdecoder_lib.h b/libAACdec/include/aacdecoder_lib.h
index 6c2fda4..56f4ec1 100644
--- a/libAACdec/include/aacdecoder_lib.h
+++ b/libAACdec/include/aacdecoder_lib.h
@@ -164,9 +164,6 @@
 files are provided for usage in specific C/C++ programs. The main AAC decoder
 library API functions are located in aacdecoder_lib.h header file.
 
-In binary releases the decoder core resides in statically linkable libraries,
-for example libAACdec.a.
-
 
 \section Calling_Sequence Calling Sequence
 
@@ -174,19 +171,7 @@
 HE-AAC v2, or MPEG-D USAC bitstreams. In the following description, input stream
 read and output write function details are left out, since they may be
 implemented in a variety of configurations depending on the user's specific
-requirements. The example implementation uses file-based input/output, and in
-such case one may call mpegFileRead_Open() to open an input file and to allocate
-memory for the required structures, and the corresponding mpegFileRead_Close()
-to close opened files and to de-allocate associated structures.
-mpegFileRead_Open() will attempt to detect the bitstream format and in case of
-MPEG-4 file format or Raw Packets file format (a proprietary Fraunhofer IIS file
-format suitable only for testing) it will read the Audio Specific Config data
-(ASC). An unsuccessful attempt to recognize the bitstream format requires the
-user to provide this information manually. For any other bitstream formats that
-are usually applicable in streaming applications, the decoder itself will try to
-synchronize and parse the given bitstream fragment using the FDK transport
-library. Hence, for streaming applications (without file access) this step is
-not necessary.
+requirements.
 
 
 -# Call aacDecoder_Open() to open and retrieve a handle to a new AAC decoder
@@ -205,19 +190,17 @@
 working memory (a client-supplied input buffer "inBuffer" in framework). This
 buffer will be used to load AAC bitstream data to the decoder.  Only when all
 data in this buffer has been processed will the decoder signal an empty buffer.
-For file-based input, you may invoke mpegFileRead_Read() to acquire new
-bitstream data.
 -# Call aacDecoder_Fill() to fill the decoder's internal bitstream input buffer
 with the client-supplied bitstream input buffer. Note, if the data loaded in to
 the internal buffer is not sufficient to decode a frame,
 aacDecoder_DecodeFrame() will return ::AAC_DEC_NOT_ENOUGH_BITS until a
 sufficient amount of data is loaded in to the internal buffer. For streaming
 formats (ADTS, LOAS), it is acceptable to load more than one frame to the
-decoder. However, for RAW file format (Fraunhofer IIS proprietary format), only
-one frame may be loaded to the decoder per aacDecoder_DecodeFrame() call. For
-least amount of communication delay, fill and decode should be performed on a
-frame by frame basis. \code ErrorStatus = aacDecoder_Fill(aacDecoderInfo,
-inBuffer, bytesRead, bytesValid); \endcode
+decoder. However, for packed based formats, only one frame may be loaded to the
+decoder per aacDecoder_DecodeFrame() call. For least amount of communication
+delay, fill and decode should be performed on a frame by frame basis. \code
+    ErrorStatus = aacDecoder_Fill(aacDecoderInfo, inBuffer, bytesRead,
+bytesValid); \endcode
 -# Call aacDecoder_DecodeFrame(). This function decodes one frame and writes
 decoded PCM audio data to a client-supplied buffer. It is the client's
 responsibility to allocate a buffer which is large enough to hold the decoded
@@ -225,12 +208,9 @@
 TimeData, OUT_BUF_SIZE, flags); \endcode If the bitstream configuration (number
 of channels, sample rate, frame size) is not known a priori, you may call
 aacDecoder_GetStreamInfo() to retrieve a structure that contains this
-information. You may use this data to initialize an audio output device. In the
-example program, if the number of channels or the sample rate has changed since
-program start or the previously decoded frame, the audio output device is then
-re-initialized. If WAVE file output is chosen, a new WAVE file for each new
-stream configuration is be created. \code p_si =
-aacDecoder_GetStreamInfo(aacDecoderInfo); \endcode
+information. You may use this data to initialize an audio output device. \code
+    p_si = aacDecoder_GetStreamInfo(aacDecoderInfo);
+\endcode
 -# Repeat steps 5 to 7 until no data is available to decode any more, or in case
 of error. \code } while (bytesRead[0] > 0 || doFlush || doBsFlush ||
 forceContinue); \endcode
@@ -239,7 +219,7 @@
 
 \image latex decode.png "Decode calling sequence" width=11cm
 
-\image latex change_source.png "Change data source sequence" width 5cm
+\image latex change_source.png "Change data source sequence" width=5cm
 
 \image latex conceal.png "Error concealment sequence" width=14cm
 
@@ -296,16 +276,14 @@
 limited applications, the output buffer may be reused as an external input
 buffer prior to the subsequence aacDecoder_Fill() function call.
 
-The external input buffer is set in the example program and its size is defined
-by ::IN_BUF_SIZE. You may freely choose different buffer sizes. To feed the data
-to the decoder-internal input buffer, use the function aacDecoder_Fill(). This
-function returns important information regarding the number of bytes in the
-external input buffer that have not yet been copied into the internal input
-buffer (variable bytesValid). Once the external buffer has been fully copied, it
-can be completely re-filled again. In case you wish to refill the buffer while
-there are unprocessed bytes (bytesValid is unequal 0), you should preserve the
-unconsumed data. However, we recommend to refill the buffer only when bytesValid
-returns 0.
+To feed the data to the decoder-internal input buffer, use the
+function aacDecoder_Fill(). This function returns important information
+regarding the number of bytes in the external input buffer that have not yet
+been copied into the internal input buffer (variable bytesValid). Once the
+external buffer has been fully copied, it can be completely re-filled again. In
+case you wish to refill the buffer while there are unprocessed bytes (bytesValid
+is unequal 0), you should preserve the unconsumed data. However, we recommend to
+refill the buffer only when bytesValid returns 0.
 
 The bytesValid parameter is an input and output parameter to the FDK decoder. As
 an input, it signals how many valid bytes are available in the external buffer.
@@ -340,10 +318,7 @@
 In case a Program Config is included in the audio configuration, the channel
 mapping described within it will be adopted.
 
-In case of MPEG-D Surround the channel mapping will follow the same criteria
-described in ISO/IEC 13818-7:2005(E), but adding corresponding top channels (if
-available) to the channel types in order to avoid ambiguity. The examples below
-explain these aspects in detail.
+The examples below explain these aspects in detail.
 
 \section OutputFormatChange Changing the audio output format
 
@@ -689,9 +664,7 @@
                      2. If the parameter value is greater than that of
                  ::AAC_PCM_MAX_OUTPUT_CHANNELS both will be set to the same
                  value. \n
-                     3. This parameter does not affect MPEG Surround processing.
-                 \n
-                     4. This parameter will be ignored if the number of encoded
+                     3. This parameter will be ignored if the number of encoded
                  audio channels is greater than 8. */
   AAC_PCM_MAX_OUTPUT_CHANNELS =
       0x0012, /*!< Maximum number of PCM output channels. If lower than the
@@ -718,11 +691,7 @@
                      2. If the parameter value is greater than zero but smaller
                  than ::AAC_PCM_MIN_OUTPUT_CHANNELS both will be set to same
                  value. \n
-                     3. The operating mode of the MPEG Surround module will be
-                 set accordingly. \n
-                     4. Setting this parameter with any value will disable the
-                 binaural processing of the MPEG Surround module
-                     5. This parameter will be ignored if the number of encoded
+                     3. This parameter will be ignored if the number of encoded
                  audio channels is greater than 8. */
   AAC_METADATA_PROFILE =
       0x0020, /*!< See ::AAC_MD_PROFILE for all available values. */
@@ -803,11 +772,11 @@
                  sequences for fading in and out, if provided in the
                  bitstream.\n Enabled album mode makes use of dedicated album
                  loudness information, if provided in the bitstream.\n */
-  AAC_QMF_LOWPOWER = 0x0300, /*!< Quadrature Mirror Filter (QMF) Bank processing
-                                mode. \n -1: Use internal default. Implies MPEG
-                                Surround partially complex accordingly. \n 0:
-                                Use complex QMF data mode. \n 1: Use real (low
-                                power) QMF data mode. \n */
+  AAC_QMF_LOWPOWER =
+      0x0300, /*!< Quadrature Mirror Filter (QMF) Bank processing mode. \n
+                   -1: Use internal default. \n
+                    0: Use complex QMF data mode. \n
+                    1: Use real (low power) QMF data mode. \n */
   AAC_TPDEC_CLEAR_BUFFER =
       0x0603 /*!< Clear internal bit stream buffer of transport layers. The
                 decoder will start decoding at new data passed after this event
@@ -892,15 +861,25 @@
                           1770. If no level has been found in the bitstream the
                           value is -1. */
   SCHAR
-  drcPresMode; /*!< DRC presentation mode. According to ETSI TS 101 154,
-                  this field indicates whether   light (MPEG-4 Dynamic Range
-                  Control tool) or heavy compression (DVB heavy
-                  compression)   dynamic range control shall take priority
-                  on the outputs.   For details, see ETSI TS 101 154, table
-                  C.33. Possible values are: \n   -1: No corresponding
-                  metadata found in the bitstream \n   0: DRC presentation
-                  mode not indicated \n   1: DRC presentation mode 1 \n   2:
-                  DRC presentation mode 2 \n   3: Reserved */
+  drcPresMode;        /*!< DRC presentation mode. According to ETSI TS 101 154,
+                         this field indicates whether   light (MPEG-4 Dynamic Range
+                         Control tool) or heavy compression (DVB heavy
+                         compression)   dynamic range control shall take priority
+                         on the outputs.   For details, see ETSI TS 101 154, table
+                         C.33. Possible values are: \n   -1: No corresponding
+                         metadata found in the bitstream \n   0: DRC presentation
+                         mode not indicated \n   1: DRC presentation mode 1 \n   2:
+                         DRC presentation mode 2 \n   3: Reserved */
+  INT outputLoudness; /*!< Audio output loudness in steps of -0.25 dB. Range: 0
+                         (0 dBFS) to 231 (-57.75 dBFS).\n  A value of -1
+                         indicates that no loudness metadata is present.\n  If
+                         loudness normalization is active, the value corresponds
+                         to the target loudness value set with
+                         ::AAC_DRC_REFERENCE_LEVEL.\n  If loudness normalization
+                         is not active, the output loudness value corresponds to
+                         the loudness metadata given in the bitstream.\n
+                           Loudness metadata can originate from MPEG-4 DRC or
+                         MPEG-D DRC. */
 
 } CStreamInfo;
 
@@ -1028,21 +1007,24 @@
                                              const UINT bufferSize[],
                                              UINT *bytesValid);
 
-#define AACDEC_CONCEAL                                                        \
-  1 /*!< Flag for aacDecoder_DecodeFrame(): Trigger the built-in error        \
-       concealment module to generate a substitute signal for one lost frame. \
-       New input data will not be considered. */
-#define AACDEC_FLUSH                                                         \
-  2 /*!< Flag for aacDecoder_DecodeFrame(): Flush all filterbanks to get all \
-       delayed audio without having new input data. Thus new input data will \
-       not be considered.*/
-#define AACDEC_INTR                                                         \
-  4 /*!< Flag for aacDecoder_DecodeFrame(): Signal an input bit stream data \
-       discontinuity. Resync any internals as necessary. */
-#define AACDEC_CLRHIST                                                        \
-  8 /*!< Flag for aacDecoder_DecodeFrame(): Clear all signal delay lines and  \
-       history buffers. CAUTION: This can cause discontinuities in the output \
-       signal. */
+/** Flag for aacDecoder_DecodeFrame(): Trigger the built-in error concealment
+ * module to generate a substitute signal for one lost frame. New input data
+ * will not be considered.
+ */
+#define AACDEC_CONCEAL 1
+/** Flag for aacDecoder_DecodeFrame(): Flush all filterbanks to get all delayed
+ * audio without having new input data. Thus new input data will not be
+ * considered.
+ */
+#define AACDEC_FLUSH 2
+/** Flag for aacDecoder_DecodeFrame(): Signal an input bit stream data
+ * discontinuity. Resync any internals as necessary.
+ */
+#define AACDEC_INTR 4
+/** Flag for aacDecoder_DecodeFrame(): Clear all signal delay lines and history
+ * buffers. CAUTION: This can cause discontinuities in the output signal.
+ */
+#define AACDEC_CLRHIST 8
 
 /**
  * \brief               Decode one audio frame
diff --git a/libAACdec/src/FDK_delay.cpp b/libAACdec/src/FDK_delay.cpp
index 0ab1a66..0cc869c 100644
--- a/libAACdec/src/FDK_delay.cpp
+++ b/libAACdec/src/FDK_delay.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -113,7 +113,7 @@
 
   if (delay > 0) {
     data->delay_line =
-        (INT_PCM*)FDKcalloc(num_channels * delay, sizeof(INT_PCM));
+        (PCM_DEC*)FDKcalloc(num_channels * delay, sizeof(PCM_DEC));
     if (data->delay_line == NULL) {
       return -1;
     }
@@ -126,36 +126,36 @@
   return 0;
 }
 
-void FDK_Delay_Apply(FDK_SignalDelay* data, FIXP_PCM* time_buffer,
+void FDK_Delay_Apply(FDK_SignalDelay* data, PCM_DEC* time_buffer,
                      const UINT frame_length, const UCHAR channel) {
   FDK_ASSERT(data != NULL);
 
   if (data->delay > 0) {
-    C_ALLOC_SCRATCH_START(tmp, FIXP_PCM, MAX_FRAME_LENGTH)
+    C_ALLOC_SCRATCH_START(tmp, PCM_DEC, MAX_FRAME_LENGTH)
     FDK_ASSERT(frame_length <= MAX_FRAME_LENGTH);
     FDK_ASSERT(channel < data->num_channels);
     FDK_ASSERT(time_buffer != NULL);
     if (frame_length >= data->delay) {
       FDKmemcpy(tmp, &time_buffer[frame_length - data->delay],
-                data->delay * sizeof(FIXP_PCM));
+                data->delay * sizeof(PCM_DEC));
       FDKmemmove(&time_buffer[data->delay], &time_buffer[0],
-                 (frame_length - data->delay) * sizeof(FIXP_PCM));
+                 (frame_length - data->delay) * sizeof(PCM_DEC));
       FDKmemcpy(&time_buffer[0], &data->delay_line[channel * data->delay],
-                data->delay * sizeof(FIXP_PCM));
+                data->delay * sizeof(PCM_DEC));
       FDKmemcpy(&data->delay_line[channel * data->delay], tmp,
-                data->delay * sizeof(FIXP_PCM));
+                data->delay * sizeof(PCM_DEC));
     } else {
-      FDKmemcpy(tmp, &time_buffer[0], frame_length * sizeof(FIXP_PCM));
+      FDKmemcpy(tmp, &time_buffer[0], frame_length * sizeof(PCM_DEC));
       FDKmemcpy(&time_buffer[0], &data->delay_line[channel * data->delay],
-                frame_length * sizeof(FIXP_PCM));
+                frame_length * sizeof(PCM_DEC));
       FDKmemcpy(&data->delay_line[channel * data->delay],
                 &data->delay_line[channel * data->delay + frame_length],
-                (data->delay - frame_length) * sizeof(FIXP_PCM));
+                (data->delay - frame_length) * sizeof(PCM_DEC));
       FDKmemcpy(&data->delay_line[channel * data->delay +
                                   (data->delay - frame_length)],
-                tmp, frame_length * sizeof(FIXP_PCM));
+                tmp, frame_length * sizeof(PCM_DEC));
     }
-    C_ALLOC_SCRATCH_END(tmp, FIXP_PCM, MAX_FRAME_LENGTH)
+    C_ALLOC_SCRATCH_END(tmp, PCM_DEC, MAX_FRAME_LENGTH)
   }
 
   return;
diff --git a/libAACdec/src/FDK_delay.h b/libAACdec/src/FDK_delay.h
index f89c3a2..6317d9d 100644
--- a/libAACdec/src/FDK_delay.h
+++ b/libAACdec/src/FDK_delay.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -109,7 +109,7 @@
  * Structure representing one delay element for multiple channels.
  */
 typedef struct {
-  INT_PCM* delay_line; /*!< Pointer which stores allocated delay line. */
+  PCM_DEC* delay_line; /*!< Pointer which stores allocated delay line. */
   USHORT delay;        /*!< Delay required in samples (per channel). */
   UCHAR num_channels;  /*!< Number of channels to delay. */
 } FDK_SignalDelay;
@@ -137,7 +137,7 @@
  *
  * \return void
  */
-void FDK_Delay_Apply(FDK_SignalDelay* data, FIXP_PCM* time_buffer,
+void FDK_Delay_Apply(FDK_SignalDelay* data, PCM_DEC* time_buffer,
                      const UINT frame_length, const UCHAR channel);
 
 /**
diff --git a/libAACdec/src/aac_ram.cpp b/libAACdec/src/aac_ram.cpp
index e13167d..aa8f6a6 100644
--- a/libAACdec/src/aac_ram.cpp
+++ b/libAACdec/src/aac_ram.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -105,12 +105,7 @@
 
 #define WORKBUFFER1_TAG 0
 #define WORKBUFFER2_TAG 1
-
-#define WORKBUFFER3_TAG 4
-#define WORKBUFFER4_TAG 5
-
 #define WORKBUFFER5_TAG 6
-
 #define WORKBUFFER6_TAG 7
 
 /*! The structure AAC_DECODER_INSTANCE is the top level structure holding all
@@ -169,9 +164,6 @@
 C_ALLOC_MEM_OVERLAY(WorkBufferCore2, FIXP_DBL, ((8) * 1024), SECT_DATA_L2,
                     WORKBUFFER2_TAG)
 
-C_ALLOC_MEM_OVERLAY(WorkBufferCore3, FIXP_DBL, WB_SECTION_SIZE, SECT_DATA_L2,
-                    WORKBUFFER3_TAG)
-C_AALLOC_MEM(WorkBufferCore4, FIXP_DBL, WB_SECTION_SIZE)
 C_ALLOC_MEM_OVERLAY(WorkBufferCore6, SCHAR,
                     fMax((INT)(sizeof(FIXP_DBL) * WB_SECTION_SIZE),
                          (INT)sizeof(CAacDecoderCommonData)),
diff --git a/libAACdec/src/aac_ram.h b/libAACdec/src/aac_ram.h
index a861e25..b9b95b7 100644
--- a/libAACdec/src/aac_ram.h
+++ b/libAACdec/src/aac_ram.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -136,12 +136,7 @@
 
 H_ALLOC_MEM_OVERLAY(WorkBufferCore1, CWorkBufferCore1)
 H_ALLOC_MEM_OVERLAY(WorkBufferCore2, FIXP_DBL)
-
-H_ALLOC_MEM_OVERLAY(WorkBufferCore3, FIXP_DBL)
-H_ALLOC_MEM(WorkBufferCore4, FIXP_DBL)
-
 H_ALLOC_MEM_OVERLAY(WorkBufferCore5, PCM_DEC)
-
 H_ALLOC_MEM_OVERLAY(WorkBufferCore6, SCHAR)
 
 #endif /* #ifndef AAC_RAM_H */
diff --git a/libAACdec/src/aac_rom.h b/libAACdec/src/aac_rom.h
index ffaf951..7a1597c 100644
--- a/libAACdec/src/aac_rom.h
+++ b/libAACdec/src/aac_rom.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -108,6 +108,7 @@
 #include "aacdec_hcr_types.h"
 #include "aacdec_hcrs.h"
 
+#define PCM_AAC LONG
 #define PCM_DEC FIXP_DBL
 #define MAXVAL_PCM_DEC MAXVAL_DBL
 #define MINVAL_PCM_DEC MINVAL_DBL
diff --git a/libAACdec/src/aacdec_drc.cpp b/libAACdec/src/aacdec_drc.cpp
index 4129d0f..b6f5b49 100644
--- a/libAACdec/src/aacdec_drc.cpp
+++ b/libAACdec/src/aacdec_drc.cpp
@@ -150,6 +150,20 @@
 }
 
 /*!
+\brief Reset DRC information
+
+\self Handle of DRC info
+
+\return none
+*/
+void aacDecoder_drcReset(HANDLE_AAC_DRC self) {
+  self->applyExtGain = 0;
+  self->additionalGainPrev = AACDEC_DRC_GAIN_INIT_VALUE;
+  self->additionalGainFilterState = AACDEC_DRC_GAIN_INIT_VALUE;
+  self->additionalGainFilterState1 = AACDEC_DRC_GAIN_INIT_VALUE;
+}
+
+/*!
   \brief Initialize DRC information
 
   \self Handle of DRC info
@@ -176,7 +190,6 @@
   pParams->usrBoost = FL2FXCONST_DBL(0.0f);
   pParams->targetRefLevel = 96;
   pParams->expiryFrame = AACDEC_DRC_DFLT_EXPIRY_FRAMES;
-  pParams->applyDigitalNorm = ON;
   pParams->applyHeavyCompression = OFF;
   pParams->usrApplyHeavyCompression = OFF;
 
@@ -192,6 +205,8 @@
   self->progRefLevelPresent = 0;
   self->presMode = -1;
   self->uniDrcPrecedence = 0;
+
+  aacDecoder_drcReset(self);
 }
 
 /*!
@@ -258,11 +273,8 @@
         return AAC_DEC_INVALID_HANDLE;
       }
       if (value < 0) {
-        self->params.applyDigitalNorm = OFF;
         self->params.targetRefLevel = -1;
       } else {
-        /* ref_level must be between 0 and MAX_REFERENCE_LEVEL, inclusive */
-        self->params.applyDigitalNorm = ON;
         if (self->params.targetRefLevel != (SCHAR)value) {
           self->params.targetRefLevel = (SCHAR)value;
           self->progRefLevel = (SCHAR)value; /* Always set the program reference
@@ -273,16 +285,6 @@
         self->update = 1;
       }
       break;
-    case APPLY_NORMALIZATION:
-      if ((value != OFF) && (value != ON)) {
-        return AAC_DEC_SET_PARAM_FAIL;
-      }
-      if (self == NULL) {
-        return AAC_DEC_INVALID_HANDLE;
-      }
-      /* Store new parameter value */
-      self->params.applyDigitalNorm = (UCHAR)value;
-      break;
     case APPLY_HEAVY_COMPRESSION:
       if ((value != OFF) && (value != ON)) {
         return AAC_DEC_SET_PARAM_FAIL;
@@ -910,11 +912,9 @@
       FDK_ASSERT(0);
     }
   }
-  if (self->params.applyDigitalNorm == OFF) {
-    /* Reset normalization gain since this module must not apply it */
-    norm_mantissa = FL2FXCONST_DBL(0.5f);
-    norm_exponent = 1;
-  }
+  /* Reset normalization gain since this module must not apply it */
+  norm_mantissa = FL2FXCONST_DBL(0.5f);
+  norm_exponent = 1;
 
   /* calc scale factors */
   for (band = 0; band < numBands; band++) {
@@ -1353,3 +1353,152 @@
     }
   }
 }
+
+/**
+ * \brief  Apply DRC Level Normalization.
+ *
+ *         This function prepares/applies the gain values for the DRC Level
+ * Normalization and returns the exponent of the time data. The following two
+ * cases are handled:
+ *
+ *         - Limiter enabled:
+ *           The input data must be interleaved.
+ *           One gain per sample is written to the buffer pGainPerSample.
+ *           If necessary the time data is rescaled.
+ *
+ *         - Limiter disabled:
+ *           The input data can be interleaved or deinterleaved.
+ *           The gain values are applied to the time data.
+ *           If necessary the time data is rescaled.
+ *
+ * \param hDrcInfo                     [i/o] handle to drc data structure.
+ * \param samplesIn                    [i/o] pointer to time data.
+ * \param pGain                        [i  ] pointer to gain to be applied to
+ * the time data.
+ * \param pGainPerSample               [o  ] pointer to the gain per sample to
+ * be applied to the time data in the limiter.
+ * \param gain_scale                   [i  ] exponent to be applied to the time
+ * data.
+ * \param gain_delay                   [i  ] delay[samples] with which the gains
+ * in pGain shall be applied (gain_delay <= nSamples).
+ * \param nSamples                     [i  ] number of samples per frame.
+ * \param channels                     [i  ] number of channels.
+ * \param stride                       [i  ] channel stride of time data.
+ * \param limiterEnabled               [i  ] 1 if limiter is enabled, otherwise
+ * 0.
+ *
+ * \return exponent of time data
+ */
+INT applyDrcLevelNormalization(HANDLE_AAC_DRC hDrcInfo, PCM_DEC *samplesIn,
+                               FIXP_DBL *pGain, FIXP_DBL *pGainPerSample,
+                               const INT gain_scale, const UINT gain_delay,
+                               const UINT nSamples, const UINT channels,
+                               const UINT stride, const UINT limiterEnabled) {
+  UINT i;
+  INT additionalGain_scaling;
+  FIXP_DBL additionalGain;
+
+  FDK_ASSERT(gain_delay <= nSamples);
+
+  FIXP_DBL additionalGainSmoothState = hDrcInfo->additionalGainFilterState;
+  FIXP_DBL additionalGainSmoothState1 = hDrcInfo->additionalGainFilterState1;
+
+  if (!gain_delay) {
+    additionalGain = pGain[0];
+
+    /* Apply the additional scaling gain_scale[0] that has no delay and no
+     * smoothing */
+    additionalGain_scaling =
+        fMin(gain_scale, CntLeadingZeros(additionalGain) - 1);
+    additionalGain = scaleValue(additionalGain, additionalGain_scaling);
+
+    /* if it's not possible to fully apply gain_scale to additionalGain, apply
+     * it to the input signal */
+    additionalGain_scaling -= gain_scale;
+
+    if (additionalGain_scaling) {
+      scaleValuesSaturate(samplesIn, channels * nSamples,
+                          -additionalGain_scaling);
+    }
+
+    if (limiterEnabled) {
+      FDK_ASSERT(pGainPerSample != NULL);
+
+      for (i = 0; i < nSamples; i++) {
+        pGainPerSample[i] = additionalGain;
+      }
+    } else {
+      for (i = 0; i < channels * nSamples; i++) {
+        samplesIn[i] = FIXP_DBL2PCM_DEC(fMult(samplesIn[i], additionalGain));
+      }
+    }
+  } else {
+    UINT inc;
+    FIXP_DBL additionalGainUnfiltered;
+
+    inc = (stride == 1) ? channels : 1;
+
+    for (i = 0; i < nSamples; i++) {
+      if (i < gain_delay) {
+        additionalGainUnfiltered = hDrcInfo->additionalGainPrev;
+      } else {
+        additionalGainUnfiltered = pGain[0];
+      }
+
+      /* Smooth additionalGain */
+
+      /* [b,a] = butter(1, 0.01) */
+      static const FIXP_SGL b[] = {FL2FXCONST_SGL(0.015466 * 2.0),
+                                   FL2FXCONST_SGL(0.015466 * 2.0)};
+      static const FIXP_SGL a[] = {(FIXP_SGL)MAXVAL_SGL,
+                                   FL2FXCONST_SGL(-0.96907)};
+
+      additionalGain = -fMult(additionalGainSmoothState, a[1]) +
+                       fMultDiv2(additionalGainUnfiltered, b[0]) +
+                       fMultDiv2(additionalGainSmoothState1, b[1]);
+      additionalGainSmoothState1 = additionalGainUnfiltered;
+      additionalGainSmoothState = additionalGain;
+
+      /* Apply the additional scaling gain_scale[0] that has no delay and no
+       * smoothing */
+      additionalGain_scaling =
+          fMin(gain_scale, CntLeadingZeros(additionalGain) - 1);
+      additionalGain = scaleValue(additionalGain, additionalGain_scaling);
+
+      /* if it's not possible to fully apply gain_scale[0] to additionalGain,
+       * apply it to the input signal */
+      additionalGain_scaling -= gain_scale;
+
+      if (limiterEnabled) {
+        FDK_ASSERT(stride == 1);
+        FDK_ASSERT(pGainPerSample != NULL);
+
+        if (additionalGain_scaling) {
+          scaleValuesSaturate(samplesIn, channels, -additionalGain_scaling);
+        }
+
+        pGainPerSample[i] = additionalGain;
+      } else {
+        if (additionalGain_scaling) {
+          for (UINT k = 0; k < channels; k++) {
+            scaleValuesSaturate(&samplesIn[k * stride], 1,
+                                -additionalGain_scaling);
+          }
+        }
+
+        for (UINT k = 0; k < channels; k++) {
+          samplesIn[k * stride] =
+              FIXP_DBL2PCM_DEC(fMult(samplesIn[k * stride], additionalGain));
+        }
+      }
+
+      samplesIn += inc;
+    }
+  }
+
+  hDrcInfo->additionalGainPrev = pGain[0];
+  hDrcInfo->additionalGainFilterState = additionalGainSmoothState;
+  hDrcInfo->additionalGainFilterState1 = additionalGainSmoothState1;
+
+  return (AACDEC_DRC_GAIN_SCALING);
+}
diff --git a/libAACdec/src/aacdec_drc.h b/libAACdec/src/aacdec_drc.h
index 924ec6f..76a44d6 100644
--- a/libAACdec/src/aacdec_drc.h
+++ b/libAACdec/src/aacdec_drc.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -109,6 +109,11 @@
 #include "channel.h"
 #include "FDK_bitstream.h"
 
+#define AACDEC_DRC_GAIN_SCALING (11) /* Scaling of DRC gains */
+#define AACDEC_DRC_GAIN_INIT_VALUE \
+  (FL2FXCONST_DBL(                 \
+      1.0f / (1 << AACDEC_DRC_GAIN_SCALING))) /* Init value for DRC gains */
+
 #define AACDEC_DRC_DFLT_EXPIRY_FRAMES \
   (0) /* Default DRC data expiry time in AAC frames   */
 
@@ -125,7 +130,6 @@
   TARGET_REF_LEVEL,
   DRC_BS_DELAY,
   DRC_DATA_EXPIRY_FRAME,
-  APPLY_NORMALIZATION,
   APPLY_HEAVY_COMPRESSION,
   DEFAULT_PRESENTATION_MODE,
   ENCODER_TARGET_LEVEL,
@@ -136,6 +140,8 @@
 /**
  * \brief DRC module interface functions
  */
+void aacDecoder_drcReset(HANDLE_AAC_DRC self);
+
 void aacDecoder_drcInit(HANDLE_AAC_DRC self);
 
 void aacDecoder_drcInitChannelData(CDrcChannelData *pDrcChannel);
@@ -189,4 +195,45 @@
 void aacDecoder_drcGetInfo(HANDLE_AAC_DRC self, SCHAR *pPresMode,
                            SCHAR *pProgRefLevel);
 
+/**
+ * \brief  Apply DRC Level Normalization.
+ *
+ *         This function prepares/applies the gain values for the DRC Level
+ * Normalization and returns the exponent of the time data. The following two
+ * cases are handled:
+ *
+ *         - Limiter enabled:
+ *           The input data must be interleaved.
+ *           One gain per sample is written to the buffer pGainPerSample.
+ *           If necessary the time data is rescaled.
+ *
+ *         - Limiter disabled:
+ *           The input data can be interleaved or deinterleaved.
+ *           The gain values are applied to the time data.
+ *           If necessary the time data is rescaled.
+ *
+ * \param hDrcInfo                     [i/o] handle to drc data structure.
+ * \param samplesIn                    [i/o] pointer to time data.
+ * \param pGain                        [i  ] pointer to gain to be applied to
+ * the time data.
+ * \param pGainPerSample               [o  ] pointer to the gain per sample to
+ * be applied to the time data in the limiter.
+ * \param gain_scale                   [i  ] exponent to be applied to the time
+ * data.
+ * \param gain_delay                   [i  ] delay[samples] with which the gains
+ * in pGain shall be applied (gain_delay <= nSamples).
+ * \param nSamples                     [i  ] number of samples per frame.
+ * \param channels                     [i  ] number of channels.
+ * \param stride                       [i  ] channel stride of time data.
+ * \param limiterEnabled               [i  ] 1 if limiter is enabled, otherwise
+ * 0.
+ *
+ * \return exponent of time data
+ */
+INT applyDrcLevelNormalization(HANDLE_AAC_DRC hDrcInfo, PCM_DEC *samplesIn,
+                               FIXP_DBL *pGain, FIXP_DBL *pGainPerSample,
+                               const INT gain_scale, const UINT gain_delay,
+                               const UINT nSamples, const UINT channels,
+                               const UINT stride, const UINT limiterEnabled);
+
 #endif /* AACDEC_DRC_H */
diff --git a/libAACdec/src/aacdec_drc_types.h b/libAACdec/src/aacdec_drc_types.h
index 76c35d0..d4393f7 100644
--- a/libAACdec/src/aacdec_drc_types.h
+++ b/libAACdec/src/aacdec_drc_types.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -168,7 +168,6 @@
 
   UINT expiryFrame;
   UCHAR bsDelayEnable;
-  UCHAR applyDigitalNorm;
 
   AACDEC_DRC_PARAMETER_HANDLING defaultPresentationMode;
   UCHAR encoderTargetLevel;
@@ -213,6 +212,13 @@
   uniDrcPrecedence; /* Flag for signalling that uniDrc is active and takes
                        precedence over legacy DRC */
 
+  UCHAR applyExtGain; /* Flag is 1 if extGain has to be applied, otherwise 0. */
+
+  FIXP_DBL additionalGainPrev; /* Gain of previous frame to be applied to the
+                                  time data */
+  FIXP_DBL additionalGainFilterState;  /* Filter state for the gain smoothing */
+  FIXP_DBL additionalGainFilterState1; /* Filter state for the gain smoothing */
+
 } CDrcInfo;
 
 typedef CDrcInfo *HANDLE_AAC_DRC;
diff --git a/libAACdec/src/aacdec_hcr.cpp b/libAACdec/src/aacdec_hcr.cpp
index 6114756..a7e9cce 100644
--- a/libAACdec/src/aacdec_hcr.cpp
+++ b/libAACdec/src/aacdec_hcr.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -137,7 +137,7 @@
 static INT DecodeEscapeSequence(HANDLE_FDK_BITSTREAM bs, const INT bsAnchor,
                                 INT quantSpecCoef, INT *pLeftStartOfSegment,
                                 SCHAR *pRemainingBitsInSegment,
-                                int *pNumDecodedBits);
+                                int *pNumDecodedBits, UINT *errorWord);
 
 static int DecodePCW_Sign(HANDLE_FDK_BITSTREAM bs, const INT bsAnchor,
                           UINT codebookDim, const SCHAR *pQuantVal,
@@ -1179,8 +1179,8 @@
                   bs, pHcr->decInOut.bitstreamAnchor,
                   pQuantizedSpectralCoefficients
                       [quantizedSpectralCoefficientsIdx],
-                  pLeftStartOfSegment, pRemainingBitsInSegment,
-                  &numDecodedBits);
+                  pLeftStartOfSegment, pRemainingBitsInSegment, &numDecodedBits,
+                  &pHcr->decInOut.errorLog);
         }
         quantizedSpectralCoefficientsIdx++;
         if (quantizedSpectralCoefficientsIdx >= 1024) {
@@ -1195,8 +1195,8 @@
                   bs, pHcr->decInOut.bitstreamAnchor,
                   pQuantizedSpectralCoefficients
                       [quantizedSpectralCoefficientsIdx],
-                  pLeftStartOfSegment, pRemainingBitsInSegment,
-                  &numDecodedBits);
+                  pLeftStartOfSegment, pRemainingBitsInSegment, &numDecodedBits,
+                  &pHcr->decInOut.errorLog);
         }
         quantizedSpectralCoefficientsIdx++;
         if (quantizedSpectralCoefficientsIdx >= 1024) {
@@ -1386,7 +1386,7 @@
 static INT DecodeEscapeSequence(HANDLE_FDK_BITSTREAM bs, const INT bsAnchor,
                                 INT quantSpecCoef, INT *pLeftStartOfSegment,
                                 SCHAR *pRemainingBitsInSegment,
-                                int *pNumDecodedBits) {
+                                int *pNumDecodedBits, UINT *errorWord) {
   UINT i;
   INT sign;
   UINT escapeOnesCounter = 0;
@@ -1400,6 +1400,9 @@
                                        FROM_LEFT_TO_RIGHT);
     *pRemainingBitsInSegment -= 1;
     *pNumDecodedBits += 1;
+    if (*pRemainingBitsInSegment < 0) {
+      return Q_VALUE_INVALID;
+    }
 
     if (carryBit != 0) {
       escapeOnesCounter += 1;
@@ -1416,6 +1419,9 @@
                                        FROM_LEFT_TO_RIGHT);
     *pRemainingBitsInSegment -= 1;
     *pNumDecodedBits += 1;
+    if (*pRemainingBitsInSegment < 0) {
+      return Q_VALUE_INVALID;
+    }
 
     escape_word <<= 1;
     escape_word = escape_word | carryBit;
@@ -1423,8 +1429,12 @@
 
   sign = (quantSpecCoef >= 0) ? 1 : -1;
 
-  quantSpecCoef = sign * (((INT)1 << escapeOnesCounter) + escape_word);
-
+  if (escapeOnesCounter < 13) {
+    quantSpecCoef = sign * (((INT)1 << escapeOnesCounter) + escape_word);
+  } else {
+    *errorWord |= TOO_MANY_PCW_BODY_SIGN_ESC_BITS_DECODED;
+    quantSpecCoef = Q_VALUE_INVALID;
+  }
   return quantSpecCoef;
 }
 
diff --git a/libAACdec/src/aacdec_hcrs.cpp b/libAACdec/src/aacdec_hcrs.cpp
index d2bc867..44b32a5 100644
--- a/libAACdec/src/aacdec_hcrs.cpp
+++ b/libAACdec/src/aacdec_hcrs.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -1324,6 +1324,10 @@
     /* count ones and store sum in escapePrefixUp */
     if (carryBit == 1) {
       escapePrefixUp += 1; /* update conter for ones */
+      if (escapePrefixUp > 8) {
+        pHcr->decInOut.errorLog |= STATE_ERROR_BODY_SIGN_ESC__ESC_PREFIX;
+        return BODY_SIGN_ESC__ESC_PREFIX;
+      }
 
       /* store updated counter in sideinfo of current codeword */
       pEscapeSequenceInfo[codewordOffset] &=
diff --git a/libAACdec/src/aacdecoder.cpp b/libAACdec/src/aacdecoder.cpp
index 7617937..965631b 100644
--- a/libAACdec/src/aacdecoder.cpp
+++ b/libAACdec/src/aacdecoder.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -1225,6 +1225,8 @@
   pStreamInfo->drcProgRefLev =
       -1; /* set program reference level to not indicated */
   pStreamInfo->drcPresMode = -1; /* default: presentation mode not indicated */
+
+  pStreamInfo->outputLoudness = -1; /* default: no loudness metadata present */
 }
 
 /*!
@@ -1279,6 +1281,7 @@
   /* Set default frame delay */
   aacDecoder_drcSetParam(self->hDrcInfo, DRC_BS_DELAY,
                          CConcealment_GetDelay(&self->concealCommonData));
+  self->workBufferCore1 = (FIXP_DBL *)GetWorkBufferCore1();
 
   self->workBufferCore2 = GetWorkBufferCore2();
   if (self->workBufferCore2 == NULL) goto bail;
@@ -1303,7 +1306,8 @@
                                const int subStreamIndex) {
   int ch;
   int aacChannelOffset = 0, aacChannels = (8);
-  int numElements = (((8)) + (8)), elementOffset = 0;
+  int numElements = (3 * ((8) * 2) + (((8) * 2)) / 2 + 4 * (1) + 1),
+      elementOffset = 0;
 
   if (self == NULL) return;
 
@@ -1453,6 +1457,10 @@
     FreeDrcInfo(&self->hDrcInfo);
   }
 
+  if (self->workBufferCore1 != NULL) {
+    FreeWorkBufferCore1((CWorkBufferCore1 **)&self->workBufferCore1);
+  }
+
   /* Free WorkBufferCore2 */
   if (self->workBufferCore2 != NULL) {
     FreeWorkBufferCore2(&self->workBufferCore2);
@@ -1490,6 +1498,8 @@
   UCHAR downscaleFactor = self->downscaleFactor;
   UCHAR downscaleFactorInBS = self->downscaleFactorInBS;
 
+  self->aacOutDataHeadroom = (3);
+
   // set profile and check for supported aot
   // leave profile on default (=-1) for all other supported MPEG-4 aot's except
   // aot=2 (=AAC-LC)
@@ -1847,6 +1857,12 @@
           self->streamInfo.extSamplingRate / self->downscaleFactor;
     }
   }
+  if ((asc->m_aot == AOT_AAC_LC) && (asc->m_sbrPresentFlag == 1) &&
+      (asc->m_extensionSamplingFrequency > (2 * asc->m_samplingFrequency))) {
+    return AAC_DEC_UNSUPPORTED_SAMPLINGRATE; /* Core decoder supports at most a
+                                                1:2 upsampling for HE-AAC and
+                                                HE-AACv2 */
+  }
 
   /* --------- vcb11 ------------ */
   self->flags[streamIndex] |= (asc->m_vcb11Flag) ? AC_ER_VCB11 : 0;
@@ -1928,6 +1944,9 @@
           self->samplingRateInfo[0].samplingRate / self->downscaleFactor;
       self->streamInfo.aacSamplesPerFrame =
           asc->m_samplesPerFrame / self->downscaleFactor;
+      if (self->streamInfo.aacSampleRate <= 0) {
+        return AAC_DEC_UNSUPPORTED_SAMPLINGRATE;
+      }
     }
   }
 
@@ -2362,6 +2381,13 @@
       goto bail;
   }
 
+  if (*configChanged) {
+    if (asc->m_aot == AOT_USAC) {
+      self->hDrcInfo->enable = 0;
+      self->hDrcInfo->progRefLevelPresent = 0;
+    }
+  }
+
   if (asc->m_aot == AOT_USAC) {
     pcmLimiter_SetAttack(self->hLimiter, (5));
     pcmLimiter_SetThreshold(self->hLimiter, FL2FXCONST_DBL(0.89125094f));
@@ -2375,7 +2401,7 @@
 }
 
 LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
-    HANDLE_AACDECODER self, const UINT flags, FIXP_PCM *pTimeData,
+    HANDLE_AACDECODER self, const UINT flags, PCM_DEC *pTimeData,
     const INT timeDataSize, const int timeDataChannelOffset) {
   AAC_DECODER_ERROR ErrorStatus = AAC_DEC_OK;
 
@@ -3151,11 +3177,6 @@
       FDKmemcpy(drcChMap, self->chMapping, (8) * sizeof(UCHAR));
     }
 
-    /* Turn on/off DRC modules level normalization in digital domain depending
-     * on the limiter status. */
-    aacDecoder_drcSetParam(self->hDrcInfo, APPLY_NORMALIZATION,
-                           (self->limiterEnableCurr) ? 0 : 1);
-
     /* deactivate legacy DRC in case uniDrc is active, i.e. uniDrc payload is
      * present and one of DRC or Loudness Normalization is switched on */
     aacDecoder_drcSetParam(
@@ -3168,9 +3189,15 @@
         self->hDrcInfo, bs, self->pAacDecoderStaticChannelInfo,
         pce->ElementInstanceTag, drcChMap, aacChannels);
     if (mapped > 0) {
-      /* If at least one DRC thread has been mapped to a channel threre was DRC
-       * data in the bitstream. */
-      self->flags[streamIndex] |= AC_DRC_PRESENT;
+      if (!(self->flags[streamIndex] & (AC_USAC | AC_RSV603DA))) {
+        /* If at least one DRC thread has been mapped to a channel there was DRC
+         * data in the bitstream. */
+        self->flags[streamIndex] |= AC_DRC_PRESENT;
+      } else {
+        self->hDrcInfo->enable = 0;
+        self->hDrcInfo->progRefLevelPresent = 0;
+        ErrorStatus = AAC_DEC_UNSUPPORTED_FORMAT;
+      }
     }
 
     /* Create a reverse mapping table */
@@ -3300,9 +3327,11 @@
                 &pAacDecoderStaticChannelInfo->drcData);
           }
         }
+
         /* The DRC module demands to be called with the gain field holding the
          * gain scale. */
-        self->extGain[0] = (FIXP_DBL)TDL_GAIN_SCALING;
+        self->extGain[0] = (FIXP_DBL)AACDEC_DRC_GAIN_SCALING;
+
         /* DRC processing */
         aacDecoder_drcApply(
             self->hDrcInfo, self->hSbrDecoder, pAacDecoderChannelInfo,
@@ -3318,7 +3347,7 @@
         if (self->flushStatus && (self->flushCnt > 0) &&
             !(flags & AACDEC_CONCEAL)) {
           FDKmemclear(pTimeData + offset,
-                      sizeof(FIXP_PCM) * self->streamInfo.aacSamplesPerFrame);
+                      sizeof(PCM_DEC) * self->streamInfo.aacSamplesPerFrame);
         } else
           switch (pAacDecoderChannelInfo->renderMode) {
             case AACDEC_RENDER_IMDCT:
@@ -3330,7 +3359,7 @@
                    !frameOk_butConceal),
                   pAacDecoderChannelInfo->pComStaticData->pWorkBufferCore1
                       ->mdctOutTemp,
-                  self->elFlags[el], elCh);
+                  self->aacOutDataHeadroom, self->elFlags[el], elCh);
 
               self->extGainDelay = self->streamInfo.aacSamplesPerFrame;
               break;
@@ -3351,7 +3380,7 @@
                   &self->samplingRateInfo[streamIndex],
                   (self->frameOK && !(flags & AACDEC_CONCEAL) &&
                    !frameOk_butConceal),
-                  flags, self->flags[streamIndex]);
+                  self->aacOutDataHeadroom, flags, self->flags[streamIndex]);
 
               self->extGainDelay = self->streamInfo.aacSamplesPerFrame;
               break;
@@ -3363,7 +3392,8 @@
         if (!CConceal_TDFading_Applied[c]) {
           CConceal_TDFading_Applied[c] = CConcealment_TDFading(
               self->streamInfo.aacSamplesPerFrame,
-              &self->pAacDecoderStaticChannelInfo[c], pTimeData + offset, 0);
+              &self->pAacDecoderStaticChannelInfo[c], self->aacOutDataHeadroom,
+              pTimeData + offset, 0);
           if (c + 1 < (8) && c < aacChannels - 1) {
             /* update next TDNoise Seed to avoid muting in case of Parametric
              * Stereo */
@@ -3385,22 +3415,17 @@
       if ((aacChannels == 2) && bsPseudoLr) {
         int i, offset2;
         const FIXP_SGL invSqrt2 = FL2FXCONST_SGL(0.707106781186547f);
-        FIXP_PCM *pTD = pTimeData;
+        PCM_DEC *pTD = pTimeData;
 
         offset2 = timeDataChannelOffset;
 
         for (i = 0; i < self->streamInfo.aacSamplesPerFrame; i++) {
-          FIXP_DBL L = FX_PCM2FX_DBL(pTD[0]);
-          FIXP_DBL R = FX_PCM2FX_DBL(pTD[offset2]);
+          FIXP_DBL L = PCM_DEC2FIXP_DBL(pTD[0]);
+          FIXP_DBL R = PCM_DEC2FIXP_DBL(pTD[offset2]);
           L = fMult(L, invSqrt2);
           R = fMult(R, invSqrt2);
-#if (SAMPLE_BITS == 16)
-          pTD[0] = FX_DBL2FX_PCM(fAddSaturate(L + R, (FIXP_DBL)0x8000));
-          pTD[offset2] = FX_DBL2FX_PCM(fAddSaturate(L - R, (FIXP_DBL)0x8000));
-#else
-          pTD[0] = FX_DBL2FX_PCM(L + R);
-          pTD[offset2] = FX_DBL2FX_PCM(L - R);
-#endif
+          pTD[0] = L + R;
+          pTD[offset2] = L - R;
           pTD++;
         }
       }
@@ -3411,9 +3436,15 @@
         self->hDrcInfo, bs, self->pAacDecoderStaticChannelInfo,
         pce->ElementInstanceTag, drcChMap, aacChannels);
     if (mapped > 0) {
-      /* If at least one DRC thread has been mapped to a channel threre was DRC
-       * data in the bitstream. */
-      self->flags[streamIndex] |= AC_DRC_PRESENT;
+      if (!(self->flags[streamIndex] & (AC_USAC | AC_RSV603DA))) {
+        /* If at least one DRC thread has been mapped to a channel there was DRC
+         * data in the bitstream. */
+        self->flags[streamIndex] |= AC_DRC_PRESENT;
+      } else {
+        self->hDrcInfo->enable = 0;
+        self->hDrcInfo->progRefLevelPresent = 0;
+        ErrorStatus = AAC_DEC_UNSUPPORTED_FORMAT;
+      }
     }
   }
 
diff --git a/libAACdec/src/aacdecoder.h b/libAACdec/src/aacdecoder.h
index 20f4c45..bd1f38f 100644
--- a/libAACdec/src/aacdecoder.h
+++ b/libAACdec/src/aacdecoder.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -191,6 +191,9 @@
   INT outputInterleaved; /*!< PCM output format (interleaved/none interleaved).
                           */
 
+  INT aacOutDataHeadroom; /*!< Headroom of the output time signal to prevent
+                             clipping */
+
   HANDLE_TRANSPORTDEC hInput; /*!< Transport layer handle. */
 
   SamplingRateInfo
@@ -235,6 +238,7 @@
   CAacDecoderStaticChannelInfo
       *pAacDecoderStaticChannelInfo[(8)]; /*!< Persistent channel memory */
 
+  FIXP_DBL *workBufferCore1;
   FIXP_DBL *workBufferCore2;
   PCM_DEC *pTimeData2;
   INT timeData2Size;
@@ -311,11 +315,10 @@
   UCHAR limiterEnableUser; /*!< The limiter configuration requested by the
                               library user */
   UCHAR limiterEnableCurr; /*!< The current limiter configuration.         */
+
   FIXP_DBL extGain[1]; /*!< Gain that must be applied to the output signal. */
   UINT extGainDelay;   /*!< Delay that must be accounted for extGain. */
 
-  INT_PCM pcmOutputBuffer[(8) * (1024 * 2)];
-
   HANDLE_DRC_DECODER hUniDrcDecoder;
   UCHAR multibandDrcPresent;
   UCHAR numTimeSlots;
@@ -427,7 +430,7 @@
   \return  error status
 */
 LINKSPEC_H AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
-    HANDLE_AACDECODER self, const UINT flags, FIXP_PCM *pTimeData,
+    HANDLE_AACDECODER self, const UINT flags, PCM_DEC *pTimeData,
     const INT timeDataSize, const int timeDataChannelOffset);
 
 /* Free config dependent AAC memory */
diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp
index 86ec899..f5ce7e0 100644
--- a/libAACdec/src/aacdecoder_lib.cpp
+++ b/libAACdec/src/aacdecoder_lib.cpp
@@ -119,8 +119,8 @@
 
 /* Decoder library info */
 #define AACDECODER_LIB_VL0 3
-#define AACDECODER_LIB_VL1 1
-#define AACDECODER_LIB_VL2 2
+#define AACDECODER_LIB_VL1 2
+#define AACDECODER_LIB_VL2 0
 #define AACDECODER_LIB_TITLE "AAC Decoder Lib"
 #ifdef __ANDROID__
 #define AACDECODER_LIB_BUILD_DATE ""
@@ -1131,35 +1131,31 @@
   return n;
 }
 
-LINKSPEC_CPP AAC_DECODER_ERROR
-aacDecoder_DecodeFrame(HANDLE_AACDECODER self, INT_PCM *pTimeData_extern,
-                       const INT timeDataSize_extern, const UINT flags) {
+LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(HANDLE_AACDECODER self,
+                                                      INT_PCM *pTimeData,
+                                                      const INT timeDataSize,
+                                                      const UINT flags) {
   AAC_DECODER_ERROR ErrorStatus;
   INT layer;
   INT nBits;
+  INT timeData2Size;
+  INT timeData3Size;
+  INT timeDataHeadroom;
   HANDLE_FDK_BITSTREAM hBs;
   int fTpInterruption = 0; /* Transport originated interruption detection. */
   int fTpConceal = 0;      /* Transport originated concealment. */
-  INT_PCM *pTimeData = NULL;
-  INT timeDataSize = 0;
   UINT accessUnit = 0;
   UINT numAccessUnits = 1;
   UINT numPrerollAU = 0;
-  int fEndAuNotAdjusted = 0;  /* The end of the access unit was not adjusted */
-  int applyCrossfade = 1;     /* flag indicates if flushing was possible */
-  FIXP_PCM *pTimeDataFixpPcm; /* Signal buffer for decoding process before PCM
-                                 processing */
-  INT timeDataFixpPcmSize;
-  PCM_DEC *pTimeDataPcmPost; /* Signal buffer for PCM post-processing */
-  INT timeDataPcmPostSize;
+  int fEndAuNotAdjusted = 0; /* The end of the access unit was not adjusted */
+  int applyCrossfade = 1;    /* flag indicates if flushing was possible */
+  PCM_DEC *pTimeData2;
+  PCM_AAC *pTimeData3;
 
   if (self == NULL) {
     return AAC_DEC_INVALID_HANDLE;
   }
 
-  pTimeData = self->pcmOutputBuffer;
-  timeDataSize = sizeof(self->pcmOutputBuffer) / sizeof(*self->pcmOutputBuffer);
-
   if (flags & AACDEC_INTR) {
     self->streamInfo.numLostAccessUnits = 0;
   }
@@ -1269,9 +1265,9 @@
     }
 
     /* Signal bit stream interruption to other modules if required. */
-    if (fTpInterruption || (flags & AACDEC_INTR)) {
+    if (fTpInterruption || ((flags & AACDEC_INTR) && (accessUnit == 0))) {
       aacDecoder_SignalInterruption(self);
-      if (!(flags & AACDEC_INTR)) {
+      if (!((flags & AACDEC_INTR) && (accessUnit == 0))) {
         ErrorStatus = AAC_DEC_TRANSPORT_SYNC_ERROR;
         goto bail;
       }
@@ -1315,19 +1311,23 @@
       /* Use limiter configuration as requested. */
       self->limiterEnableCurr = self->limiterEnableUser;
     }
-    /* reset limiter gain on a per frame basis */
-    self->extGain[0] = FL2FXCONST_DBL(1.0f / (float)(1 << TDL_GAIN_SCALING));
 
-    pTimeDataFixpPcm = pTimeData;
-    timeDataFixpPcmSize = timeDataSize;
+    /* reset DRC level normalization gain on a per frame basis */
+    self->extGain[0] = AACDEC_DRC_GAIN_INIT_VALUE;
+
+    pTimeData2 = self->pTimeData2;
+    timeData2Size = self->timeData2Size / sizeof(PCM_DEC);
+    pTimeData3 = (PCM_AAC *)self->pTimeData2;
+    timeData3Size = self->timeData2Size / sizeof(PCM_AAC);
 
     ErrorStatus = CAacDecoder_DecodeFrame(
         self,
         flags | (fTpConceal ? AACDEC_CONCEAL : 0) |
             ((self->flushStatus && !(flags & AACDEC_CONCEAL)) ? AACDEC_FLUSH
                                                               : 0),
-        pTimeDataFixpPcm + 0, timeDataFixpPcmSize,
-        self->streamInfo.aacSamplesPerFrame + 0);
+        pTimeData2 + 0, timeData2Size, self->streamInfo.aacSamplesPerFrame + 0);
+
+    timeDataHeadroom = self->aacOutDataHeadroom;
 
     /* if flushing for USAC DASH IPF was not possible go on with decoding
      * preroll */
@@ -1352,7 +1352,7 @@
         }
       }
 
-      /* If the current pTimeDataFixpPcm does not contain a valid signal, there
+      /* If the current pTimeData2 does not contain a valid signal, there
        * nothing else we can do, so bail. */
       if (!IS_OUTPUT_VALID(ErrorStatus)) {
         goto bail;
@@ -1366,10 +1366,10 @@
       self->streamInfo.numChannels = self->streamInfo.aacNumChannels;
 
       {
-        FDK_Delay_Apply(&self->usacResidualDelay,
-                        pTimeDataFixpPcm +
-                            1 * (self->streamInfo.aacSamplesPerFrame + 0) + 0,
-                        self->streamInfo.frameSize, 0);
+        FDK_Delay_Apply(
+            &self->usacResidualDelay,
+            pTimeData2 + 1 * (self->streamInfo.aacSamplesPerFrame + 0) + 0,
+            self->streamInfo.frameSize, 0);
       }
 
       /* Setting of internal MPS state; may be reset in CAacDecoder_SyncQmfMode
@@ -1416,8 +1416,6 @@
         }
       }
 
-      self->qmfDomain.globalConf.TDinput = pTimeData;
-
       switch (FDK_QmfDomain_Configure(&self->qmfDomain)) {
         default:
         case QMF_DOMAIN_INIT_ERROR:
@@ -1474,18 +1472,18 @@
         sbrDecoder_SetParam(self->hSbrDecoder, SBR_SKIP_QMF,
                             (self->mpsEnableCurr) ? 2 : 0);
 
-        INT_PCM *input;
-        input = (INT_PCM *)self->workBufferCore2;
-        FDKmemcpy(input, pTimeData,
-                  sizeof(INT_PCM) * (self->streamInfo.numChannels) *
+        PCM_AAC *input;
+        input = (PCM_AAC *)self->workBufferCore2;
+        FDKmemcpy(input, pTimeData3,
+                  sizeof(PCM_AAC) * (self->streamInfo.numChannels) *
                       (self->streamInfo.frameSize));
 
         /* apply SBR processing */
-        sbrError = sbrDecoder_Apply(self->hSbrDecoder, input, pTimeData,
-                                    timeDataSize, &self->streamInfo.numChannels,
-                                    &self->streamInfo.sampleRate,
-                                    &self->mapDescr, self->chMapIndex,
-                                    self->frameOK, &self->psPossible);
+        sbrError = sbrDecoder_Apply(
+            self->hSbrDecoder, input, pTimeData3, timeData3Size,
+            &self->streamInfo.numChannels, &self->streamInfo.sampleRate,
+            &self->mapDescr, self->chMapIndex, self->frameOK, &self->psPossible,
+            self->aacOutDataHeadroom, &timeDataHeadroom);
 
         if (sbrError == SBRDEC_OK) {
           /* Update data in streaminfo structure. Assume that the SBR upsampling
@@ -1564,10 +1562,11 @@
         if (err == 0) {
           err = mpegSurroundDecoder_Apply(
               (CMpegSurroundDecoder *)self->pMpegSurroundDecoder,
-              (INT_PCM *)self->workBufferCore2, pTimeData, timeDataSize,
+              (PCM_AAC *)self->workBufferCore2, pTimeData3, timeData3Size,
               self->streamInfo.aacSamplesPerFrame, &nChannels, &frameSize,
               self->streamInfo.sampleRate, self->streamInfo.aot,
-              self->channelType, self->channelIndices, &self->mapDescr);
+              self->channelType, self->channelIndices, &self->mapDescr,
+              self->aacOutDataHeadroom, &timeDataHeadroom);
         }
 
         if (err == MPS_OUTPUT_BUFFER_TOO_SMALL) {
@@ -1590,8 +1589,8 @@
           self->streamInfo.frameSize = self->mpsFrameSizeLast;
           /* ... and clear output buffer so that potentially corrupted data does
            * not reach the framework. */
-          FDKmemclear(pTimeData, self->mpsOutChannelsLast *
-                                     self->mpsFrameSizeLast * sizeof(INT_PCM));
+          FDKmemclear(pTimeData3, self->mpsOutChannelsLast *
+                                      self->mpsFrameSizeLast * sizeof(PCM_AAC));
           /* Additionally proclaim that this frame had errors during decoding.
            */
           ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR;
@@ -1612,11 +1611,11 @@
         sbrDecoder_SetParam(self->hSbrDecoder, SBR_SKIP_QMF, 1);
 
         /* apply SBR processing */
-        sbrError = sbrDecoder_Apply(self->hSbrDecoder, pTimeData, pTimeData,
-                                    timeDataSize, &self->streamInfo.numChannels,
-                                    &self->streamInfo.sampleRate,
-                                    &self->mapDescr, self->chMapIndex,
-                                    self->frameOK, &self->psPossible);
+        sbrError = sbrDecoder_Apply(
+            self->hSbrDecoder, pTimeData3, pTimeData3, timeData3Size,
+            &self->streamInfo.numChannels, &self->streamInfo.sampleRate,
+            &self->mapDescr, self->chMapIndex, self->frameOK, &self->psPossible,
+            self->aacOutDataHeadroom, &timeDataHeadroom);
 
         if (sbrError == SBRDEC_OK) {
           /* Update data in streaminfo structure. Assume that the SBR upsampling
@@ -1644,17 +1643,15 @@
         }
       }
 
-      /* Use dedicated memory for PCM postprocessing */
-      pTimeDataPcmPost = self->pTimeData2;
-      timeDataPcmPostSize = self->timeData2Size;
-
       {
-        const int size =
-            self->streamInfo.frameSize * self->streamInfo.numChannels;
-        FDK_ASSERT(timeDataPcmPostSize >= size);
-        for (int i = 0; i < size; i++) {
-          pTimeDataPcmPost[i] =
-              (PCM_DEC)FX_PCM2PCM_DEC(pTimeData[i]) >> PCM_OUT_HEADROOM;
+        if ((INT)PCM_OUT_HEADROOM != timeDataHeadroom) {
+          for (int i = ((self->streamInfo.frameSize *
+                         self->streamInfo.numChannels) -
+                        1);
+               i >= 0; i--) {
+            pTimeData2[i] =
+                (PCM_DEC)pTimeData3[i] >> (PCM_OUT_HEADROOM - timeDataHeadroom);
+          }
         }
       }
 
@@ -1709,22 +1706,21 @@
           if ((self->streamInfo.numChannels > 1) &&
               (0 || (self->sbrEnabled) || (self->mpsEnableCurr))) {
             /* interleaving/deinterleaving is performed on upper part of
-             * pTimeDataPcmPost. Check if this buffer is large enough. */
-            if (timeDataPcmPostSize <
-                (INT)(2 * self->streamInfo.numChannels *
-                      self->streamInfo.frameSize * sizeof(PCM_DEC))) {
+             * pTimeData2. Check if this buffer is large enough. */
+            if (timeData2Size < (INT)(2 * self->streamInfo.numChannels *
+                                      self->streamInfo.frameSize)) {
               ErrorStatus = AAC_DEC_UNKNOWN;
               goto bail;
             }
             needsDeinterleaving = 1;
             drcWorkBuffer =
-                (FIXP_DBL *)pTimeDataPcmPost +
+                (FIXP_DBL *)pTimeData2 +
                 self->streamInfo.numChannels * self->streamInfo.frameSize;
             FDK_deinterleave(
-                pTimeDataPcmPost, drcWorkBuffer, self->streamInfo.numChannels,
+                pTimeData2, drcWorkBuffer, self->streamInfo.numChannels,
                 self->streamInfo.frameSize, self->streamInfo.frameSize);
           } else {
-            drcWorkBuffer = (FIXP_DBL *)pTimeDataPcmPost;
+            drcWorkBuffer = pTimeData2;
           }
 
           /* prepare Loudness Normalisation gain */
@@ -1759,16 +1755,51 @@
 
           if (needsDeinterleaving) {
             FDK_interleave(
-                drcWorkBuffer, pTimeDataPcmPost, self->streamInfo.numChannels,
+                drcWorkBuffer, pTimeData2, self->streamInfo.numChannels,
                 self->streamInfo.frameSize, self->streamInfo.frameSize);
           }
         }
       }
+      if (FDK_drcDec_GetParam(self->hUniDrcDecoder, DRC_DEC_IS_ACTIVE)) {
+        /* return output loudness information for MPEG-D DRC */
+        LONG outputLoudness =
+            FDK_drcDec_GetParam(self->hUniDrcDecoder, DRC_DEC_OUTPUT_LOUDNESS);
+        if (outputLoudness == DRC_DEC_LOUDNESS_NOT_PRESENT) {
+          /* no valid MPEG-D DRC loudness value contained */
+          self->streamInfo.outputLoudness = -1;
+        } else {
+          if (outputLoudness > 0) {
+            /* positive output loudness values (very unusual) are limited to 0
+             * dB */
+            self->streamInfo.outputLoudness = 0;
+          } else {
+            self->streamInfo.outputLoudness =
+                -(INT)outputLoudness >>
+                22; /* negate and scale from e = 7 to e = (31-2) */
+          }
+        }
+      } else {
+        /* return output loudness information for MPEG-4 DRC */
+        if (self->streamInfo.drcProgRefLev <
+            0) { /* no MPEG-4 DRC loudness metadata contained */
+          self->streamInfo.outputLoudness = -1;
+        } else {
+          if (self->defaultTargetLoudness <
+              0) { /* loudness normalization is off */
+            self->streamInfo.outputLoudness = self->streamInfo.drcProgRefLev;
+          } else {
+            self->streamInfo.outputLoudness = self->defaultTargetLoudness;
+          }
+        }
+      }
 
       if (self->streamInfo.extAot != AOT_AAC_SLS) {
         INT pcmLimiterScale = 0;
+        INT interleaved = 0;
+        interleaved |= (self->sbrEnabled) ? 1 : 0;
+        interleaved |= (self->mpsEnableCurr) ? 1 : 0;
         PCMDMX_ERROR dmxErr = PCMDMX_OK;
-        if (flags & (AACDEC_INTR)) {
+        if ((flags & AACDEC_INTR) && (accessUnit == 0)) {
           /* delete data from the past (e.g. mixdown coeficients) */
           pcmDmx_Reset(self->hPcmUtils, PCMDMX_RESET_BS_DATA);
         }
@@ -1779,17 +1810,12 @@
           }
         }
 
-        INT interleaved = 0;
-        interleaved |= (self->sbrEnabled) ? 1 : 0;
-        interleaved |= (self->mpsEnableCurr) ? 1 : 0;
-
         /* do PCM post processing */
-        dmxErr = pcmDmx_ApplyFrame(
-            self->hPcmUtils, pTimeDataPcmPost, timeDataFixpPcmSize,
-            self->streamInfo.frameSize, &self->streamInfo.numChannels,
-            interleaved, self->channelType, self->channelIndices,
-            &self->mapDescr,
-            (self->limiterEnableCurr) ? &pcmLimiterScale : NULL);
+        dmxErr = pcmDmx_ApplyFrame(self->hPcmUtils, pTimeData2, timeData2Size,
+                                   self->streamInfo.frameSize,
+                                   &self->streamInfo.numChannels, interleaved,
+                                   self->channelType, self->channelIndices,
+                                   &self->mapDescr, &pcmLimiterScale);
         if (dmxErr == PCMDMX_OUTPUT_BUFFER_TOO_SMALL) {
           ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL;
           goto bail;
@@ -1801,13 +1827,35 @@
           ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR;
         }
 
+        pcmLimiterScale += PCM_OUT_HEADROOM;
+
         if (flags & AACDEC_CLRHIST) {
           if (!(self->flags[0] & AC_USAC)) {
+            /* Reset DRC data */
+            aacDecoder_drcReset(self->hDrcInfo);
             /* Delete the delayed signal. */
             pcmLimiter_Reset(self->hLimiter);
           }
         }
 
+        /* Set applyExtGain if DRC processing is enabled and if
+           progRefLevelPresent is present for the first time. Consequences: The
+           headroom of the output signal can be set to AACDEC_DRC_GAIN_SCALING
+           only for audio formats which support legacy DRC Level Normalization.
+                         For all other audio formats the headroom of the output
+           signal is set to PCM_OUT_HEADROOM. */
+        if (self->hDrcInfo->enable &&
+            (self->hDrcInfo->progRefLevelPresent == 1)) {
+          self->hDrcInfo->applyExtGain |= 1;
+        }
+
+        /* Check whether time data buffer is large enough. */
+        if (timeDataSize <
+            (self->streamInfo.numChannels * self->streamInfo.frameSize)) {
+          ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL;
+          goto bail;
+        }
+
         if (self->limiterEnableCurr) {
           /* use workBufferCore2 buffer for interleaving */
           PCM_LIM *pInterleaveBuffer;
@@ -1816,44 +1864,72 @@
           /* Set actual signal parameters */
           pcmLimiter_SetNChannels(self->hLimiter, self->streamInfo.numChannels);
           pcmLimiter_SetSampleRate(self->hLimiter, self->streamInfo.sampleRate);
-          pcmLimiterScale += PCM_OUT_HEADROOM;
 
           if ((self->streamInfo.numChannels == 1) || (self->sbrEnabled) ||
               (self->mpsEnableCurr)) {
-            pInterleaveBuffer = (PCM_LIM *)pTimeDataPcmPost;
+            pInterleaveBuffer = (PCM_LIM *)pTimeData2;
           } else {
-            pInterleaveBuffer = (PCM_LIM *)pTimeData;
+            pInterleaveBuffer = (PCM_LIM *)self->workBufferCore2;
+
             /* applyLimiter requests for interleaved data */
             /* Interleave ouput buffer */
-            FDK_interleave(pTimeDataPcmPost, pInterleaveBuffer,
+            FDK_interleave(pTimeData2, pInterleaveBuffer,
                            self->streamInfo.numChannels, blockLength,
                            self->streamInfo.frameSize);
           }
 
+          FIXP_DBL *pGainPerSample = NULL;
+
+          if (self->hDrcInfo->enable && self->hDrcInfo->applyExtGain) {
+            pGainPerSample = self->workBufferCore1;
+
+            if ((INT)GetRequiredMemWorkBufferCore1() <
+                (INT)(self->streamInfo.frameSize * sizeof(FIXP_DBL))) {
+              ErrorStatus = AAC_DEC_UNKNOWN;
+              goto bail;
+            }
+
+            pcmLimiterScale = applyDrcLevelNormalization(
+                self->hDrcInfo, (PCM_DEC *)pInterleaveBuffer, self->extGain,
+                pGainPerSample, pcmLimiterScale, self->extGainDelay,
+                self->streamInfo.frameSize, self->streamInfo.numChannels, 1, 1);
+          }
+
           pcmLimiter_Apply(self->hLimiter, pInterleaveBuffer, pTimeData,
-                           self->extGain, &pcmLimiterScale, 1,
-                           self->extGainDelay, self->streamInfo.frameSize);
+                           pGainPerSample, pcmLimiterScale,
+                           self->streamInfo.frameSize);
 
           {
             /* Announce the additional limiter output delay */
             self->streamInfo.outputDelay += pcmLimiter_GetDelay(self->hLimiter);
           }
         } else {
+          if (self->hDrcInfo->enable && self->hDrcInfo->applyExtGain) {
+            pcmLimiterScale = applyDrcLevelNormalization(
+                self->hDrcInfo, pTimeData2, self->extGain, NULL,
+                pcmLimiterScale, self->extGainDelay, self->streamInfo.frameSize,
+                self->streamInfo.numChannels,
+                (interleaved || (self->streamInfo.numChannels == 1))
+                    ? 1
+                    : self->streamInfo.frameSize,
+                0);
+          }
+
           /* If numChannels = 1 we do not need interleaving. The same applies if
           SBR or MPS are used, since their output is interleaved already
           (resampled or not) */
           if ((self->streamInfo.numChannels == 1) || (self->sbrEnabled) ||
               (self->mpsEnableCurr)) {
             scaleValuesSaturate(
-                pTimeData, pTimeDataPcmPost,
+                pTimeData, pTimeData2,
                 self->streamInfo.frameSize * self->streamInfo.numChannels,
-                PCM_OUT_HEADROOM);
+                pcmLimiterScale);
 
           } else {
             scaleValuesSaturate(
-                (INT_PCM *)self->workBufferCore2, pTimeDataPcmPost,
+                (INT_PCM *)self->workBufferCore2, pTimeData2,
                 self->streamInfo.frameSize * self->streamInfo.numChannels,
-                PCM_OUT_HEADROOM);
+                pcmLimiterScale);
             /* Interleave ouput buffer */
             FDK_interleave((INT_PCM *)self->workBufferCore2, pTimeData,
                            self->streamInfo.numChannels,
@@ -1949,20 +2025,8 @@
     ErrorStatus = AAC_DEC_UNKNOWN;
   }
 
-  /* Check whether external output buffer is large enough. */
-  if (timeDataSize_extern <
-      self->streamInfo.numChannels * self->streamInfo.frameSize) {
-    ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL;
-  }
-
-  /* Update external output buffer. */
-  if (IS_OUTPUT_VALID(ErrorStatus)) {
-    FDKmemcpy(pTimeData_extern, pTimeData,
-              self->streamInfo.numChannels * self->streamInfo.frameSize *
-                  sizeof(*pTimeData));
-  } else {
-    FDKmemclear(pTimeData_extern,
-                timeDataSize_extern * sizeof(*pTimeData_extern));
+  if (!IS_OUTPUT_VALID(ErrorStatus)) {
+    FDKmemclear(pTimeData, timeDataSize * sizeof(*pTimeData));
   }
 
   return ErrorStatus;
diff --git a/libAACdec/src/block.cpp b/libAACdec/src/block.cpp
index b3d09a6..0bca577 100644
--- a/libAACdec/src/block.cpp
+++ b/libAACdec/src/block.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -1015,9 +1015,9 @@
 
 void CBlock_FrequencyToTime(
     CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo,
-    CAacDecoderChannelInfo *pAacDecoderChannelInfo, FIXP_PCM outSamples[],
+    CAacDecoderChannelInfo *pAacDecoderChannelInfo, PCM_DEC outSamples[],
     const SHORT frameLen, const int frameOk, FIXP_DBL *pWorkBuffer1,
-    UINT elFlags, INT elCh) {
+    const INT aacOutDataHeadroom, UINT elFlags, INT elCh) {
   int fr, fl, tl, nSpec;
 
 #if defined(FDK_ASSERT_ENABLE)
@@ -1213,6 +1213,7 @@
         bass_pf_1sf_delay(p2_synth, pitch, pit_gain, frameLen,
                           (LpdSfd + 2) * L_SUBFR + BPF_SFD * L_SUBFR,
                           frameLen - (LpdSfd + 4) * L_SUBFR, outSamples,
+                          aacOutDataHeadroom,
                           pAacDecoderStaticChannelInfo->mem_bpf);
       }
 
@@ -1236,7 +1237,8 @@
                          ? MLT_FLAG_CURR_ALIAS_SYMMETRY
                          : 0);
 
-      scaleValuesSaturate(outSamples, tmp, frameLen, MDCT_OUT_HEADROOM);
+      scaleValuesSaturate(outSamples, tmp, frameLen,
+                          MDCT_OUT_HEADROOM - aacOutDataHeadroom);
     }
   }
 
@@ -1251,7 +1253,7 @@
 #include "ldfiltbank.h"
 void CBlock_FrequencyToTimeLowDelay(
     CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo,
-    CAacDecoderChannelInfo *pAacDecoderChannelInfo, FIXP_PCM outSamples[],
+    CAacDecoderChannelInfo *pAacDecoderChannelInfo, PCM_DEC outSamples[],
     const short frameLen) {
   InvMdctTransformLowDelay_fdk(
       SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient),
diff --git a/libAACdec/src/block.h b/libAACdec/src/block.h
index f0f56cd..f5118a2 100644
--- a/libAACdec/src/block.h
+++ b/libAACdec/src/block.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -218,16 +218,16 @@
  */
 void CBlock_FrequencyToTime(
     CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo,
-    CAacDecoderChannelInfo *pAacDecoderChannelInfo, FIXP_PCM outSamples[],
+    CAacDecoderChannelInfo *pAacDecoderChannelInfo, PCM_DEC outSamples[],
     const SHORT frameLen, const int frameOk, FIXP_DBL *pWorkBuffer1,
-    UINT elFlags, INT elCh);
+    const INT aacOutDataHeadroom, UINT elFlags, INT elCh);
 
 /**
  * \brief Transform double lapped MDCT (AAC-ELD) spectral data into time domain.
  */
 void CBlock_FrequencyToTimeLowDelay(
     CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo,
-    CAacDecoderChannelInfo *pAacDecoderChannelInfo, FIXP_PCM outSamples[],
+    CAacDecoderChannelInfo *pAacDecoderChannelInfo, PCM_DEC outSamples[],
     const short frameLen);
 
 AAC_DECODER_ERROR CBlock_InverseQuantizeSpectralData(
diff --git a/libAACdec/src/conceal.cpp b/libAACdec/src/conceal.cpp
index 5895cb8..0939bb5 100644
--- a/libAACdec/src/conceal.cpp
+++ b/libAACdec/src/conceal.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -226,7 +226,7 @@
 
 /* TimeDomainFading */
 static void CConcealment_TDFadePcmAtt(int start, int len, FIXP_DBL fadeStart,
-                                      FIXP_DBL fadeStop, FIXP_PCM *pcmdata);
+                                      FIXP_DBL fadeStop, PCM_DEC *pcmdata);
 static void CConcealment_TDFadeFillFadingStations(FIXP_DBL *fadingStations,
                                                   int *fadingSteps,
                                                   FIXP_DBL fadeStop,
@@ -242,7 +242,9 @@
 
 static int CConcealment_TDNoise_Random(ULONG *seed);
 static void CConcealment_TDNoise_Apply(CConcealmentInfo *const pConcealmentInfo,
-                                       const int len, FIXP_PCM *const pcmdata);
+                                       const int len,
+                                       const INT aacOutDataHeadroom,
+                                       PCM_DEC *const pcmdata);
 
 static BLOCK_TYPE CConcealment_GetWinSeq(int prevWinSeq) {
   BLOCK_TYPE newWinSeq = BLOCK_LONG;
@@ -1228,7 +1230,6 @@
   int sfb, line = 0;
   int fac_shift;
   int fac_mod;
-  FIXP_DBL accu;
 
   for (sfb = 0; sfb < sfbCnt; sfb++) {
     fac_shift =
@@ -1236,15 +1237,11 @@
     fac_mod = fac_shift & 3;
     fac_shift = (fac_shift >> 2) + 1;
     fac_shift += *pSpecScalePrv - fixMax(*pSpecScalePrv, *pSpecScaleAct);
+    fac_shift = fMax(fMin(fac_shift, DFRACT_BITS - 1), -(DFRACT_BITS - 1));
 
     for (; line < pSfbOffset[sfb + 1]; line++) {
-      accu = fMult(*(spectrum + line), facMod4Table[fac_mod]);
-      if (fac_shift < 0) {
-        accu >>= -fac_shift;
-      } else {
-        accu <<= fac_shift;
-      }
-      *(spectrum + line) = accu;
+      FIXP_DBL accu = fMult(*(spectrum + line), facMod4Table[fac_mod]);
+      *(spectrum + line) = scaleValue(accu, fac_shift);
     }
   }
   *pSpecScaleOut = fixMax(*pSpecScalePrv, *pSpecScaleAct);
@@ -1618,7 +1615,7 @@
     }
 
     if (packedSign & 0x1) {
-      spec[i] = -spec[i];
+      spec[i] = -fMax(spec[i], (FIXP_DBL)(MINVAL_DBL + 1));
     }
     packedSign >>= 1;
 
@@ -1849,7 +1846,7 @@
 
 INT CConcealment_TDFading(
     int len, CAacDecoderStaticChannelInfo **ppAacDecoderStaticChannelInfo,
-    FIXP_PCM *pcmdata, FIXP_PCM *pcmdata_1) {
+    const INT aacOutDataHeadroom, PCM_DEC *pcmdata, PCM_DEC *pcmdata_1) {
   /*
   Do the fading in Time domain based on concealment states and core mode
   */
@@ -1962,7 +1959,8 @@
       start += len;
     }
   }
-  CConcealment_TDNoise_Apply(pConcealmentInfo, len, pcmdata);
+  CConcealment_TDNoise_Apply(pConcealmentInfo, len, aacOutDataHeadroom,
+                             pcmdata);
 
   /* Save end-of-frame attenuation and fading type */
   pConcealmentInfo->lastFadingType = fadingType;
@@ -1974,12 +1972,11 @@
 
 /* attenuate pcmdata in Time Domain Fading process */
 static void CConcealment_TDFadePcmAtt(int start, int len, FIXP_DBL fadeStart,
-                                      FIXP_DBL fadeStop, FIXP_PCM *pcmdata) {
+                                      FIXP_DBL fadeStop, PCM_DEC *pcmdata) {
   int i;
   FIXP_DBL dStep;
   FIXP_DBL dGain;
   FIXP_DBL dGain_apply;
-  int bitshift = (DFRACT_BITS - SAMPLE_BITS);
 
   /* set start energy */
   dGain = fadeStart;
@@ -1992,7 +1989,7 @@
      */
     dGain_apply = fMax((FIXP_DBL)0, dGain);
     /* finally, attenuate samples */
-    pcmdata[i] = (FIXP_PCM)((fMult(pcmdata[i], (dGain_apply))) >> bitshift);
+    pcmdata[i] = FIXP_DBL2PCM_DEC(fMult(pcmdata[i], dGain_apply));
   }
 }
 
@@ -2055,9 +2052,11 @@
 }
 
 static void CConcealment_TDNoise_Apply(CConcealmentInfo *const pConcealmentInfo,
-                                       const int len, FIXP_PCM *const pcmdata) {
-  FIXP_PCM *states = pConcealmentInfo->TDNoiseStates;
-  FIXP_PCM noiseVal;
+                                       const int len,
+                                       const INT aacOutDataHeadroom,
+                                       PCM_DEC *const pcmdata) {
+  PCM_DEC *states = pConcealmentInfo->TDNoiseStates;
+  PCM_DEC noiseVal;
   FIXP_DBL noiseValLong;
   FIXP_SGL *coef = pConcealmentInfo->TDNoiseCoef;
   FIXP_DBL TDNoiseAtt;
@@ -2075,18 +2074,20 @@
       /* create filtered noise */
       states[2] = states[1];
       states[1] = states[0];
-      states[0] = ((FIXP_PCM)CConcealment_TDNoise_Random(&seed));
+      states[0] =
+          FIXP_DBL2PCM_DEC((FIXP_DBL)CConcealment_TDNoise_Random(&seed));
       noiseValLong = fMult(states[0], coef[0]) + fMult(states[1], coef[1]) +
                      fMult(states[2], coef[2]);
-      noiseVal = FX_DBL2FX_PCM(fMult(noiseValLong, TDNoiseAtt));
+      noiseVal = FIXP_DBL2PCM_DEC(fMult(noiseValLong, TDNoiseAtt) >>
+                                  aacOutDataHeadroom);
 
       /* add filtered noise - check for clipping, before */
-      if (noiseVal > (FIXP_PCM)0 &&
-          pcmdata[ii] > (FIXP_PCM)MAXVAL_FIXP_PCM - noiseVal) {
-        noiseVal = noiseVal * (FIXP_PCM)-1;
-      } else if (noiseVal < (FIXP_PCM)0 &&
-                 pcmdata[ii] < (FIXP_PCM)MINVAL_FIXP_PCM - noiseVal) {
-        noiseVal = noiseVal * (FIXP_PCM)-1;
+      if (noiseVal > (PCM_DEC)0 &&
+          pcmdata[ii] > (PCM_DEC)MAXVAL_PCM_DEC - noiseVal) {
+        noiseVal = noiseVal * (PCM_DEC)-1;
+      } else if (noiseVal < (PCM_DEC)0 &&
+                 pcmdata[ii] < (PCM_DEC)MINVAL_PCM_DEC - noiseVal) {
+        noiseVal = noiseVal * (PCM_DEC)-1;
       }
 
       pcmdata[ii] += noiseVal;
diff --git a/libAACdec/src/conceal.h b/libAACdec/src/conceal.h
index e01a796..0c002a5 100644
--- a/libAACdec/src/conceal.h
+++ b/libAACdec/src/conceal.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -147,6 +147,6 @@
 
 INT CConcealment_TDFading(
     int len, CAacDecoderStaticChannelInfo **ppAacDecoderStaticChannelInfo,
-    FIXP_PCM *pcmdata, FIXP_PCM *pcmdata_1);
+    const INT aacOutDataHeadroom, PCM_DEC *pcmdata, PCM_DEC *pcmdata_1);
 
 #endif /* #ifndef CONCEAL_H */
diff --git a/libAACdec/src/conceal_types.h b/libAACdec/src/conceal_types.h
index d90374e..36e7dec 100644
--- a/libAACdec/src/conceal_types.h
+++ b/libAACdec/src/conceal_types.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -194,7 +194,7 @@
   FIXP_DBL last_tcx_gain;
   INT last_tcx_gain_e;
   ULONG TDNoiseSeed;
-  FIXP_PCM TDNoiseStates[3];
+  PCM_DEC TDNoiseStates[3];
   FIXP_SGL TDNoiseCoef[3];
   FIXP_SGL TDNoiseAtt;
 
diff --git a/libAACdec/src/ldfiltbank.cpp b/libAACdec/src/ldfiltbank.cpp
index c7d2928..13e61a5 100644
--- a/libAACdec/src/ldfiltbank.cpp
+++ b/libAACdec/src/ldfiltbank.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -112,17 +112,20 @@
 #if defined(__arm__)
 #endif
 
-static void multE2_DinvF_fdk(FIXP_PCM *output, FIXP_DBL *x, const FIXP_WTB *fb,
+static void multE2_DinvF_fdk(PCM_DEC *output, FIXP_DBL *x, const FIXP_WTB *fb,
                              FIXP_DBL *z, const int N) {
   int i;
 
-  /*  scale for FIXP_DBL -> INT_PCM conversion. */
-  const int scale = (DFRACT_BITS - SAMPLE_BITS) - LDFB_HEADROOM;
-#if ((DFRACT_BITS - SAMPLE_BITS - LDFB_HEADROOM) > 0)
+  /*  scale for FIXP_DBL -> PCM_DEC conversion:       */
+  const int scale = (DFRACT_BITS - PCM_OUT_BITS) - LDFB_HEADROOM + (3);
+
+#if ((DFRACT_BITS - PCM_OUT_BITS - LDFB_HEADROOM + (3) - 1) > 0)
   FIXP_DBL rnd_val_wts0 = (FIXP_DBL)0;
   FIXP_DBL rnd_val_wts1 = (FIXP_DBL)0;
+#if ((DFRACT_BITS - PCM_OUT_BITS - LDFB_HEADROOM + (3) - WTS0 - 1) > 0)
   if (-WTS0 - 1 + scale)
     rnd_val_wts0 = (FIXP_DBL)(1 << (-WTS0 - 1 + scale - 1));
+#endif
   if (-WTS1 - 1 + scale)
     rnd_val_wts1 = (FIXP_DBL)(1 << (-WTS1 - 1 + scale - 1));
 #endif
@@ -131,24 +134,26 @@
     FIXP_DBL z0, z2, tmp;
 
     z2 = x[N / 2 + i];
-    z0 = z2 + (fMultDiv2(z[N / 2 + i], fb[2 * N + i]) >> (-WTS2 - 1));
+    z0 = fAddSaturate(z2,
+                      (fMultDiv2(z[N / 2 + i], fb[2 * N + i]) >> (-WTS2 - 1)));
 
-    z[N / 2 + i] = x[N / 2 - 1 - i] +
-                   (fMultDiv2(z[N + i], fb[2 * N + N / 2 + i]) >> (-WTS2 - 1));
+    z[N / 2 + i] = fAddSaturate(
+        x[N / 2 - 1 - i],
+        (fMultDiv2(z[N + i], fb[2 * N + N / 2 + i]) >> (-WTS2 - 1)));
 
     tmp = (fMultDiv2(z[N / 2 + i], fb[N + N / 2 - 1 - i]) +
            fMultDiv2(z[i], fb[N + N / 2 + i]));
 
-#if ((DFRACT_BITS - SAMPLE_BITS - LDFB_HEADROOM) > 0)
+#if ((DFRACT_BITS - PCM_OUT_BITS - LDFB_HEADROOM + (3) - 1) > 0)
     FDK_ASSERT((-WTS1 - 1 + scale) >= 0);
     FDK_ASSERT(tmp <= ((FIXP_DBL)0x7FFFFFFF -
                        rnd_val_wts1)); /* rounding must not cause overflow */
-    output[(N * 3 / 4 - 1 - i)] = (FIXP_PCM)SATURATE_RIGHT_SHIFT(
+    output[(N * 3 / 4 - 1 - i)] = (PCM_DEC)SATURATE_RIGHT_SHIFT(
         tmp + rnd_val_wts1, -WTS1 - 1 + scale, PCM_OUT_BITS);
 #else
     FDK_ASSERT((WTS1 + 1 - scale) >= 0);
     output[(N * 3 / 4 - 1 - i)] =
-        (FIXP_PCM)SATURATE_LEFT_SHIFT(tmp, WTS1 + 1 - scale, PCM_OUT_BITS);
+        (PCM_DEC)SATURATE_LEFT_SHIFT(tmp, WTS1 + 1 - scale, PCM_OUT_BITS);
 #endif
 
     z[i] = z0;
@@ -159,32 +164,34 @@
     FIXP_DBL z0, z2, tmp0, tmp1;
 
     z2 = x[N / 2 + i];
-    z0 = z2 + (fMultDiv2(z[N / 2 + i], fb[2 * N + i]) >> (-WTS2 - 1));
+    z0 = fAddSaturate(z2,
+                      (fMultDiv2(z[N / 2 + i], fb[2 * N + i]) >> (-WTS2 - 1)));
 
-    z[N / 2 + i] = x[N / 2 - 1 - i] +
-                   (fMultDiv2(z[N + i], fb[2 * N + N / 2 + i]) >> (-WTS2 - 1));
+    z[N / 2 + i] = fAddSaturate(
+        x[N / 2 - 1 - i],
+        (fMultDiv2(z[N + i], fb[2 * N + N / 2 + i]) >> (-WTS2 - 1)));
 
     tmp0 = (fMultDiv2(z[N / 2 + i], fb[N / 2 - 1 - i]) +
             fMultDiv2(z[i], fb[N / 2 + i]));
     tmp1 = (fMultDiv2(z[N / 2 + i], fb[N + N / 2 - 1 - i]) +
             fMultDiv2(z[i], fb[N + N / 2 + i]));
 
-#if ((DFRACT_BITS - SAMPLE_BITS - LDFB_HEADROOM) > 0)
+#if ((DFRACT_BITS - PCM_OUT_BITS - LDFB_HEADROOM + (3) - 1) > 0)
     FDK_ASSERT((-WTS0 - 1 + scale) >= 0);
     FDK_ASSERT(tmp0 <= ((FIXP_DBL)0x7FFFFFFF -
                         rnd_val_wts0)); /* rounding must not cause overflow */
     FDK_ASSERT(tmp1 <= ((FIXP_DBL)0x7FFFFFFF -
                         rnd_val_wts1)); /* rounding must not cause overflow */
-    output[(i - N / 4)] = (FIXP_PCM)SATURATE_RIGHT_SHIFT(
+    output[(i - N / 4)] = (PCM_DEC)SATURATE_RIGHT_SHIFT(
         tmp0 + rnd_val_wts0, -WTS0 - 1 + scale, PCM_OUT_BITS);
-    output[(N * 3 / 4 - 1 - i)] = (FIXP_PCM)SATURATE_RIGHT_SHIFT(
+    output[(N * 3 / 4 - 1 - i)] = (PCM_DEC)SATURATE_RIGHT_SHIFT(
         tmp1 + rnd_val_wts1, -WTS1 - 1 + scale, PCM_OUT_BITS);
 #else
     FDK_ASSERT((WTS0 + 1 - scale) >= 0);
     output[(i - N / 4)] =
-        (FIXP_PCM)SATURATE_LEFT_SHIFT(tmp0, WTS0 + 1 - scale, PCM_OUT_BITS);
+        (PCM_DEC)SATURATE_LEFT_SHIFT(tmp0, WTS0 + 1 - scale, PCM_OUT_BITS);
     output[(N * 3 / 4 - 1 - i)] =
-        (FIXP_PCM)SATURATE_LEFT_SHIFT(tmp1, WTS1 + 1 - scale, PCM_OUT_BITS);
+        (PCM_DEC)SATURATE_LEFT_SHIFT(tmp1, WTS1 + 1 - scale, PCM_OUT_BITS);
 #endif
     z[i] = z0;
     z[N + i] = z2;
@@ -194,22 +201,22 @@
   for (i = 0; i < N / 4; i++) {
     FIXP_DBL tmp0 = fMultDiv2(z[i], fb[N / 2 + i]);
 
-#if ((DFRACT_BITS - SAMPLE_BITS - LDFB_HEADROOM) > 0)
+#if ((DFRACT_BITS - PCM_OUT_BITS - LDFB_HEADROOM + (3) - 1) > 0)
     FDK_ASSERT((-WTS0 - 1 + scale) >= 0);
     FDK_ASSERT(tmp0 <= ((FIXP_DBL)0x7FFFFFFF -
                         rnd_val_wts0)); /* rounding must not cause overflow */
-    output[(N * 3 / 4 + i)] = (FIXP_PCM)SATURATE_RIGHT_SHIFT(
+    output[(N * 3 / 4 + i)] = (PCM_DEC)SATURATE_RIGHT_SHIFT(
         tmp0 + rnd_val_wts0, -WTS0 - 1 + scale, PCM_OUT_BITS);
 #else
     FDK_ASSERT((WTS0 + 1 - scale) >= 0);
     output[(N * 3 / 4 + i)] =
-        (FIXP_PCM)SATURATE_LEFT_SHIFT(tmp0, WTS0 + 1 - scale, PCM_OUT_BITS);
+        (PCM_DEC)SATURATE_LEFT_SHIFT(tmp0, WTS0 + 1 - scale, PCM_OUT_BITS);
 #endif
   }
 }
 
 int InvMdctTransformLowDelay_fdk(FIXP_DBL *mdctData, const int mdctData_e,
-                                 FIXP_PCM *output, FIXP_DBL *fs_buffer,
+                                 PCM_DEC *output, FIXP_DBL *fs_buffer,
                                  const int N) {
   const FIXP_WTB *coef;
   FIXP_DBL gain = (FIXP_DBL)0;
diff --git a/libAACdec/src/ldfiltbank.h b/libAACdec/src/ldfiltbank.h
index b63da6b..02971d0 100644
--- a/libAACdec/src/ldfiltbank.h
+++ b/libAACdec/src/ldfiltbank.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -104,9 +104,10 @@
 #define LDFILTBANK_H
 
 #include "common_fix.h"
+#include "aac_rom.h"
 
 int InvMdctTransformLowDelay_fdk(FIXP_DBL *mdctdata_m, const int mdctdata_e,
-                                 FIXP_PCM *mdctOut, FIXP_DBL *fs_buffer,
+                                 PCM_DEC *mdctOut, FIXP_DBL *fs_buffer,
                                  const int frameLength);
 
 #endif
diff --git a/libAACdec/src/stereo.cpp b/libAACdec/src/stereo.cpp
index eed826b..47f1a31 100644
--- a/libAACdec/src/stereo.cpp
+++ b/libAACdec/src/stereo.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -807,19 +807,17 @@
                   for (int i = 0; i < windowLen; i++) {
                     dmx_re_prev[i] =
                         ((staticSpectralCoeffsL[index_offset + i] >>
-                          srLeftChan) +
+                          fMin(DFRACT_BITS - 1, srLeftChan + 1)) +
                          (staticSpectralCoeffsR[index_offset + i] >>
-                          srRightChan)) >>
-                        1;
+                          fMin(DFRACT_BITS - 1, srRightChan + 1)));
                   }
                 } else {
                   for (int i = 0; i < windowLen; i++) {
                     dmx_re_prev[i] =
                         ((staticSpectralCoeffsL[index_offset + i] >>
-                          srLeftChan) -
+                          fMin(DFRACT_BITS - 1, srLeftChan + 1)) -
                          (staticSpectralCoeffsR[index_offset + i] >>
-                          srRightChan)) >>
-                        1;
+                          fMin(DFRACT_BITS - 1, srRightChan + 1)));
                   }
                 }
               }
@@ -854,12 +852,13 @@
           if (window == 0) {
             if (dmx_re_prev_e < frameMaxScale) {
               if (mainband_flag == 0) {
-                scaleValues(dmx_re_prev, store_dmx_re_prev, windowLen,
-                            -(frameMaxScale - dmx_re_prev_e));
+                scaleValues(
+                    dmx_re_prev, store_dmx_re_prev, windowLen,
+                    -fMin(DFRACT_BITS - 1, (frameMaxScale - dmx_re_prev_e)));
               } else {
-                for (int i = 0; i < windowLen; i++) {
-                  dmx_re_prev[i] >>= (frameMaxScale - dmx_re_prev_e);
-                }
+                scaleValues(
+                    dmx_re_prev, windowLen,
+                    -fMin(DFRACT_BITS - 1, (frameMaxScale - dmx_re_prev_e)));
               }
             } else {
               if (mainband_flag == 0) {
@@ -873,10 +872,9 @@
             FDK_ASSERT(pAacDecoderChannelInfo[L]->icsInfo.WindowSequence ==
                        BLOCK_SHORT);
             if (specScaleL[window - 1] < frameMaxScale) {
-              for (int i = 0; i < windowLen; i++) {
-                dmx_re[windowLen * (window - 1) + i] >>=
-                    (frameMaxScale - specScaleL[window - 1]);
-              }
+              scaleValues(&dmx_re[windowLen * (window - 1)], windowLen,
+                          -fMin(DFRACT_BITS - 1,
+                                (frameMaxScale - specScaleL[window - 1])));
             } else {
               specScaleL[window] = specScaleL[window - 1];
               specScaleR[window] = specScaleR[window - 1];
@@ -991,7 +989,7 @@
         }   /* if ( pJointStereoData->complex_coef == 1 ) */
 
         /* 4. upmix process */
-        INT pred_dir = cplxPredictionData->pred_dir ? -1 : 1;
+        LONG pred_dir = cplxPredictionData->pred_dir ? -1 : 1;
         /* 0.1 in Q-3.34 */
         const FIXP_DBL pointOne = 0x66666666; /* 0.8 */
         /* Shift value for the downmix */
@@ -1041,34 +1039,24 @@
                 the downmix. "dmx_re" and "specL" are two different pointers
                 pointing to separate arrays, which may or may not contain the
                 same data (with different scaling).
+
+                specL[i] =   + (specL[i] + side);
+                specR[i] = -/+ (specL[i] - side);
               */
+              FIXP_DBL side, left, right;
 
-              /* help1: alpha_re[i] * dmx_re[i] */
-              FIXP_DBL help1 = fMultDiv2(alpha_re_tmp, *p2dmxRe++);
+              side = fMultAddDiv2(fMultDiv2(alpha_re_tmp, *p2dmxRe++),
+                                  alpha_im_tmp, (*p2dmxIm++) << shift_dmx);
+              side = ((*p2CoeffR) >> 2) -
+                     (FIXP_DBL)SATURATE_SHIFT(side, -(help3_shift - 2),
+                                              DFRACT_BITS - 2);
 
-              /* tmp: dmx_im[i] */
-              FIXP_DBL tmp = (*p2dmxIm++) << shift_dmx;
+              left = ((*p2CoeffL) >> 2) + side;
+              right = ((*p2CoeffL) >> 2) - side;
+              right = (FIXP_DBL)((LONG)right * pred_dir);
 
-              /* help2: alpha_im[i] * dmx_im[i] */
-              FIXP_DBL help2 = fMultDiv2(alpha_im_tmp, tmp);
-
-              /* help3: alpha_re[i] * dmx_re[i] + alpha_im[i] * dmx_im[i] */
-              FIXP_DBL help3 = help1 + help2;
-
-              /* side (= help4) = specR[i] - (dmx_re[i] * specL[i] + alpha_im[i]
-               * * dmx_im[i]) */
-              FIXP_DBL help4 = *p2CoeffR - scaleValue(help3, help3_shift);
-
-              /* We calculate the left and right output by using the helper
-               * function */
-              /* specR[i] = -/+ (specL[i] - side); */
-              *p2CoeffR =
-                  (FIXP_DBL)((LONG)(*p2CoeffL - help4) * (LONG)pred_dir);
-              p2CoeffR++;
-
-              /* specL[i] = specL[i] + side; */
-              *p2CoeffL = *p2CoeffL + help4;
-              p2CoeffL++;
+              *p2CoeffL++ = SATURATE_LEFT_SHIFT_ALT(left, 2, DFRACT_BITS);
+              *p2CoeffR++ = SATURATE_LEFT_SHIFT_ALT(right, 2, DFRACT_BITS);
             }
           }
 
diff --git a/libAACdec/src/usacdec_acelp.cpp b/libAACdec/src/usacdec_acelp.cpp
index c836c6a..a8dadc0 100644
--- a/libAACdec/src/usacdec_acelp.cpp
+++ b/libAACdec/src/usacdec_acelp.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -131,7 +131,7 @@
   int i;
 
   for (i = 0; i < L; i++) {
-    out[i] = in[i] - fMult(PREEMPH_FAC, in[i - 1]);
+    out[i] = fAddSaturate(in[i], -fMult(PREEMPH_FAC, in[i - 1]));
   }
 
   return;
@@ -465,7 +465,9 @@
 /* Note: code[L_SUBFR] and exc2[L_SUBFR] share the same memory!
          If exc2[i] is written, code[i] will be destroyed!
 */
-#define SF (SF_CODE + SF_GAIN_C + 1 - SF_EXC)
+#define SF_HEADROOM (1)
+#define SF (SF_CODE + SF_GAIN_C + 1 - SF_EXC - SF_HEADROOM)
+#define SF_GAIN_P2 (SF_GAIN_P - SF_HEADROOM)
 
   int i;
   FIXP_DBL tmp, cpe, code_smooth_prev, code_smooth;
@@ -477,8 +479,8 @@
   cpe = (period_fac >> (2 - SF_PFAC)) + FL2FXCONST_DBL(0.25f);
 
   /* u'(n) */
-  tmp = fMultDiv2(*exc, gain_pit) << (SF_GAIN_P + 1); /* v(0)*g_p */
-  *exc++ = tmp + (fMultDiv2(code[0], gain_code) << SF);
+  tmp = fMultDiv2(*exc, gain_pit) << (SF_GAIN_P2 + 1); /* v(0)*g_p */
+  *exc++ = (tmp + (fMultDiv2(code[0], gain_code) << SF)) << SF_HEADROOM;
 
   /* u(n) */
   code_smooth_prev = fMultDiv2(*code++, gain_code_smoothed)
@@ -487,15 +489,15 @@
   code_smooth = fMultDiv2(code_i, gain_code_smoothed) << SF; /* c(1) * g_sc */
   tmp += code_smooth_prev; /* tmp = v(0)*g_p + c(0)*g_sc */
   cpe_code_smooth = fMultDiv2(cpe, code_smooth);
-  *exc2++ = tmp - cpe_code_smooth;
+  *exc2++ = (tmp - cpe_code_smooth) << SF_HEADROOM;
   cpe_code_smooth_prev = fMultDiv2(cpe, code_smooth_prev);
 
   i = L_SUBFR - 2;
   do /* ARM926: 22 cycles per iteration */
   {
     /* u'(n) */
-    tmp = fMultDiv2(*exc, gain_pit) << (SF_GAIN_P + 1);
-    *exc++ = tmp + (fMultDiv2(code_i, gain_code) << SF);
+    tmp = fMultDiv2(*exc, gain_pit) << (SF_GAIN_P2 + 1);
+    *exc++ = (tmp + (fMultDiv2(code_i, gain_code) << SF)) << SF_HEADROOM;
     /* u(n) */
     tmp += code_smooth; /* += g_sc * c(i) */
     tmp -= cpe_code_smooth_prev;
@@ -503,16 +505,17 @@
     code_i = *code++;
     code_smooth = fMultDiv2(code_i, gain_code_smoothed) << SF;
     cpe_code_smooth = fMultDiv2(cpe, code_smooth);
-    *exc2++ = tmp - cpe_code_smooth; /* tmp - c_pe * g_sc * c(i+1) */
+    *exc2++ = (tmp - cpe_code_smooth)
+              << SF_HEADROOM; /* tmp - c_pe * g_sc * c(i+1) */
   } while (--i != 0);
 
   /* u'(n) */
-  tmp = fMultDiv2(*exc, gain_pit) << (SF_GAIN_P + 1);
-  *exc = tmp + (fMultDiv2(code_i, gain_code) << SF);
+  tmp = fMultDiv2(*exc, gain_pit) << (SF_GAIN_P2 + 1);
+  *exc = (tmp + (fMultDiv2(code_i, gain_code) << SF)) << SF_HEADROOM;
   /* u(n) */
   tmp += code_smooth;
   tmp -= cpe_code_smooth_prev;
-  *exc2++ = tmp;
+  *exc2++ = tmp << SF_HEADROOM;
 
   return;
 }
diff --git a/libAACdec/src/usacdec_fac.cpp b/libAACdec/src/usacdec_fac.cpp
index 0d3d844..b246171 100644
--- a/libAACdec/src/usacdec_fac.cpp
+++ b/libAACdec/src/usacdec_fac.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -344,7 +344,7 @@
       /* Overlap Add */
       x0 = -fMult(*pOvl--, pWindow[i].v.re);
 
-      *pOut0 += IMDCT_SCALE_DBL(x0);
+      *pOut0 = fAddSaturate(*pOut0, IMDCT_SCALE_DBL(x0));
       pOut0++;
     }
   } else {
@@ -354,7 +354,7 @@
       /* Overlap Add */
       x0 = fMult(*pOvl--, pWindow[i].v.re);
 
-      *pOut0 += IMDCT_SCALE_DBL(x0);
+      *pOut0 = fAddSaturate(*pOut0, IMDCT_SCALE_DBL(x0));
       pOut0++;
     }
   }
@@ -362,7 +362,7 @@
       0) { /* this should only happen for ACELP -> TCX20 -> ACELP transition */
     FIXP_DBL *pOut = pOut0 - fl / 2; /* fl/2 == fac_length */
     for (i = 0; i < fl / 2; i++) {
-      pOut[i] += IMDCT_SCALE_DBL(hMdct->pFacZir[i]);
+      pOut[i] = fAddSaturate(pOut[i], IMDCT_SCALE_DBL(hMdct->pFacZir[i]));
     }
     hMdct->pFacZir = NULL;
   }
@@ -493,9 +493,7 @@
           /* Div2 is compensated by table scaling */
           x = fMultDiv2(pTmp2[i], FacWindowZir[w]);
           x += fMultDiv2(pTmp1[-i - 1], FacWindowSynth[w]);
-          x += pFAC_and_FAC_ZIR[i];
-          pOut1[i] = x;
-
+          pOut1[i] = fAddSaturate(x, pFAC_and_FAC_ZIR[i]);
           w++;
         }
       }
@@ -552,7 +550,7 @@
     FDK_ASSERT((pOut1 >= hMdct->overlap.time &&
                 pOut1 < hMdct->overlap.time + hMdct->ov_size) ||
                (pOut1 >= output && pOut1 < output + 1024));
-    *pOut1 += IMDCT_SCALE_DBL(-x1);
+    *pOut1 = fAddSaturate(*pOut1, IMDCT_SCALE_DBL(-x1));
     pOut1--;
   }
 
@@ -578,7 +576,7 @@
     FIXP_DBL x = -(*pCurr--);
     /* 5) (item 4) Synthesis filter Zir component, FAC ZIR (another one). */
     if (i < f_len) {
-      x += *pF++;
+      x = fAddSaturate(x, *pF++);
     }
 
     FDK_ASSERT((pOut1 >= hMdct->overlap.time &&
@@ -668,9 +666,9 @@
       for (i = 0; i < fl / 2; i++) {
         FIXP_DBL x0, x1;
 
-        cplxMult(&x1, &x0, *pCurr++, -*pOvl--, pWindow_prev[i]);
-        *pOut0 = IMDCT_SCALE_DBL(x0);
-        *pOut1 = IMDCT_SCALE_DBL(-x1);
+        cplxMultDiv2(&x1, &x0, *pCurr++, -*pOvl--, pWindow_prev[i]);
+        *pOut0 = IMDCT_SCALE_DBL_LSH1(x0);
+        *pOut1 = IMDCT_SCALE_DBL_LSH1(-x1);
         pOut0++;
         pOut1--;
       }
@@ -680,9 +678,9 @@
         for (i = 0; i < fl / 2; i++) {
           FIXP_DBL x0, x1;
 
-          cplxMult(&x1, &x0, *pCurr++, -*pOvl--, pWindow_prev[i]);
-          *pOut0 = IMDCT_SCALE_DBL(x0);
-          *pOut1 = IMDCT_SCALE_DBL(x1);
+          cplxMultDiv2(&x1, &x0, *pCurr++, -*pOvl--, pWindow_prev[i]);
+          *pOut0 = IMDCT_SCALE_DBL_LSH1(x0);
+          *pOut1 = IMDCT_SCALE_DBL_LSH1(x1);
           pOut0++;
           pOut1--;
         }
@@ -691,9 +689,9 @@
         for (i = 0; i < fl / 2; i++) {
           FIXP_DBL x0, x1;
 
-          cplxMult(&x1, &x0, *pCurr++, *pOvl--, pWindow_prev[i]);
-          *pOut0 = IMDCT_SCALE_DBL(x0);
-          *pOut1 = IMDCT_SCALE_DBL(x1);
+          cplxMultDiv2(&x1, &x0, *pCurr++, *pOvl--, pWindow_prev[i]);
+          *pOut0 = IMDCT_SCALE_DBL_LSH1(x0);
+          *pOut1 = IMDCT_SCALE_DBL_LSH1(x1);
           pOut0++;
           pOut1--;
         }
@@ -705,7 +703,7 @@
       FIXP_DBL *pOut = pOut0 - fl / 2;
       FDK_ASSERT(fl / 2 <= 128);
       for (i = 0; i < fl / 2; i++) {
-        pOut[i] += IMDCT_SCALE_DBL(hMdct->pFacZir[i]);
+        pOut[i] = fAddSaturate(pOut[i], IMDCT_SCALE_DBL(hMdct->pFacZir[i]));
       }
       hMdct->pFacZir = NULL;
     }
diff --git a/libAACdec/src/usacdec_lpc.cpp b/libAACdec/src/usacdec_lpc.cpp
index 271463f..88601b7 100644
--- a/libAACdec/src/usacdec_lpc.cpp
+++ b/libAACdec/src/usacdec_lpc.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -231,7 +231,7 @@
 void RE8_PPV(FIXP_ZF x[], SHORT y[], int r) {
   int i, y0[8], y1[8];
   FIXP_ZF x1[8], tmp;
-  FIXP_DBL e;
+  INT64 e;
 
   /* find the nearest neighbor y0 of x in 2D8 */
   nearest_neighbor_2D8(x, y0);
@@ -245,16 +245,16 @@
   }
 
   /* compute e0=||x-y0||^2 and e1=||x-y1||^2 */
-  e = (FIXP_DBL)0;
+  e = 0;
   for (i = 0; i < 8; i++) {
     tmp = x[i] - INT2ZF(y0[i], 0);
-    e += fPow2Div2(
+    e += (INT64)fPow2Div2(
         tmp << r); /* shift left to ensure that no fract part bits get lost. */
     tmp = x[i] - INT2ZF(y1[i], 0);
-    e -= fPow2Div2(tmp << r);
+    e -= (INT64)fPow2Div2(tmp << r);
   }
   /* select best candidate y0 or y1 to minimize distortion */
-  if (e < (FIXP_DBL)0) {
+  if (e < 0) {
     for (i = 0; i < 8; i++) {
       y[i] = y0[i];
     }
@@ -565,7 +565,8 @@
   /* add non-weighted residual LSF vector to LSF1st */
   for (i = 0; i < M_LP_FILTER_ORDER; i++) {
     w = (LONG)fMultDiv2(factor, sqrtFixp(fMult(d[i], d[i + 1])));
-    lsfq[i] = fAddSaturate(lsfq[i], FX_DBL2FX_LPC((FIXP_DBL)(w * (LONG)xq[i])));
+    lsfq[i] = fAddSaturate(lsfq[i],
+                           FX_DBL2FX_LPC((FIXP_DBL)((INT64)w * (LONG)xq[i])));
   }
 
   return;
@@ -1138,9 +1139,12 @@
   for (i = 2; i <= n; i++) {
     plsp += 2;
     b = -FX_LPC2FX_DBL(*plsp);
-    f[i] = ((fMultDiv2(b, f[i - 1]) << 1) + (f[i - 2])) << 1;
+    f[i] = SATURATE_LEFT_SHIFT((fMultDiv2(b, f[i - 1]) + (f[i - 2] >> 1)), 2,
+                               DFRACT_BITS);
     for (j = i - 1; j > 1; j--) {
-      f[j] = f[j] + (fMultDiv2(b, f[j - 1]) << 2) + f[j - 2];
+      f[j] = SATURATE_LEFT_SHIFT(
+          ((f[j] >> 2) + fMultDiv2(b, f[j - 1]) + (f[j - 2] >> 2)), 2,
+          DFRACT_BITS);
     }
     f[1] = f[1] + (b >> (SF_F - 1));
   }
@@ -1167,6 +1171,9 @@
   /*-----------------------------------------------------*
    *  Multiply F1(z) by (1+z^-1) and F2(z) by (1-z^-1)   *
    *-----------------------------------------------------*/
+  scaleValues(f1, NC + 1, -2);
+  scaleValues(f2, NC + 1, -2);
+
   for (i = NC; i > 0; i--) {
     f1[i] += f1[i - 1];
     f2[i] -= f2[i - 1];
@@ -1175,13 +1182,8 @@
   FIXP_DBL aDBL[M_LP_FILTER_ORDER];
 
   for (i = 1, k = M_LP_FILTER_ORDER - 1; i <= NC; i++, k--) {
-    FIXP_DBL tmp1, tmp2;
-
-    tmp1 = f1[i] >> 1;
-    tmp2 = f2[i] >> 1;
-
-    aDBL[i - 1] = (tmp1 + tmp2);
-    aDBL[k] = (tmp1 - tmp2);
+    aDBL[i - 1] = f1[i] + f2[i];
+    aDBL[k] = f1[i] - f2[i];
   }
 
   int headroom_a = getScalefactor(aDBL, M_LP_FILTER_ORDER);
@@ -1190,5 +1192,5 @@
     a[i] = FX_DBL2FX_LPC(aDBL[i] << headroom_a);
   }
 
-  *a_exp = 8 - headroom_a;
+  *a_exp = SF_F + (2 - 1) - headroom_a;
 }
diff --git a/libAACdec/src/usacdec_lpd.cpp b/libAACdec/src/usacdec_lpd.cpp
index e0a2631..fbf6fab 100644
--- a/libAACdec/src/usacdec_lpd.cpp
+++ b/libAACdec/src/usacdec_lpd.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -122,17 +122,21 @@
 
 #include "ac_arith_coder.h"
 
-void filtLP(const FIXP_DBL *syn, FIXP_PCM *syn_out, FIXP_DBL *noise,
-            const FIXP_SGL *filt, INT stop, int len) {
+void filtLP(const FIXP_DBL *syn, PCM_DEC *syn_out, FIXP_DBL *noise,
+            const FIXP_SGL *filt, const INT aacOutDataHeadroom, INT stop,
+            int len) {
   INT i, j;
   FIXP_DBL tmp;
 
+  FDK_ASSERT((aacOutDataHeadroom - 1) >= -(MDCT_OUTPUT_SCALE));
+
   for (i = 0; i < stop; i++) {
     tmp = fMultDiv2(noise[i], filt[0]);  // Filt in Q-1.16
     for (j = 1; j <= len; j++) {
-      tmp += fMultDiv2((noise[i - j] + noise[i + j]), filt[j]);
+      tmp += fMult((noise[i - j] >> 1) + (noise[i + j] >> 1), filt[j]);
     }
-    syn_out[i] = (FIXP_PCM)(IMDCT_SCALE(syn[i] - tmp));
+    syn_out[i] = (PCM_DEC)(
+        IMDCT_SCALE((syn[i] >> 1) - (tmp >> 1), aacOutDataHeadroom - 1));
   }
 }
 
@@ -142,8 +146,10 @@
     FIXP_DBL *pit_gain,
     const int frame_length, /* (i) : frame length (should be 768|1024) */
     const INT l_frame,
-    const INT l_next, /* (i) : look ahead for symmetric filtering           */
-    FIXP_PCM *synth_out, /* (o) : filtered synthesis (with delay of 1 subfr) */
+    const INT l_next,   /* (i) : look ahead for symmetric filtering           */
+    PCM_DEC *synth_out, /* (o) : filtered synthesis (with delay of 1 subfr)   */
+    const INT aacOutDataHeadroom, /* (i) : headroom of the output time signal to
+                                     prevent clipping */
     FIXP_DBL mem_bpf[]) /* i/o : memory state [L_FILT+L_SUBFR]                */
 {
   INT i, sf, i_subfr, T, T2, lg;
@@ -335,17 +341,22 @@
 
       {
         for (i = 0; i < lg; i++) {
-          /* scaled with SF_SYNTH + gain_sf + 1 */
+          /* scaled with SF_SYNTH + gain_sf + 1; composition of scalefactor 2:
+           * one additional shift of syn values + fMult => fMultDiv2 */
           noise_in[i] =
-              (fMult(gainSGL, syn[i + i_subfr] - (syn[i + i_subfr - T] >> 1) -
-                                  (syn[i + i_subfr + T] >> 1))) >>
-              s1;
+              scaleValue(fMultDiv2(gainSGL, (syn[i + i_subfr] >> 1) -
+                                                (syn[i + i_subfr - T] >> 2) -
+                                                (syn[i + i_subfr + T] >> 2)),
+                         2 - s1);
         }
 
         for (i = lg; i < L_SUBFR; i++) {
-          /* scaled with SF_SYNTH + gain_sf + 1 */
+          /* scaled with SF_SYNTH + gain_sf + 1; composition of scalefactor 2:
+           * one additional shift of syn values + fMult => fMultDiv2 */
           noise_in[i] =
-              (fMult(gainSGL, syn[i + i_subfr] - syn[i + i_subfr - T])) >> s1;
+              scaleValue(fMultDiv2(gainSGL, (syn[i + i_subfr] >> 1) -
+                                                (syn[i + i_subfr - T] >> 1)),
+                         2 - s1);
         }
       }
     } else {
@@ -364,7 +375,7 @@
 
     {
       filtLP(&syn[i_subfr - L_SUBFR], &synth_out[i_subfr], noise,
-             fdk_dec_filt_lp, L_SUBFR, L_FILT);
+             fdk_dec_filt_lp, aacOutDataHeadroom, L_SUBFR, L_FILT);
     }
   }
 
@@ -377,9 +388,9 @@
     /* Output scaling of the BPF memory */
     scaleValues(mem_bpf, (L_FILT + L_SUBFR), -1);
     /* Copy the rest of the signal (after the fac) */
-    scaleValuesSaturate((FIXP_PCM *)&synth_out[l_frame],
-                        (FIXP_DBL *)&syn[l_frame - L_SUBFR],
-                        (frame_length - l_frame), MDCT_OUT_HEADROOM);
+    scaleValuesSaturate(
+        (PCM_DEC *)&synth_out[l_frame], (FIXP_DBL *)&syn[l_frame - L_SUBFR],
+        (frame_length - l_frame), MDCT_OUT_HEADROOM - aacOutDataHeadroom);
   }
 
   return;
@@ -1222,7 +1233,7 @@
       (INT)(samplingRate * PIT_MIN_12k8 + (FSCALE_DENOM / 2)) / FSCALE_DENOM -
       (INT)PIT_MIN_12k8;
 
-  if ((samplingRate < 6000) || (samplingRate > 24000)) {
+  if ((samplingRate < FAC_FSCALE_MIN) || (samplingRate > FAC_FSCALE_MAX)) {
     error = AAC_DEC_PARSE_ERROR;
     goto bail;
   }
@@ -1546,9 +1557,9 @@
 
 AAC_DECODER_ERROR CLpd_RenderTimeSignal(
     CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo,
-    CAacDecoderChannelInfo *pAacDecoderChannelInfo, FIXP_PCM *pTimeData,
-    INT lFrame, SamplingRateInfo *pSamplingRateInfo, UINT frameOk, UINT flags,
-    UINT strmFlags) {
+    CAacDecoderChannelInfo *pAacDecoderChannelInfo, PCM_DEC *pTimeData,
+    INT lFrame, SamplingRateInfo *pSamplingRateInfo, UINT frameOk,
+    const INT aacOutDataHeadroom, UINT flags, UINT strmFlags) {
   UCHAR *mod = pAacDecoderChannelInfo->data.usac.mod;
   AAC_DECODER_ERROR error = AAC_DEC_OK;
   int k, i_offset;
@@ -2011,7 +2022,8 @@
     {
       bass_pf_1sf_delay(p2_synth, pitch, pit_gain, lFrame, lFrame / facFB,
                         mod[nbDiv - 1] ? (SynDelay - (lDiv / 2)) : SynDelay,
-                        pTimeData, pAacDecoderStaticChannelInfo->mem_bpf);
+                        pTimeData, aacOutDataHeadroom,
+                        pAacDecoderStaticChannelInfo->mem_bpf);
     }
   }
 
diff --git a/libAACdec/src/usacdec_lpd.h b/libAACdec/src/usacdec_lpd.h
index 3e7938d..448dc55 100644
--- a/libAACdec/src/usacdec_lpd.h
+++ b/libAACdec/src/usacdec_lpd.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -140,13 +140,14 @@
  * \param pTimeData pointer to output buffer
  * \param samplesPerFrame amount of output samples
  * \param pSamplingRateInfo holds the sampling rate information
- * \param pWorkBuffer1 pointer to work buffer for temporal data
+ * \param aacOutDataHeadroom headroom of the output time signal to prevent
+ * clipping
  */
 AAC_DECODER_ERROR CLpd_RenderTimeSignal(
     CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo,
-    CAacDecoderChannelInfo *pAacDecoderChannelInfo, FIXP_PCM *pTimeData,
+    CAacDecoderChannelInfo *pAacDecoderChannelInfo, PCM_DEC *pTimeData,
     INT samplesPerFrame, SamplingRateInfo *pSamplingRateInfo, UINT frameOk,
-    UINT flags, UINT strmFlags);
+    const INT aacOutDataHeadroom, UINT flags, UINT strmFlags);
 
 static inline INT CLpd_FAC_getLength(int fNotShortBlock, int fac_length_long) {
   if (fNotShortBlock) {
@@ -156,8 +157,9 @@
   }
 }
 
-void filtLP(const FIXP_DBL *syn, FIXP_PCM *syn_out, FIXP_DBL *noise,
-            const FIXP_SGL *filt, INT stop, int len);
+void filtLP(const FIXP_DBL *syn, PCM_DEC *syn_out, FIXP_DBL *noise,
+            const FIXP_SGL *filt, const INT aacOutDataHeadroom, INT stop,
+            int len);
 
 /**
  * \brief perform a low-frequency pitch enhancement on time domain signal
@@ -171,13 +173,14 @@
  * \param[in] l_frame length of filtering, must be multiple of L_SUBFR
  * \param[in] l_next length of allowed look ahead on syn[i], i < l_frame+l_next
  * \param[out] synth_out pointer to time domain output signal
+ * \param[in] headroom of the output time signal to prevent clipping
  * \param[in,out] mem_bpf pointer to filter memory (L_FILT+L_SUBFR)
  */
 
 void bass_pf_1sf_delay(FIXP_DBL syn[], const INT T_sf[], FIXP_DBL *pit_gain,
                        const int frame_length, const INT l_frame,
-                       const INT l_next, FIXP_PCM *synth_out,
-                       FIXP_DBL mem_bpf[]);
+                       const INT l_next, PCM_DEC *synth_out,
+                       const INT aacOutDataHeadroom, FIXP_DBL mem_bpf[]);
 
 /**
  * \brief random sign generator for FD and TCX noise filling
diff --git a/libAACenc/include/aacenc_lib.h b/libAACenc/include/aacenc_lib.h
index 2e47571..71f7556 100644
--- a/libAACenc/include/aacenc_lib.h
+++ b/libAACenc/include/aacenc_lib.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -149,12 +149,6 @@
 All header files are provided for usage in C/C++ programs. The AAC encoder
 library API functions are located in aacenc_lib.h.
 
-In binary releases the encoder core resides in statically linkable libraries
-called for example libAACenc.a/libFDK.a (LINUX) or FDK_fastaaclib.lib (MS Visual
-C++) for the plain AAC-LC core encoder and libSBRenc.a (LINUX) or
-FDK_sbrEncLib.lib (MS Visual C++) for the SBR (Spectral Band Replication) and PS
-(Parametric Stereo) modules.
-
 \section CallingSequence Calling Sequence
 
 For encoding of ISO/MPEG-2/4 AAC bitstreams the following sequence is mandatory.
@@ -326,18 +320,12 @@
 \endcode
 
 \section writeOutData Output Bitstream Data
-If any AAC bitstream data is available, write it to output file or device. This
-can be done once the following condition is true: \code if
-(outargs.numOutBytes>0) {
-
+If any AAC bitstream data is available, write it to output file or device as
+follows. \code if (outargs.numOutBytes>0) { FDKfwrite(outputBuffer,
+outargs.numOutBytes, 1, pOutFile);
 }
 \endcode
 
-If you use file I/O then for example call mpegFileWrite_Write() from the library
-libMpegFileWrite \code mpegFileWrite_Write(hMpegFile, outputBuffer,
-outargs.numOutBytes, aacEncoder_GetParam(hAacEncoder, AACENC_GRANULE_LENGTH));
-\endcode
-
 \section cfgMetaData Meta Data Configuration
 
 If the present library is configured with Metadata support, it is possible to
@@ -427,7 +415,7 @@
 return chMode;
 \endcode
 
-\subsection bitreservoir Bitreservoir Configuration
+\subsection peakbitrate Peak Bitrate Configuration
 In AAC, the default bitreservoir configuration depends on the chosen bitrate per
 frame and the number of effective channels. The size can be determined as below.
 \f[
@@ -436,17 +424,10 @@
 Due to audio quality concerns it is not recommended to change the bitreservoir
 size to a lower value than the default setting! However, for minimizing the
 delay for streaming applications or for achieving a constant size of the
-bitstream packages in each frame, it may be necessaray to change the
-bitreservoir size. This can be done with the ::AACENC_PEAK_BITRATE parameter.
-\code
+bitstream packages in each frame, it may be necessaray to limit the maximum bits
+per frame size. This can be done with the ::AACENC_PEAK_BITRATE parameter. \code
 aacEncoder_SetParam(hAacEncoder, AACENC_PEAK_BITRATE, value);
 \endcode
-By setting ::AACENC_BITRATEMODE to fixed framing, the bitreservoir is disabled.
-A disabled bitreservoir results in a constant size for each bitstream package.
-Please note that especially at lower bitrates a disabled bitreservoir can
-downgrade the audio quality considerably! The default bitreservoir configuration
-can be achieved as follows. \code aacEncoder_SetParam(hAacEncoder,
-AACENC_BITRESERVOIR, -1); \endcode
 
 To achieve acceptable audio quality with a reduced bitreservoir size setting at
 least 1000 bits per audio channel is recommended. For a multichannel audio file
@@ -455,31 +436,32 @@
 
 
 \subsection vbrmode Variable Bitrate Mode
-The encoder provides various Variable Bitrate Modes that differ in audio quality
-and average overall bitrate. The given values are averages over time, different
-encoder settings and strongly depend on the type of audio signal. The VBR
-configurations can be adjusted via ::AACENC_BITRATEMODE encoder parameter.
+The variable bitrate (VBR) mode coding adapts the bit consumption to the
+psychoacoustic requirements of the signal. The encoder ignores the user-defined
+bit rate and selects a suitable pre-defined configuration based on the provided
+AOT. The VBR mode 1 is tuned for HE-AACv2, for VBR mode 2, HE-AACv1 should be
+used. VBR modes 3-5 should be used with Low-Complexity AAC. When encoding
+AAC-ELD, the best mode is selected automatically.
+
+The bitrates given in the table are averages over time and different encoder
+settings. They strongly depend on the type of audio signal. The VBR
+configurations can be adjusted with the ::AACENC_BITRATEMODE encoder parameter.
 \verbatim
---------------------------------------------
- VBR_MODE | Approx. Bitrate in kbps/channel
-          |     AAC-LC    |  AAC-LD/AC_ELD
-----------+---------------+-----------------
-    VBR_1 |    32 -  48   |      32 -  56
-    VBR_2 |    40 -  56   |      40 -  64
-    VBR_3 |    48 -  64   |      48 -  72
-    VBR_4 |    64 -  80   |      64 -  88
-    VBR_5 |    96 - 120   |     112 - 144
+-----------------------------------------------
+ VBR_MODE | Approx. Bitrate in kbps for stereo
+          |     AAC-LC    |      AAC-ELD
+----------+---------------+--------------------
+    VBR_1 | 32 (HE-AACv2) |         48
+    VBR_2 | 72 (HE-AACv1) |         56
+    VBR_3 |      112      |         72
+    VBR_4 |      148      |        148
+    VBR_5 |      228      |        224
 --------------------------------------------
 \endverbatim
-The bitrate ranges apply for individual audio channels. In case of multichannel
-configurations the average bitrate might be estimated by multiplying with the
-number of effective channels. This corresponds to all audio input channels
-exclusively the low frequency channel. At configurations which are making use of
-downmix modules the AAC core channels respectively downmix channels shall be
-considered. For ::AACENC_AOT which are using SBR, the average bitrate can be
-estimated by using the ratio of 0.5 for dualrate SBR and 0.75 for downsampled
-SBR configurations.
-
+Note that these figures are valid for stereo encoding only. VBR modes 2-5 will
+yield much lower bit rates when encoding single-channel input. For
+configurations which are making use of downmix modules the AAC core channels
+respectively downmix channels shall be considered.
 
 \subsection encQual Audio Quality Considerations
 The default encoder configuration is suggested to be used. Encoder tools such as
@@ -967,9 +949,7 @@
 
 \subsection BEHAVIOUR_ESTIM_AVG_FRAMESIZES Estimating Average Frame Sizes
 
-A HE-AAC v1 or v2 audio frame contains 2048 PCM samples per channel (there is
-also one mode with 1920 samples per channel but this is only for special
-purposes such as DAB+ digital radio).
+A HE-AAC v1 or v2 audio frame contains 2048 PCM samples per channel.
 
 The number of HE-AAC frames \f$N\_FRAMES\f$ per second at 44.1 kHz is:
 
@@ -1082,9 +1062,7 @@
 typedef struct {
   UINT maxOutBufBytes; /*!< Maximum number of encoder bitstream bytes within one
                           frame. Size depends on maximum number of supported
-                          channels in encoder instance. For superframing (as
-                          used for example in DAB+), size has to be a multiple
-                          accordingly. */
+                          channels in encoder instance. */
 
   UINT maxAncBytes; /*!< Maximum number of ancillary data bytes which can be
                        inserted into bitstream within one frame. */
diff --git a/libAACenc/src/aacEnc_ram.cpp b/libAACenc/src/aacEnc_ram.cpp
index 77b1131..25e2aec 100644
--- a/libAACenc/src/aacEnc_ram.cpp
+++ b/libAACenc/src/aacEnc_ram.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -204,5 +204,5 @@
    * (dynamic_RAM + P_BUF_0 + n*sizeof(QC_OUT_CHANNEL)) is sufficiently aligned,
    * so the cast is safe */
   return reinterpret_cast<QC_OUT_CHANNEL *>(reinterpret_cast<void *>(
-      dynamic_RAM + P_BUF_0 + n * sizeof(QC_OUT_CHANNEL)));
+      dynamic_RAM + P_BUF_0 + n * ALIGN_SIZE(sizeof(QC_OUT_CHANNEL))));
 }
diff --git a/libAACenc/src/aacEnc_ram.h b/libAACenc/src/aacEnc_ram.h
index 0775aae..f24eef1 100644
--- a/libAACenc/src/aacEnc_ram.h
+++ b/libAACenc/src/aacEnc_ram.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -198,7 +198,7 @@
  +++++++++++++++++++++++++++++++++++++++++++++++++++++
 */
 
-#define BUF_SIZE_0 (ALIGN_SIZE(sizeof(QC_OUT_CHANNEL) * (8)))
+#define BUF_SIZE_0 (ALIGN_SIZE(sizeof(QC_OUT_CHANNEL)) * (8))
 #define BUF_SIZE_1                                                           \
   (ALIGN_SIZE(maxSize(maxSize(sizeof(PSY_DYNAMIC),                           \
                               (BIT_LOOK_UP_SIZE + MERGE_GAIN_LOOK_UP_SIZE)), \
diff --git a/libAACenc/src/aacenc.cpp b/libAACenc/src/aacenc.cpp
index 8b8a1ad..b6f733d 100644
--- a/libAACenc/src/aacenc.cpp
+++ b/libAACenc/src/aacenc.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -114,6 +114,8 @@
 
 #include "genericStds.h"
 
+#define BITRES_MIN \
+  300 /* default threshold for using reduced/disabled bitres mode */
 #define BITRES_MAX_LD 4000
 #define BITRES_MIN_LD 500
 #define BITRATE_MAX_LD 70000 /* Max assumed bitrate for bitres calculation */
@@ -550,7 +552,8 @@
         (config->minBitsPerFrame != -1) ? config->minBitsPerFrame : 0;
     qcInit.minBits = fixMin(qcInit.minBits, averageBitsPerFrame & ~7);
   } else {
-    INT bitreservoir = -1; /* default bitrservoir size*/
+    INT bitreservoir = -1; /* default bitreservoir size*/
+    bitresMin = BITRES_MIN;
     if (isLowDelay(config->audioObjectType)) {
       INT brPerChannel = config->bitRate / config->nChannels;
       brPerChannel = fMin(BITRATE_MAX_LD, fMax(BITRATE_MIN_LD, brPerChannel));
@@ -601,9 +604,9 @@
   qcInit.nSubFrames = config->nSubFrames;
   qcInit.padding.paddingRest = config->sampleRate;
 
-  if (qcInit.bitRes >= bitresMin * config->nChannels) {
+  if (qcInit.maxBits - qcInit.averageBits >= bitresMin * config->nChannels) {
     qcInit.bitResMode = AACENC_BR_MODE_FULL; /* full bitreservoir */
-  } else if (qcInit.bitRes > 0) {
+  } else if (qcInit.maxBits > qcInit.averageBits) {
     qcInit.bitResMode = AACENC_BR_MODE_REDUCED; /* reduced bitreservoir */
   } else {
     qcInit.bitResMode = AACENC_BR_MODE_DISABLED; /* disabled bitreservoir */
diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp
index 0f0094f..2c2010f 100644
--- a/libAACenc/src/aacenc_lib.cpp
+++ b/libAACenc/src/aacenc_lib.cpp
@@ -110,7 +110,7 @@
 /* Encoder library info */
 #define AACENCODER_LIB_VL0 4
 #define AACENCODER_LIB_VL1 0
-#define AACENCODER_LIB_VL2 0
+#define AACENCODER_LIB_VL2 1
 #define AACENCODER_LIB_TITLE "AAC Encoder"
 #ifdef __ANDROID__
 #define AACENCODER_LIB_BUILD_DATE ""
@@ -446,6 +446,24 @@
   return sbrSignaling;
 }
 
+static inline INT getAssociatedChElement(SBR_ELEMENT_INFO *elInfoSbr,
+                                         CHANNEL_MAPPING *channelMapping) {
+  ELEMENT_INFO *elInfo = channelMapping->elInfo;
+  INT nElements = channelMapping->nElements;
+  INT associatedChElement = -1;
+  int i;
+
+  for (i = 0; i < nElements; i++) {
+    if (elInfoSbr->elType == elInfo[i].elType &&
+        elInfoSbr->instanceTag == elInfo[i].instanceTag) {
+      associatedChElement = i;
+      break;
+    }
+  }
+
+  return associatedChElement;
+}
+
 /****************************************************************************
                                Allocate Encoder
 ****************************************************************************/
@@ -1921,7 +1939,15 @@
           {
             hAacEncoder->extPayload[nExtensions].dataSize =
                 hAacEncoder->pSbrPayload->dataSize[nPayload][i];
-            hAacEncoder->extPayload[nExtensions].associatedChElement = i;
+            hAacEncoder->extPayload[nExtensions].associatedChElement =
+                getAssociatedChElement(
+                    &hAacEncoder->hEnvEnc->sbrElement[i]->elInfo,
+                    &hAacEncoder->hAacEnc->channelMapping);
+            if (hAacEncoder->extPayload[nExtensions].associatedChElement ==
+                -1) {
+              err = AACENC_ENCODE_ERROR;
+              goto bail;
+            }
           }
           hAacEncoder->extPayload[nExtensions].dataType =
               EXT_SBR_DATA; /* Once SBR Encoder supports SBR CRC set
diff --git a/libAACenc/src/adj_thr.cpp b/libAACenc/src/adj_thr.cpp
index 226d003..239abd0 100644
--- a/libAACenc/src/adj_thr.cpp
+++ b/libAACenc/src/adj_thr.cpp
@@ -1302,14 +1302,6 @@
           if (sfbThrReducedLdData < FL2FXCONST_DBL(-0.5f))
             sfbThrReducedLdData = FL2FXCONST_DBL(-1.f);
 
-          /* minimum of 29 dB Ratio for Thresholds */
-          if ((sfbEnLdData + FL2FXCONST_DBL(1.0f)) >
-              FL2FXCONST_DBL(9.6336206 / LD_DATA_SCALING)) {
-            sfbThrReducedLdData = fixMax(
-                sfbThrReducedLdData,
-                sfbEnLdData - FL2FXCONST_DBL(9.6336206 / LD_DATA_SCALING));
-          }
-
           sfbThrReducedLdData = fixMax(MIN_LDTHRESH, sfbThrReducedLdData);
 
           qcOutChan->sfbThresholdLdData[sfbGrp + sfb] = sfbThrReducedLdData;
diff --git a/libAACenc/src/bandwidth.cpp b/libAACenc/src/bandwidth.cpp
index 36cd64d..e814f05 100644
--- a/libAACenc/src/bandwidth.cpp
+++ b/libAACenc/src/bandwidth.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -151,11 +151,11 @@
 
 static const BANDWIDTH_TAB_VBR bandWidthTableVBR[] = {
     {AACENC_BR_MODE_CBR, 0, 0},
-    {AACENC_BR_MODE_VBR_1, 13050, 13050},
-    {AACENC_BR_MODE_VBR_2, 13050, 13050},
-    {AACENC_BR_MODE_VBR_3, 14260, 14260},
-    {AACENC_BR_MODE_VBR_4, 15500, 15500},
-    {AACENC_BR_MODE_VBR_5, 48000, 48000},
+    {AACENC_BR_MODE_VBR_1, 13000, 13000},
+    {AACENC_BR_MODE_VBR_2, 13000, 13000},
+    {AACENC_BR_MODE_VBR_3, 15750, 15750},
+    {AACENC_BR_MODE_VBR_4, 16500, 16500},
+    {AACENC_BR_MODE_VBR_5, 19293, 19293},
     {AACENC_BR_MODE_SFR, 0, 0},
     {AACENC_BR_MODE_FF, 0, 0}
 
diff --git a/libAACenc/src/qc_main.cpp b/libAACenc/src/qc_main.cpp
index ba3bc7e..bcfaa23 100644
--- a/libAACenc/src/qc_main.cpp
+++ b/libAACenc/src/qc_main.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -121,20 +121,15 @@
 
 static const TAB_VBR_QUAL_FACTOR tableVbrQualFactor[] = {
     {QCDATA_BR_MODE_VBR_1,
-     FL2FXCONST_DBL(0.160f)}, /* Approx. 32 -  48 (AC-LC),  32 -  56
-                                 (AAC-LD/ELD) kbps/channel */
+     FL2FXCONST_DBL(0.150f)}, /* Approx.  32 kbps mono   AAC-LC + SBR + PS */
     {QCDATA_BR_MODE_VBR_2,
-     FL2FXCONST_DBL(0.148f)}, /* Approx. 40 -  56 (AC-LC),  40 -  64
-                                 (AAC-LD/ELD) kbps/channel */
+     FL2FXCONST_DBL(0.162f)}, /* Approx.  64 kbps stereo AAC-LC + SBR      */
     {QCDATA_BR_MODE_VBR_3,
-     FL2FXCONST_DBL(0.135f)}, /* Approx. 48 -  64 (AC-LC),  48 -  72
-                                 (AAC-LD/ELD) kbps/channel */
+     FL2FXCONST_DBL(0.176f)}, /* Approx.  96 kbps stereo AAC-LC            */
     {QCDATA_BR_MODE_VBR_4,
-     FL2FXCONST_DBL(0.111f)}, /* Approx. 64 -  80 (AC-LC),  64 -  88
-                                 (AAC-LD/ELD) kbps/channel */
+     FL2FXCONST_DBL(0.120f)}, /* Approx. 128 kbps stereo AAC-LC            */
     {QCDATA_BR_MODE_VBR_5,
-     FL2FXCONST_DBL(0.070f)} /* Approx. 96 - 120 (AC-LC), 112 - 144
-                                (AAC-LD/ELD) kbps/channel */
+     FL2FXCONST_DBL(0.070f)} /* Approx. 192 kbps stereo AAC-LC            */
 };
 
 static INT isConstantBitrateMode(const QCDATA_BR_MODE bitrateMode) {
diff --git a/libDRCdec/include/FDK_drcDecLib.h b/libDRCdec/include/FDK_drcDecLib.h
index 2d28d23..79f8566 100644
--- a/libDRCdec/include/FDK_drcDecLib.h
+++ b/libDRCdec/include/FDK_drcDecLib.h
@@ -114,6 +114,8 @@
 extern "C" {
 #endif
 
+#define DRC_DEC_LOUDNESS_NOT_PRESENT (LONG)0x7FFFFFFE
+
 typedef struct s_drc_decoder* HANDLE_DRC_DECODER;
 typedef struct s_uni_drc_interface* HANDLE_UNI_DRC_INTERFACE;
 typedef struct s_selection_process_output* HANDLE_SEL_PROC_OUTPUT;
@@ -150,9 +152,12 @@
   DRC_DEC_IS_ACTIVE, /**< MPEG-D DRC payload is present and at least one of
                         Dynamic Range Control (DRC) or Loudness Normalization
                         (LN) is activated */
-  DRC_DEC_TARGET_CHANNEL_COUNT_SELECTED /**< number of output channels if
-                                           appropriate downmixInstruction exists
-                                         */
+  DRC_DEC_TARGET_CHANNEL_COUNT_SELECTED, /**< number of output channels if
+                                            appropriate downmixInstruction
+                                            exists */
+  DRC_DEC_OUTPUT_LOUDNESS /**< output loudness in dB, with exponent e = 7, or
+                             DRC_DEC_LOUDNESS_NOT_PRESENT if no loudness is
+                             contained in the bitstream */
 } DRC_DEC_USERPARAM;
 
 typedef enum {
diff --git a/libDRCdec/src/FDK_drcDecLib.cpp b/libDRCdec/src/FDK_drcDecLib.cpp
index 4f8ebc7..83b5773 100644
--- a/libDRCdec/src/FDK_drcDecLib.cpp
+++ b/libDRCdec/src/FDK_drcDecLib.cpp
@@ -145,6 +145,10 @@
   SEL_PROC_OUTPUT selProcOutput;
 } DRC_DECODER;
 
+static int _getGainStatus(HANDLE_UNI_DRC_GAIN hUniDrcGain) {
+  return hUniDrcGain->status;
+}
+
 static int isResetNeeded(HANDLE_DRC_DECODER hDrcDec,
                          const SEL_PROC_OUTPUT oldSelProcOutput) {
   int i, resetNeeded = 0;
@@ -515,6 +519,8 @@
     }
     case DRC_DEC_TARGET_CHANNEL_COUNT_SELECTED:
       return (LONG)hDrcDec->selProcOutput.targetChannelCount;
+    case DRC_DEC_OUTPUT_LOUDNESS:
+      return (LONG)hDrcDec->selProcOutput.outputLoudness;
     default:
       return 0;
   }
@@ -729,7 +735,9 @@
       &(hDrcDec->uniDrcGain));
   if (dErr) return DRC_DEC_NOT_OK;
 
-  hDrcDec->status = DRC_DEC_NEW_GAIN_PAYLOAD;
+  if (_getGainStatus(&(hDrcDec->uniDrcGain))) {
+    hDrcDec->status = DRC_DEC_NEW_GAIN_PAYLOAD;
+  }
 
   return DRC_DEC_OK;
 }
@@ -751,7 +759,9 @@
   startSelectionProcess(hDrcDec);
   if (dErr) return DRC_DEC_NOT_OK;
 
-  hDrcDec->status = DRC_DEC_NEW_GAIN_PAYLOAD;
+  if (_getGainStatus(&(hDrcDec->uniDrcGain))) {
+    hDrcDec->status = DRC_DEC_NEW_GAIN_PAYLOAD;
+  }
 
   return DRC_DEC_OK;
 }
diff --git a/libDRCdec/src/drcDec_gainDecoder.cpp b/libDRCdec/src/drcDec_gainDecoder.cpp
index 9d91267..de54dde 100644
--- a/libDRCdec/src/drcDec_gainDecoder.cpp
+++ b/libDRCdec/src/drcDec_gainDecoder.cpp
@@ -297,9 +297,11 @@
   int seq, gainSequenceCount;
   DRC_COEFFICIENTS_UNI_DRC* pCoef =
       selectDrcCoefficients(hUniDrcConfig, LOCATION_SELECTED);
-  if (pCoef == NULL) return DE_OK;
-
-  gainSequenceCount = fMin(pCoef->gainSequenceCount, (UCHAR)12);
+  if (pCoef && pCoef->gainSequenceCount) {
+    gainSequenceCount = fMin(pCoef->gainSequenceCount, (UCHAR)12);
+  } else {
+    gainSequenceCount = 1;
+  }
 
   for (seq = 0; seq < gainSequenceCount; seq++) {
     int lastNodeIndex = 0;
diff --git a/libDRCdec/src/drcDec_reader.cpp b/libDRCdec/src/drcDec_reader.cpp
index a784457..367a352 100644
--- a/libDRCdec/src/drcDec_reader.cpp
+++ b/libDRCdec/src/drcDec_reader.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -199,11 +199,8 @@
     }
   }
 
-  if (hUniDrcGain != NULL) {
-    err = drcDec_readUniDrcGain(hBs, hUniDrcConfig, frameSize, deltaTminDefault,
-                                hUniDrcGain);
-    if (err) return err;
-  }
+  err = drcDec_readUniDrcGain(hBs, hUniDrcConfig, frameSize, deltaTminDefault,
+                              hUniDrcGain);
 
   return err;
 }
@@ -487,10 +484,13 @@
   int seq, gainSequenceCount;
   DRC_COEFFICIENTS_UNI_DRC* pCoef =
       selectDrcCoefficients(hUniDrcConfig, LOCATION_SELECTED);
-  if (pCoef == NULL) return DE_OK;
-  if (hUniDrcGain == NULL) return DE_OK; /* hUniDrcGain not initialized yet */
-
-  gainSequenceCount = fMin(pCoef->gainSequenceCount, (UCHAR)12);
+  if (hUniDrcGain == NULL) return DE_NOT_OK;
+  hUniDrcGain->status = 0;
+  if (pCoef) {
+    gainSequenceCount = fMin(pCoef->gainSequenceCount, (UCHAR)12);
+  } else {
+    gainSequenceCount = 0;
+  }
 
   for (seq = 0; seq < gainSequenceCount; seq++) {
     UCHAR index = pCoef->gainSetIndexForGainSequence[seq];
@@ -518,6 +518,9 @@
     if (err) return err;
   }
 
+  if (err == DE_OK && gainSequenceCount > 0) {
+    hUniDrcGain->status = 1;
+  }
   return err;
 }
 
@@ -1018,6 +1021,7 @@
   int additionalDrcSetIdPresent, additionalDrcSetIdCount;
   int dependsOnEqSetPresent, eqChannelGroupCount, tdFilterCascadePresent,
       subbandGainsPresent, eqTransitionDurationPresent;
+  UCHAR eqChannelGroupForChannel[8];
 
   FDKpushFor(hBs, 6); /* eqSetId */
   FDKpushFor(hBs, 4); /* eqSetComplexityLevel */
@@ -1067,7 +1071,6 @@
 
   eqChannelGroupCount = 0;
   for (c = 0; c < channelCount; c++) {
-    UCHAR eqChannelGroupForChannel[8];
     int newGroup = 1;
     if (c >= 8) return DE_MEMORY_ERROR;
     eqChannelGroupForChannel[c] = FDKreadBits(hBs, 7);
diff --git a/libDRCdec/src/drcDec_selectionProcess.cpp b/libDRCdec/src/drcDec_selectionProcess.cpp
index c33bf74..46ed740 100644
--- a/libDRCdec/src/drcDec_selectionProcess.cpp
+++ b/libDRCdec/src/drcDec_selectionProcess.cpp
@@ -103,8 +103,6 @@
 #include "drcDec_selectionProcess.h"
 #include "drcDec_tools.h"
 
-#define UNDEFINED_LOUDNESS_VALUE (FIXP_DBL) MAXVAL_DBL
-
 typedef enum {
   DETR_NONE = 0,
   DETR_NIGHT = 1,
@@ -753,8 +751,8 @@
   hSelProcInput->loudnessNormalizationOn = 1;
   hSelProcInput->targetLoudness = FL2FXCONST_DBL(-24.0f / (float)(1 << 7));
   hSelProcInput->loudnessDeviationMax = DEFAULT_LOUDNESS_DEVIATION_MAX;
-  hSelProcInput->loudnessMeasurementMethod = MDR_DEFAULT;
-  hSelProcInput->loudnessMeasurementSystem = MSR_DEFAULT;
+  hSelProcInput->loudnessMeasurementMethod = MDR_ANCHOR_LOUDNESS;
+  hSelProcInput->loudnessMeasurementSystem = MSR_EXPERT_PANEL;
   hSelProcInput->loudnessMeasurementPreProc = LPR_DEFAULT;
   hSelProcInput->deviceCutOffFrequency = 500;
   hSelProcInput->loudnessNormalizationGainDbMax =
@@ -956,17 +954,31 @@
   return DRCDEC_SELECTION_PROCESS_NO_ERROR;
 }
 
-/* #5: The number of DRC bands is supported. */
+/* #5: The number of DRC bands is supported. Moreover, gainSetIndex and
+ * gainSequenceIndex are within the allowed range. */
 static DRCDEC_SELECTION_PROCESS_RETURN _preSelectionRequirement5(
     DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc,
     DRC_COEFFICIENTS_UNI_DRC* pCoef, int* pMatchFound) {
-  int i;
+  int b, i;
 
   *pMatchFound = 1;
 
+  if (pDrcInstructionUniDrc->drcSetId < 0) /* virtual DRC sets are okay */
+  {
+    return DRCDEC_SELECTION_PROCESS_NO_ERROR;
+  }
+
   if (pCoef == NULL) /* check for parametricDRC */
   {
-    *pMatchFound = 1;
+    *pMatchFound = 0; /* parametricDRC not supported */
+    return DRCDEC_SELECTION_PROCESS_NO_ERROR;
+  }
+
+  if (pCoef->drcLocation !=
+      pDrcInstructionUniDrc
+          ->drcLocation) /* drcLocation must be LOCATION_SELECTED */
+  {
+    *pMatchFound = 0;
     return DRCDEC_SELECTION_PROCESS_NO_ERROR;
   }
 
@@ -974,10 +986,14 @@
     int indexDrcCoeff = pDrcInstructionUniDrc->gainSetIndexForChannelGroup[i];
     int bandCount = 0;
 
+    if (indexDrcCoeff >= 12) {
+      *pMatchFound = 0;
+      return DRCDEC_SELECTION_PROCESS_NO_ERROR;
+    }
+
     if (indexDrcCoeff > pCoef->gainSetCount - 1) /* check for parametricDRC */
     {
-      *pMatchFound = 1;
-      return DRCDEC_SELECTION_PROCESS_NO_ERROR;
+      continue;
     }
 
     GAIN_SET* gainSet = &(pCoef->gainSet[indexDrcCoeff]);
@@ -986,6 +1002,14 @@
     if (bandCount > 4) {
       *pMatchFound = 0;
     }
+
+    for (b = 0; b < bandCount; b++) {
+      if ((gainSet->gainSequenceIndex[b] >= 12) ||
+          (gainSet->gainSequenceIndex[b] >= pCoef->gainSequenceCount)) {
+        *pMatchFound = 0;
+        return DRCDEC_SELECTION_PROCESS_NO_ERROR;
+      }
+    }
   }
 
   return DRCDEC_SELECTION_PROCESS_NO_ERROR;
@@ -1078,6 +1102,19 @@
   return retVal;
 }
 
+static int _drcSetIsUsable(HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
+                           DRC_INSTRUCTIONS_UNI_DRC* pInst) {
+  int usable = 0;
+  DRC_COEFFICIENTS_UNI_DRC* pCoef =
+      selectDrcCoefficients(hUniDrcConfig, LOCATION_SELECTED);
+
+  /* check if ID is unique */
+  if (selectDrcInstructions(hUniDrcConfig, pInst->drcSetId) != pInst) return 0;
+  /* sanity check on drcInstructions */
+  _preSelectionRequirement5(pInst, pCoef, &usable);
+  return usable;
+}
+
 /* #8: The range of the target loudness specified for a DRC set has to include
  * the requested decoder target loudness. */
 static DRCDEC_SELECTION_PROCESS_RETURN _preSelectionRequirement8(
@@ -1097,9 +1134,8 @@
 
   FIXP_DBL loudnessDeviationMax =
       ((FIXP_DBL)hSelProcInput->loudnessDeviationMax) << (DFRACT_BITS - 1 - 7);
-  ;
 
-  if (hSelProcInput->loudnessNormalizationOn) {
+  {
     retVal = _getLoudness(hLoudnessInfoSet, hSelProcInput->albumMode,
                           hSelProcInput->loudnessMeasurementMethod,
                           hSelProcInput->loudnessMeasurementSystem,
@@ -1108,9 +1144,10 @@
                           hSelProcInput->downmixIdRequested[downmixIdIndex],
                           &loudnessNormalizationGainDb, &loudness);
     if (retVal) return (retVal);
-  } else {
+  }
+
+  if (!hSelProcInput->loudnessNormalizationOn) {
     loudnessNormalizationGainDb = (FIXP_DBL)0;
-    loudness = UNDEFINED_LOUDNESS_VALUE;
   }
 
   retVal = _getSignalPeakLevel(
@@ -2031,6 +2068,7 @@
       pSelectionData->loudnessNormalizationGainDbAdjusted +
       hSelProcInput->loudnessNormalizationGainModificationDb;
   hSelProcOutput->outputPeakLevelDb = pSelectionData->outputPeakLevel;
+  hSelProcOutput->outputLoudness = pSelectionData->outputLoudness;
 
   hSelProcOutput->boost = boost;
   hSelProcOutput->compress = compress;
@@ -2051,8 +2089,11 @@
     int dependsOnDrcSetID = pSelectionData->pInst->dependsOnDrcSet;
 
     for (i = 0; i < hUniDrcConfig->drcInstructionsCountInclVirtual; i++) {
-      if (hUniDrcConfig->drcInstructionsUniDrc[i].drcSetId ==
-          dependsOnDrcSetID) {
+      DRC_INSTRUCTIONS_UNI_DRC* pInst =
+          &(hUniDrcConfig->drcInstructionsUniDrc[i]);
+      if (!_drcSetIsUsable(hUniDrcConfig, pInst)) continue;
+
+      if (pInst->drcSetId == dependsOnDrcSetID) {
         hSelProcOutput->selectedDrcSetIds[hSelProcOutput->numSelectedDrcSets] =
             hUniDrcConfig->drcInstructionsUniDrc[i].drcSetId;
         hSelProcOutput->selectedDownmixIds[hSelProcOutput->numSelectedDrcSets] =
@@ -2071,6 +2112,7 @@
     for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCount; i++) {
       DRC_INSTRUCTIONS_UNI_DRC* pInst =
           &(hUniDrcConfig->drcInstructionsUniDrc[i]);
+      if (!_drcSetIsUsable(hUniDrcConfig, pInst)) continue;
 
       if (pInst->drcSetEffect & EB_FADE) {
         if (pInst->downmixId[0] == DOWNMIX_ID_ANY_DOWNMIX) {
@@ -2098,6 +2140,7 @@
   for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCount; i++) {
     DRC_INSTRUCTIONS_UNI_DRC* pInst =
         &(hUniDrcConfig->drcInstructionsUniDrc[i]);
+    if (!_drcSetIsUsable(hUniDrcConfig, pInst)) continue;
 
     if (pInst->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) {
       for (j = 0; j < pInst->downmixIdCount; j++) {
@@ -2124,6 +2167,7 @@
     for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCount; i++) {
       DRC_INSTRUCTIONS_UNI_DRC* pInst =
           &(hUniDrcConfig->drcInstructionsUniDrc[i]);
+      if (!_drcSetIsUsable(hUniDrcConfig, pInst)) continue;
 
       if (pInst->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) {
         for (j = 0; j < pInst->downmixIdCount; j++) {
@@ -2231,6 +2275,11 @@
     for (j = 0; j < hUniDrcConfig->drcInstructionsCountInclVirtual; j++) {
       DRC_INSTRUCTIONS_UNI_DRC* pDrcInstruction =
           &(hUniDrcConfig->drcInstructionsUniDrc[j]);
+      /* check if ID is unique */
+      if (selectDrcInstructions(hUniDrcConfig, pDrcInstruction->drcSetId) !=
+          pDrcInstruction)
+        continue;
+
       retVal = _drcSetPreSelectionSingleInstruction(
           hSelProcInput, i, hUniDrcConfig, hLoudnessInfoSet, pDrcInstruction,
           *ppCandidatesPotential, *ppCandidatesSelected, codecMode);
diff --git a/libDRCdec/src/drcDec_selectionProcess.h b/libDRCdec/src/drcDec_selectionProcess.h
index 420bae6..0f878cf 100644
--- a/libDRCdec/src/drcDec_selectionProcess.h
+++ b/libDRCdec/src/drcDec_selectionProcess.h
@@ -111,6 +111,8 @@
 
 typedef struct s_drcdec_selection_process* HANDLE_DRC_SELECTION_PROCESS;
 
+#define UNDEFINED_LOUDNESS_VALUE (FIXP_DBL)(MAXVAL_DBL - 1)
+
 typedef enum {
   DRCDEC_SELECTION_PROCESS_NO_ERROR = 0,
 
diff --git a/libDRCdec/src/drcDec_types.h b/libDRCdec/src/drcDec_types.h
index 6b99018..b0d89c1 100644
--- a/libDRCdec/src/drcDec_types.h
+++ b/libDRCdec/src/drcDec_types.h
@@ -130,6 +130,9 @@
 
   UCHAR uniDrcGainExtPresent;
   UNI_DRC_GAIN_EXTENSION uniDrcGainExtension;
+
+  /* derived data */
+  UCHAR status;
 } UNI_DRC_GAIN, *HANDLE_UNI_DRC_GAIN;
 
 /****************/
diff --git a/libDRCdec/src/drcGainDec_preprocess.cpp b/libDRCdec/src/drcGainDec_preprocess.cpp
index c543c53..8d94ace 100644
--- a/libDRCdec/src/drcGainDec_preprocess.cpp
+++ b/libDRCdec/src/drcGainDec_preprocess.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -285,6 +285,9 @@
                   &e_tmp2);
   invExp = fDivNorm(FL2FXCONST_DBL(1.0f / (float)(1 << 1)), exp, &e_invExp);
   e_invExp += 1 - 5;
+  if (tmp2 < (FIXP_DBL)0) {
+    return DE_NOT_OK;
+  }
   denom = fPow(tmp2, e_tmp2, invExp, e_invExp, &e_denom);
   *out = fDivNormSigned(tmp, denom, &e_out);
   e_out += 7 - e_denom;
diff --git a/libFDK/include/FDK_qmf_domain.h b/libFDK/include/FDK_qmf_domain.h
index 5c12682..0e83da3 100644
--- a/libFDK/include/FDK_qmf_domain.h
+++ b/libFDK/include/FDK_qmf_domain.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -123,11 +123,10 @@
 #define QMF_WB_SECTION_SIZE (1024 * 2)
 
 H_ALLOC_MEM_OVERLAY(QmfWorkBufferCore1, FIXP_DBL)
-H_ALLOC_MEM_OVERLAY(QmfWorkBufferCore2, FIXP_DBL)
 H_ALLOC_MEM_OVERLAY(QmfWorkBufferCore3, FIXP_DBL)
 H_ALLOC_MEM_OVERLAY(QmfWorkBufferCore4, FIXP_DBL)
-H_ALLOC_MEM_OVERLAY(QmfWorkBufferCore5, FIXP_DBL)
 H_ALLOC_MEM_OVERLAY(QmfWorkBufferCore6, FIXP_DBL)
+H_ALLOC_MEM_OVERLAY(QmfWorkBufferCore7, FIXP_DBL)
 
 #define QMF_DOMAIN_MAX_ANALYSIS_QMF_BANDS (64)
 #define QMF_DOMAIN_MAX_SYNTHESIS_QMF_BANDS (QMF_MAX_SYNTHESIS_BANDS)
@@ -145,15 +144,15 @@
 #define QMF_DOMAIN_OV_TIMESLOTS_16 (3)
 #define QMF_DOMAIN_OV_TIMESLOTS_32 (6)
 
-H_ALLOC_MEM(AnaQmfStates, FIXP_QAS)
+H_ALLOC_MEM(AnaQmfStates, FIXP_DBL)
 H_ALLOC_MEM(SynQmfStates, FIXP_QSS)
 H_ALLOC_MEM(QmfSlotsReal, FIXP_DBL *)
 H_ALLOC_MEM(QmfSlotsImag, FIXP_DBL *)
 H_ALLOC_MEM(QmfOverlapBuffer, FIXP_DBL)
 
-H_ALLOC_MEM(AnaQmfStates16, FIXP_QAS)
-H_ALLOC_MEM(AnaQmfStates24, FIXP_QAS)
-H_ALLOC_MEM(AnaQmfStates32, FIXP_QAS)
+H_ALLOC_MEM(AnaQmfStates16, FIXP_DBL)
+H_ALLOC_MEM(AnaQmfStates24, FIXP_DBL)
+H_ALLOC_MEM(AnaQmfStates32, FIXP_DBL)
 H_ALLOC_MEM(QmfSlotsReal16, FIXP_DBL *)
 H_ALLOC_MEM(QmfSlotsReal32, FIXP_DBL *)
 H_ALLOC_MEM(QmfSlotsImag16, FIXP_DBL *)
@@ -161,8 +160,6 @@
 H_ALLOC_MEM(QmfOverlapBuffer16, FIXP_DBL)
 H_ALLOC_MEM(QmfOverlapBuffer32, FIXP_DBL)
 
-#define QDOM_PCM INT_PCM
-
 /**
  * Structure to hold the configuration data which is global whithin a QMF domain
  * instance.
@@ -182,9 +179,6 @@
                   park a channel if only one processing channel is
                   available. */
   UCHAR parkChannel_requested;
-  QDOM_PCM
-  *TDinput; /*!< Pointer to time domain data used as input for the QMF
-               analysis. */
   FIXP_DBL *
       pWorkBuffer[QMF_MAX_WB_SECTIONS]; /*!< Pointerarray to volatile memory. */
   UINT flags; /*!< Flags to be set on all QMF analysis/synthesis filter
@@ -244,7 +238,7 @@
                                 (workBuf_nTimeSlots * workBuf_nBands * CMPLX_MOD). */
   USHORT workBufferOffset;   /*!< Offset within work buffer. */
   USHORT workBufferSectSize; /*!< Size of work buffer section. */
-  FIXP_QAS *
+  FIXP_DBL *
       pAnaQmfStates; /*!< Pointer to QMF analysis states (persistent memory). */
   FIXP_DBL
   *pOverlapBuffer;        /*!< Pointer to QMF overlap/delay memory (persistent
diff --git a/libFDK/include/fixpoint_math.h b/libFDK/include/fixpoint_math.h
index 3805892..51df4d7 100644
--- a/libFDK/include/fixpoint_math.h
+++ b/libFDK/include/fixpoint_math.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -171,6 +171,19 @@
  * \return non-zero if (a_m*2^a_e) < (b_m*2^b_e), 0 otherwise
  */
 FDK_INLINE INT fIsLessThan(FIXP_DBL a_m, INT a_e, FIXP_DBL b_m, INT b_e) {
+  INT n;
+
+  n = fixnorm_D(a_m);
+  a_m <<= n;
+  a_e -= n;
+
+  n = fixnorm_D(b_m);
+  b_m <<= n;
+  b_e -= n;
+
+  if (a_m == (FIXP_DBL)0) a_e = b_e;
+  if (b_m == (FIXP_DBL)0) b_e = a_e;
+
   if (a_e > b_e) {
     return ((b_m >> fMin(a_e - b_e, DFRACT_BITS - 1)) > a_m);
   } else {
@@ -179,6 +192,19 @@
 }
 
 FDK_INLINE INT fIsLessThan(FIXP_SGL a_m, INT a_e, FIXP_SGL b_m, INT b_e) {
+  INT n;
+
+  n = fixnorm_S(a_m);
+  a_m <<= n;
+  a_e -= n;
+
+  n = fixnorm_S(b_m);
+  b_m <<= n;
+  b_e -= n;
+
+  if (a_m == (FIXP_SGL)0) a_e = b_e;
+  if (b_m == (FIXP_SGL)0) b_e = a_e;
+
   if (a_e > b_e) {
     return ((b_m >> fMin(a_e - b_e, FRACT_BITS - 1)) > a_m);
   } else {
@@ -545,15 +571,20 @@
   m = fMultNorm(a, (FIXP_DBL)b, &m_e);
 
   if (m_e < (INT)0) {
-    if (m_e > (INT)-DFRACT_BITS) {
+    if (m_e > (INT) - (DFRACT_BITS - 1)) {
       mi = (m >> (-m_e));
       if ((LONG)m & ((1 << (-m_e)) - 1)) {
         mi = mi + (FIXP_DBL)1;
       }
     } else {
-      mi = (FIXP_DBL)1;
-      if (m < (FIXP_DBL)0) {
-        mi = (FIXP_DBL)0;
+      if (m > (FIXP_DBL)0) {
+        mi = (FIXP_DBL)1;
+      } else {
+        if ((m_e == -(DFRACT_BITS - 1)) && (m == (FIXP_DBL)MINVAL_DBL)) {
+          mi = (FIXP_DBL)-1;
+        } else {
+          mi = (FIXP_DBL)0;
+        }
       }
     }
   } else {
@@ -744,7 +775,7 @@
 
 /**
  * \brief return (base_m * 2^base_e) ^ N
- * \param base_m mantissa of the base
+ * \param base_m mantissa of the base. Must not be negative.
  * \param base_e exponent of the base
  * \param N power to be calculated of the base
  * \param result_e pointer to a INT where the exponent of the result will be
diff --git a/libFDK/include/mdct.h b/libFDK/include/mdct.h
index 1382374..e7cf3ad 100644
--- a/libFDK/include/mdct.h
+++ b/libFDK/include/mdct.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -106,18 +106,16 @@
 #include "common_fix.h"
 
 #define MDCT_OUT_HEADROOM 2 /* Output additional headroom */
-#define PCM_OUT_BITS SAMPLE_BITS
+
+#define PCM_OUT_BITS DFRACT_BITS
 #define PCM_OUT_HEADROOM 8 /* Must have the same values as DMXH_HEADROOM */
 
-#define MDCT_OUTPUT_SCALE (-MDCT_OUT_HEADROOM + (DFRACT_BITS - SAMPLE_BITS))
+#define MDCT_OUTPUT_SCALE (-MDCT_OUT_HEADROOM + (DFRACT_BITS - PCM_OUT_BITS))
 /* Refer to "Output word length" in ISO/IEC 14496-3:2008(E) 23.2.3.6 */
 #define MDCT_OUTPUT_GAIN 16
 
-#if (MDCT_OUTPUT_SCALE >= 0)
-#define IMDCT_SCALE(x) SATURATE_RIGHT_SHIFT(x, MDCT_OUTPUT_SCALE, PCM_OUT_BITS)
-#else
-#define IMDCT_SCALE(x) SATURATE_LEFT_SHIFT(x, -MDCT_OUTPUT_SCALE, PCM_OUT_BITS)
-#endif
+#define IMDCT_SCALE(x, s) \
+  SATURATE_RIGHT_SHIFT((x), ((s) + MDCT_OUTPUT_SCALE), PCM_OUT_BITS)
 #define IMDCT_SCALE_DBL(x) (FIXP_DBL)(x)
 #define IMDCT_SCALE_DBL_LSH1(x) SATURATE_LEFT_SHIFT_ALT((x), 1, DFRACT_BITS)
 
diff --git a/libFDK/include/qmf.h b/libFDK/include/qmf.h
index 609c6f1..78770b3 100644
--- a/libFDK/include/qmf.h
+++ b/libFDK/include/qmf.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -116,6 +116,7 @@
 
 #define FIXP_QAS FIXP_PCM
 #define QAS_BITS SAMPLE_BITS
+#define INT_PCM_QMFIN INT_PCM
 
 #define FIXP_QSS FIXP_DBL
 #define QSS_BITS DFRACT_BITS
@@ -201,16 +202,25 @@
 
 typedef struct QMF_FILTER_BANK *HANDLE_QMF_FILTER_BANK;
 
-void qmfAnalysisFiltering(
-    HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank   */
-    FIXP_DBL **qmfReal,            /*!< Pointer to real subband slots */
-    FIXP_DBL **qmfImag,            /*!< Pointer to imag subband slots */
-    QMF_SCALE_FACTOR *scaleFactor, /*!< Scale factors of QMF data     */
-    const LONG *timeIn,            /*!< Time signal */
-    const int timeIn_e,            /*!< Exponent of audio data        */
-    const int stride,              /*!< Stride factor of audio data   */
-    FIXP_DBL *pWorkBuffer          /*!< pointer to temporary working buffer */
-);
+int qmfInitAnalysisFilterBank(
+    HANDLE_QMF_FILTER_BANK h_Qmf, /*!< QMF Handle */
+    FIXP_QAS *pFilterStates,      /*!< Pointer to filter state buffer */
+    int noCols,                   /*!< Number of time slots  */
+    int lsb,                      /*!< Number of lower bands */
+    int usb,                      /*!< Number of upper bands */
+    int no_channels,              /*!< Number of critically sampled bands */
+    int flags);                   /*!< Flags */
+#if SAMPLE_BITS == 16
+
+int qmfInitAnalysisFilterBank(
+    HANDLE_QMF_FILTER_BANK h_Qmf, /*!< QMF Handle */
+    FIXP_DBL *pFilterStates,      /*!< Pointer to filter state buffer */
+    int noCols,                   /*!< Number of time slots  */
+    int lsb,                      /*!< Number of lower bands */
+    int usb,                      /*!< Number of upper bands */
+    int no_channels,              /*!< Number of critically sampled bands */
+    int flags);                   /*!< Flags */
+#endif
 
 void qmfAnalysisFiltering(
     HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank   */
@@ -222,6 +232,48 @@
     const int stride,              /*!< Stride factor of audio data   */
     FIXP_DBL *pWorkBuffer          /*!< pointer to temporal working buffer */
 );
+#if SAMPLE_BITS == 16
+
+void qmfAnalysisFiltering(
+    HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank   */
+    FIXP_DBL **qmfReal,            /*!< Pointer to real subband slots */
+    FIXP_DBL **qmfImag,            /*!< Pointer to imag subband slots */
+    QMF_SCALE_FACTOR *scaleFactor, /*!< Scale factors of QMF data     */
+    const LONG *timeIn,            /*!< Time signal */
+    const int timeIn_e,            /*!< Exponent of audio data        */
+    const int stride,              /*!< Stride factor of audio data   */
+    FIXP_DBL *pWorkBuffer          /*!< pointer to temporary working buffer */
+);
+#endif
+
+void qmfAnalysisFilteringSlot(
+    HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Synthesis Bank  */
+    FIXP_DBL *qmfReal,             /*!< Low and High band, real */
+    FIXP_DBL *qmfImag,             /*!< Low and High band, imag */
+    const INT_PCM *timeIn,         /*!< Pointer to input */
+    const int stride,              /*!< stride factor of input */
+    FIXP_DBL *pWorkBuffer          /*!< pointer to temporal working buffer */
+);
+#if SAMPLE_BITS == 16
+
+void qmfAnalysisFilteringSlot(
+    HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Synthesis Bank  */
+    FIXP_DBL *qmfReal,             /*!< Low and High band, real */
+    FIXP_DBL *qmfImag,             /*!< Low and High band, imag */
+    const LONG *timeIn,            /*!< Pointer to input */
+    const int stride,              /*!< stride factor of input */
+    FIXP_DBL *pWorkBuffer          /*!< pointer to temporary working buffer */
+);
+#endif
+
+int qmfInitSynthesisFilterBank(
+    HANDLE_QMF_FILTER_BANK h_Qmf, /*!< QMF Handle */
+    FIXP_QSS *pFilterStates,      /*!< Pointer to filter state buffer */
+    int noCols,                   /*!< Number of time slots  */
+    int lsb,                      /*!< Number of lower bands */
+    int usb,                      /*!< Number of upper bands */
+    int no_channels,              /*!< Number of critically sampled bands */
+    int flags);                   /*!< Flags */
 
 void qmfSynthesisFiltering(
     HANDLE_QMF_FILTER_BANK synQmf,       /*!< Handle of Qmf Synthesis Bank  */
@@ -234,41 +286,19 @@
     FIXP_DBL *pWorkBuffer /*!< pointer to temporary working buffer. It must be
                              aligned */
 );
+#if SAMPLE_BITS == 16
 
-int qmfInitAnalysisFilterBank(
-    HANDLE_QMF_FILTER_BANK h_Qmf, /*!< QMF Handle */
-    FIXP_QAS *pFilterStates,      /*!< Pointer to filter state buffer */
-    int noCols,                   /*!< Number of time slots  */
-    int lsb,                      /*!< Number of lower bands */
-    int usb,                      /*!< Number of upper bands */
-    int no_channels,              /*!< Number of critically sampled bands */
-    int flags);                   /*!< Flags */
-
-void qmfAnalysisFilteringSlot(
-    HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Synthesis Bank  */
-    FIXP_DBL *qmfReal,             /*!< Low and High band, real */
-    FIXP_DBL *qmfImag,             /*!< Low and High band, imag */
-    const LONG *timeIn,            /*!< Pointer to input */
-    const int stride,              /*!< stride factor of input */
-    FIXP_DBL *pWorkBuffer          /*!< pointer to temporary working buffer */
+void qmfSynthesisFiltering(
+    HANDLE_QMF_FILTER_BANK synQmf,       /*!< Handle of Qmf Synthesis Bank  */
+    FIXP_DBL **QmfBufferReal,            /*!< Pointer to real subband slots */
+    FIXP_DBL **QmfBufferImag,            /*!< Pointer to imag subband slots */
+    const QMF_SCALE_FACTOR *scaleFactor, /*!< Scale factors of QMF data     */
+    const int ov_len,                    /*!< Length of band overlap        */
+    LONG *timeOut,                       /*!< Time signal */
+    const int timeOut_e,                 /*!< Target exponent for timeOut  */
+    FIXP_DBL *pWorkBuffer /*!< pointer to temporary working buffer */
 );
-
-void qmfAnalysisFilteringSlot(
-    HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Synthesis Bank  */
-    FIXP_DBL *qmfReal,             /*!< Low and High band, real */
-    FIXP_DBL *qmfImag,             /*!< Low and High band, imag */
-    const INT_PCM *timeIn,         /*!< Pointer to input */
-    const int stride,              /*!< stride factor of input */
-    FIXP_DBL *pWorkBuffer          /*!< pointer to temporal working buffer */
-);
-int qmfInitSynthesisFilterBank(
-    HANDLE_QMF_FILTER_BANK h_Qmf, /*!< QMF Handle */
-    FIXP_QSS *pFilterStates,      /*!< Pointer to filter state buffer */
-    int noCols,                   /*!< Number of time slots  */
-    int lsb,                      /*!< Number of lower bands */
-    int usb,                      /*!< Number of upper bands */
-    int no_channels,              /*!< Number of critically sampled bands */
-    int flags);                   /*!< Flags */
+#endif
 
 void qmfSynthesisFilteringSlot(HANDLE_QMF_FILTER_BANK synQmf,
                                const FIXP_DBL *realSlot,
@@ -276,6 +306,15 @@
                                const int scaleFactorLowBand,
                                const int scaleFactorHighBand, INT_PCM *timeOut,
                                const int timeOut_e, FIXP_DBL *pWorkBuffer);
+#if SAMPLE_BITS == 16
+
+void qmfSynthesisFilteringSlot(HANDLE_QMF_FILTER_BANK synQmf,
+                               const FIXP_DBL *realSlot,
+                               const FIXP_DBL *imagSlot,
+                               const int scaleFactorLowBand,
+                               const int scaleFactorHighBand, LONG *timeOut,
+                               const int timeOut_e, FIXP_DBL *pWorkBuffer);
+#endif
 
 void qmfChangeOutScalefactor(
     HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */
@@ -291,11 +330,5 @@
     FIXP_DBL outputGain,           /*!< New gain for output data (mantissa) */
     int outputGainScale            /*!< New gain for output data (exponent) */
 );
-void qmfSynPrototypeFirSlot(
-    HANDLE_QMF_FILTER_BANK qmf,
-    FIXP_DBL *RESTRICT realSlot, /*!< Input: Pointer to real Slot */
-    FIXP_DBL *RESTRICT imagSlot, /*!< Input: Pointer to imag Slot */
-    INT_PCM *RESTRICT timeOut,   /*!< Time domain data */
-    const int timeOut_e);
 
 #endif /*ifndef QMF_H       */
diff --git a/libFDK/include/qmf_pcm.h b/libFDK/include/qmf_pcm.h
index f24e0cd..5da53db 100644
--- a/libFDK/include/qmf_pcm.h
+++ b/libFDK/include/qmf_pcm.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -402,4 +402,220 @@
                               timeOut + (i * L * stride), stride, pWorkBuffer);
   } /* no_col loop  i  */
 }
+
+/*!
+ *
+ * \brief Create QMF filter bank instance
+ *
+ *
+ * \return 0 if successful
+ *
+ */
+int qmfInitAnalysisFilterBank(
+    HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Returns handle */
+    FIXP_QAS *pFilterStates,      /*!< Handle to filter states */
+    int noCols,                   /*!< Number of timeslots per frame */
+    int lsb,                      /*!< lower end of QMF */
+    int usb,                      /*!< upper end of QMF */
+    int no_channels,              /*!< Number of channels (bands) */
+    int flags)                    /*!< Low Power flag */
+{
+  int err = qmfInitFilterBank(h_Qmf, pFilterStates, noCols, lsb, usb,
+                              no_channels, flags, 0);
+  if (!(flags & QMF_FLAG_KEEP_STATES) && (h_Qmf->FilterStates != NULL)) {
+    FDKmemclear(h_Qmf->FilterStates,
+                (2 * QMF_NO_POLY - 1) * h_Qmf->no_channels * sizeof(FIXP_QAS));
+  }
+
+  FDK_ASSERT(h_Qmf->no_channels >= h_Qmf->lsb);
+
+  return err;
+}
+
+#ifndef FUNCTION_qmfAnaPrototypeFirSlot
+/*!
+  \brief Perform Analysis Prototype Filtering on a single slot of input data.
+*/
+static void qmfAnaPrototypeFirSlot(
+    FIXP_DBL *analysisBuffer,
+    INT no_channels, /*!< Number channels of analysis filter */
+    const FIXP_PFT *p_filter, INT p_stride, /*!< Stride of analysis filter    */
+    FIXP_QAS *RESTRICT pFilterStates) {
+  INT k;
+
+  FIXP_DBL accu;
+  const FIXP_PFT *RESTRICT p_flt = p_filter;
+  FIXP_DBL *RESTRICT pData_0 = analysisBuffer + 2 * no_channels - 1;
+  FIXP_DBL *RESTRICT pData_1 = analysisBuffer;
+
+  FIXP_QAS *RESTRICT sta_0 = (FIXP_QAS *)pFilterStates;
+  FIXP_QAS *RESTRICT sta_1 =
+      (FIXP_QAS *)pFilterStates + (2 * QMF_NO_POLY * no_channels) - 1;
+  INT pfltStep = QMF_NO_POLY * (p_stride);
+  INT staStep1 = no_channels << 1;
+  INT staStep2 = (no_channels << 3) - 1; /* Rewind one less */
+
+  /* FIR filters 127..64 0..63 */
+  for (k = 0; k < no_channels; k++) {
+    accu = fMultDiv2(p_flt[0], *sta_1);
+    sta_1 -= staStep1;
+    accu += fMultDiv2(p_flt[1], *sta_1);
+    sta_1 -= staStep1;
+    accu += fMultDiv2(p_flt[2], *sta_1);
+    sta_1 -= staStep1;
+    accu += fMultDiv2(p_flt[3], *sta_1);
+    sta_1 -= staStep1;
+    accu += fMultDiv2(p_flt[4], *sta_1);
+    *pData_1++ = (accu << 1);
+    sta_1 += staStep2;
+
+    p_flt += pfltStep;
+    accu = fMultDiv2(p_flt[0], *sta_0);
+    sta_0 += staStep1;
+    accu += fMultDiv2(p_flt[1], *sta_0);
+    sta_0 += staStep1;
+    accu += fMultDiv2(p_flt[2], *sta_0);
+    sta_0 += staStep1;
+    accu += fMultDiv2(p_flt[3], *sta_0);
+    sta_0 += staStep1;
+    accu += fMultDiv2(p_flt[4], *sta_0);
+    *pData_0-- = (accu << 1);
+    sta_0 -= staStep2;
+  }
+}
+#endif /* !defined(FUNCTION_qmfAnaPrototypeFirSlot) */
+
+#ifndef FUNCTION_qmfAnaPrototypeFirSlot_NonSymmetric
+/*!
+  \brief Perform Analysis Prototype Filtering on a single slot of input data.
+*/
+static void qmfAnaPrototypeFirSlot_NonSymmetric(
+    FIXP_DBL *analysisBuffer,
+    int no_channels, /*!< Number channels of analysis filter */
+    const FIXP_PFT *p_filter, int p_stride, /*!< Stride of analysis filter    */
+    FIXP_QAS *RESTRICT pFilterStates) {
+  const FIXP_PFT *RESTRICT p_flt = p_filter;
+  int p, k;
+
+  for (k = 0; k < 2 * no_channels; k++) {
+    FIXP_DBL accu = (FIXP_DBL)0;
+
+    p_flt += QMF_NO_POLY * (p_stride - 1);
+
+    /*
+      Perform FIR-Filter
+    */
+    for (p = 0; p < QMF_NO_POLY; p++) {
+      accu += fMultDiv2(*p_flt++, pFilterStates[2 * no_channels * p]);
+    }
+    analysisBuffer[2 * no_channels - 1 - k] = (accu << 1);
+    pFilterStates++;
+  }
+}
+#endif /* FUNCTION_qmfAnaPrototypeFirSlot_NonSymmetric */
+
+/*
+ * \brief Perform one QMF slot analysis of the time domain data of timeIn
+ *        with specified stride and stores the real part of the subband
+ *        samples in rSubband, and the imaginary part in iSubband
+ *
+ *        Note: anaQmf->lsb can be greater than anaQmf->no_channels in case
+ *        of implicit resampling (USAC with reduced 3/4 core frame length).
+ */
+void qmfAnalysisFilteringSlot(
+    HANDLE_QMF_FILTER_BANK anaQmf,        /*!< Handle of Qmf Synthesis Bank  */
+    FIXP_DBL *qmfReal,                    /*!< Low and High band, real */
+    FIXP_DBL *qmfImag,                    /*!< Low and High band, imag */
+    const INT_PCM_QMFIN *RESTRICT timeIn, /*!< Pointer to input */
+    const int stride,                     /*!< stride factor of input */
+    FIXP_DBL *pWorkBuffer /*!< pointer to temporal working buffer */
+) {
+  int offset = anaQmf->no_channels * (QMF_NO_POLY * 2 - 1);
+  /*
+    Feed time signal into oldest anaQmf->no_channels states
+  */
+  {
+    FIXP_QAS *FilterStatesAnaTmp = ((FIXP_QAS *)anaQmf->FilterStates) + offset;
+
+    /* Feed and scale actual time in slot */
+    for (int i = anaQmf->no_channels >> 1; i != 0; i--) {
+      /* Place INT_PCM value left aligned in scaledTimeIn */
+      *FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
+      timeIn += stride;
+      *FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
+      timeIn += stride;
+    }
+  }
+
+  if (anaQmf->flags & QMF_FLAG_NONSYMMETRIC) {
+    qmfAnaPrototypeFirSlot_NonSymmetric(pWorkBuffer, anaQmf->no_channels,
+                                        anaQmf->p_filter, anaQmf->p_stride,
+                                        (FIXP_QAS *)anaQmf->FilterStates);
+  } else {
+    qmfAnaPrototypeFirSlot(pWorkBuffer, anaQmf->no_channels, anaQmf->p_filter,
+                           anaQmf->p_stride, (FIXP_QAS *)anaQmf->FilterStates);
+  }
+
+  if (anaQmf->flags & QMF_FLAG_LP) {
+    if (anaQmf->flags & QMF_FLAG_CLDFB)
+      qmfForwardModulationLP_odd(anaQmf, pWorkBuffer, qmfReal);
+    else
+      qmfForwardModulationLP_even(anaQmf, pWorkBuffer, qmfReal);
+
+  } else {
+    qmfForwardModulationHQ(anaQmf, pWorkBuffer, qmfReal, qmfImag);
+  }
+  /*
+    Shift filter states
+
+    Should be realized with modulo addressing on a DSP instead of a true buffer
+    shift
+  */
+  FDKmemmove(anaQmf->FilterStates,
+             (FIXP_QAS *)anaQmf->FilterStates + anaQmf->no_channels,
+             offset * sizeof(FIXP_QAS));
+}
+
+/*!
+ *
+ * \brief Perform complex-valued subband filtering of the time domain
+ *        data of timeIn and stores the real part of the subband
+ *        samples in rAnalysis, and the imaginary part in iAnalysis
+ * The qmf coefficient table is symmetric. The symmetry is expoited by
+ * shrinking the coefficient table to half the size. The addressing mode
+ * takes care of the symmetries.
+ *
+ *
+ * \sa PolyphaseFiltering
+ */
+void qmfAnalysisFiltering(
+    HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
+    FIXP_DBL **qmfReal,            /*!< Pointer to real subband slots */
+    FIXP_DBL **qmfImag,            /*!< Pointer to imag subband slots */
+    QMF_SCALE_FACTOR *scaleFactor,
+    const INT_PCM_QMFIN *timeIn, /*!< Time signal */
+    const int timeIn_e, const int stride,
+    FIXP_DBL *pWorkBuffer /*!< pointer to temporal working buffer */
+) {
+  int i;
+  int no_channels = anaQmf->no_channels;
+
+  scaleFactor->lb_scale =
+      -ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK - timeIn_e;
+  scaleFactor->lb_scale -= anaQmf->filterScale;
+
+  for (i = 0; i < anaQmf->no_col; i++) {
+    FIXP_DBL *qmfImagSlot = NULL;
+
+    if (!(anaQmf->flags & QMF_FLAG_LP)) {
+      qmfImagSlot = qmfImag[i];
+    }
+
+    qmfAnalysisFilteringSlot(anaQmf, qmfReal[i], qmfImagSlot, timeIn, stride,
+                             pWorkBuffer);
+
+    timeIn += no_channels * stride;
+
+  } /* no_col loop  i  */
+}
 #endif /* QMF_PCM_H */
diff --git a/libFDK/include/scale.h b/libFDK/include/scale.h
index 655ccaf..a58614e 100644
--- a/libFDK/include/scale.h
+++ b/libFDK/include/scale.h
@@ -129,15 +129,13 @@
 void scaleValuesWithFactor(FIXP_DBL *vector, FIXP_DBL factor, INT len,
                            INT scalefactor);
 void scaleValuesSaturate(FIXP_DBL *vector, INT len, INT scalefactor);
-void scaleValuesSaturate(FIXP_DBL *dst, FIXP_DBL *src, INT len,
+void scaleValuesSaturate(FIXP_DBL *dst, const FIXP_DBL *src, INT len,
                          INT scalefactor);
-void scaleValuesSaturate(FIXP_SGL *dst, FIXP_DBL *src, INT len,
+void scaleValuesSaturate(FIXP_SGL *dst, const FIXP_DBL *src, INT len,
                          INT scalefactor);
-void scaleValuesSaturate(INT_PCM *dst, FIXP_DBL *src, INT len, INT scalefactor);
 void scaleValuesSaturate(FIXP_SGL *vector, INT len, INT scalefactor);
-void scaleValuesSaturate(FIXP_SGL *dst, FIXP_SGL *src, INT len,
+void scaleValuesSaturate(FIXP_SGL *dst, const FIXP_SGL *src, INT len,
                          INT scalefactor);
-void scaleValuesSaturate(INT_PCM *dst, INT_PCM *src, INT len, INT scalefactor);
 INT getScalefactorShort(const SHORT *vector, INT len);
 INT getScalefactorPCM(const INT_PCM *vector, INT len, INT stride);
 INT getScalefactor(const FIXP_DBL *vector, INT len);
diff --git a/libFDK/src/FDK_bitbuffer.cpp b/libFDK/src/FDK_bitbuffer.cpp
index 98905ea..9b7f5b8 100644
--- a/libFDK/src/FDK_bitbuffer.cpp
+++ b/libFDK/src/FDK_bitbuffer.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -368,7 +368,10 @@
 
   UINT bTotal = 0;
 
-  UINT bToRead = (hBitBuf->bufBits - hBitBuf->ValidBits) >> 3;
+  UINT bToRead =
+      fMin(hBitBuf->bufBits,
+           (UINT)fMax(0, ((INT)hBitBuf->bufBits - (INT)hBitBuf->ValidBits))) >>
+      3;
   UINT noOfBytes =
       fMin(bToRead,
            *bytesValid);  //(bToRead < *bytesValid) ? bToRead : *bytesValid ;
@@ -384,7 +387,7 @@
               bToRead * sizeof(UCHAR));
 
     /* add noOfBits to number of valid bits in buffer */
-    hBitBuf->ValidBits += bToRead << 3;
+    hBitBuf->ValidBits = (UINT)((INT)hBitBuf->ValidBits + (INT)(bToRead << 3));
     bTotal += bToRead;
     inputBuffer += bToRead;
 
diff --git a/libFDK/src/FDK_core.cpp b/libFDK/src/FDK_core.cpp
index 75ea8a2..2f77179 100644
--- a/libFDK/src/FDK_core.cpp
+++ b/libFDK/src/FDK_core.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -104,7 +104,7 @@
 
 /* FDK tools library info */
 #define FDK_TOOLS_LIB_VL0 3
-#define FDK_TOOLS_LIB_VL1 0
+#define FDK_TOOLS_LIB_VL1 1
 #define FDK_TOOLS_LIB_VL2 0
 #define FDK_TOOLS_LIB_TITLE "FDK Tools"
 #ifdef __ANDROID__
diff --git a/libFDK/src/FDK_decorrelate.cpp b/libFDK/src/FDK_decorrelate.cpp
index c5de79a..324983a 100644
--- a/libFDK/src/FDK_decorrelate.cpp
+++ b/libFDK/src/FDK_decorrelate.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -227,7 +227,7 @@
 }
 
 #define DUCKER_MAX_NRG_SCALE (24)
-#define DUCKER_HEADROOM_BITS (3)
+#define DUCKER_HEADROOM_BITS (2)
 
 #define FILTER_SF (2)
 
@@ -606,10 +606,6 @@
       dataImagIn += start;
       dataRealOut += start;
       dataImagOut += start;
-#ifdef FUNCTION_DecorrFilterApplyPASS_func1
-      DecorrFilterApplyPASS_func1(i, dataRealIn, dataImagIn, dataRealOut,
-                                  dataImagOut, pDelayBuffer, offset);
-#else
       do {
         FIXP_DBL delay_re, delay_im, real, imag;
 
@@ -623,7 +619,6 @@
         *dataImagOut++ = delay_im;
         pDelayBuffer += offset;
       } while (--i != 0);
-#endif
     }
   }
 
@@ -1061,24 +1056,15 @@
     FIXP_DBL maxVal = FL2FXCONST_DBL(-1.0f);
 
     if (maxVal == FL2FXCONST_DBL(-1.0f)) {
-#ifdef FUNCTION_DuckerCalcEnergy_func2
-      maxVal = DuckerCalcEnergy_func2(inputReal, inputImag, startHybBand,
-                                      maxHybBand, maxHybridBand);
-#else
-      FIXP_DBL localMaxVal = FL2FXCONST_DBL(0.0f);
-      for (qs = startHybBand; qs <= maxHybBand; qs++) {
-        localMaxVal |= fAbs(inputReal[qs]);
-        localMaxVal |= fAbs(inputImag[qs]);
-      }
-      for (; qs <= maxHybridBand; qs++) {
-        localMaxVal |= fAbs(inputReal[qs]);
-      }
-      maxVal = localMaxVal;
-#endif
+      clz = fMin(getScalefactor(&inputReal[startHybBand],
+                                fMax(0, maxHybridBand - startHybBand + 1)),
+                 getScalefactor(&inputImag[startHybBand],
+                                fMax(0, maxHybBand - startHybBand + 1)));
+    } else {
+      clz = CntLeadingZeros(maxVal) - 1;
     }
 
-    clz = fixMax(0, CntLeadingZeros(maxVal) - DUCKER_HEADROOM_BITS);
-    clz = fixMin(clz, DUCKER_MAX_NRG_SCALE);
+    clz = fMin(fMax(0, clz - DUCKER_HEADROOM_BITS), DUCKER_MAX_NRG_SCALE);
     *nrgScale = (SCHAR)clz << 1;
 
     /* Initialize pb since it would stay uninitialized for the case startHybBand
@@ -1086,9 +1072,10 @@
     pb = SpatialDecGetProcessingBand(maxHybBand, self->mapHybBands2ProcBands);
     for (qs = startHybBand; qs <= maxHybBand; qs++) {
       pb = SpatialDecGetProcessingBand(qs, self->mapHybBands2ProcBands);
-      energy[pb] =
-          fAddSaturate(energy[pb], fPow2Div2(inputReal[qs] << clz) +
-                                       fPow2Div2(inputImag[qs] << clz));
+      energy[pb] = SATURATE_LEFT_SHIFT(
+          (energy[pb] >> 1) + (fPow2Div2(inputReal[qs] << clz) >> 1) +
+              (fPow2Div2(inputImag[qs] << clz) >> 1),
+          1, DFRACT_BITS);
     }
     pb++;
 
@@ -1112,43 +1099,29 @@
     maxVal = inputMaxVal;
 
     if (maxVal == FL2FXCONST_DBL(-1.0f)) {
-#ifdef FUNCTION_DuckerCalcEnergy_func2
-      maxVal = DuckerCalcEnergy_func2(inputReal, inputImag, startHybBand,
-                                      maxHybBand, maxHybridBand);
-#else
-      FIXP_DBL localMaxVal = FL2FXCONST_DBL(0.0f);
-      for (qs = startHybBand; qs <= maxHybBand; qs++) {
-        localMaxVal |= fAbs(inputReal[qs]);
-        localMaxVal |= fAbs(inputImag[qs]);
-      }
-      for (; qs <= maxHybridBand; qs++) {
-        localMaxVal |= fAbs(inputReal[qs]);
-      }
-      maxVal = localMaxVal;
-#endif
+      clz = fMin(getScalefactor(&inputReal[startHybBand],
+                                fMax(0, maxHybridBand - startHybBand + 1)),
+                 getScalefactor(&inputImag[startHybBand],
+                                fMax(0, maxHybBand - startHybBand + 1)));
+    } else {
+      clz = CntLeadingZeros(maxVal) - 1;
     }
 
-    clz = fixMax(0, CntLeadingZeros(maxVal) - DUCKER_HEADROOM_BITS);
-    clz = fixMin(clz, DUCKER_MAX_NRG_SCALE);
+    clz = fMin(fMax(0, clz - DUCKER_HEADROOM_BITS), DUCKER_MAX_NRG_SCALE);
     *nrgScale = (SCHAR)clz << 1;
 
-#ifdef FUNCTION_DuckerCalcEnergy_func4
-    DuckerCalcEnergy_func4(inputReal, inputImag, energy,
-                           self->mapHybBands2ProcBands, clz, startHybBand,
-                           maxHybBand, maxHybridBand);
-#else
     for (qs = startHybBand; qs <= maxHybBand; qs++) {
       int pb = SpatialDecGetProcessingBand(qs, self->mapHybBands2ProcBands);
-      energy[pb] =
-          fAddSaturate(energy[pb], fPow2Div2(inputReal[qs] << clz) +
-                                       fPow2Div2(inputImag[qs] << clz));
+      energy[pb] = SATURATE_LEFT_SHIFT(
+          (energy[pb] >> 1) + (fPow2Div2(inputReal[qs] << clz) >> 1) +
+              (fPow2Div2(inputImag[qs] << clz) >> 1),
+          1, DFRACT_BITS);
     }
 
     for (; qs <= maxHybridBand; qs++) {
       int pb = SpatialDecGetProcessingBand(qs, self->mapHybBands2ProcBands);
       energy[pb] = fAddSaturate(energy[pb], fPow2Div2(inputReal[qs] << clz));
     }
-#endif /* FUNCTION_DuckerCalcEnergy_func4 */
   }
 
   {
@@ -1295,10 +1268,6 @@
       }
     }
 
-#ifdef FUNCTION_DuckerApply_func1
-    qs = DuckerApply_func1(qs, hybBands, qs_next, outputReal, outputImag,
-                           duckGain);
-#else
     /* general gain*output section */
     if (qs < hybBands) {           /* true for about 39% */
       for (; qs < qs_next; qs++) { /* runs about 2 times */
@@ -1310,7 +1279,6 @@
         outputReal[qs] = fMultDiv2(outputReal[qs], duckGain) << 2;
       }
     }
-#endif
   } /* pb */
 
   self->headroomSmoothDirRevNrg =
diff --git a/libFDK/src/FDK_hybrid.cpp b/libFDK/src/FDK_hybrid.cpp
index b661f82..08d32a8 100644
--- a/libFDK/src/FDK_hybrid.cpp
+++ b/libFDK/src/FDK_hybrid.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -142,11 +142,12 @@
   } /* How to arrange the packed values. */
 
 struct FDK_HYBRID_SETUP {
-  UCHAR nrQmfBands;   /*!< Number of QMF bands to be converted to hybrid. */
-  UCHAR nHybBands[3]; /*!< Number of Hybrid bands generated by nrQmfBands. */
-  SCHAR kHybrid[3];   /*!< Filter configuration of each QMF band. */
-  UCHAR protoLen;     /*!< Prototype filter length. */
-  UCHAR filterDelay;  /*!< Delay caused by hybrid filter. */
+  UCHAR nrQmfBands;     /*!< Number of QMF bands to be converted to hybrid. */
+  UCHAR nHybBands[3];   /*!< Number of Hybrid bands generated by nrQmfBands. */
+  UCHAR synHybScale[3]; /*!< Headroom needed in hybrid synthesis filterbank. */
+  SCHAR kHybrid[3];     /*!< Filter configuration of each QMF band. */
+  UCHAR protoLen;       /*!< Prototype filter length. */
+  UCHAR filterDelay;    /*!< Delay caused by hybrid filter. */
   const INT
       *pReadIdxTable; /*!< Helper table to access input data ringbuffer. */
 };
@@ -156,12 +157,12 @@
                                            9, 10, 11, 12, 0, 1,  2,  3, 4,
                                            5, 6,  7,  8,  9, 10, 11, 12};
 
-static const FDK_HYBRID_SETUP setup_3_16 = {3,  {8, 4, 4},    {8, 4, 4},
-                                            13, (13 - 1) / 2, ringbuffIdxTab};
-static const FDK_HYBRID_SETUP setup_3_12 = {3,  {8, 2, 2},    {8, 2, 2},
-                                            13, (13 - 1) / 2, ringbuffIdxTab};
-static const FDK_HYBRID_SETUP setup_3_10 = {3,  {6, 2, 2},    {-8, -2, 2},
-                                            13, (13 - 1) / 2, ringbuffIdxTab};
+static const FDK_HYBRID_SETUP setup_3_16 = {
+    3, {8, 4, 4}, {4, 3, 3}, {8, 4, 4}, 13, (13 - 1) / 2, ringbuffIdxTab};
+static const FDK_HYBRID_SETUP setup_3_12 = {
+    3, {8, 2, 2}, {4, 2, 2}, {8, 2, 2}, 13, (13 - 1) / 2, ringbuffIdxTab};
+static const FDK_HYBRID_SETUP setup_3_10 = {
+    3, {6, 2, 2}, {3, 2, 2}, {-8, -2, 2}, 13, (13 - 1) / 2, ringbuffIdxTab};
 
 static const FIXP_HTP HybFilterCoef8[] = {
     HTCP(0x10000000, 0x00000000), HTCP(0x0df26407, 0xfa391882),
@@ -477,17 +478,18 @@
    */
   for (k = 0; k < nrQmfBandsLF; k++) {
     const int nHybBands = hSynthesisHybFilter->pSetup->nHybBands[k];
+    const int scale = hSynthesisHybFilter->pSetup->synHybScale[k];
 
     FIXP_DBL accu1 = FL2FXCONST_DBL(0.f);
     FIXP_DBL accu2 = FL2FXCONST_DBL(0.f);
 
     /* Perform hybrid filtering. */
     for (n = 0; n < nHybBands; n++) {
-      accu1 += pHybridReal[hybOffset + n];
-      accu2 += pHybridImag[hybOffset + n];
+      accu1 += pHybridReal[hybOffset + n] >> scale;
+      accu2 += pHybridImag[hybOffset + n] >> scale;
     }
-    pQmfReal[k] = accu1;
-    pQmfImag[k] = accu2;
+    pQmfReal[k] = SATURATE_LEFT_SHIFT(accu1, scale, DFRACT_BITS);
+    pQmfImag[k] = SATURATE_LEFT_SHIFT(accu2, scale, DFRACT_BITS);
 
     hybOffset += nHybBands;
   }
diff --git a/libFDK/src/FDK_qmf_domain.cpp b/libFDK/src/FDK_qmf_domain.cpp
index 3245deb..77c5ca2 100644
--- a/libFDK/src/FDK_qmf_domain.cpp
+++ b/libFDK/src/FDK_qmf_domain.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -106,35 +106,31 @@
 #include "common_fix.h"
 
 #define WORKBUFFER1_TAG 0
-#define WORKBUFFER2_TAG 1
-
 #define WORKBUFFER3_TAG 4
 #define WORKBUFFER4_TAG 5
-#define WORKBUFFER5_TAG 6
 #define WORKBUFFER6_TAG 7
+#define WORKBUFFER7_TAG 8
 
 C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore1, FIXP_DBL, QMF_WB_SECTION_SIZE,
                     SECT_DATA_L1, WORKBUFFER1_TAG)
-C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore2, FIXP_DBL, QMF_WB_SECTION_SIZE,
-                    SECT_DATA_L2, WORKBUFFER2_TAG)
 C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore3, FIXP_DBL, QMF_WB_SECTION_SIZE,
                     SECT_DATA_L2, WORKBUFFER3_TAG)
 C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore4, FIXP_DBL, QMF_WB_SECTION_SIZE,
                     SECT_DATA_L2, WORKBUFFER4_TAG)
-C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore5, FIXP_DBL, QMF_WB_SECTION_SIZE,
-                    SECT_DATA_L2, WORKBUFFER5_TAG)
 C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore6, FIXP_DBL, QMF_WB_SECTION_SIZE,
                     SECT_DATA_L2, WORKBUFFER6_TAG)
+C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore7, FIXP_DBL, QMF_WB_SECTION_SIZE,
+                    SECT_DATA_L2, WORKBUFFER7_TAG)
 
 /*! Analysis states buffer. <br>
     Dimension: #((8) + (1))                                                   */
-C_ALLOC_MEM2(AnaQmfStates, FIXP_QAS, 10 * QMF_DOMAIN_MAX_ANALYSIS_QMF_BANDS,
-             ((8) + (1)))
+C_AALLOC_MEM2(AnaQmfStates, FIXP_DBL, 10 * QMF_DOMAIN_MAX_ANALYSIS_QMF_BANDS,
+              ((8) + (1)))
 
 /*! Synthesis states buffer. <br>
     Dimension: #((8) + (1))                                                  */
-C_ALLOC_MEM2(SynQmfStates, FIXP_QSS, 9 * QMF_DOMAIN_MAX_SYNTHESIS_QMF_BANDS,
-             ((8) + (1)))
+C_AALLOC_MEM2(SynQmfStates, FIXP_QSS, 9 * QMF_DOMAIN_MAX_SYNTHESIS_QMF_BANDS,
+              ((8) + (1)))
 
 /*! Pointer to real qmf data for each time slot. <br>
     Dimension: #((8) + (1))                                                   */
@@ -156,18 +152,17 @@
 
 /*! Analysis states buffer. <br>
     Dimension: #((8) + (1))                                                   */
-C_ALLOC_MEM2(AnaQmfStates16, FIXP_QAS, 10 * QMF_DOMAIN_ANALYSIS_QMF_BANDS_16,
-             ((8) + (1)))
+C_AALLOC_MEM2(AnaQmfStates16, FIXP_DBL, 10 * QMF_DOMAIN_ANALYSIS_QMF_BANDS_16,
+              ((8) + (1)))
+/*! Analysis states buffer. <br>
+    Dimension: #((8) + (1))                                                   */
+C_AALLOC_MEM2(AnaQmfStates24, FIXP_DBL, 10 * QMF_DOMAIN_ANALYSIS_QMF_BANDS_24,
+              ((8) + (1)))
 
 /*! Analysis states buffer. <br>
     Dimension: #((8) + (1))                                                   */
-C_ALLOC_MEM2(AnaQmfStates24, FIXP_QAS, 10 * QMF_DOMAIN_ANALYSIS_QMF_BANDS_24,
-             ((8) + (1)))
-
-/*! Analysis states buffer. <br>
-    Dimension: #((8) + (1))                                                   */
-C_ALLOC_MEM2(AnaQmfStates32, FIXP_QAS, 10 * QMF_DOMAIN_ANALYSIS_QMF_BANDS_32,
-             ((8) + (1)))
+C_AALLOC_MEM2(AnaQmfStates32, FIXP_DBL, 10 * QMF_DOMAIN_ANALYSIS_QMF_BANDS_32,
+              ((8) + (1)))
 
 /*! Pointer to real qmf data for each time slot. <br>
     Dimension: #((8) + (1))                                                   */
@@ -642,10 +637,10 @@
 
   if (pQmfOutImag == NULL) {
     for (; b < fMin(lsb, stop_band); b++) {
-      pQmfOutReal[b] = scaleValue(real[b], lb_sf);
+      pQmfOutReal[b] = scaleValueSaturate(real[b], lb_sf);
     }
     for (; b < fMin(usb, stop_band); b++) {
-      pQmfOutReal[b] = scaleValue(real[b], hb_sf);
+      pQmfOutReal[b] = scaleValueSaturate(real[b], hb_sf);
     }
     for (; b < stop_band; b++) {
       pQmfOutReal[b] = (FIXP_DBL)0;
@@ -653,12 +648,12 @@
   } else {
     FDK_ASSERT(imag != NULL);
     for (; b < fMin(lsb, stop_band); b++) {
-      pQmfOutReal[b] = scaleValue(real[b], lb_sf);
-      pQmfOutImag[b] = scaleValue(imag[b], lb_sf);
+      pQmfOutReal[b] = scaleValueSaturate(real[b], lb_sf);
+      pQmfOutImag[b] = scaleValueSaturate(imag[b], lb_sf);
     }
     for (; b < fMin(usb, stop_band); b++) {
-      pQmfOutReal[b] = scaleValue(real[b], hb_sf);
-      pQmfOutImag[b] = scaleValue(imag[b], hb_sf);
+      pQmfOutReal[b] = scaleValueSaturate(real[b], hb_sf);
+      pQmfOutImag[b] = scaleValueSaturate(imag[b], hb_sf);
     }
     for (; b < stop_band; b++) {
       pQmfOutReal[b] = (FIXP_DBL)0;
@@ -950,7 +945,7 @@
 
     if ((size > 4 * QMF_WB_SECTION_SIZE) && (pWorkBuffer[4] == NULL)) {
       /* get work buffer of size QMF_WB_SECTION_SIZE */
-      pWorkBuffer[4] = GetQmfWorkBufferCore5();
+      pWorkBuffer[4] = GetQmfWorkBufferCore7();
     }
 
     /* 8. distribute workbuffer over processing channels */
@@ -996,7 +991,7 @@
   if (pWorkBuffer[1]) FreeQmfWorkBufferCore1(&pWorkBuffer[1]);
   if (pWorkBuffer[2]) FreeQmfWorkBufferCore3(&pWorkBuffer[2]);
   if (pWorkBuffer[3]) FreeQmfWorkBufferCore4(&pWorkBuffer[3]);
-  if (pWorkBuffer[4]) FreeQmfWorkBufferCore5(&pWorkBuffer[4]);
+  if (pWorkBuffer[4]) FreeQmfWorkBufferCore7(&pWorkBuffer[4]);
 }
 
 void FDK_QmfDomain_FreeMem(HANDLE_FDK_QMF_DOMAIN hqd) {
diff --git a/libFDK/src/dct.cpp b/libFDK/src/dct.cpp
index 776493e..bd26736 100644
--- a/libFDK/src/dct.cpp
+++ b/libFDK/src/dct.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -489,18 +489,18 @@
     for (i = 0; i < M - 1; i += 2, pDat_0 += 2, pDat_1 -= 2) {
       FIXP_DBL accu1, accu2, accu3, accu4;
 
-      accu1 = pDat_1[1];
-      accu2 = -pDat_0[0];
-      accu3 = pDat_0[1];
-      accu4 = -pDat_1[0];
+      accu1 = pDat_1[1] >> 1;
+      accu2 = -(pDat_0[0] >> 1);
+      accu3 = pDat_0[1] >> 1;
+      accu4 = -(pDat_1[0] >> 1);
 
       cplxMultDiv2(&accu1, &accu2, accu1, accu2, twiddle[i]);
       cplxMultDiv2(&accu3, &accu4, accu4, accu3, twiddle[i + 1]);
 
-      pDat_0[0] = accu2 >> 1;
-      pDat_0[1] = accu1 >> 1;
-      pDat_1[0] = accu4 >> 1;
-      pDat_1[1] = -(accu3 >> 1);
+      pDat_0[0] = accu2;
+      pDat_0[1] = accu1;
+      pDat_1[0] = accu4;
+      pDat_1[1] = -accu3;
     }
     if (M & 1) {
       FIXP_DBL accu1, accu2;
diff --git a/libFDK/src/fixpoint_math.cpp b/libFDK/src/fixpoint_math.cpp
index 6c656fa..1e26420 100644
--- a/libFDK/src/fixpoint_math.cpp
+++ b/libFDK/src/fixpoint_math.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -650,6 +650,12 @@
   INT ans_lg2_e, baselg2_e;
   FIXP_DBL base_lg2, ans_lg2, result;
 
+  if (base_m <= (FIXP_DBL)0) {
+    result = (FIXP_DBL)0;
+    *result_e = 0;
+    return result;
+  }
+
   /* Calc log2 of base */
   base_lg2 = fLog2(base_m, base_e, &baselg2_e);
 
diff --git a/libFDK/src/mdct.cpp b/libFDK/src/mdct.cpp
index d697cfb..0062b27 100644
--- a/libFDK/src/mdct.cpp
+++ b/libFDK/src/mdct.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -569,7 +569,7 @@
        */
       for (i = 0; i < hMdct->prev_nr; i++) {
         FIXP_DBL x = -(*pOvl--);
-        *pOut0 = IMDCT_SCALE_DBL(x + hMdct->pFacZir[i]);
+        *pOut0 = fAddSaturate(x, IMDCT_SCALE_DBL(hMdct->pFacZir[i]));
         pOut0++;
       }
       hMdct->pFacZir = NULL;
@@ -678,7 +678,7 @@
       FIXP_DBL *pOut = pOut0 - fl / 2;
       FDK_ASSERT(fl / 2 <= 128);
       for (i = 0; i < fl / 2; i++) {
-        pOut[i] += IMDCT_SCALE_DBL(hMdct->pFacZir[i]);
+        pOut[i] = fAddSaturate(pOut[i], IMDCT_SCALE_DBL(hMdct->pFacZir[i]));
       }
       hMdct->pFacZir = NULL;
     }
diff --git a/libFDK/src/qmf.cpp b/libFDK/src/qmf.cpp
index 6fca043..440bec2 100644
--- a/libFDK/src/qmf.cpp
+++ b/libFDK/src/qmf.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -147,88 +147,6 @@
 /* moved to qmf_pcm.h: -> qmfSynPrototypeFirSlot_NonSymmetric */
 /* moved to qmf_pcm.h: -> qmfSynthesisFilteringSlot */
 
-#ifndef FUNCTION_qmfAnaPrototypeFirSlot
-/*!
-  \brief Perform Analysis Prototype Filtering on a single slot of input data.
-*/
-static void qmfAnaPrototypeFirSlot(
-    FIXP_DBL *analysisBuffer,
-    INT no_channels, /*!< Number channels of analysis filter */
-    const FIXP_PFT *p_filter, INT p_stride, /*!< Stride of analysis filter    */
-    FIXP_QAS *RESTRICT pFilterStates) {
-  INT k;
-
-  FIXP_DBL accu;
-  const FIXP_PFT *RESTRICT p_flt = p_filter;
-  FIXP_DBL *RESTRICT pData_0 = analysisBuffer + 2 * no_channels - 1;
-  FIXP_DBL *RESTRICT pData_1 = analysisBuffer;
-
-  FIXP_QAS *RESTRICT sta_0 = (FIXP_QAS *)pFilterStates;
-  FIXP_QAS *RESTRICT sta_1 =
-      (FIXP_QAS *)pFilterStates + (2 * QMF_NO_POLY * no_channels) - 1;
-  INT pfltStep = QMF_NO_POLY * (p_stride);
-  INT staStep1 = no_channels << 1;
-  INT staStep2 = (no_channels << 3) - 1; /* Rewind one less */
-
-  /* FIR filters 127..64 0..63 */
-  for (k = 0; k < no_channels; k++) {
-    accu = fMultDiv2(p_flt[0], *sta_1);
-    sta_1 -= staStep1;
-    accu += fMultDiv2(p_flt[1], *sta_1);
-    sta_1 -= staStep1;
-    accu += fMultDiv2(p_flt[2], *sta_1);
-    sta_1 -= staStep1;
-    accu += fMultDiv2(p_flt[3], *sta_1);
-    sta_1 -= staStep1;
-    accu += fMultDiv2(p_flt[4], *sta_1);
-    *pData_1++ = (accu << 1);
-    sta_1 += staStep2;
-
-    p_flt += pfltStep;
-    accu = fMultDiv2(p_flt[0], *sta_0);
-    sta_0 += staStep1;
-    accu += fMultDiv2(p_flt[1], *sta_0);
-    sta_0 += staStep1;
-    accu += fMultDiv2(p_flt[2], *sta_0);
-    sta_0 += staStep1;
-    accu += fMultDiv2(p_flt[3], *sta_0);
-    sta_0 += staStep1;
-    accu += fMultDiv2(p_flt[4], *sta_0);
-    *pData_0-- = (accu << 1);
-    sta_0 -= staStep2;
-  }
-}
-#endif /* !defined(FUNCTION_qmfAnaPrototypeFirSlot) */
-
-#ifndef FUNCTION_qmfAnaPrototypeFirSlot_NonSymmetric
-/*!
-  \brief Perform Analysis Prototype Filtering on a single slot of input data.
-*/
-static void qmfAnaPrototypeFirSlot_NonSymmetric(
-    FIXP_DBL *analysisBuffer,
-    int no_channels, /*!< Number channels of analysis filter */
-    const FIXP_PFT *p_filter, int p_stride, /*!< Stride of analysis filter    */
-    FIXP_QAS *RESTRICT pFilterStates) {
-  const FIXP_PFT *RESTRICT p_flt = p_filter;
-  int p, k;
-
-  for (k = 0; k < 2 * no_channels; k++) {
-    FIXP_DBL accu = (FIXP_DBL)0;
-
-    p_flt += QMF_NO_POLY * (p_stride - 1);
-
-    /*
-      Perform FIR-Filter
-    */
-    for (p = 0; p < QMF_NO_POLY; p++) {
-      accu += fMultDiv2(*p_flt++, pFilterStates[2 * no_channels * p]);
-    }
-    analysisBuffer[2 * no_channels - 1 - k] = (accu << 1);
-    pFilterStates++;
-  }
-}
-#endif /* FUNCTION_qmfAnaPrototypeFirSlot_NonSymmetric */
-
 /*!
  *
  * \brief Perform real-valued forward modulation of the time domain
@@ -244,7 +162,7 @@
   int i;
   int L = anaQmf->no_channels;
   int M = L >> 1;
-  int scale;
+  int scale = 0;
   FIXP_DBL accu;
 
   const FIXP_DBL *timeInTmp1 = (FIXP_DBL *)&timeIn[3 * M];
@@ -381,211 +299,6 @@
 }
 #endif /* FUNCTION_qmfForwardModulationHQ */
 
-/*
- * \brief Perform one QMF slot analysis of the time domain data of timeIn
- *        with specified stride and stores the real part of the subband
- *        samples in rSubband, and the imaginary part in iSubband
- *
- *        Note: anaQmf->lsb can be greater than anaQmf->no_channels in case
- *        of implicit resampling (USAC with reduced 3/4 core frame length).
- */
-#if (SAMPLE_BITS != DFRACT_BITS) && (QAS_BITS == DFRACT_BITS)
-void qmfAnalysisFilteringSlot(
-    HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Synthesis Bank  */
-    FIXP_DBL *qmfReal,             /*!< Low and High band, real */
-    FIXP_DBL *qmfImag,             /*!< Low and High band, imag */
-    const LONG *RESTRICT timeIn,   /*!< Pointer to input */
-    const int stride,              /*!< stride factor of input */
-    FIXP_DBL *pWorkBuffer          /*!< pointer to temporal working buffer */
-) {
-  int offset = anaQmf->no_channels * (QMF_NO_POLY * 2 - 1);
-  /*
-    Feed time signal into oldest anaQmf->no_channels states
-  */
-  {
-    FIXP_DBL *FilterStatesAnaTmp = ((FIXP_DBL *)anaQmf->FilterStates) + offset;
-
-    /* Feed and scale actual time in slot */
-    for (int i = anaQmf->no_channels >> 1; i != 0; i--) {
-      /* Place INT_PCM value left aligned in scaledTimeIn */
-
-      *FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
-      timeIn += stride;
-      *FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
-      timeIn += stride;
-    }
-  }
-
-  if (anaQmf->flags & QMF_FLAG_NONSYMMETRIC) {
-    qmfAnaPrototypeFirSlot_NonSymmetric(pWorkBuffer, anaQmf->no_channels,
-                                        anaQmf->p_filter, anaQmf->p_stride,
-                                        (FIXP_QAS *)anaQmf->FilterStates);
-  } else {
-    qmfAnaPrototypeFirSlot(pWorkBuffer, anaQmf->no_channels, anaQmf->p_filter,
-                           anaQmf->p_stride, (FIXP_QAS *)anaQmf->FilterStates);
-  }
-
-  if (anaQmf->flags & QMF_FLAG_LP) {
-    if (anaQmf->flags & QMF_FLAG_CLDFB)
-      qmfForwardModulationLP_odd(anaQmf, pWorkBuffer, qmfReal);
-    else
-      qmfForwardModulationLP_even(anaQmf, pWorkBuffer, qmfReal);
-
-  } else {
-    qmfForwardModulationHQ(anaQmf, pWorkBuffer, qmfReal, qmfImag);
-  }
-  /*
-    Shift filter states
-
-    Should be realized with modulo adressing on a DSP instead of a true buffer
-    shift
-  */
-  FDKmemmove(anaQmf->FilterStates,
-             (FIXP_QAS *)anaQmf->FilterStates + anaQmf->no_channels,
-             offset * sizeof(FIXP_QAS));
-}
-#endif
-
-void qmfAnalysisFilteringSlot(
-    HANDLE_QMF_FILTER_BANK anaQmf,  /*!< Handle of Qmf Synthesis Bank  */
-    FIXP_DBL *qmfReal,              /*!< Low and High band, real */
-    FIXP_DBL *qmfImag,              /*!< Low and High band, imag */
-    const INT_PCM *RESTRICT timeIn, /*!< Pointer to input */
-    const int stride,               /*!< stride factor of input */
-    FIXP_DBL *pWorkBuffer           /*!< pointer to temporal working buffer */
-) {
-  int offset = anaQmf->no_channels * (QMF_NO_POLY * 2 - 1);
-  /*
-    Feed time signal into oldest anaQmf->no_channels states
-  */
-  {
-    FIXP_QAS *FilterStatesAnaTmp = ((FIXP_QAS *)anaQmf->FilterStates) + offset;
-
-    /* Feed and scale actual time in slot */
-    for (int i = anaQmf->no_channels >> 1; i != 0; i--) {
-    /* Place INT_PCM value left aligned in scaledTimeIn */
-#if (QAS_BITS == SAMPLE_BITS)
-      *FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
-      timeIn += stride;
-      *FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
-      timeIn += stride;
-#elif (QAS_BITS > SAMPLE_BITS)
-      *FilterStatesAnaTmp++ = ((FIXP_QAS)*timeIn) << (QAS_BITS - SAMPLE_BITS);
-      timeIn += stride;
-      *FilterStatesAnaTmp++ = ((FIXP_QAS)*timeIn) << (QAS_BITS - SAMPLE_BITS);
-      timeIn += stride;
-#else
-      *FilterStatesAnaTmp++ = (FIXP_QAS)((*timeIn) >> (SAMPLE_BITS - QAS_BITS));
-      timeIn += stride;
-      *FilterStatesAnaTmp++ = (FIXP_QAS)((*timeIn) >> (SAMPLE_BITS - QAS_BITS));
-      timeIn += stride;
-#endif
-    }
-  }
-
-  if (anaQmf->flags & QMF_FLAG_NONSYMMETRIC) {
-    qmfAnaPrototypeFirSlot_NonSymmetric(pWorkBuffer, anaQmf->no_channels,
-                                        anaQmf->p_filter, anaQmf->p_stride,
-                                        (FIXP_QAS *)anaQmf->FilterStates);
-  } else {
-    qmfAnaPrototypeFirSlot(pWorkBuffer, anaQmf->no_channels, anaQmf->p_filter,
-                           anaQmf->p_stride, (FIXP_QAS *)anaQmf->FilterStates);
-  }
-
-  if (anaQmf->flags & QMF_FLAG_LP) {
-    if (anaQmf->flags & QMF_FLAG_CLDFB)
-      qmfForwardModulationLP_odd(anaQmf, pWorkBuffer, qmfReal);
-    else
-      qmfForwardModulationLP_even(anaQmf, pWorkBuffer, qmfReal);
-
-  } else {
-    qmfForwardModulationHQ(anaQmf, pWorkBuffer, qmfReal, qmfImag);
-  }
-  /*
-    Shift filter states
-
-    Should be realized with modulo adressing on a DSP instead of a true buffer
-    shift
-  */
-  FDKmemmove(anaQmf->FilterStates,
-             (FIXP_QAS *)anaQmf->FilterStates + anaQmf->no_channels,
-             offset * sizeof(FIXP_QAS));
-}
-
-/*!
- *
- * \brief Perform complex-valued subband filtering of the time domain
- *        data of timeIn and stores the real part of the subband
- *        samples in rAnalysis, and the imaginary part in iAnalysis
- * The qmf coefficient table is symmetric. The symmetry is expoited by
- * shrinking the coefficient table to half the size. The addressing mode
- * takes care of the symmetries.
- *
- *
- * \sa PolyphaseFiltering
- */
-#if (SAMPLE_BITS != DFRACT_BITS) && (QAS_BITS == DFRACT_BITS)
-void qmfAnalysisFiltering(
-    HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
-    FIXP_DBL **qmfReal,            /*!< Pointer to real subband slots */
-    FIXP_DBL **qmfImag,            /*!< Pointer to imag subband slots */
-    QMF_SCALE_FACTOR *scaleFactor, const LONG *timeIn, /*!< Time signal */
-    const int timeIn_e, const int stride,
-    FIXP_DBL *pWorkBuffer /*!< pointer to temporal working buffer */
-) {
-  int i;
-  int no_channels = anaQmf->no_channels;
-
-  scaleFactor->lb_scale =
-      -ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK - timeIn_e;
-  scaleFactor->lb_scale -= anaQmf->filterScale;
-
-  for (i = 0; i < anaQmf->no_col; i++) {
-    FIXP_DBL *qmfImagSlot = NULL;
-
-    if (!(anaQmf->flags & QMF_FLAG_LP)) {
-      qmfImagSlot = qmfImag[i];
-    }
-
-    qmfAnalysisFilteringSlot(anaQmf, qmfReal[i], qmfImagSlot, timeIn, stride,
-                             pWorkBuffer);
-
-    timeIn += no_channels * stride;
-
-  } /* no_col loop  i  */
-}
-#endif
-
-void qmfAnalysisFiltering(
-    HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
-    FIXP_DBL **qmfReal,            /*!< Pointer to real subband slots */
-    FIXP_DBL **qmfImag,            /*!< Pointer to imag subband slots */
-    QMF_SCALE_FACTOR *scaleFactor, const INT_PCM *timeIn, /*!< Time signal */
-    const int timeIn_e, const int stride,
-    FIXP_DBL *pWorkBuffer /*!< pointer to temporal working buffer */
-) {
-  int i;
-  int no_channels = anaQmf->no_channels;
-
-  scaleFactor->lb_scale =
-      -ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK - timeIn_e;
-  scaleFactor->lb_scale -= anaQmf->filterScale;
-
-  for (i = 0; i < anaQmf->no_col; i++) {
-    FIXP_DBL *qmfImagSlot = NULL;
-
-    if (!(anaQmf->flags & QMF_FLAG_LP)) {
-      qmfImagSlot = qmfImag[i];
-    }
-
-    qmfAnalysisFilteringSlot(anaQmf, qmfReal[i], qmfImagSlot, timeIn, stride,
-                             pWorkBuffer);
-
-    timeIn += no_channels * stride;
-
-  } /* no_col loop  i  */
-}
-
 /*!
  *
  * \brief Perform low power inverse modulation of the subband
@@ -603,15 +316,15 @@
   int i;
   int L = synQmf->no_channels;
   int M = L >> 1;
-  int scale;
+  int scale = 0;
   FIXP_DBL tmp;
   FIXP_DBL *RESTRICT tReal = pTimeOut;
   FIXP_DBL *RESTRICT tImag = pTimeOut + L;
 
   /* Move input to output vector with offset */
-  scaleValues(&tReal[0], &qmfReal[0], synQmf->lsb, (int)scaleFactorLowBand);
-  scaleValues(&tReal[0 + synQmf->lsb], &qmfReal[0 + synQmf->lsb],
-              synQmf->usb - synQmf->lsb, (int)scaleFactorHighBand);
+  scaleValuesSaturate(&tReal[0], &qmfReal[0], synQmf->lsb, scaleFactorLowBand);
+  scaleValuesSaturate(&tReal[0 + synQmf->lsb], &qmfReal[0 + synQmf->lsb],
+                      synQmf->usb - synQmf->lsb, scaleFactorHighBand);
   FDKmemclear(&tReal[0 + synQmf->usb], (L - synQmf->usb) * sizeof(FIXP_DBL));
 
   /* Dct type-2 transform */
@@ -662,9 +375,9 @@
   int shift = 0;
 
   /* Move input to output vector with offset */
-  scaleValues(pTimeOut + M, qmfReal, synQmf->lsb, scaleFactorLowBand);
-  scaleValues(pTimeOut + M + synQmf->lsb, qmfReal + synQmf->lsb,
-              synQmf->usb - synQmf->lsb, scaleFactorHighBand);
+  scaleValuesSaturate(pTimeOut + M, qmfReal, synQmf->lsb, scaleFactorLowBand);
+  scaleValuesSaturate(pTimeOut + M + synQmf->lsb, qmfReal + synQmf->lsb,
+                      synQmf->usb - synQmf->lsb, scaleFactorHighBand);
   FDKmemclear(pTimeOut + M + synQmf->usb, (L - synQmf->usb) * sizeof(FIXP_DBL));
 
   dct_IV(pTimeOut + M, L, &shift);
@@ -698,26 +411,27 @@
   FIXP_DBL *RESTRICT tImag = pWorkBuffer + L;
 
   if (synQmf->flags & QMF_FLAG_CLDFB) {
-    for (i = 0; i < synQmf->lsb; i++) {
-      cplxMult(&tImag[i], &tReal[i], scaleValue(qmfImag[i], scaleFactorLowBand),
-               scaleValue(qmfReal[i], scaleFactorLowBand), synQmf->t_cos[i],
-               synQmf->t_sin[i]);
+    for (i = 0; i < synQmf->usb; i++) {
+      cplxMultDiv2(&tImag[i], &tReal[i], qmfImag[i], qmfReal[i],
+                   synQmf->t_cos[i], synQmf->t_sin[i]);
     }
-    for (; i < synQmf->usb; i++) {
-      cplxMult(&tImag[i], &tReal[i],
-               scaleValue(qmfImag[i], scaleFactorHighBand),
-               scaleValue(qmfReal[i], scaleFactorHighBand), synQmf->t_cos[i],
-               synQmf->t_sin[i]);
-    }
+    scaleValuesSaturate(&tReal[0], synQmf->lsb, scaleFactorLowBand + 1);
+    scaleValuesSaturate(&tReal[0 + synQmf->lsb], synQmf->usb - synQmf->lsb,
+                        scaleFactorHighBand + 1);
+    scaleValuesSaturate(&tImag[0], synQmf->lsb, scaleFactorLowBand + 1);
+    scaleValuesSaturate(&tImag[0 + synQmf->lsb], synQmf->usb - synQmf->lsb,
+                        scaleFactorHighBand + 1);
   }
 
   if ((synQmf->flags & QMF_FLAG_CLDFB) == 0) {
-    scaleValues(&tReal[0], &qmfReal[0], synQmf->lsb, (int)scaleFactorLowBand);
-    scaleValues(&tReal[0 + synQmf->lsb], &qmfReal[0 + synQmf->lsb],
-                synQmf->usb - synQmf->lsb, (int)scaleFactorHighBand);
-    scaleValues(&tImag[0], &qmfImag[0], synQmf->lsb, (int)scaleFactorLowBand);
-    scaleValues(&tImag[0 + synQmf->lsb], &qmfImag[0 + synQmf->lsb],
-                synQmf->usb - synQmf->lsb, (int)scaleFactorHighBand);
+    scaleValuesSaturate(&tReal[0], &qmfReal[0], synQmf->lsb,
+                        scaleFactorLowBand);
+    scaleValuesSaturate(&tReal[0 + synQmf->lsb], &qmfReal[0 + synQmf->lsb],
+                        synQmf->usb - synQmf->lsb, scaleFactorHighBand);
+    scaleValuesSaturate(&tImag[0], &qmfImag[0], synQmf->lsb,
+                        scaleFactorLowBand);
+    scaleValuesSaturate(&tImag[0 + synQmf->lsb], &qmfImag[0 + synQmf->lsb],
+                        synQmf->usb - synQmf->lsb, scaleFactorHighBand);
   }
 
   FDKmemclear(&tReal[synQmf->usb],
@@ -1004,35 +718,6 @@
  * \return 0 if succesful
  *
  */
-int qmfInitAnalysisFilterBank(
-    HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Returns handle */
-    FIXP_QAS *pFilterStates,      /*!< Handle to filter states */
-    int noCols,                   /*!< Number of timeslots per frame */
-    int lsb,                      /*!< lower end of QMF */
-    int usb,                      /*!< upper end of QMF */
-    int no_channels,              /*!< Number of channels (bands) */
-    int flags)                    /*!< Low Power flag */
-{
-  int err = qmfInitFilterBank(h_Qmf, pFilterStates, noCols, lsb, usb,
-                              no_channels, flags, 0);
-  if (!(flags & QMF_FLAG_KEEP_STATES) && (h_Qmf->FilterStates != NULL)) {
-    FDKmemclear(h_Qmf->FilterStates,
-                (2 * QMF_NO_POLY - 1) * h_Qmf->no_channels * sizeof(FIXP_QAS));
-  }
-
-  FDK_ASSERT(h_Qmf->no_channels >= h_Qmf->lsb);
-
-  return err;
-}
-
-/*!
- *
- * \brief Create QMF filter bank instance
- *
- *
- * \return 0 if succesful
- *
- */
 int qmfInitSynthesisFilterBank(
     HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Returns handle */
     FIXP_QSS *pFilterStates,      /*!< Handle to filter states */
@@ -1128,8 +813,21 @@
   synQmf->outGain_e = outputGainScale;
 }
 
-/* When QMF_16IN_32OUT is set, synthesis functions for 16 and 32 bit parallel
- * output is compiled */
 #define INT_PCM_QMFOUT INT_PCM
 #define SAMPLE_BITS_QMFOUT SAMPLE_BITS
 #include "qmf_pcm.h"
+#if SAMPLE_BITS == 16
+  /* also create a 32 bit output version */
+#undef INT_PCM_QMFOUT
+#undef SAMPLE_BITS_QMFOUT
+#undef QMF_PCM_H
+#undef FIXP_QAS
+#undef QAS_BITS
+#undef INT_PCM_QMFIN
+#define INT_PCM_QMFOUT LONG
+#define SAMPLE_BITS_QMFOUT 32
+#define FIXP_QAS FIXP_DBL
+#define QAS_BITS 32
+#define INT_PCM_QMFIN LONG
+#include "qmf_pcm.h"
+#endif
diff --git a/libFDK/src/scale.cpp b/libFDK/src/scale.cpp
index 24a8a5b..6192170 100644
--- a/libFDK/src/scale.cpp
+++ b/libFDK/src/scale.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -250,10 +250,10 @@
  */
 #define FUNCTION_scaleValuesSaturate_DBL_DBL
 SCALE_INLINE
-void scaleValuesSaturate(FIXP_DBL *dst,  /*!< Output */
-                         FIXP_DBL *src,  /*!< Input   */
-                         INT len,        /*!< Length */
-                         INT scalefactor /*!< Scalefactor */
+void scaleValuesSaturate(FIXP_DBL *dst,       /*!< Output */
+                         const FIXP_DBL *src, /*!< Input   */
+                         INT len,             /*!< Length */
+                         INT scalefactor      /*!< Scalefactor */
 ) {
   INT i;
 
@@ -285,10 +285,10 @@
  */
 #define FUNCTION_scaleValuesSaturate_SGL_DBL
 SCALE_INLINE
-void scaleValuesSaturate(FIXP_SGL *dst,   /*!< Output */
-                         FIXP_DBL *src,   /*!< Input   */
-                         INT len,         /*!< Length */
-                         INT scalefactor) /*!< Scalefactor */
+void scaleValuesSaturate(FIXP_SGL *dst,       /*!< Output */
+                         const FIXP_DBL *src, /*!< Input   */
+                         INT len,             /*!< Length */
+                         INT scalefactor)     /*!< Scalefactor */
 {
   INT i;
   scalefactor = fixmax_I(fixmin_I(scalefactor, (INT)DFRACT_BITS - 1),
@@ -345,10 +345,10 @@
  */
 #define FUNCTION_scaleValuesSaturate_SGL_SGL
 SCALE_INLINE
-void scaleValuesSaturate(FIXP_SGL *dst,  /*!< Output */
-                         FIXP_SGL *src,  /*!< Input */
-                         INT len,        /*!< Length */
-                         INT scalefactor /*!< Scalefactor */
+void scaleValuesSaturate(FIXP_SGL *dst,       /*!< Output */
+                         const FIXP_SGL *src, /*!< Input */
+                         INT len,             /*!< Length */
+                         INT scalefactor      /*!< Scalefactor */
 ) {
   INT i;
 
diff --git a/libMpegTPDec/src/tpdec_adts.cpp b/libMpegTPDec/src/tpdec_adts.cpp
index 1a4e3fd..f936634 100644
--- a/libMpegTPDec/src/tpdec_adts.cpp
+++ b/libMpegTPDec/src/tpdec_adts.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -213,8 +213,8 @@
     goto bail;
   }
 
+  FDKcrcReset(&pAdts->crcInfo);
   if (!bs.protection_absent) {
-    FDKcrcReset(&pAdts->crcInfo);
     FDKpushBack(hBs, 56); /* complete fixed and variable header! */
     crcReg = FDKcrcStartReg(&pAdts->crcInfo, hBs, 0);
     FDKpushFor(hBs, 56);
@@ -314,15 +314,55 @@
   if (bs.channel_config == 0) {
     int pceBits = 0;
     UINT alignAnchor = FDKgetValidBits(hBs);
+    CProgramConfig tmpPce;
 
     if (FDKreadBits(hBs, 3) == ID_PCE) {
       /* Got luck! Parse the PCE */
       crcReg = adtsRead_CrcStartReg(pAdts, hBs, 0);
 
-      CProgramConfig_Read(&pAsc->m_progrConfigElement, hBs, alignAnchor);
+      CProgramConfig_Init(&tmpPce);
+      CProgramConfig_Read(&tmpPce, hBs, alignAnchor);
+
+      if (CProgramConfig_IsValid(&tmpPce)) {
+        if (CProgramConfig_IsValid(&oldPce)) {
+          /* Compare the new and the old PCE (tags ignored) */
+          switch (CProgramConfig_Compare(&tmpPce, &oldPce)) {
+            case 0: /* Nothing to do because PCE matches the old one exactly. */
+            case 1: /* Channel configuration not changed. Just new metadata. */
+              FDKmemcpy(&pAsc->m_progrConfigElement, &tmpPce,
+                        sizeof(CProgramConfig));
+              break;
+            case 2:  /* The number of channels are identical but not the config
+                      */
+            case -1: /* The channel configuration is completely different */
+            default:
+              FDKmemcpy(&pAsc->m_progrConfigElement, &oldPce,
+                        sizeof(CProgramConfig));
+              FDKpushBack(hBs, adtsHeaderLength);
+              return TRANSPORTDEC_PARSE_ERROR;
+          }
+        } else {
+          FDKmemcpy(&pAsc->m_progrConfigElement, &tmpPce,
+                    sizeof(CProgramConfig));
+        }
+      } else {
+        if (CProgramConfig_IsValid(&oldPce)) {
+          FDKmemcpy(&pAsc->m_progrConfigElement, &oldPce,
+                    sizeof(CProgramConfig));
+        } else {
+          FDKpushBack(hBs, adtsHeaderLength);
+          return TRANSPORTDEC_PARSE_ERROR;
+        }
+      }
 
       adtsRead_CrcEndReg(pAdts, hBs, crcReg);
-      pceBits = alignAnchor - FDKgetValidBits(hBs);
+      pceBits = (INT)alignAnchor - (INT)FDKgetValidBits(hBs);
+      adtsHeaderLength += pceBits;
+
+      if (pceBits > (INT)alignAnchor) {
+        goto bail;
+      }
+
       /* store the number of PCE bits */
       bs.num_pce_bits = pceBits;
     } else {
diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp
index 28bc22d..82f840e 100644
--- a/libMpegTPDec/src/tpdec_asc.cpp
+++ b/libMpegTPDec/src/tpdec_asc.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -1325,9 +1325,9 @@
                                                   CSTpCallBacks *cb) {
   TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
   CSEldSpecificConfig *esc = &asc->m_sc.m_eldSpecificConfig;
-  ASC_ELD_EXT_TYPE eldExtType;
+  UINT eldExtType;
   int eldExtLen, len, cnt, ldSbrLen = 0, eldExtLenSum, numSbrHeader = 0,
-                           sbrIndex;
+                           sbrIndex, eldExtCnt = 0;
 
   unsigned char downscale_fill_nibble;
 
@@ -1394,9 +1394,8 @@
   eldExtLenSum = FDKgetValidBits(hBs);
   esc->m_downscaledSamplingFrequency = asc->m_samplingFrequency;
   /* parse ExtTypeConfigData */
-  while (
-      ((eldExtType = (ASC_ELD_EXT_TYPE)FDKreadBits(hBs, 4)) != ELDEXT_TERM) &&
-      ((INT)FDKgetValidBits(hBs) >= 0)) {
+  while (((eldExtType = FDKreadBits(hBs, 4)) != ELDEXT_TERM) &&
+         ((INT)FDKgetValidBits(hBs) >= 0) && (eldExtCnt++ < 15)) {
     eldExtLen = len = FDKreadBits(hBs, 4);
     if (len == 0xf) {
       len = FDKreadBits(hBs, 8);
@@ -1440,7 +1439,8 @@
         UCHAR tmpDownscaleFreqIdx;
         esc->m_downscaledSamplingFrequency =
             getSampleRate(hBs, &tmpDownscaleFreqIdx, 4);
-        if (esc->m_downscaledSamplingFrequency == 0) {
+        if (esc->m_downscaledSamplingFrequency == 0 ||
+            esc->m_downscaledSamplingFrequency > 96000) {
           return TRANSPORTDEC_PARSE_ERROR;
         }
         downscale_fill_nibble = FDKreadBits(hBs, 4);
@@ -1454,6 +1454,9 @@
         break;
     }
   }
+  if (eldExtType != ELDEXT_TERM) {
+    return TRANSPORTDEC_PARSE_ERROR;
+  }
 
   if ((INT)FDKgetValidBits(hBs) < 0) {
     return TRANSPORTDEC_PARSE_ERROR;
@@ -1948,6 +1951,9 @@
   INT nbits = (INT)FDKgetValidBits(hBs);
 
   usacSamplingFrequency = getSampleRate(hBs, &asc->m_samplingFrequencyIndex, 5);
+  if (usacSamplingFrequency == 0 || usacSamplingFrequency > 96000) {
+    return TRANSPORTDEC_PARSE_ERROR;
+  }
   asc->m_samplingFrequency = (UINT)usacSamplingFrequency;
 
   coreSbrFrameLengthIndex = FDKreadBits(hBs, 3);
@@ -2027,7 +2033,8 @@
               self->m_extensionSamplingFrequency = getSampleRate(
                   bs, &self->m_extensionSamplingFrequencyIndex, 4);
 
-              if ((INT)self->m_extensionSamplingFrequency <= 0) {
+              if (self->m_extensionSamplingFrequency == 0 ||
+                  self->m_extensionSamplingFrequency > 96000) {
                 return TRANSPORTDEC_PARSE_ERROR;
               }
             }
@@ -2139,6 +2146,24 @@
 
     self->m_channelConfiguration = FDKreadBits(bs, 4);
 
+    /* MPEG-04 standard ISO/IEC 14496-3: channelConfiguration == 0 is reserved
+       in er_raw_data_block (table 4.19) and er_raw_data_block_eld (table 4.75)
+       MPEG-04 conformance ISO/IEC 14496-4: channelConfiguration == 0 is not
+       permitted for AOT_ER_AAC_LC, AOT_ER_AAC_LTP, AOT_ER_AAC_LD,
+       AOT_ER_AAC_SCAL (chapter 6.6.4.1.2.1.1) */
+    if ((self->m_channelConfiguration == 0) &&
+        ((self->m_aot == AOT_ER_AAC_LC) || (self->m_aot == AOT_ER_AAC_LTP) ||
+         (self->m_aot == AOT_ER_AAC_LD) || (self->m_aot == AOT_ER_AAC_SCAL) ||
+         (self->m_aot == AOT_ER_AAC_ELD))) {
+      return TRANSPORTDEC_UNSUPPORTED_FORMAT;
+    }
+    /* MPEG-04 conformance ISO/IEC 14496-4: channelConfiguration > 2 is not
+     * permitted for AOT_AAC_SCAL and AOT_ER_AAC_SCAL (chapter 6.6.4.1.2.1.1) */
+    if ((self->m_channelConfiguration > 2) &&
+        ((self->m_aot == AOT_AAC_SCAL) || (self->m_aot == AOT_ER_AAC_SCAL))) {
+      return TRANSPORTDEC_UNSUPPORTED_FORMAT;
+    }
+
     /* SBR extension ( explicit non-backwards compatible mode ) */
     self->m_sbrPresentFlag = 0;
     self->m_psPresentFlag = 0;
@@ -2153,6 +2178,10 @@
 
       self->m_extensionSamplingFrequency =
           getSampleRate(bs, &self->m_extensionSamplingFrequencyIndex, 4);
+      if (self->m_extensionSamplingFrequency == 0 ||
+          self->m_extensionSamplingFrequency > 96000) {
+        return TRANSPORTDEC_PARSE_ERROR;
+      }
       self->m_aot = getAOT(bs);
 
       switch (self->m_aot) {
diff --git a/libMpegTPDec/src/tpdec_latm.cpp b/libMpegTPDec/src/tpdec_latm.cpp
index 2edf055..3b71db8 100644
--- a/libMpegTPDec/src/tpdec_latm.cpp
+++ b/libMpegTPDec/src/tpdec_latm.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -367,10 +367,10 @@
           }
           if (pLatmDemux->m_AudioMuxVersion == 1) {
             FDK_BITSTREAM tmpBs;
-            UINT ascLen = 0;
+            INT ascLen = 0;
             ascLen = CLatmDemux_GetValue(bs);
             /* The ascLen could be wrong, so check if validBits<=bufBits*/
-            if (ascLen > FDKgetValidBits(bs)) {
+            if (ascLen < 0 || ascLen > (INT)FDKgetValidBits(bs)) {
               ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
               goto bail;
             }
diff --git a/libMpegTPDec/src/tpdec_lib.cpp b/libMpegTPDec/src/tpdec_lib.cpp
index 506aed3..ca35184 100644
--- a/libMpegTPDec/src/tpdec_lib.cpp
+++ b/libMpegTPDec/src/tpdec_lib.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -482,7 +482,8 @@
 
         for (int i = 0; i < 2; i++) {
           if (i > 0) {
-            FDKpushBack(hBs, newConfigLength * 8 - FDKgetValidBits(hBs));
+            FDKpushBack(hBs,
+                        (INT)newConfigLength * 8 - (INT)FDKgetValidBits(hBs));
             configMode = AC_CM_ALLOC_MEM;
           }
           /* config transport decoder */
@@ -663,10 +664,14 @@
     if (*pBytesValid == 0) {
       /* nothing to do */
       return TRANSPORTDEC_OK;
-    }
-
-    if (hTp->numberOfRawDataBlocks <= 0) {
+    } else {
+      const int bytesValid = *pBytesValid;
       FDKfeedBuffer(hBs, pBuffer, bufferSize, pBytesValid);
+
+      if (hTp->numberOfRawDataBlocks > 0) {
+        hTp->globalFramePos += (bytesValid - *pBytesValid) * 8;
+        hTp->accessUnitAnchor[layer] = FDKgetValidBits(hBs);
+      }
     }
   }
 
@@ -924,6 +929,11 @@
               }
             }
           }
+          /* if an error is detected terminate config parsing to avoid that an
+           * invalid config is accepted in the second pass */
+          if (err != TRANSPORTDEC_OK) {
+            break;
+          }
         }
       } else {
         /* Reset CRC because the next bits are the beginning of a
@@ -976,6 +986,9 @@
               CLatmDemux_GetNrOfSubFrames(&hTp->parser.latm);
           if (hTp->transportFmt == TT_MP4_LOAS) {
             syncLayerFrameBits -= startPos - (INT)FDKgetValidBits(hBs) - (13);
+            if (syncLayerFrameBits <= 0) {
+              err = TRANSPORTDEC_SYNC_ERROR;
+            }
           }
         }
       } else {
@@ -1151,6 +1164,11 @@
                                     &rawDataBlockLength, &fTraverseMoreFrames,
                                     &syncLayerFrameBits, &fConfigFound,
                                     &headerBits);
+      if (headerBits > bitsAvail) {
+        err = (headerBits < (INT)hBs->hBitBuf.bufBits)
+                  ? TRANSPORTDEC_NOT_ENOUGH_BITS
+                  : TRANSPORTDEC_SYNC_ERROR;
+      }
       if (TPDEC_IS_FATAL_ERROR(err)) {
         /* Rewind - TPDEC_SYNCSKIP, in order to look for a synch one bit ahead
          * next time. Ensure that the bit amount lands at a multiple of
@@ -1181,8 +1199,6 @@
     }
 
     if (err == TRANSPORTDEC_NOT_ENOUGH_BITS) {
-      /* Enforce reading of new data */
-      hTp->numberOfRawDataBlocks = 0;
       break;
     }
 
@@ -1263,8 +1279,9 @@
   if (!(hTp->flags & (TPDEC_LOST_FRAMES_PENDING | TPDEC_IGNORE_BUFFERFULLNESS |
                       TPDEC_SYNCOK)) &&
       err == TRANSPORTDEC_OK) {
-    err = additionalHoldOffNeeded(hTp, transportDec_GetBufferFullness(hTp),
-                                  FDKgetValidBits(hBs) - syncLayerFrameBits);
+    err =
+        additionalHoldOffNeeded(hTp, transportDec_GetBufferFullness(hTp),
+                                (INT)FDKgetValidBits(hBs) - syncLayerFrameBits);
     if (err == TRANSPORTDEC_NOT_ENOUGH_BITS) {
       hTp->holdOffFrames++;
     }
@@ -1273,7 +1290,9 @@
   /* Rewind for retry because of not enough bits */
   if (err == TRANSPORTDEC_NOT_ENOUGH_BITS) {
     FDKpushBack(hBs, headerBits);
+    hTp->numberOfRawDataBlocks = numRawDataBlocksPrevious;
     headerBits = 0;
+    rawDataBlockLength = rawDataBlockLengthPrevious;
   } else {
     /* reset hold off frame counter */
     hTp->holdOffFrames = 0;
@@ -1460,7 +1479,7 @@
 
         for (i = 0; i < 2; i++) {
           if (i > 0) {
-            FDKpushBack(hBs, bsStart - FDKgetValidBits(hBs));
+            FDKpushBack(hBs, bsStart - (INT)FDKgetValidBits(hBs));
             configMode = AC_CM_ALLOC_MEM;
           }
 
diff --git a/libPCMutils/include/limiter.h b/libPCMutils/include/limiter.h
index fab7226..419e891 100644
--- a/libPCMutils/include/limiter.h
+++ b/libPCMutils/include/limiter.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -109,8 +109,6 @@
 #define TDL_ATTACK_DEFAULT_MS (15)  /* default attack  time in ms */
 #define TDL_RELEASE_DEFAULT_MS (50) /* default release time in ms */
 
-#define TDL_GAIN_SCALING (15) /* scaling of gain value. */
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -128,10 +126,7 @@
   unsigned int maxBufIdx, delayBufIdx;
   FIXP_DBL smoothState0;
   FIXP_DBL minGain;
-
-  FIXP_DBL additionalGainPrev;
-  FIXP_DBL additionalGainFilterState;
-  FIXP_DBL additionalGainFilterState1;
+  INT scaling;
 };
 
 typedef enum {
@@ -255,27 +250,16 @@
 
 /******************************************************************************
  * pcmLimiter_Apply                                                            *
- * limiter:    limiter handle                                                  *
- * pGain :     pointer to gains to be applied to the signal before limiting,   *
- *             which are downscaled by TDL_GAIN_SCALING bit.                   *
- *             These gains are delayed by gain_delay, and smoothed.            *
- *             Smoothing is done by a butterworth lowpass filter with a cutoff *
- *             frequency which is fixed with respect to the sampling rate.     *
- *             It is a substitute for the smoothing due to windowing and       *
- *             overlap/add, if a gain is applied in frequency domain.          *
- * gain_scale: pointer to scaling exponents to be applied to the signal before *
- *             limiting, without delay and without smoothing                   *
- * gain_size:  number of elements in pGain, currently restricted to 1          *
- * gain_delay: delay [samples] with which the gains in pGain shall be applied  *
- *             gain_delay <= nSamples                                          *
- * samples:    input/output buffer containing interleaved samples              *
- *             precision of output will be DFRACT_BITS-TDL_GAIN_SCALING bits   *
- * nSamples:   number of samples per channel                                   *
+ * limiter:        limiter handle                                              *
+ * samplesIn:      pointer to input buffer containing interleaved samples      *
+ * samplesOut:     pointer to output buffer containing interleaved samples     *
+ * pGainPerSample: pointer to gains for each sample                            *
+ * scaling:        scaling of output samples                                   *
+ * nSamples:       number of samples per channel                               *
  * returns:    error code                                                      *
  ******************************************************************************/
 TDLIMITER_ERROR pcmLimiter_Apply(TDLimiterPtr limiter, PCM_LIM* samplesIn,
-                                 INT_PCM* samplesOut, FIXP_DBL* pGain,
-                                 const INT* gain_scale, const UINT gain_size,
-                                 const UINT gain_delay, const UINT nSamples);
+                                 INT_PCM* samplesOut, FIXP_DBL* pGainPerSample,
+                                 const INT scaling, const UINT nSamples);
 
 #endif /* #ifndef LIMITER_H */
diff --git a/libPCMutils/src/limiter.cpp b/libPCMutils/src/limiter.cpp
index a799a51..598dc0c 100644
--- a/libPCMutils/src/limiter.cpp
+++ b/libPCMutils/src/limiter.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -152,7 +152,7 @@
   limiter->attack = attack;
   limiter->attackConst = attackConst;
   limiter->releaseConst = releaseConst;
-  limiter->threshold = threshold >> TDL_GAIN_SCALING;
+  limiter->threshold = threshold;
   limiter->channels = maxChannels;
   limiter->maxChannels = maxChannels;
   limiter->sampleRate = maxSampleRate;
@@ -165,18 +165,13 @@
 
 /* apply limiter */
 TDLIMITER_ERROR pcmLimiter_Apply(TDLimiterPtr limiter, PCM_LIM* samplesIn,
-                                 INT_PCM* samplesOut, FIXP_DBL* RESTRICT pGain,
-                                 const INT* RESTRICT gain_scale,
-                                 const UINT gain_size, const UINT gain_delay,
-                                 const UINT nSamples) {
+                                 INT_PCM* samplesOut, FIXP_DBL* pGainPerSample,
+                                 const INT scaling, const UINT nSamples) {
   unsigned int i, j;
-  FIXP_DBL tmp1;
   FIXP_DBL tmp2;
-  FIXP_DBL tmp, old, gain, additionalGain = 0, additionalGainUnfiltered;
+  FIXP_DBL tmp, old, gain, additionalGain = 0;
   FIXP_DBL minGain = FL2FXCONST_DBL(1.0f / (1 << 1));
-
-  FDK_ASSERT(gain_size == 1);
-  FDK_ASSERT(gain_delay <= nSamples);
+  UINT additionalGainAvailable = 1;
 
   if (limiter == NULL) return TDLIMIT_INVALID_HANDLE;
 
@@ -185,7 +180,7 @@
     unsigned int attack = limiter->attack;
     FIXP_DBL attackConst = limiter->attackConst;
     FIXP_DBL releaseConst = limiter->releaseConst;
-    FIXP_DBL threshold = limiter->threshold;
+    FIXP_DBL threshold = limiter->threshold >> scaling;
 
     FIXP_DBL max = limiter->max;
     FIXP_DBL* maxBuf = limiter->maxBuf;
@@ -195,55 +190,34 @@
     unsigned int delayBufIdx = limiter->delayBufIdx;
 
     FIXP_DBL smoothState0 = limiter->smoothState0;
-    FIXP_DBL additionalGainSmoothState = limiter->additionalGainFilterState;
-    FIXP_DBL additionalGainSmoothState1 = limiter->additionalGainFilterState1;
 
-    if (!gain_delay) {
-      additionalGain = pGain[0];
-      if (gain_scale[0] > 0) {
-        additionalGain <<= gain_scale[0];
-      } else {
-        additionalGain >>= -gain_scale[0];
-      }
+    if (limiter->scaling != scaling) {
+      scaleValuesSaturate(delayBuf, attack * channels,
+                          limiter->scaling - scaling);
+      scaleValuesSaturate(maxBuf, attack + 1, limiter->scaling - scaling);
+      max = scaleValueSaturate(max, limiter->scaling - scaling);
+      limiter->scaling = scaling;
+    }
+
+    if (pGainPerSample == NULL) {
+      additionalGainAvailable = 0;
     }
 
     for (i = 0; i < nSamples; i++) {
-      if (gain_delay) {
-        if (i < gain_delay) {
-          additionalGainUnfiltered = limiter->additionalGainPrev;
-        } else {
-          additionalGainUnfiltered = pGain[0];
-        }
-
-        /* Smooth additionalGain */
-        /* [b,a] = butter(1, 0.01) */
-        static const FIXP_SGL b[] = {FL2FXCONST_SGL(0.015466 * 2.0),
-                                     FL2FXCONST_SGL(0.015466 * 2.0)};
-        static const FIXP_SGL a[] = {(FIXP_SGL)MAXVAL_SGL,
-                                     FL2FXCONST_SGL(-0.96907)};
-        additionalGain = -fMult(additionalGainSmoothState, a[1]) +
-                         fMultDiv2(additionalGainUnfiltered, b[0]) +
-                         fMultDiv2(additionalGainSmoothState1, b[1]);
-        additionalGainSmoothState1 = additionalGainUnfiltered;
-        additionalGainSmoothState = additionalGain;
-
-        /* Apply the additional scaling that has no delay and no smoothing */
-        if (gain_scale[0] > 0) {
-          additionalGain <<= gain_scale[0];
-        } else {
-          additionalGain >>= -gain_scale[0];
-        }
-      }
       /* get maximum absolute sample value of all channels, including the
        * additional gain. */
-      tmp1 = (FIXP_DBL)0;
+      tmp = (FIXP_DBL)0;
       for (j = 0; j < channels; j++) {
         tmp2 = PCM_LIM2FIXP_DBL(samplesIn[j]);
-        tmp2 = fAbs(tmp2);
-        tmp2 = FIXP_DBL(INT(tmp2) ^ INT((tmp2 >> (SAMPLE_BITS_LIM - 1))));
-        tmp1 = fMax(tmp1, tmp2);
+        tmp2 =
+            (tmp2 == (FIXP_DBL)MINVAL_DBL) ? (FIXP_DBL)MAXVAL_DBL : fAbs(tmp2);
+        tmp = fMax(tmp, tmp2);
       }
-      tmp = fMult(tmp1, additionalGain);
+
+      if (additionalGainAvailable) {
+        additionalGain = pGainPerSample[i];
+        tmp = fMult(tmp, additionalGain);
+      }
 
       /* set threshold as lower border to save calculations in running maximum
        * algorithm */
@@ -314,22 +288,42 @@
         /* lookahead delay, apply gain */
         for (j = 0; j < channels; j++) {
           tmp = p_delayBuf[j];
-          p_delayBuf[j] = fMult((FIXP_PCM_LIM)samplesIn[j], additionalGain);
+
+          if (additionalGainAvailable) {
+            p_delayBuf[j] = fMult((FIXP_PCM_LIM)samplesIn[j], additionalGain);
+          } else {
+            p_delayBuf[j] = PCM_LIM2FIXP_DBL(samplesIn[j]);
+          }
 
           /* Apply gain to delayed signal */
           tmp = fMultDiv2(tmp, gain);
-
+#if (SAMPLE_BITS == DFRACT_BITS)
+          samplesOut[j] = (INT_PCM)FX_DBL2FX_PCM(
+              (FIXP_DBL)SATURATE_LEFT_SHIFT(tmp, scaling + 1, DFRACT_BITS));
+#else
           samplesOut[j] = (INT_PCM)FX_DBL2FX_PCM((FIXP_DBL)SATURATE_LEFT_SHIFT(
-              tmp, TDL_GAIN_SCALING + 1, DFRACT_BITS));
+              tmp + ((FIXP_DBL)0x8000 >> (scaling + 1)), scaling + 1,
+              DFRACT_BITS));
+#endif
         }
         gain >>= 1;
       } else {
         /* lookahead delay, apply gain=1.0f */
         for (j = 0; j < channels; j++) {
           tmp = p_delayBuf[j];
-          p_delayBuf[j] = fMult((FIXP_PCM_LIM)samplesIn[j], additionalGain);
+          if (additionalGainAvailable) {
+            p_delayBuf[j] = fMult((FIXP_PCM_LIM)samplesIn[j], additionalGain);
+          } else {
+            p_delayBuf[j] = PCM_LIM2FIXP_DBL(samplesIn[j]);
+          }
+
+#if (SAMPLE_BITS == DFRACT_BITS)
+          samplesOut[j] = (INT_PCM)FX_DBL2FX_PCM(
+              (FIXP_DBL)SATURATE_LEFT_SHIFT(tmp, scaling, DFRACT_BITS));
+#else
           samplesOut[j] = (INT_PCM)FX_DBL2FX_PCM((FIXP_DBL)SATURATE_LEFT_SHIFT(
-              tmp, TDL_GAIN_SCALING, DFRACT_BITS));
+              tmp + ((FIXP_DBL)0x8000 >> scaling), scaling, DFRACT_BITS));
+#endif
         }
       }
 
@@ -354,13 +348,9 @@
     limiter->delayBufIdx = delayBufIdx;
 
     limiter->smoothState0 = smoothState0;
-    limiter->additionalGainFilterState = additionalGainSmoothState;
-    limiter->additionalGainFilterState1 = additionalGainSmoothState1;
 
     limiter->minGain = minGain;
 
-    limiter->additionalGainPrev = pGain[0];
-
     return TDLIMIT_OK;
   }
 }
@@ -370,7 +360,7 @@
                                         FIXP_DBL threshold) {
   if (limiter == NULL) return TDLIMIT_INVALID_HANDLE;
 
-  limiter->threshold = threshold >> TDL_GAIN_SCALING;
+  limiter->threshold = threshold;
 
   return TDLIMIT_OK;
 }
@@ -384,13 +374,7 @@
     limiter->cor = FL2FXCONST_DBL(1.0f / (1 << 1));
     limiter->smoothState0 = FL2FXCONST_DBL(1.0f / (1 << 1));
     limiter->minGain = FL2FXCONST_DBL(1.0f / (1 << 1));
-
-    limiter->additionalGainPrev =
-        FL2FXCONST_DBL(1.0f / (1 << TDL_GAIN_SCALING));
-    limiter->additionalGainFilterState =
-        FL2FXCONST_DBL(1.0f / (1 << TDL_GAIN_SCALING));
-    limiter->additionalGainFilterState1 =
-        FL2FXCONST_DBL(1.0f / (1 << TDL_GAIN_SCALING));
+    limiter->scaling = 0;
 
     FDKmemset(limiter->maxBuf, 0, (limiter->attack + 1) * sizeof(FIXP_DBL));
     FDKmemset(limiter->delayBuf, 0,
diff --git a/libPCMutils/src/version.h b/libPCMutils/src/version.h
index fa31af1..05371f8 100644
--- a/libPCMutils/src/version.h
+++ b/libPCMutils/src/version.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -105,7 +105,7 @@
 
 /* library info */
 #define PCMUTIL_LIB_VL0 3
-#define PCMUTIL_LIB_VL1 0
+#define PCMUTIL_LIB_VL1 1
 #define PCMUTIL_LIB_VL2 0
 #define PCMUTIL_LIB_TITLE "PCM Utility Lib"
 #ifdef __ANDROID__
diff --git a/libSACdec/include/sac_dec_lib.h b/libSACdec/include/sac_dec_lib.h
index 9913279..1827504 100644
--- a/libSACdec/include/sac_dec_lib.h
+++ b/libSACdec/include/sac_dec_lib.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -252,7 +252,7 @@
                 scenario. Default parameter value is 3 frames. */
 } SACDEC_PARAM;
 
-#define PCM_MPS INT_PCM
+#define PCM_MPS LONG
 
 /**
  * \brief MPEG Surround decoder handle.
@@ -401,17 +401,22 @@
  * for each output audio channel is stored into.
  * \param mapDescr             Channep map descriptor for output channel mapping
  * to be used (From MPEG PCE ordering to whatever is required).
+ * \param inDataHeadroom       Headroom of SAC input time signal to prevent
+ * clipping.
+ * \param outDataHeadroom      Pointer to headroom of SAC output time signal to
+ * prevent clipping.
  *
  * \return  Error code.
  */
 int mpegSurroundDecoder_Apply(CMpegSurroundDecoder *pMpegSurroundDecoder,
-                              INT_PCM *input, PCM_MPS *pTimeData,
+                              PCM_MPS *input, PCM_MPS *pTimeData,
                               const int timeDataSize, int timeDataFrameSize,
                               int *nChannels, int *frameSize, int sampleRate,
                               AUDIO_OBJECT_TYPE coreCodec,
                               AUDIO_CHANNEL_TYPE channelType[],
                               UCHAR channelIndices[],
-                              const FDK_channelMapDescr *const mapDescr);
+                              const FDK_channelMapDescr *const mapDescr,
+                              const INT inDataHeadroom, INT *outDataHeadroom);
 
 /**
  * \brief                       Deallocate a MPEG Surround decoder instance.
diff --git a/libSACdec/src/sac_bitdec.cpp b/libSACdec/src/sac_bitdec.cpp
index a1bdca4..4485ccf 100644
--- a/libSACdec/src/sac_bitdec.cpp
+++ b/libSACdec/src/sac_bitdec.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -1554,22 +1554,20 @@
   /* Interpolate */
   i1 = 0;
   for (i = 0; i < numParameterSets; i++) {
-    int xi, i2, x1, x2;
-
     if (aInterpolate[i] != 1) {
       i1 = i;
-    }
-    i2 = i;
-    while (aInterpolate[i2] == 1) {
-      i2++;
-      if (i2 >= MAX_PARAMETER_SETS) return MPS_WRONG_PARAMETERSETS;
-    }
-    x1 = paramSlot[i1];
-    xi = paramSlot[i];
-    x2 = paramSlot[i2];
+    } else {
+      int xi, i2, x1, x2;
 
-    if (aInterpolate[i] == 1) {
+      for (i2 = i; i2 < numParameterSets; i2++) {
+        if (aInterpolate[i2] != 1) break;
+      }
       if (i2 >= numParameterSets) return MPS_WRONG_PARAMETERSETS;
+
+      x1 = paramSlot[i1];
+      xi = paramSlot[i];
+      x2 = paramSlot[i2];
+
       for (band = startBand; band < stopBand; band++) {
         int yi, y1, y2;
         y1 = outputIdxData[xttIdx][i1][band];
@@ -1588,9 +1586,9 @@
   for (ps = 0; ps < numParameterSets; ps++) {
     if (quantMode && (paramType == t_CLD)) {
       if (pOttVsTotDbIn == 0) return MPS_WRONG_OTT;
-      if ((pOttVsTotDb1 == 0) && (ottVsTotDbMode == ottVsTotDb1Activ))
+      if ((pOttVsTotDb1 == 0) && (ottVsTotDbMode & ottVsTotDb1Activ))
         return MPS_WRONG_OTT;
-      if ((pOttVsTotDb2 == 0) && (ottVsTotDbMode == ottVsTotDb2Activ))
+      if ((pOttVsTotDb2 == 0) && (ottVsTotDbMode & ottVsTotDb2Activ))
         return MPS_WRONG_OTT;
 
       for (pb = startBand; pb < stopBand; pb++) {
@@ -1612,6 +1610,10 @@
   } /* for( i = 0 ; i < numParameterSets; i++ ) */
 
   if (extendFrame) {
+    if (paramType == t_IPD) {
+      llData->bsQuantCoarseXXX[numParameterSets] =
+          llData->bsQuantCoarseXXX[numParameterSets - 1];
+    }
     for (band = startBand; band < stopBand; band++) {
       outputDataIdx[xttIdx][numParameterSets][band] =
           outputDataIdx[xttIdx][numParameterSets - 1][band];
diff --git a/libSACdec/src/sac_calcM1andM2.h b/libSACdec/src/sac_calcM1andM2.h
index 996238d..cefc4bb 100644
--- a/libSACdec/src/sac_calcM1andM2.h
+++ b/libSACdec/src/sac_calcM1andM2.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -117,6 +117,9 @@
 /* Scaling of spectral data after applying M2 matrix, but only for binaural
    upmix type Scaling is compensated later in synthesis qmf filterbank */
 #define SCALE_DATA_APPLY_M2 (1)
+/* Applying M2 parameter in combination with phase coding needs 2 bits headroom
+ * because up to a maximum of 4 spectral values can be added for USAC */
+#define SCALE_DATA_APPLY_M2_PC (2)
 
 SACDEC_ERROR initM1andM2(spatialDec* self, int initStatesFlag,
                          int configChanged);
diff --git a/libSACdec/src/sac_dec.cpp b/libSACdec/src/sac_dec.cpp
index 3f55a7d..a7b50df 100644
--- a/libSACdec/src/sac_dec.cpp
+++ b/libSACdec/src/sac_dec.cpp
@@ -766,7 +766,7 @@
 
     /* output scaling */
     for (nCh = 0; nCh < self->numOutputChannelsAT; nCh++) {
-      int outputScale = 0, outputGain_e = 0, scale = 0;
+      int outputScale = 0, outputGain_e = 0, scale = -(8) + (1);
       FIXP_DBL outputGain_m = getChGain(self, nCh, &outputGain_e);
 
       if (!isTwoChMode(self->upmixType) && !bypassMode) {
@@ -775,7 +775,7 @@
                                              synthesis qmf */
       }
 
-      scale = outputScale;
+      scale += outputScale;
 
       qmfChangeOutScalefactor(&self->pQmfDomain->QmfDomainOut[nCh].fb, scale);
       qmfChangeOutGain(&self->pQmfDomain->QmfDomainOut[nCh].fb, outputGain_m,
@@ -1223,18 +1223,24 @@
               !(self->stereoConfigIndex == 3)) {
             for (i = 0; i < self->qmfBands; i++) {
               self_qmfResidualReal__FDK_0_0[i] =
-                  fMult(self_qmfResidualReal__FDK_0_0[i] << 1,
+                  fMult(scaleValueSaturate(self_qmfResidualReal__FDK_0_0[i],
+                                           1 + self->sacInDataHeadroom - (1)),
                         self->clipProtectGain__FDK);
               self_qmfResidualImag__FDK_0_0[i] =
-                  fMult(self_qmfResidualImag__FDK_0_0[i] << 1,
+                  fMult(scaleValueSaturate(self_qmfResidualImag__FDK_0_0[i],
+                                           1 + self->sacInDataHeadroom - (1)),
                         self->clipProtectGain__FDK);
             }
           } else {
             for (i = 0; i < self->qmfBands; i++) {
-              self_qmfResidualReal__FDK_0_0[i] = fMult(
-                  self_qmfResidualReal__FDK_0_0[i], self->clipProtectGain__FDK);
-              self_qmfResidualImag__FDK_0_0[i] = fMult(
-                  self_qmfResidualImag__FDK_0_0[i], self->clipProtectGain__FDK);
+              self_qmfResidualReal__FDK_0_0[i] =
+                  fMult(scaleValueSaturate(self_qmfResidualReal__FDK_0_0[i],
+                                           self->sacInDataHeadroom - (1)),
+                        self->clipProtectGain__FDK);
+              self_qmfResidualImag__FDK_0_0[i] =
+                  fMult(scaleValueSaturate(self_qmfResidualImag__FDK_0_0[i],
+                                           self->sacInDataHeadroom - (1)),
+                        self->clipProtectGain__FDK);
             }
           }
         }
@@ -1317,10 +1323,12 @@
       if ((self->tempShapeConfig == 1) && (!isTwoChMode(self->upmixType))) {
         for (ch = 0; ch < self->numOutputChannels; ch++) {
           for (hyb = 0; hyb < self->tp_hybBandBorder; hyb++) {
-            self->hybOutputRealDry__FDK[ch][hyb] +=
-                self->hybOutputRealWet__FDK[ch][hyb];
-            self->hybOutputImagDry__FDK[ch][hyb] +=
-                self->hybOutputImagWet__FDK[ch][hyb];
+            self->hybOutputRealDry__FDK[ch][hyb] =
+                fAddSaturate(self->hybOutputRealDry__FDK[ch][hyb],
+                             self->hybOutputRealWet__FDK[ch][hyb]);
+            self->hybOutputImagDry__FDK[ch][hyb] =
+                fAddSaturate(self->hybOutputImagDry__FDK[ch][hyb],
+                             self->hybOutputImagWet__FDK[ch][hyb]);
           } /* loop hyb */
         }   /* loop ch */
         err = subbandTPApply(
@@ -1341,11 +1349,11 @@
             FIXP_DBL *RESTRICT pRealWet = self->hybOutputRealWet__FDK[ch];
             FIXP_DBL *RESTRICT pImagWet = self->hybOutputImagWet__FDK[ch];
             for (hyb = 0; hyb < nHybBands; hyb++) {
-              pRealDry[hyb] += pRealWet[hyb];
-              pImagDry[hyb] += pImagWet[hyb];
+              pRealDry[hyb] = fAddSaturate(pRealDry[hyb], pRealWet[hyb]);
+              pImagDry[hyb] = fAddSaturate(pImagDry[hyb], pImagWet[hyb]);
             } /* loop hyb */
             for (; hyb < self->hybridBands; hyb++) {
-              pRealDry[hyb] += pRealWet[hyb];
+              pRealDry[hyb] = fAddSaturate(pRealDry[hyb], pRealWet[hyb]);
             } /* loop hyb */
           }   /* loop ch */
         } /* ( self->tempShapeConfig == 1 ) || ( self->tempShapeConfig == 2 ) */
@@ -1414,6 +1422,7 @@
   FDK_ASSERT(self != NULL);
   FDK_ASSERT(pControlFlags != NULL);
   FDK_ASSERT(pcmOutBuf != NULL);
+  FDK_ASSERT(self->sacInDataHeadroom >= (1));
 
   self->errInt = err; /* Init internal error */
 
diff --git a/libSACdec/src/sac_dec.h b/libSACdec/src/sac_dec.h
index 992acad..1c3df71 100644
--- a/libSACdec/src/sac_dec.h
+++ b/libSACdec/src/sac_dec.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -523,6 +523,9 @@
                              new frame after SSC change (aka
                              decodeAfterConfigHasChangedFlag). */
   SpatialDecConcealmentInfo concealInfo;
+
+  INT sacInDataHeadroom; /* Headroom of the SAC input time signal to prevent
+                            clipping */
 };
 
 #define SACDEC_SYNTAX_MPS 1
diff --git a/libSACdec/src/sac_dec_interface.h b/libSACdec/src/sac_dec_interface.h
index a2eea92..05a9a75 100644
--- a/libSACdec/src/sac_dec_interface.h
+++ b/libSACdec/src/sac_dec_interface.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -249,10 +249,10 @@
 
 } MEM_REQUIREMENTS;
 
-#define PCM_MPS INT_PCM
-#define PCM_MPSF FIXP_PCM
+#define PCM_MPS LONG
+#define PCM_MPSF FIXP_DBL
 
-#define FIXP_DBL2PCM_MPS(x) ((INT_PCM)FX_DBL2FX_PCM(x))
+#define FIXP_DBL2PCM_MPS(x) ((LONG)(x))
 
 /* exposed functions (library interface) */
 
diff --git a/libSACdec/src/sac_dec_lib.cpp b/libSACdec/src/sac_dec_lib.cpp
index bf6dedf..856a923 100644
--- a/libSACdec/src/sac_dec_lib.cpp
+++ b/libSACdec/src/sac_dec_lib.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -1507,15 +1507,17 @@
 }
 
 int mpegSurroundDecoder_Apply(CMpegSurroundDecoder *pMpegSurroundDecoder,
-                              INT_PCM *input, PCM_MPS *pTimeData,
+                              PCM_MPS *input, PCM_MPS *pTimeData,
                               const int timeDataSize, int timeDataFrameSize,
                               int *nChannels, int *frameSize, int sampleRate,
                               AUDIO_OBJECT_TYPE coreCodec,
                               AUDIO_CHANNEL_TYPE channelType[],
                               UCHAR channelIndices[],
-                              const FDK_channelMapDescr *const mapDescr) {
+                              const FDK_channelMapDescr *const mapDescr,
+                              const INT inDataHeadroom, INT *outDataHeadroom) {
   SACDEC_ERROR err = MPS_OK;
   PCM_MPS *pTimeOut = pTimeData;
+  PCM_MPS *TDinput = NULL;
   UINT initControlFlags = 0, controlFlags = 0;
   int timeDataRequiredSize = 0;
   int newData;
@@ -1534,6 +1536,9 @@
     return MPS_NOTOK;
   }
 
+  pMpegSurroundDecoder->pSpatialDec->sacInDataHeadroom = inDataHeadroom;
+  *outDataHeadroom = (INT)(8);
+
   pMpegSurroundDecoder->pSpatialDec->pConfigCurrent =
       &pMpegSurroundDecoder
            ->spatialSpecificConfig[pMpegSurroundDecoder->bsFrameDecode];
@@ -1682,8 +1687,7 @@
         (timeDataFrameSize *
          pMpegSurroundDecoder->pQmfDomain->globalConf.nBandsSynthesis) /
         pMpegSurroundDecoder->pQmfDomain->globalConf.nBandsAnalysis;
-    pMpegSurroundDecoder->pQmfDomain->globalConf.TDinput =
-        pTimeData + timeDataFrameSizeOut - timeDataFrameSize;
+    TDinput = pTimeData + timeDataFrameSizeOut - timeDataFrameSize;
     for (int i = *nChannels - 1; i >= 0; i--) {
       FDKmemmove(pTimeData + (i + 1) * timeDataFrameSizeOut - timeDataFrameSize,
                  pTimeData + timeDataFrameSize * i,
@@ -1694,8 +1698,8 @@
   } else {
     if (pMpegSurroundDecoder->mpegSurroundUseTimeInterface) {
       FDKmemcpy(input, pTimeData,
-                sizeof(INT_PCM) * (*nChannels) * (*frameSize));
-      pMpegSurroundDecoder->pQmfDomain->globalConf.TDinput = input;
+                sizeof(PCM_MPS) * (*nChannels) * (*frameSize));
+      TDinput = input;
     }
   }
 
@@ -1707,8 +1711,8 @@
       &pMpegSurroundDecoder->bsFrames[pMpegSurroundDecoder->bsFrameDecode],
       pMpegSurroundDecoder->mpegSurroundUseTimeInterface ? INPUTMODE_TIME
                                                          : INPUTMODE_QMF_SBR,
-      pMpegSurroundDecoder->pQmfDomain->globalConf.TDinput, NULL, NULL,
-      pTimeOut, *frameSize, &controlFlags, *nChannels, mapDescr);
+      TDinput, NULL, NULL, pTimeOut, *frameSize, &controlFlags, *nChannels,
+      mapDescr);
   *nChannels = pMpegSurroundDecoder->pSpatialDec->numOutputChannelsAT;
 
   if (err !=
@@ -1781,7 +1785,7 @@
 }
 
 #define SACDEC_VL0 2
-#define SACDEC_VL1 0
+#define SACDEC_VL1 1
 #define SACDEC_VL2 0
 
 int mpegSurroundDecoder_GetLibInfo(LIB_INFO *info) {
diff --git a/libSACdec/src/sac_process.cpp b/libSACdec/src/sac_process.cpp
index 56c72ad..22091a9 100644
--- a/libSACdec/src/sac_process.cpp
+++ b/libSACdec/src/sac_process.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -113,6 +113,8 @@
 #include "FDK_trigFcts.h"
 #include "FDK_decorrelate.h"
 
+#define SAC_DEC_APPLY_M2_SCALE(spec, s) ((spec) >> (-(s)))
+
 /**
  * \brief  Linear interpolation between two parameter values.
  *         a*alpha + b*(1-alpha)
@@ -185,8 +187,12 @@
       if (!isTwoChMode(self->upmixType) && !bypassMode) {
         int i;
         for (i = 0; i < self->qmfBands; i++) {
-          qmfReal[ch][i] = fMult(qmfReal[ch][i], self->clipProtectGain__FDK);
-          qmfImag[ch][i] = fMult(qmfImag[ch][i], self->clipProtectGain__FDK);
+          qmfReal[ch][i] = fMult(
+              scaleValueSaturate(qmfReal[ch][i], self->sacInDataHeadroom - (1)),
+              self->clipProtectGain__FDK);
+          qmfImag[ch][i] = fMult(
+              scaleValueSaturate(qmfImag[ch][i], self->sacInDataHeadroom - (1)),
+              self->clipProtectGain__FDK);
         }
       }
     }
@@ -214,16 +220,17 @@
 
       /* Write Input data to pQmfRealAnalysis. */
       if (self->bShareDelayWithSBR) {
-        FDK_QmfDomain_GetSlot(
-            &self->pQmfDomain->QmfDomainIn[ch], ts + HYBRID_FILTER_DELAY, 0,
-            MAX_QMF_BANDS_TO_HYBRID, pQmfRealAnalysis, pQmfImagAnalysis, 15);
+        FDK_QmfDomain_GetSlot(&self->pQmfDomain->QmfDomainIn[ch],
+                              ts + HYBRID_FILTER_DELAY, 0,
+                              MAX_QMF_BANDS_TO_HYBRID, pQmfRealAnalysis,
+                              pQmfImagAnalysis, 15 + (1));
         FDK_QmfDomain_GetSlot(&self->pQmfDomain->QmfDomainIn[ch], ts,
                               MAX_QMF_BANDS_TO_HYBRID, self->qmfBands,
-                              pQmfRealAnalysis, pQmfImagAnalysis, 15);
+                              pQmfRealAnalysis, pQmfImagAnalysis, 15 + (1));
       } else {
         FDK_QmfDomain_GetSlot(&self->pQmfDomain->QmfDomainIn[ch], ts, 0,
                               self->qmfBands, pQmfRealAnalysis,
-                              pQmfImagAnalysis, 15);
+                              pQmfImagAnalysis, 15 + (1));
       }
       if (ts == self->pQmfDomain->globalConf.nQmfTimeSlots - 1) {
         /* Is currently also needed in case we dont have any overlap. We need to
@@ -499,8 +506,8 @@
     for (pb = 0, qs = 3; pb < 2; pb++) {
       INT s;
       FIXP_DBL maxVal;
-      FIXP_SGL mReal1;
-      FIXP_SGL mReal0, mImag0;
+      FIXP_DBL mReal1;
+      FIXP_DBL mReal0, mImag0;
       FIXP_DBL iReal0, iImag0, iReal1;
 
       iReal0 = interpolateParameter(alpha, MReal0[pb], MRealPrev0[pb]);
@@ -513,9 +520,9 @@
       s = fMax(CntLeadingZeros(maxVal) - 1, 0);
       s = fMin(s, scale_param_m2);
 
-      mReal0 = FX_DBL2FX_SGL(iReal0 << s);
-      mImag0 = FX_DBL2FX_SGL(iImag0 << s);
-      mReal1 = FX_DBL2FX_SGL(iReal1 << s);
+      mReal0 = iReal0 << s;
+      mImag0 = iImag0 << s;
+      mReal1 = iReal1 << s;
 
       s = scale_param_m2 - s;
 
@@ -634,8 +641,7 @@
     }
 
     if (self->phaseCoding == 3) {
-      /* + SCALE_DATA_APPLY_M2 to compensate for Div2 below ?! */
-      scale_param_m2 = SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2;
+      scale_param_m2 = -(SCALE_DATA_APPLY_M2_PC - 1);
     }
 
     for (row = 0; row < self->numM2rows; row++) {
@@ -686,10 +692,10 @@
           } else { /*  isBinauralMode(self->upmixType)  */
 
             for (qs = 0; qs < complexHybBands; qs++) {
-              pHybOutRealDry[qs] += fMultDiv2(pWReal[qs], pKernel[qs])
-                                    << (scale_param_m2);
-              pHybOutImagDry[qs] += fMultDiv2(pWImag[qs], pKernel[qs])
-                                    << (scale_param_m2);
+              pHybOutRealDry[qs] += SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
+              pHybOutImagDry[qs] += SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
             }
 
             M2ParamToKernelMult(pKernel, self->M2Imag__FDK[row][col],
@@ -697,27 +703,27 @@
                                 self->kernels_width, alpha, complexParBands);
 
             /* direct signals sign is -1 for qs = 0,2 */
-            pHybOutRealDry[0] += fMultDiv2(pWImag[0], pKernel[0])
-                                 << (scale_param_m2);
-            pHybOutImagDry[0] -= fMultDiv2(pWReal[0], pKernel[0])
-                                 << (scale_param_m2);
+            pHybOutRealDry[0] += SAC_DEC_APPLY_M2_SCALE(
+                fMultDiv2(pWImag[0], pKernel[0]), scale_param_m2);
+            pHybOutImagDry[0] -= SAC_DEC_APPLY_M2_SCALE(
+                fMultDiv2(pWReal[0], pKernel[0]), scale_param_m2);
 
-            pHybOutRealDry[2] += fMultDiv2(pWImag[2], pKernel[2])
-                                 << (scale_param_m2);
-            pHybOutImagDry[2] -= fMultDiv2(pWReal[2], pKernel[2])
-                                 << (scale_param_m2);
+            pHybOutRealDry[2] += SAC_DEC_APPLY_M2_SCALE(
+                fMultDiv2(pWImag[2], pKernel[2]), scale_param_m2);
+            pHybOutImagDry[2] -= SAC_DEC_APPLY_M2_SCALE(
+                fMultDiv2(pWReal[2], pKernel[2]), scale_param_m2);
 
             /* direct signals sign is +1 for qs = 1,3,4,5,...,complexHybBands */
-            pHybOutRealDry[1] -= fMultDiv2(pWImag[1], pKernel[1])
-                                 << (scale_param_m2);
-            pHybOutImagDry[1] += fMultDiv2(pWReal[1], pKernel[1])
-                                 << (scale_param_m2);
+            pHybOutRealDry[1] -= SAC_DEC_APPLY_M2_SCALE(
+                fMultDiv2(pWImag[1], pKernel[1]), scale_param_m2);
+            pHybOutImagDry[1] += SAC_DEC_APPLY_M2_SCALE(
+                fMultDiv2(pWReal[1], pKernel[1]), scale_param_m2);
 
             for (qs = 3; qs < complexHybBands; qs++) {
-              pHybOutRealDry[qs] -= fMultDiv2(pWImag[qs], pKernel[qs])
-                                    << (scale_param_m2);
-              pHybOutImagDry[qs] += fMultDiv2(pWReal[qs], pKernel[qs])
-                                    << (scale_param_m2);
+              pHybOutRealDry[qs] -= SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
+              pHybOutImagDry[qs] += SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
             }
           } /* self->upmixType */
         }   /* if (activParamBands) */
@@ -770,17 +776,17 @@
             FIXP_DBL *RESTRICT pHybOutImag;
 
             for (qs = 0; qs < resHybIndex; qs++) {
-              pHybOutRealDry[qs] += fMultDiv2(pWReal[qs], pKernel[qs])
-                                    << (scale_param_m2);
-              pHybOutImagDry[qs] += fMultDiv2(pWImag[qs], pKernel[qs])
-                                    << (scale_param_m2);
+              pHybOutRealDry[qs] += SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
+              pHybOutImagDry[qs] += SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
             }
             /* decor signals */
             for (; qs < complexHybBands; qs++) {
-              pHybOutRealWet[qs] += fMultDiv2(pWReal[qs], pKernel[qs])
-                                    << (scale_param_m2);
-              pHybOutImagWet[qs] += fMultDiv2(pWImag[qs], pKernel[qs])
-                                    << (scale_param_m2);
+              pHybOutRealWet[qs] += SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
+              pHybOutImagWet[qs] += SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
             }
 
             M2ParamToKernelMult(pKernel, self->M2Imag__FDK[row][col],
@@ -790,20 +796,20 @@
             /* direct signals sign is -1 for qs = 0,2 */
             /* direct signals sign is +1 for qs = 1,3.. */
             if (toolsDisabled) {
-              pHybOutRealDry[0] += fMultDiv2(pWImag[0], pKernel[0])
-                                   << (scale_param_m2);
-              pHybOutImagDry[0] -= fMultDiv2(pWReal[0], pKernel[0])
-                                   << (scale_param_m2);
+              pHybOutRealDry[0] += SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWImag[0], pKernel[0]), scale_param_m2);
+              pHybOutImagDry[0] -= SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWReal[0], pKernel[0]), scale_param_m2);
 
-              pHybOutRealDry[1] -= fMultDiv2(pWImag[1], pKernel[1])
-                                   << (scale_param_m2);
-              pHybOutImagDry[1] += fMultDiv2(pWReal[1], pKernel[1])
-                                   << (scale_param_m2);
+              pHybOutRealDry[1] -= SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWImag[1], pKernel[1]), scale_param_m2);
+              pHybOutImagDry[1] += SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWReal[1], pKernel[1]), scale_param_m2);
 
-              pHybOutRealDry[2] += fMultDiv2(pWImag[2], pKernel[2])
-                                   << (scale_param_m2);
-              pHybOutImagDry[2] -= fMultDiv2(pWReal[2], pKernel[2])
-                                   << (scale_param_m2);
+              pHybOutRealDry[2] += SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWImag[2], pKernel[2]), scale_param_m2);
+              pHybOutImagDry[2] -= SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWReal[2], pKernel[2]), scale_param_m2);
             } else {
               pHybOutReal = &pHybOutRealDry[0];
               pHybOutImag = &pHybOutImagDry[0];
@@ -811,46 +817,60 @@
                 pHybOutReal = &pHybOutRealWet[0];
                 pHybOutImag = &pHybOutImagWet[0];
               }
-              pHybOutReal[0] += fMultDiv2(pWImag[0], pKernel[0])
-                                << (scale_param_m2);
-              pHybOutImag[0] -= fMultDiv2(pWReal[0], pKernel[0])
-                                << (scale_param_m2);
+              pHybOutReal[0] += SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWImag[0], pKernel[0]), scale_param_m2);
+              pHybOutImag[0] -= SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWReal[0], pKernel[0]), scale_param_m2);
 
               if (1 == resHybIndex) {
                 pHybOutReal = &pHybOutRealWet[0];
                 pHybOutImag = &pHybOutImagWet[0];
               }
-              pHybOutReal[1] -= fMultDiv2(pWImag[1], pKernel[1])
-                                << (scale_param_m2);
-              pHybOutImag[1] += fMultDiv2(pWReal[1], pKernel[1])
-                                << (scale_param_m2);
+              pHybOutReal[1] -= SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWImag[1], pKernel[1]), scale_param_m2);
+              pHybOutImag[1] += SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWReal[1], pKernel[1]), scale_param_m2);
 
               if (2 == resHybIndex) {
                 pHybOutReal = &pHybOutRealWet[0];
                 pHybOutImag = &pHybOutImagWet[0];
               }
-              pHybOutReal[2] += fMultDiv2(pWImag[2], pKernel[2])
-                                << (scale_param_m2);
-              pHybOutImag[2] -= fMultDiv2(pWReal[2], pKernel[2])
-                                << (scale_param_m2);
+              pHybOutReal[2] += SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWImag[2], pKernel[2]), scale_param_m2);
+              pHybOutImag[2] -= SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWReal[2], pKernel[2]), scale_param_m2);
             }
 
             for (qs = 3; qs < resHybIndex; qs++) {
-              pHybOutRealDry[qs] -= fMultDiv2(pWImag[qs], pKernel[qs])
-                                    << (scale_param_m2);
-              pHybOutImagDry[qs] += fMultDiv2(pWReal[qs], pKernel[qs])
-                                    << (scale_param_m2);
+              pHybOutRealDry[qs] -= SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
+              pHybOutImagDry[qs] += SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
             }
             /* decor signals */
             for (; qs < complexHybBands; qs++) {
-              pHybOutRealWet[qs] -= fMultDiv2(pWImag[qs], pKernel[qs])
-                                    << (scale_param_m2);
-              pHybOutImagWet[qs] += fMultDiv2(pWReal[qs], pKernel[qs])
-                                    << (scale_param_m2);
+              pHybOutRealWet[qs] -= SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
+              pHybOutImagWet[qs] += SAC_DEC_APPLY_M2_SCALE(
+                  fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
             }
           } /* self->upmixType */
         }   /* if (activParamBands) { */
       }     /*  self->numVChannels */
+
+      if (self->phaseCoding == 3) {
+        scaleValuesSaturate(pHybOutRealDry, complexHybBands,
+                            SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2_PC);
+        scaleValuesSaturate(pHybOutImagDry, complexHybBands,
+                            SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2_PC);
+
+        if (!toolsDisabled) {
+          scaleValuesSaturate(pHybOutRealWet, complexHybBands,
+                              SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2_PC);
+          scaleValuesSaturate(pHybOutImagWet, complexHybBands,
+                              SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2_PC);
+        }
+      }
     }
 
     C_ALLOC_SCRATCH_END(pKernel, FIXP_SGL, MAX_HYBRID_BANDS);
@@ -919,6 +939,7 @@
         self->pQmfDomain->QmfDomainIn[outCh].scaling.lb_scale -=
             self->clipProtectGainSF__FDK;
 
+        self->pQmfDomain->QmfDomainIn[outCh].scaling.lb_scale -= (1);
       } else {
         /* Call the QMF synthesis for dry. */
         err = CalculateSpaceSynthesisQmf(&self->pQmfDomain->QmfDomainOut[outCh],
diff --git a/libSACdec/src/sac_qmf.cpp b/libSACdec/src/sac_qmf.cpp
index a075490..fd7599d 100644
--- a/libSACdec/src/sac_qmf.cpp
+++ b/libSACdec/src/sac_qmf.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -110,7 +110,7 @@
 
 SACDEC_ERROR CalculateSpaceSynthesisQmf(
     const HANDLE_FDK_QMF_DOMAIN_OUT hQmfDomainOutCh, const FIXP_DBL *Sr,
-    const FIXP_DBL *Si, const INT stride, INT_PCM *timeSig) {
+    const FIXP_DBL *Si, const INT stride, PCM_MPS *timeSig) {
   SACDEC_ERROR err = MPS_OK;
 
   if (hQmfDomainOutCh == NULL) {
diff --git a/libSACdec/src/sac_qmf.h b/libSACdec/src/sac_qmf.h
index d1dc837..5cd573e 100644
--- a/libSACdec/src/sac_qmf.h
+++ b/libSACdec/src/sac_qmf.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -124,7 +124,7 @@
  */
 SACDEC_ERROR CalculateSpaceSynthesisQmf(
     const HANDLE_FDK_QMF_DOMAIN_OUT hQmfDomainOutCh, const FIXP_DBL *Sr,
-    const FIXP_DBL *Si, const INT stride, INT_PCM *timeSig);
+    const FIXP_DBL *Si, const INT stride, PCM_MPS *timeSig);
 
 /**
  * \brief  Convert audio input data to qmf representation.
diff --git a/libSACdec/src/sac_reshapeBBEnv.cpp b/libSACdec/src/sac_reshapeBBEnv.cpp
index 87c0ac6..272d009 100644
--- a/libSACdec/src/sac_reshapeBBEnv.cpp
+++ b/libSACdec/src/sac_reshapeBBEnv.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -162,75 +162,59 @@
   FIXP_DBL nrg;
 
   /* qs = 12, 13, 14 */
-  slotNrg[0] = ((fPow2Div2((*pReal++) << maxValSF) +
-                 fPow2Div2((*pImag++) << maxValSF)) >>
-                (SF_FACTOR_SLOT - 1));
-  slotNrg[1] = ((fPow2Div2((*pReal++) << maxValSF) +
-                 fPow2Div2((*pImag++) << maxValSF)) >>
-                (SF_FACTOR_SLOT - 1));
-  slotNrg[2] = ((fPow2Div2((*pReal++) << maxValSF) +
-                 fPow2Div2((*pImag++) << maxValSF)) >>
-                (SF_FACTOR_SLOT - 1));
+  slotNrg[0] = ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+                (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
+  slotNrg[1] = ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+                (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
+  slotNrg[2] = ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+                (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
   /* qs = 15 */
-  slotNrg[3] = ((fPow2Div2((*pReal++) << maxValSF) +
-                 fPow2Div2((*pImag++) << maxValSF)) >>
-                (SF_FACTOR_SLOT - 1));
+  slotNrg[3] = ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+                (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
   /* qs = 16, 17 */
-  nrg = ((fPow2Div2((*pReal++) << maxValSF) +
-          fPow2Div2((*pImag++) << maxValSF)) >>
-         (SF_FACTOR_SLOT - 1));
-  slotNrg[4] = nrg + ((fPow2Div2((*pReal++) << maxValSF) +
-                       fPow2Div2((*pImag++) << maxValSF)) >>
-                      (SF_FACTOR_SLOT - 1));
+  nrg = ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+         (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
+  slotNrg[4] =
+      nrg + ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+             (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
   /* qs = 18, 19, 20 */
-  nrg = ((fPow2Div2((*pReal++) << maxValSF) +
-          fPow2Div2((*pImag++) << maxValSF)) >>
-         (SF_FACTOR_SLOT - 1));
-  nrg += ((fPow2Div2((*pReal++) << maxValSF) +
-           fPow2Div2((*pImag++) << maxValSF)) >>
-          (SF_FACTOR_SLOT - 1));
-  slotNrg[5] = nrg + ((fPow2Div2((*pReal++) << maxValSF) +
-                       fPow2Div2((*pImag++) << maxValSF)) >>
-                      (SF_FACTOR_SLOT - 1));
+  nrg = ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+         (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
+  nrg += ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+          (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
+  slotNrg[5] =
+      nrg + ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+             (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
   /* qs = 21, 22 */
-  nrg = ((fPow2Div2((*pReal++) << maxValSF) +
-          fPow2Div2((*pImag++) << maxValSF)) >>
-         (SF_FACTOR_SLOT - 1));
-  slotNrg[6] = nrg + ((fPow2Div2((*pReal++) << maxValSF) +
-                       fPow2Div2((*pImag++) << maxValSF)) >>
-                      (SF_FACTOR_SLOT - 1));
+  nrg = ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+         (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
+  slotNrg[6] =
+      nrg + ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+             (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
   /* qs = 23, 24 */
   if (hybBands > 23) {
-    slotNrg[6] += ((fPow2Div2((*pReal++) << maxValSF) +
-                    fPow2Div2((*pImag++) << maxValSF)) >>
-                   (SF_FACTOR_SLOT - 1));
-    slotNrg[6] += ((fPow2Div2((*pReal++) << maxValSF) +
-                    fPow2Div2((*pImag++) << maxValSF)) >>
-                   (SF_FACTOR_SLOT - 1));
+    slotNrg[6] += ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+                   (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
+    slotNrg[6] += ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+                   (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
     /* qs = 25, 26, 29, 28, 29 */
-    nrg = ((fPow2Div2((*pReal++) << maxValSF) +
-            fPow2Div2((*pImag++) << maxValSF)) >>
-           (SF_FACTOR_SLOT - 1));
-    nrg += ((fPow2Div2((*pReal++) << maxValSF) +
-             fPow2Div2((*pImag++) << maxValSF)) >>
-            (SF_FACTOR_SLOT - 1));
-    nrg += ((fPow2Div2((*pReal++) << maxValSF) +
-             fPow2Div2((*pImag++) << maxValSF)) >>
-            (SF_FACTOR_SLOT - 1));
-    nrg += ((fPow2Div2((*pReal++) << maxValSF) +
-             fPow2Div2((*pImag++) << maxValSF)) >>
-            (SF_FACTOR_SLOT - 1));
-    slotNrg[7] = nrg + ((fPow2Div2((*pReal++) << maxValSF) +
-                         fPow2Div2((*pImag++) << maxValSF)) >>
-                        (SF_FACTOR_SLOT - 1));
+    nrg = ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+           (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
+    nrg += ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+            (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
+    nrg += ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+            (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
+    nrg += ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+            (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
+    slotNrg[7] =
+        nrg + ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+               (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
     /* qs = 30 ... min(41,hybBands-1) */
-    nrg = ((fPow2Div2((*pReal++) << maxValSF) +
-            fPow2Div2((*pImag++) << maxValSF)) >>
-           (SF_FACTOR_SLOT - 1));
+    nrg = ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+           (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
     for (qs = 31; qs < hybBands; qs++) {
-      nrg += ((fPow2Div2((*pReal++) << maxValSF) +
-               fPow2Div2((*pImag++) << maxValSF)) >>
-              (SF_FACTOR_SLOT - 1));
+      nrg += ((fPow2Div2((*pReal++) << maxValSF) >> (SF_FACTOR_SLOT - 1)) +
+              (fPow2Div2((*pImag++) << maxValSF) >> (SF_FACTOR_SLOT - 1)));
     }
     slotNrg[8] = nrg;
   } else {
@@ -239,49 +223,22 @@
   }
 }
 
-static inline INT getMaxValDmx(FIXP_DBL *RESTRICT pReal,
-                               FIXP_DBL *RESTRICT pImag, INT cplxBands,
-                               INT hybBands) {
-  INT qs, clz;
-  FIXP_DBL maxVal = FL2FXCONST_DBL(0.0f);
+static inline void combineDryWet(FIXP_DBL *RESTRICT pReal,
+                                 FIXP_DBL *RESTRICT pImag,
+                                 FIXP_DBL *RESTRICT pHybOutputRealDry,
+                                 FIXP_DBL *RESTRICT pHybOutputImagDry,
+                                 FIXP_DBL *RESTRICT pHybOutputRealWet,
+                                 FIXP_DBL *RESTRICT pHybOutputImagWet,
+                                 INT cplxBands, INT hybBands) {
+  INT qs;
 
   for (qs = 12; qs < cplxBands; qs++) {
-    maxVal |= fAbs(pReal[qs]);
-    maxVal |= fAbs(pImag[qs]);
+    pReal[qs] = (pHybOutputRealDry[qs] >> 1) + (pHybOutputRealWet[qs] >> 1);
+    pImag[qs] = (pHybOutputImagDry[qs] >> 1) + (pHybOutputImagWet[qs] >> 1);
   }
   for (; qs < hybBands; qs++) {
-    maxVal |= fAbs(pReal[qs]);
+    pReal[qs] = (pHybOutputRealDry[qs] >> 1) + (pHybOutputRealWet[qs] >> 1);
   }
-
-  clz = fixMax(0, CntLeadingZeros(maxVal) - 1);
-
-  return (clz);
-}
-
-static inline INT getMaxValDryWet(FIXP_DBL *RESTRICT pReal,
-                                  FIXP_DBL *RESTRICT pImag,
-                                  FIXP_DBL *RESTRICT pHybOutputRealDry,
-                                  FIXP_DBL *RESTRICT pHybOutputImagDry,
-                                  FIXP_DBL *RESTRICT pHybOutputRealWet,
-                                  FIXP_DBL *RESTRICT pHybOutputImagWet,
-                                  INT cplxBands, INT hybBands) {
-  INT qs, clz;
-  FIXP_DBL maxVal = FL2FXCONST_DBL(0.0f);
-
-  for (qs = 12; qs < cplxBands; qs++) {
-    pReal[qs] = pHybOutputRealDry[qs] + pHybOutputRealWet[qs];
-    maxVal |= fAbs(pReal[qs]);
-    pImag[qs] = pHybOutputImagDry[qs] + pHybOutputImagWet[qs];
-    maxVal |= fAbs(pImag[qs]);
-  }
-  for (; qs < hybBands; qs++) {
-    pReal[qs] = pHybOutputRealDry[qs] + pHybOutputRealWet[qs];
-    maxVal |= fAbs(pReal[qs]);
-  }
-
-  clz = fixMax(0, CntLeadingZeros(maxVal) - 1);
-
-  return (clz);
 }
 
 static inline void slotAmp(FIXP_DBL *RESTRICT slotAmp_dry,
@@ -296,17 +253,17 @@
 
   dry = wet = FL2FXCONST_DBL(0.0f);
   for (qs = 0; qs < cplxBands; qs++) {
-    dry = fAddSaturate(dry, fPow2Div2(pHybOutputRealDry[qs]) +
-                                fPow2Div2(pHybOutputImagDry[qs]));
-    wet = fAddSaturate(wet, fPow2Div2(pHybOutputRealWet[qs]) +
-                                fPow2Div2(pHybOutputImagWet[qs]));
+    dry = fAddSaturate(dry, fPow2Div2(pHybOutputRealDry[qs] << (1)) +
+                                fPow2Div2(pHybOutputImagDry[qs] << (1)));
+    wet = fAddSaturate(wet, fPow2Div2(pHybOutputRealWet[qs] << (1)) +
+                                fPow2Div2(pHybOutputImagWet[qs] << (1)));
   }
   for (; qs < hybBands; qs++) {
-    dry = fAddSaturate(dry, fPow2Div2(pHybOutputRealDry[qs]));
-    wet = fAddSaturate(wet, fPow2Div2(pHybOutputRealWet[qs]));
+    dry = fAddSaturate(dry, fPow2Div2(pHybOutputRealDry[qs] << (1)));
+    wet = fAddSaturate(wet, fPow2Div2(pHybOutputRealWet[qs] << (1)));
   }
-  *slotAmp_dry = dry;
-  *slotAmp_wet = wet;
+  *slotAmp_dry = dry >> (2 * (1));
+  *slotAmp_wet = wet >> (2 * (1));
 }
 
 #if defined(__aarch64__)
@@ -327,11 +284,14 @@
     }
   } else {
     for (qs = 0; qs < cplxBands; qs++) {
-      pHybOutputRealDry[qs] = fMultDiv2(pHybOutputRealDry[qs], dryFac) << scale;
-      pHybOutputImagDry[qs] = fMultDiv2(pHybOutputImagDry[qs], dryFac) << scale;
+      pHybOutputRealDry[qs] = SATURATE_LEFT_SHIFT(
+          fMultDiv2(pHybOutputRealDry[qs], dryFac), scale, DFRACT_BITS);
+      pHybOutputImagDry[qs] = SATURATE_LEFT_SHIFT(
+          fMultDiv2(pHybOutputImagDry[qs], dryFac), scale, DFRACT_BITS);
     }
     for (; qs < hybBands; qs++) {
-      pHybOutputRealDry[qs] = fMultDiv2(pHybOutputRealDry[qs], dryFac) << scale;
+      pHybOutputRealDry[qs] = SATURATE_LEFT_SHIFT(
+          fMultDiv2(pHybOutputRealDry[qs], dryFac), scale, DFRACT_BITS);
     }
   }
 }
@@ -367,7 +327,7 @@
 
   INT shapeActiv = 1;
   INT hybBands = fixMin(42, self->hybridBands);
-  INT staticScale = self->staticDecScale;
+  INT staticScale = self->staticDecScale + (1);
   INT cplxBands;
   cplxBands = fixMin(42, self->hybridBands);
 
@@ -386,15 +346,18 @@
       prevChOffs = ch;
       pReal = pScratchBuffer;
       pImag = pScratchBuffer + 42;
-      clz = getMaxValDryWet(
-          pReal, pImag, self->hybOutputRealDry__FDK[ch],
-          self->hybOutputImagDry__FDK[ch], self->hybOutputRealWet__FDK[ch],
-          self->hybOutputImagWet__FDK[ch], cplxBands, hybBands);
+      combineDryWet(pReal, pImag, self->hybOutputRealDry__FDK[ch],
+                    self->hybOutputImagDry__FDK[ch],
+                    self->hybOutputRealWet__FDK[ch],
+                    self->hybOutputImagWet__FDK[ch], cplxBands, hybBands);
+      clz = fMin(getScalefactor(&pReal[12], fMax(0, hybBands - 12)),
+                 getScalefactor(&pImag[12], fMax(0, cplxBands - 12)));
     } else {
       prevChOffs = ch + self->numOutputChannels;
       pReal = self->hybInputReal__FDK[ch];
       pImag = self->hybInputImag__FDK[ch];
-      clz = getMaxValDmx(pReal, pImag, cplxBands, hybBands);
+      clz = fMin(getScalefactor(&pReal[12], fMax(0, hybBands - 12)),
+                 getScalefactor(&pImag[12], fMax(0, cplxBands - 12)));
     }
 
     partNrg = partNrgPrev = pBBEnvState->partNrgPrev__FDK[prevChOffs];
@@ -411,8 +374,10 @@
                                                       SF_FACTOR_SLOT */
     }
 
-    slotNrgSF = 2 * (staticScale - clz) + SF_FACTOR_SLOT;
-    frameNrgSF = 2 * (staticScale - clz) + SF_FACTOR_SLOT;
+    slotNrgSF = 2 * (staticScale - clz + ((inp == INP_DRY_WET) ? 1 : 0)) +
+                SF_FACTOR_SLOT;
+    frameNrgSF = 2 * (staticScale - clz + ((inp == INP_DRY_WET) ? 1 : 0)) +
+                 SF_FACTOR_SLOT;
 
     partNrgSF = fixMax(slotNrgSF - SF_ALPHA1 + 1,
                        pPartNrgPrevSF[0] - pPartNrgPrev2SF[0] + 1);
@@ -652,14 +617,16 @@
           fixMax(3, fixMax(dryFacSF, slotAmpSF)); /* scale is at least with 3
                                                      bits to avoid overflows
                                                      when calculating dryFac  */
-      dryFac = dryFac >> (scale - dryFacSF);
-      slotAmp_ratio = slotAmp_ratio >> (scale - slotAmpSF);
+      dryFac = dryFac >> fixMin(scale - dryFacSF, DFRACT_BITS - 1);
+      slotAmp_ratio =
+          slotAmp_ratio >> fixMin(scale - slotAmpSF, DFRACT_BITS - 1);
 
       /* limit dryFac */
       dryFac = fixMax(
           FL2FXCONST_DBL(0.25f) >> (INT)fixMin(2 * scale, DFRACT_BITS - 1),
-          fMult(dryFac, slotAmp_ratio) - (slotAmp_ratio >> scale) +
-              (dryFac >> scale));
+          fMult(dryFac, slotAmp_ratio) -
+              (slotAmp_ratio >> fixMin(scale, DFRACT_BITS - 1)) +
+              (dryFac >> fixMin(scale, DFRACT_BITS - 1)));
       dryFac = fixMin(
           FL2FXCONST_DBL(0.50f) >> (INT)fixMin(2 * scale - 3, DFRACT_BITS - 1),
           dryFac); /* reduce shift bits by 3, because upper
@@ -673,8 +640,8 @@
 
       /* shaping */
       shapeBBEnv(&self->hybOutputRealDry__FDK[ch][6],
-                 &self->hybOutputImagDry__FDK[ch][6], dryFac, scale, cplxBands,
-                 hybBands);
+                 &self->hybOutputImagDry__FDK[ch][6], dryFac,
+                 fixMin(scale, DFRACT_BITS - 1), cplxBands, hybBands);
     }
   }
 }
diff --git a/libSACdec/src/sac_rom.h b/libSACdec/src/sac_rom.h
index 38f17f2..d317856 100644
--- a/libSACdec/src/sac_rom.h
+++ b/libSACdec/src/sac_rom.h
@@ -111,21 +111,12 @@
 #include "machine_type.h"
 
 /* Global ROM table data type: */
-#ifndef ARCH_PREFER_MULT_32x32
-#define FIXP_CFG FIXP_SGL
-#define FX_CFG2FX_DBL FX_SGL2FX_DBL
-#define FX_CFG2FX_SGL
-#define CFG(a) (FX_DBL2FXCONST_SGL(a))
-#define FL2FXCONST_CFG FL2FXCONST_SGL
-#define FX_DBL2FX_CFG(x) FX_DBL2FX_SGL((FIXP_DBL)(x))
-#else
 #define FIXP_CFG FIXP_DBL
 #define FX_CFG2FX_DBL
 #define FX_CFG2FX_SGL FX_DBL2FX_SGL
 #define CFG(a) FIXP_DBL(a)
 #define FL2FXCONST_CFG FL2FXCONST_DBL
 #define FX_DBL2FX_CFG(x) ((FIXP_DBL)(x))
-#endif
 
 /* others  */
 #define SCALE_INV_ICC (2)
@@ -133,15 +124,9 @@
 
 #define QCC_SCALE 1
 #define M1M2_DATA FIXP_DBL
-#ifndef ARCH_PREFER_MULT_32x32
-#define M1M2_CDATA FIXP_SGL
-#define M1M2_CDATA2FX_DBL(a) FX_SGL2FX_DBL(a)
-#define FX_DBL2M1M2_CDATA(a) FX_DBL2FX_SGL(a)
-#else
 #define M1M2_CDATA FIXP_DBL
 #define M1M2_CDATA2FX_DBL(a) (a)
 #define FX_DBL2M1M2_CDATA(a) (a)
-#endif
 
 #define CLIP_PROTECT_GAIN_0(x) FL2FXCONST_CFG(((x) / (float)(1 << 0)))
 #define CLIP_PROTECT_GAIN_1(x) FL2FXCONST_CFG(((x) / (float)(1 << 1)))
diff --git a/libSACdec/src/sac_stp.cpp b/libSACdec/src/sac_stp.cpp
index 818e9df..bb66277 100644
--- a/libSACdec/src/sac_stp.cpp
+++ b/libSACdec/src/sac_stp.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -106,6 +106,8 @@
 #include "FDK_matrixCalloc.h"
 #include "sac_rom.h"
 
+#define SF_FREQ_DOMAIN_HEADROOM (2 * (1))
+
 #define BP_GF_START 6
 #define BP_GF_SIZE 25
 #define HP_SIZE 9
@@ -114,6 +116,16 @@
 #define SF_WET 5
 #define SF_DRY \
   3 /* SF_DRY == 2 would produce good conformance test results as well */
+#define SF_DRY_NRG                                                           \
+  (4 - 1) /* 8.495f = sum(BP_GF__FDK[i])                                     \
+             i=0,..,(sizeof(BP_GF__FDK)/sizeof(FIXP_CFG)-1) => energy        \
+             calculation needs 4 bits headroom, headroom can be reduced by 1 \
+             bit due to fPow2Div2() usage */
+#define SF_WET_NRG                                                           \
+  (4 - 1) /* 8.495f = sum(BP_GF__FDK[i])                                     \
+             i=0,..,(sizeof(BP_GF__FDK)/sizeof(FIXP_CFG)-1) => energy        \
+             calculation needs 4 bits headroom, headroom can be reduced by 1 \
+             bit due to fPow2Div2() usage */
 #define SF_PRODUCT_BP_GF 13
 #define SF_PRODUCT_BP_GF_GF 26
 #define SF_SCALE 2
@@ -172,18 +184,6 @@
        STP_SCALE_LIMIT_LO_LD64 = LD64(STP_SCALE_LIMIT_LO*STP_SCALE_LIMIT_LO)
 */
 
-#define DRY_ENER_WEIGHT(DryEner) DryEner = DryEner >> dry_scale_dmx
-
-#define WET_ENER_WEIGHT(WetEner) WetEner = WetEner << wet_scale_dmx
-
-#define DRY_ENER_SUM_REAL(DryEner, dmxReal, n) \
-  DryEner +=                                   \
-      fMultDiv2(fPow2Div2(dmxReal << SF_DRY), pBP[n]) >> ((2 * SF_DRY) - 2)
-
-#define DRY_ENER_SUM_CPLX(DryEner, dmxReal, dmxImag, n) \
-  DryEner += fMultDiv2(                                 \
-      fPow2Div2(dmxReal << SF_DRY) + fPow2Div2(dmxImag << SF_DRY), pBP[n])
-
 #define CALC_WET_SCALE(dryIdx, wetIdx)                                         \
   if ((DryEnerLD64[dryIdx] - STP_SCALE_LIMIT_HI_LD64) > WetEnerLD64[wetIdx]) { \
     scale[wetIdx] = STP_SCALE_LIMIT_HI;                                        \
@@ -206,29 +206,6 @@
   int update_old_ener;
 };
 
-inline void combineSignalReal(FIXP_DBL *hybOutputRealDry,
-                              FIXP_DBL *hybOutputRealWet, int bands) {
-  int n;
-
-  for (n = bands - 1; n >= 0; n--) {
-    *hybOutputRealDry = *hybOutputRealDry + *hybOutputRealWet;
-    hybOutputRealDry++, hybOutputRealWet++;
-  }
-}
-
-inline void combineSignalRealScale1(FIXP_DBL *hybOutputRealDry,
-                                    FIXP_DBL *hybOutputRealWet, FIXP_DBL scaleX,
-                                    int bands) {
-  int n;
-
-  for (n = bands - 1; n >= 0; n--) {
-    *hybOutputRealDry =
-        *hybOutputRealDry +
-        (fMultDiv2(*hybOutputRealWet, scaleX) << (SF_SCALE + 1));
-    hybOutputRealDry++, hybOutputRealWet++;
-  }
-}
-
 inline void combineSignalCplx(FIXP_DBL *hybOutputRealDry,
                               FIXP_DBL *hybOutputImagDry,
                               FIXP_DBL *hybOutputRealWet,
@@ -236,8 +213,8 @@
   int n;
 
   for (n = bands - 1; n >= 0; n--) {
-    *hybOutputRealDry = *hybOutputRealDry + *hybOutputRealWet;
-    *hybOutputImagDry = *hybOutputImagDry + *hybOutputImagWet;
+    *hybOutputRealDry = fAddSaturate(*hybOutputRealDry, *hybOutputRealWet);
+    *hybOutputImagDry = fAddSaturate(*hybOutputImagDry, *hybOutputImagWet);
     hybOutputRealDry++, hybOutputRealWet++;
     hybOutputImagDry++, hybOutputImagWet++;
   }
@@ -253,12 +230,14 @@
   FIXP_DBL scaleY;
   for (n = bands - 1; n >= 0; n--) {
     scaleY = fMultDiv2(scaleX, *pBP);
-    *hybOutputRealDry =
-        *hybOutputRealDry +
-        (fMultDiv2(*hybOutputRealWet, scaleY) << (SF_SCALE + 2));
-    *hybOutputImagDry =
-        *hybOutputImagDry +
-        (fMultDiv2(*hybOutputImagWet, scaleY) << (SF_SCALE + 2));
+    *hybOutputRealDry = SATURATE_LEFT_SHIFT(
+        (*hybOutputRealDry >> 1) +
+            (fMultDiv2(*hybOutputRealWet, scaleY) << (SF_SCALE + 1)),
+        1, DFRACT_BITS);
+    *hybOutputImagDry = SATURATE_LEFT_SHIFT(
+        (*hybOutputImagDry >> 1) +
+            (fMultDiv2(*hybOutputImagWet, scaleY) << (SF_SCALE + 1)),
+        1, DFRACT_BITS);
     hybOutputRealDry++, hybOutputRealWet++;
     hybOutputImagDry++, hybOutputImagWet++;
     pBP++;
@@ -305,12 +284,10 @@
 
   for (ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++) {
     self->prev_tp_scale[ch] = FL2FXCONST_DBL(1.0f / (1 << SF_SCALE));
-    self->oldWetEnerLD64[ch] =
-        FL2FXCONST_DBL(0.34375f); /* 32768.0*32768.0/2^(44-26-10) */
+    self->oldWetEnerLD64[ch] = FL2FXCONST_DBL(0.0);
   }
   for (ch = 0; ch < MAX_INPUT_CHANNELS; ch++) {
-    self->oldDryEnerLD64[ch] =
-        FL2FXCONST_DBL(0.1875f); /* 32768.0*32768.0/2^(44-26) */
+    self->oldDryEnerLD64[ch] = FL2FXCONST_DBL(0.0);
   }
 
   self->BP = BP__FDK;
@@ -364,7 +341,12 @@
   {
     cplxBands = BP_GF_SIZE;
     cplxHybBands = self->hybridBands;
-    dry_scale_dmx = (2 * SF_DRY) - 2;
+    if (self->treeConfig == TREE_212) {
+      dry_scale_dmx = 2; /* 2 bits to compensate fMultDiv2() and fPow2Div2()
+                            used in energy calculation */
+    } else {
+      dry_scale_dmx = (2 * SF_DRY) - 2;
+    }
     wet_scale_dmx = 2;
   }
 
@@ -390,8 +372,12 @@
           CalcLdData(hStpDec->runDryEner[ch] + ABS_THR__FDK);
     }
     for (ch = 0; ch < self->numOutputChannels; ch++) {
-      hStpDec->oldWetEnerLD64[ch] =
-          CalcLdData(hStpDec->runWetEner[ch] + ABS_THR2__FDK);
+      if (self->treeConfig == TREE_212)
+        hStpDec->oldWetEnerLD64[ch] =
+            CalcLdData(hStpDec->runWetEner[ch] + ABS_THR__FDK);
+      else
+        hStpDec->oldWetEnerLD64[ch] =
+            CalcLdData(hStpDec->runWetEner[ch] + ABS_THR2__FDK);
     }
   } else {
     hStpDec->update_old_ener++;
@@ -411,12 +397,33 @@
   pBP = hStpDec->BP_GF - BP_GF_START;
   switch (self->treeConfig) {
     case TREE_212:
+      INT sMin, sNorm, sReal, sImag;
+
+      sReal = fMin(getScalefactor(&qmfOutputRealDry[i_LF][BP_GF_START],
+                                  cplxBands - BP_GF_START),
+                   getScalefactor(&qmfOutputRealDry[i_RF][BP_GF_START],
+                                  cplxBands - BP_GF_START));
+      sImag = fMin(getScalefactor(&qmfOutputImagDry[i_LF][BP_GF_START],
+                                  cplxBands - BP_GF_START),
+                   getScalefactor(&qmfOutputImagDry[i_RF][BP_GF_START],
+                                  cplxBands - BP_GF_START));
+      sMin = fMin(sReal, sImag) - 1;
+
       for (n = BP_GF_START; n < cplxBands; n++) {
-        dmxReal0 = qmfOutputRealDry[i_LF][n] + qmfOutputRealDry[i_RF][n];
-        dmxImag0 = qmfOutputImagDry[i_LF][n] + qmfOutputImagDry[i_RF][n];
-        DRY_ENER_SUM_CPLX(DryEner0, dmxReal0, dmxImag0, n);
+        dmxReal0 = scaleValue(qmfOutputRealDry[i_LF][n], sMin) +
+                   scaleValue(qmfOutputRealDry[i_RF][n], sMin);
+        dmxImag0 = scaleValue(qmfOutputImagDry[i_LF][n], sMin) +
+                   scaleValue(qmfOutputImagDry[i_RF][n], sMin);
+
+        DryEner0 += (fMultDiv2(fPow2Div2(dmxReal0), pBP[n]) +
+                     fMultDiv2(fPow2Div2(dmxImag0), pBP[n])) >>
+                    SF_DRY_NRG;
       }
-      DRY_ENER_WEIGHT(DryEner0);
+
+      sNorm = SF_FREQ_DOMAIN_HEADROOM + SF_DRY_NRG + dry_scale_dmx -
+              (2 * sMin) + nrgScale;
+      DryEner0 = scaleValueSaturate(
+          DryEner0, fMax(fMin(sNorm, DFRACT_BITS - 1), -(DFRACT_BITS - 1)));
       break;
     default:;
   }
@@ -424,7 +431,7 @@
 
   /* normalise the 'direct' signals */
   for (ch = 0; ch < self->numInputChannels; ch++) {
-    DryEner[ch] = DryEner[ch] << (nrgScale);
+    if (self->treeConfig != TREE_212) DryEner[ch] = DryEner[ch] << nrgScale;
     hStpDec->runDryEner[ch] =
         fMult(STP_LPF_COEFF1__FDK, hStpDec->runDryEner[ch]) +
         fMult(ONE_MINUS_STP_LPF_COEFF1__FDK, DryEner[ch]);
@@ -436,10 +443,8 @@
       DryEnerLD64[ch] = FL2FXCONST_DBL(-0.484375f);
     }
   }
-  if (self->treeConfig == TREE_212) {
-    for (; ch < MAX_INPUT_CHANNELS; ch++) {
-      DryEnerLD64[ch] = FL2FXCONST_DBL(-0.484375f);
-    }
+  for (; ch < MAX_INPUT_CHANNELS; ch++) {
+    DryEnerLD64[ch] = FL2FXCONST_DBL(-0.484375f);
   }
 
   /* normalise the 'diffuse' signals */
@@ -450,14 +455,30 @@
     }
 
     WetEnerX = FL2FXCONST_DBL(0.0f);
-    for (n = BP_GF_START; n < cplxBands; n++) {
-      tmp = fPow2Div2(qmfOutputRealWet[ch][n] << SF_WET);
-      tmp += fPow2Div2(qmfOutputImagWet[ch][n] << SF_WET);
-      WetEnerX += fMultDiv2(tmp, pBP[n]);
-    }
-    WET_ENER_WEIGHT(WetEnerX);
 
-    WetEnerX = WetEnerX << (nrgScale);
+    if (self->treeConfig == TREE_212) {
+      INT sMin, sNorm;
+
+      sMin = fMin(getScalefactor(&qmfOutputRealWet[ch][BP_GF_START],
+                                 cplxBands - BP_GF_START),
+                  getScalefactor(&qmfOutputImagWet[ch][BP_GF_START],
+                                 cplxBands - BP_GF_START));
+
+      for (n = BP_GF_START; n < cplxBands; n++) {
+        WetEnerX +=
+            (fMultDiv2(fPow2Div2(scaleValue(qmfOutputRealWet[ch][n], sMin)),
+                       pBP[n]) +
+             fMultDiv2(fPow2Div2(scaleValue(qmfOutputImagWet[ch][n], sMin)),
+                       pBP[n])) >>
+            SF_WET_NRG;
+      }
+      sNorm = SF_FREQ_DOMAIN_HEADROOM + SF_WET_NRG + wet_scale_dmx -
+              (2 * sMin) + nrgScale;
+      WetEnerX = scaleValueSaturate(
+          WetEnerX, fMax(fMin(sNorm, DFRACT_BITS - 1), -(DFRACT_BITS - 1)));
+    } else
+      FDK_ASSERT(self->treeConfig == TREE_212);
+
     hStpDec->runWetEner[ch] =
         fMult(STP_LPF_COEFF1__FDK, hStpDec->runWetEner[ch]) +
         fMult(ONE_MINUS_STP_LPF_COEFF1__FDK, WetEnerX);
diff --git a/libSACdec/src/sac_tsd.cpp b/libSACdec/src/sac_tsd.cpp
index 30acca8..a07447b 100644
--- a/libSACdec/src/sac_tsd.cpp
+++ b/libSACdec/src/sac_tsd.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -123,12 +123,15 @@
 
 RAM_ALIGN
 LNK_SECTION_CONSTDATA
-static const FIXP_STP phiTsd[8] = {
-    STCP(0x7fffffff, 0x00000000), STCP(0x5a82799a, 0x5a82799a),
-    STCP(0x00000000, 0x7fffffff), STCP(0xa57d8666, 0x5a82799a),
-    STCP(0x80000000, 0x00000000), STCP(0xa57d8666, 0xa57d8666),
-    STCP(0x00000000, 0x80000000), STCP(0x5a82799a, 0xa57d8666),
-};
+static const FIXP_DPK phiTsd[8] = {
+    {{(FIXP_DBL)0x7fffffff, (FIXP_DBL)0x00000000}},
+    {{(FIXP_DBL)0x5a82799a, (FIXP_DBL)0x5a82799a}},
+    {{(FIXP_DBL)0x00000000, (FIXP_DBL)0x7fffffff}},
+    {{(FIXP_DBL)0xa57d8666, (FIXP_DBL)0x5a82799a}},
+    {{(FIXP_DBL)0x80000000, (FIXP_DBL)0x00000000}},
+    {{(FIXP_DBL)0xa57d8666, (FIXP_DBL)0xa57d8666}},
+    {{(FIXP_DBL)0x00000000, (FIXP_DBL)0x80000000}},
+    {{(FIXP_DBL)0x5a82799a, (FIXP_DBL)0xa57d8666}}};
 
 /*** Static Functions ***/
 static void longmult1(USHORT a[], USHORT b, USHORT d[], int len) {
@@ -333,16 +336,19 @@
 
   if (isTrSlot(pTsdData, ts)) {
     int k;
-    const FIXP_STP *phi = &phiTsd[pTsdData->bsTsdTrPhaseData[ts]];
+    const FIXP_DPK *phi = &phiTsd[pTsdData->bsTsdTrPhaseData[ts]];
     FDK_ASSERT((pTsdData->bsTsdTrPhaseData[ts] >= 0) &&
                (pTsdData->bsTsdTrPhaseData[ts] < 8));
 
     /* d = d_nonTr + v_direct * exp(j * bsTsdTrPhaseData[ts]/4 * pi ) */
     for (k = TSD_START_BAND; k < numHybridBands; k++) {
       FIXP_DBL tempReal, tempImag;
-      cplxMult(&tempReal, &tempImag, pVdirectReal[k], pVdirectImag[k], *phi);
-      pDnonTrReal[k] += tempReal;
-      pDnonTrImag[k] += tempImag;
+      cplxMultDiv2(&tempReal, &tempImag, pVdirectReal[k], pVdirectImag[k],
+                   *phi);
+      pDnonTrReal[k] = SATURATE_LEFT_SHIFT(
+          (pDnonTrReal[k] >> 2) + (tempReal >> 1), 2, DFRACT_BITS);
+      pDnonTrImag[k] = SATURATE_LEFT_SHIFT(
+          (pDnonTrImag[k] >> 2) + (tempImag >> 1), 2, DFRACT_BITS);
     }
   }
 
diff --git a/libSBRdec/include/sbrdecoder.h b/libSBRdec/include/sbrdecoder.h
index cc55572..c09c985 100644
--- a/libSBRdec/include/sbrdecoder.h
+++ b/libSBRdec/include/sbrdecoder.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -361,15 +361,20 @@
  * error (0: core decoder found errors, 1: no errors).
  * \param psDecoded       Pointer to a buffer holding a flag. Input: PS is
  * possible, Output: PS has been rendered.
+ * \param inDataHeadroom  Headroom of the SBR input time signal to prevent
+ * clipping.
+ * \param outDataHeadroom Pointer to headroom of the SBR output time signal to
+ * prevent clipping.
  *
  * \return  Error code.
  */
-SBR_ERROR sbrDecoder_Apply(HANDLE_SBRDECODER self, INT_PCM *input,
-                           INT_PCM *timeData, const int timeDataSize,
-                           int *numChannels, int *sampleRate,
+SBR_ERROR sbrDecoder_Apply(HANDLE_SBRDECODER self, LONG *input, LONG *timeData,
+                           const int timeDataSize, int *numChannels,
+                           int *sampleRate,
                            const FDK_channelMapDescr *const mapDescr,
                            const int mapIdx, const int coreDecodedOk,
-                           UCHAR *psDecoded);
+                           UCHAR *psDecoded, const INT inDataHeadroom,
+                           INT *outDataHeadroom);
 
 /**
  * \brief       Close SBR decoder instance and free memory.
diff --git a/libSBRdec/src/HFgen_preFlat.cpp b/libSBRdec/src/HFgen_preFlat.cpp
index 96adbb9..ad4caba 100644
--- a/libSBRdec/src/HFgen_preFlat.cpp
+++ b/libSBRdec/src/HFgen_preFlat.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -897,30 +897,31 @@
     for (i = startSample; i < stopSample; i++) {
       maxVal |=
           (FIXP_DBL)((LONG)(sourceBufferReal[i][loBand]) ^
-                     ((LONG)sourceBufferReal[i][loBand] >> (SAMPLE_BITS - 1)));
+                     ((LONG)sourceBufferReal[i][loBand] >> (DFRACT_BITS - 1)));
       maxVal |=
           (FIXP_DBL)((LONG)(sourceBufferImag[i][loBand]) ^
-                     ((LONG)sourceBufferImag[i][loBand] >> (SAMPLE_BITS - 1)));
+                     ((LONG)sourceBufferImag[i][loBand] >> (DFRACT_BITS - 1)));
     }
 
     if (maxVal != FL2FX_DBL(0.0f)) {
-      reserve = fixMax(0, CntLeadingZeros(maxVal) - 2);
+      reserve = CntLeadingZeros(maxVal) - 2;
     }
 
     nrg_ov = nrg = (FIXP_DBL)0;
     if (scale_nrg_ov > -31) {
       for (i = startSample; i < overlap; i++) {
-        nrg_ov += (fPow2Div2(sourceBufferReal[i][loBand] << reserve) +
-                   fPow2Div2(sourceBufferImag[i][loBand] << reserve)) >>
-                  sum_scale_ov;
+        nrg_ov +=
+            (fPow2Div2(scaleValue(sourceBufferReal[i][loBand], reserve)) +
+             fPow2Div2(scaleValue(sourceBufferImag[i][loBand], reserve))) >>
+            sum_scale_ov;
       }
     } else {
       scale_nrg_ov = 0;
     }
     if (scale_nrg > -31) {
       for (i = overlap; i < stopSample; i++) {
-        nrg += (fPow2Div2(sourceBufferReal[i][loBand] << reserve) +
-                fPow2Div2(sourceBufferImag[i][loBand] << reserve)) >>
+        nrg += (fPow2Div2(scaleValue(sourceBufferReal[i][loBand], reserve)) +
+                fPow2Div2(scaleValue(sourceBufferImag[i][loBand], reserve))) >>
                sum_scale;
       }
     } else {
diff --git a/libSBRdec/src/env_calc.cpp b/libSBRdec/src/env_calc.cpp
index 1242833..0b2f651 100644
--- a/libSBRdec/src/env_calc.cpp
+++ b/libSBRdec/src/env_calc.cpp
@@ -151,6 +151,9 @@
 
 #include "genericStds.h" /* need FDKpow() for debug outputs */
 
+#define MAX_SFB_NRG_HEADROOM (1)
+#define MAX_VAL_NRG_HEADROOM ((((FIXP_DBL)MAXVAL_DBL) >> MAX_SFB_NRG_HEADROOM))
+
 typedef struct {
   FIXP_DBL nrgRef[MAX_FREQ_COEFFS];
   FIXP_DBL nrgEst[MAX_FREQ_COEFFS];
@@ -699,20 +702,11 @@
       gain_sf[i] += gamma_sf + 1; /* +1 because of fMultDiv2() */
 
       /* set gain to at least 0.2f */
-      FIXP_DBL point_two = FL2FXCONST_DBL(0.8f); /* scaled up by 2 */
-      int point_two_sf = -2;
-
-      FIXP_DBL tmp = gain[i];
-      if (point_two_sf < gain_sf[i]) {
-        point_two >>= gain_sf[i] - point_two_sf;
-      } else {
-        tmp >>= point_two_sf - gain_sf[i];
-      }
-
       /* limit and calculate gain[i]^2 too */
       FIXP_DBL gain_pow2;
       int gain_pow2_sf;
-      if (tmp < point_two) {
+
+      if (fIsLessThan(gain[i], gain_sf[i], FL2FXCONST_DBL(0.2f), 0)) {
         gain[i] = FL2FXCONST_DBL(0.8f);
         gain_sf[i] = -2;
         gain_pow2 = FL2FXCONST_DBL(0.64f);
@@ -739,7 +733,8 @@
             fMin(DFRACT_BITS - 1, new_summand_sf - total_power_high_after_sf);
         total_power_high_after_sf = new_summand_sf;
       } else if (new_summand_sf < total_power_high_after_sf) {
-        subsample_power_high[i] >>= total_power_high_after_sf - new_summand_sf;
+        subsample_power_high[i] >>=
+            fMin(DFRACT_BITS - 1, total_power_high_after_sf - new_summand_sf);
       }
       total_power_high_after += subsample_power_high[i] >> preShift2;
     }
@@ -985,7 +980,8 @@
   */
   if (!useLP)
     adj_e = h_sbr_cal_env->filtBufferNoise_e -
-            getScalefactor(h_sbr_cal_env->filtBufferNoise, noSubbands);
+            getScalefactor(h_sbr_cal_env->filtBufferNoise, noSubbands) +
+            (INT)MAX_SFB_NRG_HEADROOM;
 
   /*
     Scan for maximum reference energy to be able
@@ -1005,7 +1001,7 @@
        - Smoothing can smear high gains of the previous envelope into the
        current
     */
-    maxSfbNrg_e += 6;
+    maxSfbNrg_e += (6 + MAX_SFB_NRG_HEADROOM);
 
     adj_e = maxSfbNrg_e;
     // final_e should not exist for PVC fixfix framing
@@ -1031,7 +1027,7 @@
          - Smoothing can smear high gains of the previous envelope into the
          current
       */
-      maxSfbNrg_e += 6;
+      maxSfbNrg_e += (6 + MAX_SFB_NRG_HEADROOM);
 
       if (borders[i] < hHeaderData->numberTimeSlots)
         /* This envelope affects timeslots that belong to the output frame */
@@ -1477,7 +1473,7 @@
 
       for (k = 0; k < noSubbands; k++) {
         int sc = scale_change - pNrgs->nrgGain_e[k] + (sc_change - 1);
-        pNrgs->nrgGain[k] >>= sc;
+        pNrgs->nrgGain[k] >>= fixMin(sc, DFRACT_BITS - 1);
         pNrgs->nrgGain_e[k] += sc;
       }
 
@@ -1485,7 +1481,7 @@
         for (k = 0; k < noSubbands; k++) {
           int sc =
               scale_change - h_sbr_cal_env->filtBuffer_e[k] + (sc_change - 1);
-          h_sbr_cal_env->filtBuffer[k] >>= sc;
+          h_sbr_cal_env->filtBuffer[k] >>= fixMin(sc, DFRACT_BITS - 1);
         }
       }
 
@@ -1576,12 +1572,13 @@
           FDK_ASSERT(!iTES_enable); /* not supported */
           if (flags & SBRDEC_ELD_GRID) {
             /* FDKmemset(analysBufferReal[j], 0, 64 * sizeof(FIXP_DBL)); */
-            adjustTimeSlot_EldGrid(&analysBufferReal[j][lowSubband], pNrgs,
-                                   &h_sbr_cal_env->harmIndex, lowSubband,
-                                   noSubbands,
-                                   fMin(scale_change, DFRACT_BITS - 1),
-                                   noNoiseFlag, &h_sbr_cal_env->phaseIndex,
-                                   EXP2SCALE(adj_e) - sbrScaleFactor->lb_scale);
+            adjustTimeSlot_EldGrid(
+                &analysBufferReal[j][lowSubband], pNrgs,
+                &h_sbr_cal_env->harmIndex, lowSubband, noSubbands,
+                fMin(scale_change, DFRACT_BITS - 1), noNoiseFlag,
+                &h_sbr_cal_env->phaseIndex,
+                fMax(EXP2SCALE(adj_e) - sbrScaleFactor->lb_scale,
+                     -(DFRACT_BITS - 1)));
           } else {
             adjustTimeSlotLC(&analysBufferReal[j][lowSubband], pNrgs,
                              &h_sbr_cal_env->harmIndex, lowSubband, noSubbands,
@@ -1830,7 +1827,8 @@
     diff = (int)(nrgGain_e[band] - filtBuffer_e[band]);
     if (diff > 0) {
       filtBuffer[band] >>=
-          diff; /* Compensate for the scale change by shifting the mantissa. */
+          fMin(diff, DFRACT_BITS - 1); /* Compensate for the scale change by
+                                          shifting the mantissa. */
       filtBuffer_e[band] += diff; /* New gain is bigger, use its exponent */
     } else if (diff < 0) {
       /* The buffered gains seem to be larger, but maybe there
@@ -1850,8 +1848,8 @@
         filtBuffer_e[band] -= reserve; /* Compensate in the exponent: */
 
         /* For the remaining difference, change the new gain value */
-        diff = fixMin(-(reserve + diff), DFRACT_BITS - 1);
-        nrgGain[band] >>= diff;
+        diff = -(reserve + diff);
+        nrgGain[band] >>= fMin(diff, DFRACT_BITS - 1);
         nrgGain_e[band] += diff;
       }
     }
@@ -2423,6 +2421,9 @@
   const FIXP_DBL *p_harmonicPhaseX = &harmonicPhaseX[harmIndex][0];
   const INT *p_harmonicPhase = &harmonicPhase[harmIndex][0];
 
+  const FIXP_DBL max_val = MAX_VAL_NRG_HEADROOM >> scale_change;
+  const FIXP_DBL min_val = -max_val;
+
   *(ptrReal - 1) = fAddSaturate(
       *(ptrReal - 1),
       SATURATE_SHIFT(fMultDiv2(p_harmonicPhaseX[lowSubband & 1], pSineLevel[0]),
@@ -2435,7 +2436,8 @@
     FIXP_DBL sineLevel_curr = *pSineLevel++;
     phaseIndex = (phaseIndex + 1) & (SBR_NF_NO_RANDOM_VAL - 1);
 
-    signalReal = fMultDiv2(*ptrReal, *pGain++) << ((int)scale_change);
+    signalReal = fMax(fMin(fMultDiv2(*ptrReal, *pGain++), max_val), min_val)
+                 << scale_change;
     sbNoise = *pNoiseLevel++;
     if (((INT)sineLevel_curr | noNoiseFlag) == 0) {
       signalReal +=
@@ -2469,7 +2471,8 @@
     FIXP_DBL sineLevel_curr = *pSineLevel++;
     phaseIndex = (phaseIndex + 1) & (SBR_NF_NO_RANDOM_VAL - 1);
 
-    signalReal = fMultDiv2(*ptrReal, *pGain++) << ((int)scale_change);
+    signalReal = fMax(fMin(fMultDiv2(*ptrReal, *pGain++), max_val), min_val)
+                 << scale_change;
     sbNoise = *pNoiseLevel++;
     if (((INT)sineLevel_curr | noNoiseFlag) == 0) {
       signalReal +=
@@ -2509,6 +2512,8 @@
   FIXP_DBL signalReal, sineLevel, sineLevelNext, sineLevelPrev;
   int tone_count = 0;
   int sineSign = 1;
+  const FIXP_DBL max_val = MAX_VAL_NRG_HEADROOM >> scale_change;
+  const FIXP_DBL min_val = -max_val;
 
 #define C1 ((FIXP_SGL)FL2FXCONST_SGL(2.f * 0.00815f))
 #define C1_CLDFB ((FIXP_SGL)FL2FXCONST_SGL(2.f * 0.16773f))
@@ -2524,7 +2529,8 @@
     of the signal and should be carried out with full accuracy
     (supplying #FRACT_BITS valid bits).
   */
-  signalReal = fMultDiv2(*ptrReal, *pGain++) << ((int)scale_change);
+  signalReal = fMax(fMin(fMultDiv2(*ptrReal, *pGain++), max_val), min_val)
+               << scale_change;
   sineLevel = *pSineLevel++;
   sineLevelNext = (noSubbands > 1) ? pSineLevel[0] : FL2FXCONST_DBL(0.0f);
 
@@ -2552,10 +2558,10 @@
 
       /* save switch and compare operations and reduce to XOR statement */
       if (((harmIndex >> 1) & 0x1) ^ freqInvFlag) {
-        *(ptrReal - 1) += tmp1;
+        *(ptrReal - 1) = fAddSaturate(*(ptrReal - 1), tmp1);
         signalReal -= tmp2;
       } else {
-        *(ptrReal - 1) -= tmp1;
+        *(ptrReal - 1) = fAddSaturate(*(ptrReal - 1), -tmp1);
         signalReal += tmp2;
       }
       *ptrReal++ = signalReal;
@@ -2586,7 +2592,9 @@
 
         /* The next multiplication constitutes the actual envelope adjustment of
          * the signal. */
-        signalReal += fMultDiv2(*ptrReal, *pGain++) << ((int)scale_change);
+        signalReal +=
+            fMax(fMin(fMultDiv2(*ptrReal, *pGain++), max_val), min_val)
+            << scale_change;
 
         pNoiseLevel++;
         *ptrReal++ = signalReal;
@@ -2599,7 +2607,8 @@
         index++;
         /* The next multiplication constitutes the actual envelope adjustment of
          * the signal. */
-        signalReal = fMultDiv2(*ptrReal, *pGain++) << ((int)scale_change);
+        signalReal = fMax(fMin(fMultDiv2(*ptrReal, *pGain++), max_val), min_val)
+                     << scale_change;
 
         if (*pSineLevel++ != FL2FXCONST_DBL(0.0f))
           tone_count++;
@@ -2627,7 +2636,8 @@
     index++;
     /* The next multiplication constitutes the actual envelope adjustment of the
      * signal. */
-    signalReal = fMultDiv2(*ptrReal, *pGain) << ((int)scale_change);
+    signalReal = fMax(fMin(fMultDiv2(*ptrReal, *pGain), max_val), min_val)
+                 << scale_change;
     sineLevelPrev = fMultDiv2(pSineLevel[-1], FL2FX_SGL(0.0163f));
     sineLevel = pSineLevel[0];
 
@@ -2696,6 +2706,9 @@
       /*FL2FXCONST_SGL(1.0f) */ (FIXP_SGL)MAXVAL_SGL - smooth_ratio;
   int index = *ptrPhaseIndex;
   int shift;
+  FIXP_DBL max_val_noise = 0, min_val_noise = 0;
+  const FIXP_DBL max_val = MAX_VAL_NRG_HEADROOM >> scale_change;
+  const FIXP_DBL min_val = -max_val;
 
   *ptrPhaseIndex = (index + noSubbands) & (SBR_NF_NO_RANDOM_VAL - 1);
 
@@ -2705,6 +2718,8 @@
     shift = fixMin(DFRACT_BITS - 1, -filtBufferNoiseShift);
   } else {
     shift = fixMin(DFRACT_BITS - 1, filtBufferNoiseShift);
+    max_val_noise = MAX_VAL_NRG_HEADROOM >> shift;
+    min_val_noise = -max_val_noise;
   }
 
   if (smooth_ratio > FL2FXCONST_SGL(0.0f)) {
@@ -2720,8 +2735,10 @@
         smoothedNoise = (fMultDiv2(smooth_ratio, filtBufferNoise[k]) >> shift) +
                         fMult(direct_ratio, noiseLevel[k]);
       } else {
-        smoothedNoise = (fMultDiv2(smooth_ratio, filtBufferNoise[k]) << shift) +
-                        fMult(direct_ratio, noiseLevel[k]);
+        smoothedNoise = fMultDiv2(smooth_ratio, filtBufferNoise[k]);
+        smoothedNoise =
+            (fMax(fMin(smoothedNoise, max_val_noise), min_val_noise) << shift) +
+            fMult(direct_ratio, noiseLevel[k]);
       }
 
       /*
@@ -2729,8 +2746,12 @@
         of the signal and should be carried out with full accuracy
         (supplying #DFRACT_BITS valid bits).
       */
-      signalReal = fMultDiv2(*ptrReal, smoothedGain) << ((int)scale_change);
-      signalImag = fMultDiv2(*ptrImag, smoothedGain) << ((int)scale_change);
+      signalReal =
+          fMax(fMin(fMultDiv2(*ptrReal, smoothedGain), max_val), min_val)
+          << scale_change;
+      signalImag =
+          fMax(fMin(fMultDiv2(*ptrImag, smoothedGain), max_val), min_val)
+          << scale_change;
 
       index++;
 
@@ -2752,8 +2773,12 @@
   } else {
     for (k = 0; k < noSubbands; k++) {
       smoothedGain = gain[k];
-      signalReal = fMultDiv2(*ptrReal, smoothedGain) << scale_change;
-      signalImag = fMultDiv2(*ptrImag, smoothedGain) << scale_change;
+      signalReal =
+          fMax(fMin(fMultDiv2(*ptrReal, smoothedGain), max_val), min_val)
+          << scale_change;
+      signalImag =
+          fMax(fMin(fMultDiv2(*ptrImag, smoothedGain), max_val), min_val)
+          << scale_change;
 
       index++;
 
@@ -2859,6 +2884,9 @@
   int freqInvFlag = (lowSubband & 1);
   FIXP_DBL sineLevel;
   int shift;
+  FIXP_DBL max_val_noise = 0, min_val_noise = 0;
+  const FIXP_DBL max_val = MAX_VAL_NRG_HEADROOM >> scale_change;
+  const FIXP_DBL min_val = -max_val;
 
   *ptrPhaseIndex = (index + noSubbands) & (SBR_NF_NO_RANDOM_VAL - 1);
   *ptrHarmIndex = (harmIndex + 1) & 3;
@@ -2874,10 +2902,13 @@
 
   filtBufferNoiseShift +=
       1; /* due to later use of fMultDiv2 instead of fMult */
-  if (filtBufferNoiseShift < 0)
+  if (filtBufferNoiseShift < 0) {
     shift = fixMin(DFRACT_BITS - 1, -filtBufferNoiseShift);
-  else
+  } else {
     shift = fixMin(DFRACT_BITS - 1, filtBufferNoiseShift);
+    max_val_noise = MAX_VAL_NRG_HEADROOM >> shift;
+    min_val_noise = -max_val_noise;
+  }
 
   if (smooth_ratio > FL2FXCONST_SGL(0.0f)) {
     for (k = 0; k < noSubbands; k++) {
@@ -2893,8 +2924,10 @@
         smoothedNoise = (fMultDiv2(smooth_ratio, filtBufferNoise[k]) >> shift) +
                         fMult(direct_ratio, noiseLevel[k]);
       } else {
-        smoothedNoise = (fMultDiv2(smooth_ratio, filtBufferNoise[k]) << shift) +
-                        fMult(direct_ratio, noiseLevel[k]);
+        smoothedNoise = fMultDiv2(smooth_ratio, filtBufferNoise[k]);
+        smoothedNoise =
+            (fMax(fMin(smoothedNoise, max_val_noise), min_val_noise) << shift) +
+            fMult(direct_ratio, noiseLevel[k]);
       }
 
       /*
@@ -2902,8 +2935,12 @@
         of the signal and should be carried out with full accuracy
         (supplying #DFRACT_BITS valid bits).
       */
-      signalReal = fMultDiv2(*ptrReal, smoothedGain) << ((int)scale_change);
-      signalImag = fMultDiv2(*ptrImag, smoothedGain) << ((int)scale_change);
+      signalReal =
+          fMax(fMin(fMultDiv2(*ptrReal, smoothedGain), max_val), min_val)
+          << scale_change;
+      signalImag =
+          fMax(fMin(fMultDiv2(*ptrImag, smoothedGain), max_val), min_val)
+          << scale_change;
 
       index++;
 
@@ -2956,8 +2993,12 @@
   } else {
     for (k = 0; k < noSubbands; k++) {
       smoothedGain = gain[k];
-      signalReal = fMultDiv2(*ptrReal, smoothedGain) << scale_change;
-      signalImag = fMultDiv2(*ptrImag, smoothedGain) << scale_change;
+      signalReal =
+          fMax(fMin(fMultDiv2(*ptrReal, smoothedGain), max_val), min_val)
+          << scale_change;
+      signalImag =
+          fMax(fMin(fMultDiv2(*ptrImag, smoothedGain), max_val), min_val)
+          << scale_change;
 
       index++;
 
@@ -3141,6 +3182,11 @@
       return SBRDEC_UNSUPPORTED_CONFIG;
     }
 
+    /* Restrict maximum value of limiter band table */
+    if (workLimiterBandTable[tempNoLim] > highSubband) {
+      return SBRDEC_UNSUPPORTED_CONFIG;
+    }
+
     /* Copy limiterbands from working buffer into final destination */
     for (k = 0; k <= nBands; k++) {
       limiterBandTable[k] = workLimiterBandTable[k];
diff --git a/libSBRdec/src/hbe.cpp b/libSBRdec/src/hbe.cpp
index 1141e9c..d210bb6 100644
--- a/libSBRdec/src/hbe.cpp
+++ b/libSBRdec/src/hbe.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -957,7 +957,7 @@
     hQmfTran->qmfOutBufSize = 2 * (hQmfTran->noCols / 2 + QMF_WIN_LEN - 1);
 
     hQmfTran->inBuf_F =
-        (INT_PCM*)FDKcalloc(QMF_SYNTH_CHANNELS + 20 + 1, sizeof(INT_PCM));
+        (LONG*)FDKcalloc(QMF_SYNTH_CHANNELS + 20 + 1, sizeof(LONG));
     /* buffered time signal needs to be delayed by synthesis_size; max
      * synthesis_size = 20; */
     if (hQmfTran->inBuf_F == NULL) {
@@ -1339,7 +1339,7 @@
     g_r_m = fMultDiv2(tmp_r, factor_m) << shift;
     g_i_m = fMultDiv2(tmp_i, factor_m) << shift;
     g_e = scale_factor_hbe - (g_e + factor_e + gammaCenter_e + add);
-    fMax((INT)0, g_e);
+    g_e = fMax((INT)0, g_e);
     *qmfHBEBufReal_F += g_r_m >> g_e;
     *qmfHBEBufImag_F += g_i_m >> g_e;
   }
diff --git a/libSBRdec/src/hbe.h b/libSBRdec/src/hbe.h
index fdffe1e..3556783 100644
--- a/libSBRdec/src/hbe.h
+++ b/libSBRdec/src/hbe.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -132,6 +132,9 @@
 } KEEP_STATES_SYNCED_MODE;
 
 struct hbeTransposer {
+  FIXP_DBL anaQmfStates[HBE_QMF_FILTER_STATE_ANA_SIZE];
+  FIXP_QSS synQmfStates[HBE_QMF_FILTER_STATE_SYN_SIZE];
+
   int xOverQmf[MAX_NUM_PATCHES_HBE];
 
   int maxStretch;
@@ -144,7 +147,7 @@
   int stopBand;
   int bSbr41;
 
-  INT_PCM *inBuf_F;
+  LONG *inBuf_F;
   FIXP_DBL **qmfInBufReal_F;
   FIXP_DBL **qmfInBufImag_F;
 
@@ -156,9 +159,6 @@
   FIXP_DBL const *synthesisQmfPreModCos_F;
   FIXP_DBL const *synthesisQmfPreModSin_F;
 
-  FIXP_QAS anaQmfStates[HBE_QMF_FILTER_STATE_ANA_SIZE];
-  FIXP_QSS synQmfStates[HBE_QMF_FILTER_STATE_SYN_SIZE];
-
   FIXP_DBL **qmfHBEBufReal_F;
   FIXP_DBL **qmfHBEBufImag_F;
 
diff --git a/libSBRdec/src/lpp_tran.cpp b/libSBRdec/src/lpp_tran.cpp
index 6acb626..93e1158 100644
--- a/libSBRdec/src/lpp_tran.cpp
+++ b/libSBRdec/src/lpp_tran.cpp
@@ -1014,8 +1014,8 @@
                               pSettings->nCols) +
                    lowBandShift);
 
-    dynamicScale = fixMax(
-        0, dynamicScale - 1); /* one additional bit headroom to prevent -1.0 */
+    dynamicScale =
+        dynamicScale - 1; /* one additional bit headroom to prevent -1.0 */
 
     /*
     Scale temporal QMF buffer.
@@ -1194,6 +1194,9 @@
     } else { /* bw <= 0 */
 
       int descale = fixMin(DFRACT_BITS - 1, (LPC_SCALE_FACTOR + dynamicScale));
+      dynamicScale +=
+          1; /* prevent negativ scale factor due to 'one additional bit
+                headroom' */
 
       for (i = startSample; i < stopSample; i++) {
         FIXP_DBL accu1, accu2;
@@ -1210,9 +1213,9 @@
                 dynamicScale;
 
         qmfBufferReal[i][loBand] =
-            (lowBandReal[LPC_ORDER + i] >> descale) + (accu1 << 1);
+            (lowBandReal[LPC_ORDER + i] >> descale) + (accu1 << (1 + 1));
         qmfBufferImag[i][loBand] =
-            (lowBandImag[LPC_ORDER + i] >> descale) + (accu2 << 1);
+            (lowBandImag[LPC_ORDER + i] >> descale) + (accu2 << (1 + 1));
       }
     } /* bw <= 0 */
 
diff --git a/libSBRdec/src/pvc_dec.cpp b/libSBRdec/src/pvc_dec.cpp
index b477122..e1e3c2c 100644
--- a/libSBRdec/src/pvc_dec.cpp
+++ b/libSBRdec/src/pvc_dec.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -534,7 +534,8 @@
     for (ksg = ksg_start; ksg < PVC_NBLOW; ksg++) {
       for (band = sg_borders[ksg]; band < sg_borders[ksg + 1]; band++) {
         /* The division by 8 == (RATE*lbw) is required algorithmically */
-        E[ksg] += (fPow2Div2(qmfR[band]) + fPow2Div2(qmfI[band])) >> 2;
+        E[ksg] +=
+            ((fPow2Div2(qmfR[band]) >> 1) + (fPow2Div2(qmfI[band]) >> 1)) >> 3;
       }
     }
   }
@@ -542,7 +543,7 @@
     if (E[ksg] > (FIXP_DBL)0) {
       /* 10/log2(10) = 0.752574989159953 * 2^2 */
       int exp_log;
-      FIXP_DBL nrg = CalcLog2(E[ksg], 2 * qmfExponent, &exp_log);
+      FIXP_DBL nrg = CalcLog2(E[ksg], 2 * qmfExponent + 2, &exp_log);
       nrg = fMult(nrg, FL2FXCONST_SGL(LOG10FAC));
       nrg = scaleValue(nrg, exp_log - PVC_ESG_EXP + 2);
       pEsg[ksg] = fMax(nrg, FL2FXCONST_DBL(-10.0 / (1 << PVC_ESG_EXP)));
@@ -603,22 +604,22 @@
       E_high_exp[ksg] = 0;
 
       /* residual part */
-      accu = ((LONG)(SCHAR)*pTab2++) << (DFRACT_BITS - 8 - PVC_ESG_EXP +
+      accu = ((LONG)(SCHAR)*pTab2++) << (DFRACT_BITS - 8 - PVC_ESG_EXP - 2 +
                                          pPvcDynamicData->pScalingCoef[3]);
 
       /* linear combination of lower grouped energies part */
       for (kb = 0; kb < PVC_NBLOW; kb++) {
         predCoeff = (FIXP_SGL)(
             (SHORT)(SCHAR)pTab1[kb * pPvcDynamicData->nbHigh + ksg] << 8);
-        predCoeff_exp = pPvcDynamicData->pScalingCoef[kb] +
-                        1; /* +1 to compensate for Div2 */
-        accu += fMultDiv2(E[kb], predCoeff) << predCoeff_exp;
+        predCoeff_exp = -(pPvcDynamicData->pScalingCoef[kb] + 1 -
+                          2); /* +1 to compensate for Div2; -2 for accu */
+        accu += fMultDiv2(E[kb], predCoeff) >> predCoeff_exp;
       }
       /* convert back to linear domain */
       accu = fMult(accu, FL2FXCONST_SGL(LOG10FAC_INV));
-      accu = f2Pow(
-          accu, PVC_ESG_EXP - 1,
-          &predCoeff_exp); /* -1 compensates for exponent of LOG10FAC_INV */
+      accu = f2Pow(accu, PVC_ESG_EXP - 1 + 2,
+                   &predCoeff_exp); /* -1 compensates for exponent of
+                                       LOG10FAC_INV; +2 for accu */
       predictedEsgSlot[ksg] = accu;
       E_high_exp[ksg] = predCoeff_exp;
       if (predCoeff_exp > E_high_exp_max) {
@@ -628,8 +629,8 @@
 
     /* rescale output vector according to largest exponent */
     for (ksg = 0; ksg < pPvcDynamicData->nbHigh; ksg++) {
-      int scale = E_high_exp[ksg] - E_high_exp_max;
-      predictedEsgSlot[ksg] = scaleValue(predictedEsgSlot[ksg], scale);
+      int scale = fMin(E_high_exp_max - E_high_exp[ksg], DFRACT_BITS - 1);
+      predictedEsgSlot[ksg] = predictedEsgSlot[ksg] >> scale;
     }
     *predictedEsg_exp = E_high_exp_max;
   }
diff --git a/libSBRdec/src/sbr_crc.cpp b/libSBRdec/src/sbr_crc.cpp
deleted file mode 100644
index ba0fd05..0000000
--- a/libSBRdec/src/sbr_crc.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-/* -----------------------------------------------------------------------------
-Software License for The Fraunhofer FDK AAC Codec Library for Android
-
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
-Forschung e.V. All rights reserved.
-
- 1.    INTRODUCTION
-The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
-that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
-scheme for digital audio. This FDK AAC Codec software is intended to be used on
-a wide variety of Android devices.
-
-AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
-general perceptual audio codecs. AAC-ELD is considered the best-performing
-full-bandwidth communications codec by independent studies and is widely
-deployed. AAC has been standardized by ISO and IEC as part of the MPEG
-specifications.
-
-Patent licenses for necessary patent claims for the FDK AAC Codec (including
-those of Fraunhofer) may be obtained through Via Licensing
-(www.vialicensing.com) or through the respective patent owners individually for
-the purpose of encoding or decoding bit streams in products that are compliant
-with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
-Android devices already license these patent claims through Via Licensing or
-directly from the patent owners, and therefore FDK AAC Codec software may
-already be covered under those patent licenses when it is used for those
-licensed purposes only.
-
-Commercially-licensed AAC software libraries, including floating-point versions
-with enhanced sound quality, are also available from Fraunhofer. Users are
-encouraged to check the Fraunhofer website for additional applications
-information and documentation.
-
-2.    COPYRIGHT LICENSE
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted without payment of copyright license fees provided that you
-satisfy the following conditions:
-
-You must retain the complete text of this software license in redistributions of
-the FDK AAC Codec or your modifications thereto in source code form.
-
-You must retain the complete text of this software license in the documentation
-and/or other materials provided with redistributions of the FDK AAC Codec or
-your modifications thereto in binary form. You must make available free of
-charge copies of the complete source code of the FDK AAC Codec and your
-modifications thereto to recipients of copies in binary form.
-
-The name of Fraunhofer may not be used to endorse or promote products derived
-from this library without prior written permission.
-
-You may not charge copyright license fees for anyone to use, copy or distribute
-the FDK AAC Codec software or your modifications thereto.
-
-Your modified versions of the FDK AAC Codec must carry prominent notices stating
-that you changed the software and the date of any change. For modified versions
-of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
-must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
-AAC Codec Library for Android."
-
-3.    NO PATENT LICENSE
-
-NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
-limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
-Fraunhofer provides no warranty of patent non-infringement with respect to this
-software.
-
-You may use this FDK AAC Codec software or modifications thereto only for
-purposes that are authorized by appropriate patent licenses.
-
-4.    DISCLAIMER
-
-This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
-holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
-including but not limited to the implied warranties of merchantability and
-fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
-CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
-or consequential damages, including but not limited to procurement of substitute
-goods or services; loss of use, data, or profits, or business interruption,
-however caused and on any theory of liability, whether in contract, strict
-liability, or tort (including negligence), arising in any way out of the use of
-this software, even if advised of the possibility of such damage.
-
-5.    CONTACT INFORMATION
-
-Fraunhofer Institute for Integrated Circuits IIS
-Attention: Audio and Multimedia Departments - FDK AAC LL
-Am Wolfsmantel 33
-91058 Erlangen, Germany
-
-www.iis.fraunhofer.de/amm
-amm-info@iis.fraunhofer.de
------------------------------------------------------------------------------ */
-
-/**************************** SBR decoder library ******************************
-
-   Author(s):
-
-   Description:
-
-*******************************************************************************/
-
-/*!
-  \file
-  \brief  CRC check coutines
-*/
-
-#include "sbr_crc.h"
-
-#include "FDK_bitstream.h"
-#include "transcendent.h"
-
-#define MAXCRCSTEP 16
-#define MAXCRCSTEP_LD 4
-
-/*!
-  \brief     crc calculation
-*/
-static ULONG calcCRC(HANDLE_CRC hCrcBuf, ULONG bValue, int nBits) {
-  int i;
-  ULONG bMask = (1UL << (nBits - 1));
-
-  for (i = 0; i < nBits; i++, bMask >>= 1) {
-    USHORT flag = (hCrcBuf->crcState & hCrcBuf->crcMask) ? 1 : 0;
-    USHORT flag1 = (bMask & bValue) ? 1 : 0;
-
-    flag ^= flag1;
-    hCrcBuf->crcState <<= 1;
-    if (flag) hCrcBuf->crcState ^= hCrcBuf->crcPoly;
-  }
-
-  return (hCrcBuf->crcState);
-}
-
-/*!
-  \brief     crc
-*/
-static int getCrc(HANDLE_FDK_BITSTREAM hBs, ULONG NrBits) {
-  int i;
-  CRC_BUFFER CrcBuf;
-
-  CrcBuf.crcState = SBR_CRC_START;
-  CrcBuf.crcPoly = SBR_CRC_POLY;
-  CrcBuf.crcMask = SBR_CRC_MASK;
-
-  int CrcStep = NrBits >> MAXCRCSTEP_LD;
-
-  int CrcNrBitsRest = (NrBits - CrcStep * MAXCRCSTEP);
-  ULONG bValue;
-
-  for (i = 0; i < CrcStep; i++) {
-    bValue = FDKreadBits(hBs, MAXCRCSTEP);
-    calcCRC(&CrcBuf, bValue, MAXCRCSTEP);
-  }
-
-  bValue = FDKreadBits(hBs, CrcNrBitsRest);
-  calcCRC(&CrcBuf, bValue, CrcNrBitsRest);
-
-  return (CrcBuf.crcState & SBR_CRC_RANGE);
-}
-
-/*!
-  \brief   crc interface
-  \return  1: CRC OK, 0: CRC check failure
-*/
-int SbrCrcCheck(HANDLE_FDK_BITSTREAM hBs, /*!< handle to bit-buffer  */
-                LONG NrBits)              /*!< max. CRC length       */
-{
-  int crcResult = 1;
-  ULONG NrCrcBits;
-  ULONG crcCheckResult;
-  LONG NrBitsAvailable;
-  ULONG crcCheckSum;
-
-  crcCheckSum = FDKreadBits(hBs, 10);
-
-  NrBitsAvailable = FDKgetValidBits(hBs);
-  if (NrBitsAvailable <= 0) {
-    return 0;
-  }
-
-  NrCrcBits = fixMin((INT)NrBits, (INT)NrBitsAvailable);
-
-  crcCheckResult = getCrc(hBs, NrCrcBits);
-  FDKpushBack(hBs, (NrBitsAvailable - FDKgetValidBits(hBs)));
-
-  if (crcCheckResult != crcCheckSum) {
-    crcResult = 0;
-  }
-
-  return (crcResult);
-}
diff --git a/libSBRdec/src/sbr_crc.h b/libSBRdec/src/sbr_crc.h
deleted file mode 100644
index 9633717..0000000
--- a/libSBRdec/src/sbr_crc.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/* -----------------------------------------------------------------------------
-Software License for The Fraunhofer FDK AAC Codec Library for Android
-
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
-Forschung e.V. All rights reserved.
-
- 1.    INTRODUCTION
-The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
-that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
-scheme for digital audio. This FDK AAC Codec software is intended to be used on
-a wide variety of Android devices.
-
-AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
-general perceptual audio codecs. AAC-ELD is considered the best-performing
-full-bandwidth communications codec by independent studies and is widely
-deployed. AAC has been standardized by ISO and IEC as part of the MPEG
-specifications.
-
-Patent licenses for necessary patent claims for the FDK AAC Codec (including
-those of Fraunhofer) may be obtained through Via Licensing
-(www.vialicensing.com) or through the respective patent owners individually for
-the purpose of encoding or decoding bit streams in products that are compliant
-with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
-Android devices already license these patent claims through Via Licensing or
-directly from the patent owners, and therefore FDK AAC Codec software may
-already be covered under those patent licenses when it is used for those
-licensed purposes only.
-
-Commercially-licensed AAC software libraries, including floating-point versions
-with enhanced sound quality, are also available from Fraunhofer. Users are
-encouraged to check the Fraunhofer website for additional applications
-information and documentation.
-
-2.    COPYRIGHT LICENSE
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted without payment of copyright license fees provided that you
-satisfy the following conditions:
-
-You must retain the complete text of this software license in redistributions of
-the FDK AAC Codec or your modifications thereto in source code form.
-
-You must retain the complete text of this software license in the documentation
-and/or other materials provided with redistributions of the FDK AAC Codec or
-your modifications thereto in binary form. You must make available free of
-charge copies of the complete source code of the FDK AAC Codec and your
-modifications thereto to recipients of copies in binary form.
-
-The name of Fraunhofer may not be used to endorse or promote products derived
-from this library without prior written permission.
-
-You may not charge copyright license fees for anyone to use, copy or distribute
-the FDK AAC Codec software or your modifications thereto.
-
-Your modified versions of the FDK AAC Codec must carry prominent notices stating
-that you changed the software and the date of any change. For modified versions
-of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
-must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
-AAC Codec Library for Android."
-
-3.    NO PATENT LICENSE
-
-NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
-limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
-Fraunhofer provides no warranty of patent non-infringement with respect to this
-software.
-
-You may use this FDK AAC Codec software or modifications thereto only for
-purposes that are authorized by appropriate patent licenses.
-
-4.    DISCLAIMER
-
-This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
-holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
-including but not limited to the implied warranties of merchantability and
-fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
-CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
-or consequential damages, including but not limited to procurement of substitute
-goods or services; loss of use, data, or profits, or business interruption,
-however caused and on any theory of liability, whether in contract, strict
-liability, or tort (including negligence), arising in any way out of the use of
-this software, even if advised of the possibility of such damage.
-
-5.    CONTACT INFORMATION
-
-Fraunhofer Institute for Integrated Circuits IIS
-Attention: Audio and Multimedia Departments - FDK AAC LL
-Am Wolfsmantel 33
-91058 Erlangen, Germany
-
-www.iis.fraunhofer.de/amm
-amm-info@iis.fraunhofer.de
------------------------------------------------------------------------------ */
-
-/**************************** SBR decoder library ******************************
-
-   Author(s):
-
-   Description:
-
-*******************************************************************************/
-
-/*!
-  \file
-  \brief  CRC checking routines
-*/
-#ifndef SBR_CRC_H
-#define SBR_CRC_H
-
-#include "sbrdecoder.h"
-
-#include "FDK_bitstream.h"
-
-/* some useful crc polynoms:
-
-crc5: x^5+x^4+x^2+x^1+1
-crc6: x^6+x^5+x^3+x^2+x+1
-crc7: x^7+x^6+x^2+1
-crc8: x^8+x^2+x+x+1
-*/
-
-/* default SBR CRC */ /* G(x) = x^10 + x^9 + x^5 + x^4 + x + 1 */
-#define SBR_CRC_POLY 0x0233
-#define SBR_CRC_MASK 0x0200
-#define SBR_CRC_START 0x0000
-#define SBR_CRC_RANGE 0x03FF
-
-typedef struct {
-  USHORT crcState;
-  USHORT crcMask;
-  USHORT crcPoly;
-} CRC_BUFFER;
-
-typedef CRC_BUFFER *HANDLE_CRC;
-
-int SbrCrcCheck(HANDLE_FDK_BITSTREAM hBitBuf, LONG NrCrcBits);
-
-#endif
diff --git a/libSBRdec/src/sbr_dec.cpp b/libSBRdec/src/sbr_dec.cpp
index 30611e7..b1fb0da 100644
--- a/libSBRdec/src/sbr_dec.cpp
+++ b/libSBRdec/src/sbr_dec.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -259,17 +259,18 @@
 
 void sbr_dec(
     HANDLE_SBR_DEC hSbrDec,             /*!< handle to Decoder channel */
-    INT_PCM *timeIn,                    /*!< pointer to input time signal */
-    INT_PCM *timeOut,                   /*!< pointer to output time signal */
+    LONG *timeIn,                       /*!< pointer to input time signal */
+    LONG *timeOut,                      /*!< pointer to output time signal */
     HANDLE_SBR_DEC hSbrDecRight,        /*!< handle to Decoder channel right */
-    INT_PCM *timeOutRight,              /*!< pointer to output time signal */
+    LONG *timeOutRight,                 /*!< pointer to output time signal */
     const int strideOut,                /*!< Time data traversal strideOut */
     HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
     HANDLE_SBR_FRAME_DATA hFrameData,   /*!< Control data of current frame */
     HANDLE_SBR_PREV_FRAME_DATA
         hPrevFrameData,        /*!< Some control data of last frame */
     const int applyProcessing, /*!< Flag for SBR operation */
-    HANDLE_PS_DEC h_ps_d, const UINT flags, const int codecFrameSize) {
+    HANDLE_PS_DEC h_ps_d, const UINT flags, const int codecFrameSize,
+    const INT sbrInDataHeadroom) {
   int i, slot, reserve;
   int saveLbScale;
   int lastSlotOffs;
@@ -278,7 +279,7 @@
   /* temporary pointer / variable for QMF;
      required as we want to use temporary buffer
      creating one frame delay for HBE in LP mode */
-  INT_PCM *pTimeInQmf = timeIn;
+  LONG *pTimeInQmf = timeIn;
 
   /* Number of QMF timeslots in the overlap buffer: */
   int ov_len = hSbrDec->LppTrans.pSettings->overlap;
@@ -341,8 +342,8 @@
   } else {
     C_AALLOC_SCRATCH_START(qmfTemp, FIXP_DBL, 2 * (64));
     qmfAnalysisFiltering(&hSbrDec->qmfDomainInCh->fb, pReal, pImag,
-                         &hSbrDec->qmfDomainInCh->scaling, pTimeInQmf, 0, 1,
-                         qmfTemp);
+                         &hSbrDec->qmfDomainInCh->scaling, pTimeInQmf,
+                         0 + sbrInDataHeadroom, 1, qmfTemp);
 
     C_AALLOC_SCRATCH_END(qmfTemp, FIXP_DBL, 2 * (64));
   }
@@ -658,7 +659,7 @@
 
   if (!(flags & SBRDEC_PS_DECODED)) {
     if (!(flags & SBRDEC_SKIP_QMF_SYN)) {
-      int outScalefactor = 0;
+      int outScalefactor = -(8);
 
       if (h_ps_d != NULL) {
         h_ps_d->procFrameBased = 1; /* we here do frame based processing */
@@ -743,6 +744,7 @@
       */
       FDK_ASSERT(hSbrDec->qmfDomainInCh->pGlobalConf->nBandsSynthesis <=
                  QMF_MAX_SYNTHESIS_BANDS);
+      qmfChangeOutScalefactor(synQmfRight, -(8));
       FDKmemcpy(synQmfRight->FilterStates, synQmf->FilterStates,
                 9 * hSbrDec->qmfDomainInCh->pGlobalConf->nBandsSynthesis *
                     sizeof(FIXP_QSS));
@@ -814,7 +816,8 @@
                   : scaleFactorLowBand_no_ov,
               scaleFactorHighBand, synQmf->lsb, synQmf->usb);
 
-          outScalefactorL = outScalefactorR = 1; /* psDiffScale! (MPEG-PS) */
+          outScalefactorL = outScalefactorR =
+              1 + sbrInDataHeadroom; /* psDiffScale! (MPEG-PS) */
         }
 
         sbrDecoder_drcApplySlot(/* right channel */
@@ -831,6 +834,9 @@
         outScalefactorL += maxShift;
 
         if (!(flags & SBRDEC_SKIP_QMF_SYN)) {
+          qmfChangeOutScalefactor(synQmf, -(8));
+          qmfChangeOutScalefactor(synQmfRight, -(8));
+
           qmfSynthesisFilteringSlot(
               synQmfRight, rQmfReal, /* QMF real buffer */
               rQmfImag,              /* QMF imag buffer */
diff --git a/libSBRdec/src/sbr_dec.h b/libSBRdec/src/sbr_dec.h
index 156da03..eb9c394 100644
--- a/libSBRdec/src/sbr_dec.h
+++ b/libSBRdec/src/sbr_dec.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -176,17 +176,18 @@
 
 void sbr_dec(
     HANDLE_SBR_DEC hSbrDec,             /*!< handle to Decoder channel */
-    INT_PCM *timeIn,                    /*!< pointer to input time signal */
-    INT_PCM *timeOut,                   /*!< pointer to output time signal */
+    LONG *timeIn,                       /*!< pointer to input time signal */
+    LONG *timeOut,                      /*!< pointer to output time signal */
     HANDLE_SBR_DEC hSbrDecRight,        /*!< handle to Decoder channel right */
-    INT_PCM *timeOutRight,              /*!< pointer to output time signal */
+    LONG *timeOutRight,                 /*!< pointer to output time signal */
     INT strideOut,                      /*!< Time data traversal strideOut */
     HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
     HANDLE_SBR_FRAME_DATA hFrameData,   /*!< Control data of current frame */
     HANDLE_SBR_PREV_FRAME_DATA
         hPrevFrameData,        /*!< Some control data of last frame */
     const int applyProcessing, /*!< Flag for SBR operation */
-    HANDLE_PS_DEC h_ps_d, const UINT flags, const int codecFrameSize);
+    HANDLE_PS_DEC h_ps_d, const UINT flags, const int codecFrameSize,
+    const INT sbrInDataHeadroom);
 
 SBR_ERROR
 createSbrDec(SBR_CHANNEL *hSbrChannel, HANDLE_SBR_HEADER_DATA hHeaderData,
diff --git a/libSBRdec/src/sbr_ram.cpp b/libSBRdec/src/sbr_ram.cpp
index 8b35fd2..a759d71 100644
--- a/libSBRdec/src/sbr_ram.cpp
+++ b/libSBRdec/src/sbr_ram.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -109,9 +109,6 @@
 
 #include "sbr_ram.h"
 
-#define WORKBUFFER1_TAG 2
-#define WORKBUFFER2_TAG 3
-
 /*!
   \name StaticSbrData
 
diff --git a/libSBRdec/src/sbr_ram.h b/libSBRdec/src/sbr_ram.h
index e00f8b5..452f835 100644
--- a/libSBRdec/src/sbr_ram.h
+++ b/libSBRdec/src/sbr_ram.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -170,6 +170,9 @@
                        flushed consecutively. */
 
   UINT flags;
+
+  INT sbrInDataHeadroom; /* Headroom of the SBR input time signal to prevent
+                            clipping */
 };
 
 H_ALLOC_MEM(Ram_SbrDecElement, SBR_DECODER_ELEMENT)
diff --git a/libSBRdec/src/sbrdec_freq_sca.cpp b/libSBRdec/src/sbrdec_freq_sca.cpp
index 165f94b..e187656 100644
--- a/libSBRdec/src/sbrdec_freq_sca.cpp
+++ b/libSBRdec/src/sbrdec_freq_sca.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -230,6 +230,8 @@
       }
     }
 
+    stopMin = fMin(stopMin, 64);
+
     /*
       Choose a stop band between k1 and 64 depending on stopFreq (0..13),
       based on a logarithmic scale.
@@ -523,7 +525,8 @@
       step = FL2FXCONST_DBL(0.0f);
     }
   }
-  return FX_DBL2FX_SGL(bandfactor << 1);
+  return (bandfactor >= FL2FXCONST_DBL(0.5)) ? (FIXP_SGL)MAXVAL_SGL
+                                             : FX_DBL2FX_SGL(bandfactor << 1);
 }
 
 /*!
diff --git a/libSBRdec/src/sbrdecoder.cpp b/libSBRdec/src/sbrdecoder.cpp
index 58ab9a3..55f929f 100644
--- a/libSBRdec/src/sbrdecoder.cpp
+++ b/libSBRdec/src/sbrdecoder.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -143,21 +143,19 @@
 #include "env_extr.h"
 #include "sbr_dec.h"
 #include "env_dec.h"
-#include "sbr_crc.h"
+#include "FDK_crc.h"
 #include "sbr_ram.h"
 #include "sbr_rom.h"
 #include "lpp_tran.h"
 #include "transcendent.h"
 
-#include "FDK_crc.h"
-
 #include "sbrdec_drc.h"
 
 #include "psbitdec.h"
 
 /* Decoder library info */
 #define SBRDECODER_LIB_VL0 3
-#define SBRDECODER_LIB_VL1 0
+#define SBRDECODER_LIB_VL1 1
 #define SBRDECODER_LIB_VL2 0
 #define SBRDECODER_LIB_TITLE "SBR Decoder"
 #ifdef __ANDROID__
@@ -1134,18 +1132,22 @@
   SBR_HEADER_STATUS headerStatus = HEADER_NOT_PRESENT;
 
   INT startPos = FDKgetValidBits(hBs);
-  INT CRCLen = 0;
+  FDK_CRCINFO crcInfo;
+  INT crcReg = 0;
+  USHORT sbrCrc = 0;
+  UINT crcPoly;
+  UINT crcStartValue = 0;
+  UINT crcLen;
+
   HANDLE_FDK_BITSTREAM hBsOriginal = hBs;
   FDK_BITSTREAM bsBwd;
 
-  FDK_CRCINFO crcInfo;
-  INT crcReg = 0;
-  USHORT drmSbrCrc = 0;
   const int fGlobalIndependencyFlag = acFlags & AC_INDEP;
   const int bs_pvc = acElFlags[elementIndex] & AC_EL_USAC_PVC;
   const int bs_interTes = acElFlags[elementIndex] & AC_EL_USAC_ITES;
   int stereo;
   int fDoDecodeSbrData = 1;
+  int alignBits = 0;
 
   int lastSlot, lastHdrSlot = 0, thisHdrSlot = 0;
 
@@ -1277,27 +1279,23 @@
   if (fDoDecodeSbrData) {
     if (crcFlag) {
       switch (self->coreCodec) {
-        case AOT_ER_AAC_ELD:
-          FDKpushFor(hBs, 10);
-          /* check sbrcrc later: we don't know the payload length now */
-          break;
         case AOT_DRM_AAC:
         case AOT_DRM_SURROUND:
-          drmSbrCrc = (USHORT)FDKreadBits(hBs, 8);
-          /* Setup CRC decoder */
-          FDKcrcInit(&crcInfo, 0x001d, 0xFFFF, 8);
-          /* Start CRC region */
-          crcReg = FDKcrcStartReg(&crcInfo, hBs, 0);
+          crcPoly = 0x001d;
+          crcLen = 8;
+          crcStartValue = 0x000000ff;
           break;
         default:
-          CRCLen = bsPayLen - 10; /* change: 0 => i */
-          if (CRCLen < 0) {
-            fDoDecodeSbrData = 0;
-          } else {
-            fDoDecodeSbrData = SbrCrcCheck(hBs, CRCLen);
-          }
+          crcPoly = 0x0633;
+          crcLen = 10;
+          crcStartValue = 0x00000000;
           break;
       }
+      sbrCrc = (USHORT)FDKreadBits(hBs, crcLen);
+      /* Setup CRC decoder */
+      FDKcrcInit(&crcInfo, crcPoly, crcStartValue, crcLen);
+      /* Start CRC region */
+      crcReg = FDKcrcStartReg(&crcInfo, hBs, 0);
     }
   } /* if (fDoDecodeSbrData) */
 
@@ -1450,35 +1448,6 @@
         valBits = (INT)FDKgetValidBits(hBs);
       }
 
-      if (crcFlag) {
-        switch (self->coreCodec) {
-          case AOT_ER_AAC_ELD: {
-            /* late crc check for eld */
-            INT payloadbits =
-                (INT)startPos - (INT)FDKgetValidBits(hBs) - startPos;
-            INT crcLen = payloadbits - 10;
-            FDKpushBack(hBs, payloadbits);
-            fDoDecodeSbrData = SbrCrcCheck(hBs, crcLen);
-            FDKpushFor(hBs, crcLen);
-          } break;
-          case AOT_DRM_AAC:
-          case AOT_DRM_SURROUND:
-            /* End CRC region */
-            FDKcrcEndReg(&crcInfo, hBs, crcReg);
-            /* Check CRC */
-            if ((FDKcrcGetCRC(&crcInfo) ^ 0xFF) != drmSbrCrc) {
-              fDoDecodeSbrData = 0;
-              if (headerStatus != HEADER_NOT_PRESENT) {
-                headerStatus = HEADER_ERROR;
-                hSbrHeader->syncState = SBR_NOT_INITIALIZED;
-              }
-            }
-            break;
-          default:
-            break;
-        }
-      }
-
       /* sanity check of remaining bits */
       if (valBits < 0) {
         fDoDecodeSbrData = 0;
@@ -1489,7 +1458,7 @@
           case AOT_AAC_LC: {
             /* This sanity check is only meaningful with General Audio
              * bitstreams */
-            int alignBits = valBits & 0x7;
+            alignBits = valBits & 0x7;
 
             if (valBits > alignBits) {
               fDoDecodeSbrData = 0;
@@ -1508,6 +1477,20 @@
     errorStatus = SBRDEC_PARSE_ERROR;
   }
 
+  if (crcFlag && (hSbrHeader->syncState >= SBR_HEADER) && fDoDecodeSbrData) {
+    FDKpushFor(hBs, alignBits);
+    FDKcrcEndReg(&crcInfo, hBs, crcReg); /* End CRC region */
+    FDKpushBack(hBs, alignBits);
+    /* Check CRC */
+    if ((FDKcrcGetCRC(&crcInfo) ^ crcStartValue) != sbrCrc) {
+      fDoDecodeSbrData = 0;
+      if (headerStatus != HEADER_NOT_PRESENT) {
+        headerStatus = HEADER_ERROR;
+        hSbrHeader->syncState = SBR_NOT_INITIALIZED;
+      }
+    }
+  }
+
   if (!fDoDecodeSbrData) {
     /* Set error flag for this slot to trigger concealment */
     setFrameErrorFlag(self->pSbrElement[elementIndex], FRAME_ERROR);
@@ -1587,10 +1570,10 @@
  * \return SBRDEC_OK if successfull, else error code
  */
 static SBR_ERROR sbrDecoder_DecodeElement(
-    HANDLE_SBRDECODER self, QDOM_PCM *input, INT_PCM *timeData,
-    const int timeDataSize, const FDK_channelMapDescr *const mapDescr,
-    const int mapIdx, int channelIndex, const int elementIndex,
-    const int numInChannels, int *numOutChannels, const int psPossible) {
+    HANDLE_SBRDECODER self, LONG *input, LONG *timeData, const int timeDataSize,
+    const FDK_channelMapDescr *const mapDescr, const int mapIdx,
+    int channelIndex, const int elementIndex, const int numInChannels,
+    int *numOutChannels, const int psPossible) {
   SBR_DECODER_ELEMENT *hSbrElement = self->pSbrElement[elementIndex];
   HANDLE_SBR_CHANNEL *pSbrChannel =
       self->pSbrElement[elementIndex]->pSbrChannel;
@@ -1760,7 +1743,7 @@
             timeData + offset1, strideOut, hSbrHeader, hFrameDataLeft,
             &pSbrChannel[0]->prevFrameData,
             (hSbrHeader->syncState == SBR_ACTIVE), h_ps_d, self->flags,
-            codecFrameSize);
+            codecFrameSize, self->sbrInDataHeadroom);
 
     if (stereo) {
       /* Process right channel */
@@ -1768,7 +1751,7 @@
               timeData + offset1, NULL, NULL, strideOut, hSbrHeader,
               hFrameDataRight, &pSbrChannel[1]->prevFrameData,
               (hSbrHeader->syncState == SBR_ACTIVE), NULL, self->flags,
-              codecFrameSize);
+              codecFrameSize, self->sbrInDataHeadroom);
     }
 
     C_ALLOC_SCRATCH_END(pPsScratch, struct PS_DEC_COEFFICIENTS, 1)
@@ -1788,14 +1771,14 @@
       int copyFrameSize =
           codecFrameSize * self->pQmfDomain->QmfDomainOut->fb.no_channels;
       copyFrameSize /= self->pQmfDomain->QmfDomainIn->fb.no_channels;
-      INT_PCM *ptr;
+      LONG *ptr;
       INT i;
       FDK_ASSERT(strideOut == 2);
 
       ptr = timeData;
       for (i = copyFrameSize >> 1; i--;) {
-        INT_PCM tmp; /* This temporal variable is required because some
-                        compilers can't do *ptr++ = *ptr++ correctly. */
+        LONG tmp; /* This temporal variable is required because some compilers
+                     can't do *ptr++ = *ptr++ correctly. */
         tmp = *ptr++;
         *ptr++ = tmp;
         tmp = *ptr++;
@@ -1808,12 +1791,13 @@
   return errorStatus;
 }
 
-SBR_ERROR sbrDecoder_Apply(HANDLE_SBRDECODER self, INT_PCM *input,
-                           INT_PCM *timeData, const int timeDataSize,
-                           int *numChannels, int *sampleRate,
+SBR_ERROR sbrDecoder_Apply(HANDLE_SBRDECODER self, LONG *input, LONG *timeData,
+                           const int timeDataSize, int *numChannels,
+                           int *sampleRate,
                            const FDK_channelMapDescr *const mapDescr,
                            const int mapIdx, const int coreDecodedOk,
-                           UCHAR *psDecoded) {
+                           UCHAR *psDecoded, const INT inDataHeadroom,
+                           INT *outDataHeadroom) {
   SBR_ERROR errorStatus = SBRDEC_OK;
 
   int psPossible;
@@ -1850,6 +1834,9 @@
     psPossible = 0;
   }
 
+  self->sbrInDataHeadroom = inDataHeadroom;
+  *outDataHeadroom = (INT)(8);
+
   /* Make sure that even if no SBR data was found/parsed *psDecoded is returned
    * 1 if psPossible was 0. */
   if (psPossible == 0) {