aboutsummaryrefslogtreecommitdiffstats
path: root/libSACdec/src/sac_stp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libSACdec/src/sac_stp.cpp')
-rw-r--r--libSACdec/src/sac_stp.cpp548
1 files changed, 548 insertions, 0 deletions
diff --git a/libSACdec/src/sac_stp.cpp b/libSACdec/src/sac_stp.cpp
new file mode 100644
index 0000000..818e9df
--- /dev/null
+++ b/libSACdec/src/sac_stp.cpp
@@ -0,0 +1,548 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/*********************** MPEG surround decoder library *************************
+
+ Author(s):
+
+ Description: SAC Dec subband processing
+
+*******************************************************************************/
+
+#include "sac_stp.h"
+#include "sac_calcM1andM2.h"
+#include "sac_bitdec.h"
+#include "FDK_matrixCalloc.h"
+#include "sac_rom.h"
+
+#define BP_GF_START 6
+#define BP_GF_SIZE 25
+#define HP_SIZE 9
+#define STP_UPDATE_ENERGY_RATE 32
+
+#define SF_WET 5
+#define SF_DRY \
+ 3 /* SF_DRY == 2 would produce good conformance test results as well */
+#define SF_PRODUCT_BP_GF 13
+#define SF_PRODUCT_BP_GF_GF 26
+#define SF_SCALE 2
+
+#define SF_SCALE_LD64 FL2FXCONST_DBL(0.03125) /* LD64((1<<SF_SCALE))*/
+#define STP_LPF_COEFF1__FDK FL2FXCONST_DBL(0.950f) /* 0.95 */
+#define ONE_MINUS_STP_LPF_COEFF1__FDK FL2FXCONST_DBL(0.05f) /* 1.0 - 0.95 */
+#define STP_LPF_COEFF2__FDK FL2FXCONST_DBL(0.450f) /* 0.45 */
+#define ONE_MINUS_STP_LPF_COEFF2__FDK \
+ FL2FXCONST_DBL(1.0f - 0.450f) /* 1.0 - 0.45 */
+#define STP_SCALE_LIMIT__FDK \
+ FL2FXCONST_DBL(2.82f / (float)(1 << SF_SCALE)) /* scaled by SF_SCALE */
+#define ONE_DIV_STP_SCALE_LIMIT__FDK \
+ FL2FXCONST_DBL(1.0f / 2.82f / (float)(1 << SF_SCALE)) /* scaled by SF_SCALE \
+ */
+#define ABS_THR__FDK \
+ FL2FXCONST_DBL(ABS_THR / \
+ ((float)(1 << (22 + 22 - 26)))) /* scaled by 18 bits */
+#define ABS_THR2__FDK \
+ FL2FXCONST_DBL(ABS_THR * 32.0f * 32.0f / \
+ ((float)(1 << (22 + 22 - 26)))) /* scaled by 10 bits */
+#define STP_SCALE_LIMIT_HI \
+ FL2FXCONST_DBL(3.02222222222 / (1 << SF_SCALE)) /* see 4. below */
+#define STP_SCALE_LIMIT_LO \
+ FL2FXCONST_DBL(0.28289992119 / (1 << SF_SCALE)) /* see 4. below */
+#define STP_SCALE_LIMIT_HI_LD64 \
+ FL2FXCONST_DBL(0.04986280452) /* see 4. below \
+ */
+#define STP_SCALE_LIMIT_LO_LD64 \
+ FL2FXCONST_DBL(0.05692613500) /* see 4. below \
+ */
+
+/* Scale factor calculation for the diffuse signal needs adapted thresholds
+ for STP_SCALE_LIMIT and 1/STP_SCALE_LIMIT:
+
+ 1. scale = sqrt(DryNrg/WetNrg)
+
+ 2. Damping of scale factor
+ scale2 = 0.1 + 0.9 * scale
+
+ 3. Limiting of scale factor
+ STP_SCALE_LIMIT >= scale2 >= 1/STP_SCALE_LIMIT
+ => STP_SCALE_LIMIT >= (0.1 + 0.9 * scale) >= 1/STP_SCALE_LIMIT
+ => (STP_SCALE_LIMIT-0.1)/0.9 >= scale >=
+ (1/STP_SCALE_LIMIT-0.1)/0.9
+
+ 3. Limiting of scale factor before sqrt calculation
+ ((STP_SCALE_LIMIT-0.1)/0.9)^2 >= (scale^2) >=
+ ((1/STP_SCALE_LIMIT-0.1)/0.9)^2 (STP_SCALE_LIMIT_HI)^2 >= (scale^2) >=
+ (STP_SCALE_LIMIT_LO)^2
+
+ 4. Thresholds for limiting of scale factor
+ STP_SCALE_LIMIT_HI = ((2.82-0.1)/0.9)
+ STP_SCALE_LIMIT_LO = (((1.0/2.82)-0.1)/0.9)
+ STP_SCALE_LIMIT_HI_LD64 = LD64(STP_SCALE_LIMIT_HI*STP_SCALE_LIMIT_HI)
+ 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; \
+ } else if (DryEnerLD64[dryIdx] < \
+ (WetEnerLD64[wetIdx] - STP_SCALE_LIMIT_LO_LD64)) { \
+ scale[wetIdx] = STP_SCALE_LIMIT_LO; \
+ } else { \
+ tmp = ((DryEnerLD64[dryIdx] - WetEnerLD64[wetIdx]) >> 1) - SF_SCALE_LD64; \
+ scale[wetIdx] = CalcInvLdData(tmp); \
+ }
+
+struct STP_DEC {
+ FIXP_DBL runDryEner[MAX_INPUT_CHANNELS];
+ FIXP_DBL runWetEner[MAX_OUTPUT_CHANNELS];
+ FIXP_DBL oldDryEnerLD64[MAX_INPUT_CHANNELS];
+ FIXP_DBL oldWetEnerLD64[MAX_OUTPUT_CHANNELS];
+ FIXP_DBL prev_tp_scale[MAX_OUTPUT_CHANNELS];
+ const FIXP_CFG *BP;
+ const FIXP_CFG *BP_GF;
+ 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,
+ FIXP_DBL *hybOutputImagWet, int bands) {
+ int n;
+
+ for (n = bands - 1; n >= 0; n--) {
+ *hybOutputRealDry = *hybOutputRealDry + *hybOutputRealWet;
+ *hybOutputImagDry = *hybOutputImagDry + *hybOutputImagWet;
+ hybOutputRealDry++, hybOutputRealWet++;
+ hybOutputImagDry++, hybOutputImagWet++;
+ }
+}
+
+inline void combineSignalCplxScale1(FIXP_DBL *hybOutputRealDry,
+ FIXP_DBL *hybOutputImagDry,
+ FIXP_DBL *hybOutputRealWet,
+ FIXP_DBL *hybOutputImagWet,
+ const FIXP_CFG *pBP, FIXP_DBL scaleX,
+ int bands) {
+ int n;
+ 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++, hybOutputRealWet++;
+ hybOutputImagDry++, hybOutputImagWet++;
+ pBP++;
+ }
+}
+
+inline void combineSignalCplxScale2(FIXP_DBL *hybOutputRealDry,
+ FIXP_DBL *hybOutputImagDry,
+ FIXP_DBL *hybOutputRealWet,
+ FIXP_DBL *hybOutputImagWet, FIXP_DBL scaleX,
+ int bands) {
+ int n;
+
+ for (n = bands - 1; n >= 0; n--) {
+ *hybOutputRealDry =
+ *hybOutputRealDry +
+ (fMultDiv2(*hybOutputRealWet, scaleX) << (SF_SCALE + 1));
+ *hybOutputImagDry =
+ *hybOutputImagDry +
+ (fMultDiv2(*hybOutputImagWet, scaleX) << (SF_SCALE + 1));
+ hybOutputRealDry++, hybOutputRealWet++;
+ hybOutputImagDry++, hybOutputImagWet++;
+ }
+}
+
+/*******************************************************************************
+ Functionname: subbandTPCreate
+ ******************************************************************************/
+SACDEC_ERROR subbandTPCreate(HANDLE_STP_DEC *hStpDec) {
+ HANDLE_STP_DEC self = NULL;
+ FDK_ALLOCATE_MEMORY_1D(self, 1, struct STP_DEC)
+ if (hStpDec != NULL) {
+ *hStpDec = self;
+ }
+
+ return MPS_OK;
+bail:
+ return MPS_OUTOFMEMORY;
+}
+
+SACDEC_ERROR subbandTPInit(HANDLE_STP_DEC self) {
+ SACDEC_ERROR err = MPS_OK;
+ int ch;
+
+ 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) */
+ }
+ for (ch = 0; ch < MAX_INPUT_CHANNELS; ch++) {
+ self->oldDryEnerLD64[ch] =
+ FL2FXCONST_DBL(0.1875f); /* 32768.0*32768.0/2^(44-26) */
+ }
+
+ self->BP = BP__FDK;
+ self->BP_GF = BP_GF__FDK;
+
+ self->update_old_ener = 0;
+
+ return err;
+}
+
+/*******************************************************************************
+ Functionname: subbandTPDestroy
+ ******************************************************************************/
+void subbandTPDestroy(HANDLE_STP_DEC *hStpDec) {
+ if (hStpDec != NULL) {
+ FDK_FREE_MEMORY_1D(*hStpDec);
+ }
+}
+
+/*******************************************************************************
+ Functionname: subbandTPApply
+ ******************************************************************************/
+SACDEC_ERROR subbandTPApply(spatialDec *self, const SPATIAL_BS_FRAME *frame) {
+ FIXP_DBL *qmfOutputRealDry[MAX_OUTPUT_CHANNELS];
+ FIXP_DBL *qmfOutputImagDry[MAX_OUTPUT_CHANNELS];
+ FIXP_DBL *qmfOutputRealWet[MAX_OUTPUT_CHANNELS];
+ FIXP_DBL *qmfOutputImagWet[MAX_OUTPUT_CHANNELS];
+
+ FIXP_DBL DryEner[MAX_INPUT_CHANNELS];
+ FIXP_DBL scale[MAX_OUTPUT_CHANNELS];
+
+ FIXP_DBL DryEnerLD64[MAX_INPUT_CHANNELS];
+ FIXP_DBL WetEnerLD64[MAX_OUTPUT_CHANNELS];
+
+ FIXP_DBL DryEner0 = FL2FXCONST_DBL(0.0f);
+ FIXP_DBL WetEnerX, damp, tmp;
+ FIXP_DBL dmxReal0, dmxImag0;
+ int skipChannels[MAX_OUTPUT_CHANNELS];
+ int n, ch, cplxBands, cplxHybBands;
+ int dry_scale_dmx, wet_scale_dmx;
+ int i_LF, i_RF;
+ HANDLE_STP_DEC hStpDec;
+ const FIXP_CFG *pBP;
+
+ int nrgScale = (2 * self->clipProtectGainSF__FDK);
+
+ hStpDec = self->hStpDec;
+
+ /* set scalefactor and loop counter */
+ FDK_ASSERT(SF_DRY >= 1);
+ {
+ cplxBands = BP_GF_SIZE;
+ cplxHybBands = self->hybridBands;
+ dry_scale_dmx = (2 * SF_DRY) - 2;
+ wet_scale_dmx = 2;
+ }
+
+ /* setup pointer for forming the direct downmix signal */
+ for (ch = 0; ch < self->numOutputChannels; ch++) {
+ qmfOutputRealDry[ch] = &self->hybOutputRealDry__FDK[ch][7];
+ qmfOutputRealWet[ch] = &self->hybOutputRealWet__FDK[ch][7];
+ qmfOutputImagDry[ch] = &self->hybOutputImagDry__FDK[ch][7];
+ qmfOutputImagWet[ch] = &self->hybOutputImagWet__FDK[ch][7];
+ }
+
+ /* clear skipping flag for all output channels */
+ FDKmemset(skipChannels, 0, self->numOutputChannels * sizeof(int));
+
+ /* set scale values to zero */
+ FDKmemset(scale, 0, self->numOutputChannels * sizeof(FIXP_DBL));
+
+ /* update normalisation energy with latest smoothed energy */
+ if (hStpDec->update_old_ener == STP_UPDATE_ENERGY_RATE) {
+ hStpDec->update_old_ener = 1;
+ for (ch = 0; ch < self->numInputChannels; ch++) {
+ hStpDec->oldDryEnerLD64[ch] =
+ CalcLdData(hStpDec->runDryEner[ch] + ABS_THR__FDK);
+ }
+ for (ch = 0; ch < self->numOutputChannels; ch++) {
+ hStpDec->oldWetEnerLD64[ch] =
+ CalcLdData(hStpDec->runWetEner[ch] + ABS_THR2__FDK);
+ }
+ } else {
+ hStpDec->update_old_ener++;
+ }
+
+ /* get channel configuration */
+ switch (self->treeConfig) {
+ case TREE_212:
+ i_LF = 0;
+ i_RF = 1;
+ break;
+ default:
+ return MPS_WRONG_TREECONFIG;
+ }
+
+ /* form the 'direct' downmix signal */
+ pBP = hStpDec->BP_GF - BP_GF_START;
+ switch (self->treeConfig) {
+ case TREE_212:
+ 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);
+ }
+ DRY_ENER_WEIGHT(DryEner0);
+ break;
+ default:;
+ }
+ DryEner[0] = DryEner0;
+
+ /* normalise the 'direct' signals */
+ for (ch = 0; ch < self->numInputChannels; ch++) {
+ 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]);
+ if (DryEner[ch] != FL2FXCONST_DBL(0.0f)) {
+ DryEnerLD64[ch] =
+ fixMax((CalcLdData(DryEner[ch]) - hStpDec->oldDryEnerLD64[ch]),
+ FL2FXCONST_DBL(-0.484375f));
+ } else {
+ DryEnerLD64[ch] = FL2FXCONST_DBL(-0.484375f);
+ }
+ }
+ if (self->treeConfig == TREE_212) {
+ for (; ch < MAX_INPUT_CHANNELS; ch++) {
+ DryEnerLD64[ch] = FL2FXCONST_DBL(-0.484375f);
+ }
+ }
+
+ /* normalise the 'diffuse' signals */
+ pBP = hStpDec->BP_GF - BP_GF_START;
+ for (ch = 0; ch < self->numOutputChannels; ch++) {
+ if (skipChannels[ch]) {
+ continue;
+ }
+
+ 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);
+ hStpDec->runWetEner[ch] =
+ fMult(STP_LPF_COEFF1__FDK, hStpDec->runWetEner[ch]) +
+ fMult(ONE_MINUS_STP_LPF_COEFF1__FDK, WetEnerX);
+
+ if (WetEnerX == FL2FXCONST_DBL(0.0f)) {
+ WetEnerLD64[ch] = FL2FXCONST_DBL(-0.484375f);
+ } else {
+ WetEnerLD64[ch] =
+ fixMax((CalcLdData(WetEnerX) - hStpDec->oldWetEnerLD64[ch]),
+ FL2FXCONST_DBL(-0.484375f));
+ }
+ }
+
+ /* compute scale factor for the 'diffuse' signals */
+ switch (self->treeConfig) {
+ case TREE_212:
+ if (DryEner[0] != FL2FXCONST_DBL(0.0f)) {
+ CALC_WET_SCALE(0, i_LF);
+ CALC_WET_SCALE(0, i_RF);
+ }
+ break;
+ default:;
+ }
+
+ damp = FL2FXCONST_DBL(0.1f / (1 << SF_SCALE));
+ for (ch = 0; ch < self->numOutputChannels; ch++) {
+ /* damp the scaling factor */
+ scale[ch] = damp + fMult(FL2FXCONST_DBL(0.9f), scale[ch]);
+
+ /* limiting the scale factor */
+ if (scale[ch] > STP_SCALE_LIMIT__FDK) {
+ scale[ch] = STP_SCALE_LIMIT__FDK;
+ }
+ if (scale[ch] < ONE_DIV_STP_SCALE_LIMIT__FDK) {
+ scale[ch] = ONE_DIV_STP_SCALE_LIMIT__FDK;
+ }
+
+ /* low pass filter the scaling factor */
+ scale[ch] =
+ fMult(STP_LPF_COEFF2__FDK, scale[ch]) +
+ fMult(ONE_MINUS_STP_LPF_COEFF2__FDK, hStpDec->prev_tp_scale[ch]);
+ hStpDec->prev_tp_scale[ch] = scale[ch];
+ }
+
+ /* combine 'direct' and scaled 'diffuse' signal */
+ FDK_ASSERT((HP_SIZE - 3 + 10 - 1) == PC_NUM_HYB_BANDS);
+ const SCHAR *channlIndex = row2channelSTP[self->treeConfig];
+
+ for (ch = 0; ch < self->numOutputChannels; ch++) {
+ int no_scaling;
+
+ no_scaling = !frame->tempShapeEnableChannelSTP[channlIndex[ch]];
+ if (no_scaling) {
+ combineSignalCplx(
+ &self->hybOutputRealDry__FDK[ch][self->tp_hybBandBorder],
+ &self->hybOutputImagDry__FDK[ch][self->tp_hybBandBorder],
+ &self->hybOutputRealWet__FDK[ch][self->tp_hybBandBorder],
+ &self->hybOutputImagWet__FDK[ch][self->tp_hybBandBorder],
+ cplxHybBands - self->tp_hybBandBorder);
+
+ } else {
+ FIXP_DBL scaleX;
+ scaleX = scale[ch];
+ pBP = hStpDec->BP - self->tp_hybBandBorder;
+ /* Band[HP_SIZE-3+10-1] needs not to be processed in
+ combineSignalCplxScale1(), because pB[HP_SIZE-3+10-1] would be 1.0 */
+ combineSignalCplxScale1(
+ &self->hybOutputRealDry__FDK[ch][self->tp_hybBandBorder],
+ &self->hybOutputImagDry__FDK[ch][self->tp_hybBandBorder],
+ &self->hybOutputRealWet__FDK[ch][self->tp_hybBandBorder],
+ &self->hybOutputImagWet__FDK[ch][self->tp_hybBandBorder],
+ &pBP[self->tp_hybBandBorder], scaleX,
+ (HP_SIZE - 3 + 10 - 1) - self->tp_hybBandBorder);
+
+ {
+ combineSignalCplxScale2(
+ &self->hybOutputRealDry__FDK[ch][HP_SIZE - 3 + 10 - 1],
+ &self->hybOutputImagDry__FDK[ch][HP_SIZE - 3 + 10 - 1],
+ &self->hybOutputRealWet__FDK[ch][HP_SIZE - 3 + 10 - 1],
+ &self->hybOutputImagWet__FDK[ch][HP_SIZE - 3 + 10 - 1], scaleX,
+ cplxHybBands - (HP_SIZE - 3 + 10 - 1));
+ }
+ }
+ }
+
+ return (SACDEC_ERROR)MPS_OK;
+ ;
+}