Ejemplo n.º 1
0
SCALE_INLINE
void scaleValuesWithFactor(
        FIXP_DBL *vector,
        FIXP_DBL factor,
        INT len,
        INT scalefactor
        )
{
  /* This code combines the fMult with the scaling             */
  /* It performs a fMultDiv2 and increments shift by 1         */
  int shift = scalefactor + 1;
  FIXP_DBL *mySpec = vector;

  shift = fixmin_I(shift,(INT)DFRACT_BITS-1);

  if (shift >= 0)
  {
    for (int i=0; i<(len>>2); i++)
    {
      FIXP_DBL tmp0 = mySpec[0];
      FIXP_DBL tmp1 = mySpec[1];
      FIXP_DBL tmp2 = mySpec[2];
      FIXP_DBL tmp3 = mySpec[3];
      tmp0 = fMultDiv2(tmp0, factor);
      tmp1 = fMultDiv2(tmp1, factor);
      tmp2 = fMultDiv2(tmp2, factor);
      tmp3 = fMultDiv2(tmp3, factor);
      tmp0 <<= shift;
      tmp1 <<= shift;
      tmp2 <<= shift;
      tmp3 <<= shift;
      *mySpec++ = tmp0;
      *mySpec++ = tmp1;
      *mySpec++ = tmp2;
      *mySpec++ = tmp3;
    }
    for (int i=len&3; i--;)
    {
      FIXP_DBL tmp0 = mySpec[0];
      tmp0 = fMultDiv2(tmp0, factor);
      tmp0 <<= shift;
      *mySpec++ = tmp0;
    }
  }
  else
  {
Ejemplo n.º 2
0
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++;
  }
}
Ejemplo n.º 3
0
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++;
  }
}
Ejemplo n.º 4
0
void Pred_lt4_postfilter(FIXP_DBL exc[] /* in/out: excitation buffer */
) {
  /*
  exc[i]   = A*exc[i-1] + B*exc[i] + A*exc[i+1]
  exc[i+1] =              A*exc[i] + B*exc[i+1] + A*exc[i+2] ; i = 0:2:62
  */
  int i;
  FIXP_DBL sum0, sum1, a_exc0, a_exc1;
  a_exc0 = fMultDiv2(A2, exc[-1]);
  a_exc1 = fMultDiv2(A2, exc[0]);

  /* ARM926: 22 cycles/iteration */
  for (i = 0; i < L_SUBFR; i += 2) {
    sum0 = a_exc0 + fMult(B, exc[i]);
    sum1 = a_exc1 + fMult(B, exc[i + 1]);
    a_exc0 = fMultDiv2(A2, exc[i + 1]);
    a_exc1 = fMultDiv2(A2, exc[i + 2]);
    exc[i] = sum0 + a_exc0;
    exc[i + 1] = sum1 + a_exc1;
  }
  return;
}
Ejemplo n.º 5
0
FDK_INLINE
/* __attribute__((noinline)) */
static void dct_IV_func2(
    int i,
    const FIXP_SPK *twiddle,
    FIXP_DBL *pDat_0,
    FIXP_DBL *pDat_1,
    int inc)
{
  FIXP_DBL accu1, accu2, accu3, accu4, accuX;
  LONG val_tw;

  accu1 = pDat_1[-2];
  accu2 = pDat_1[-1];

  *--pDat_1 = -(pDat_0[1]>>1);
  *pDat_0++ = (pDat_0[0]>>1);

  twiddle += inc;

__asm
  {
    LDR     val_tw, [twiddle], inc, LSL #2    // val_tw = *twiddle; twiddle += inc
    B       dct_IV_loop2_2nd_part

    /* 42 cycles for 2 iterations = 21 cycles/iteration */
dct_IV_loop2:
    SMULWT  accuX, accu2, val_tw
    SMULWB  accu2, accu2, val_tw
    RSB     accuX, accuX, #0
    SMLAWB  accuX, accu1, val_tw, accuX
    SMLAWT  accu2, accu1, val_tw, accu2
    STR     accuX, [pDat_0], #4
    STR     accu2, [pDat_1, #-4] !

    LDR     accu4, [pDat_0, #4]
    LDR     accu3, [pDat_0]
    SMULWB  accuX, accu4, val_tw
    SMULWT  accu4, accu4, val_tw
    RSB     accuX, accuX, #0
    SMLAWT  accuX, accu3, val_tw, accuX
    SMLAWB  accu4, accu3, val_tw, accu4

    LDR     accu1, [pDat_1, #-8]
    LDR     accu2, [pDat_1, #-4]

    LDR     val_tw, [twiddle], inc, LSL #2    // val_tw = *twiddle; twiddle += inc

    STR     accuX, [pDat_1, #-4] !
    STR     accu4, [pDat_0], #4

dct_IV_loop2_2nd_part:
    SMULWT  accuX, accu2, val_tw
    SMULWB  accu2, accu2, val_tw
    RSB     accuX, accuX, #0
    SMLAWB  accuX, accu1, val_tw, accuX
    SMLAWT  accu2, accu1, val_tw, accu2
    STR     accuX, [pDat_0], #4
    STR     accu2, [pDat_1, #-4] !

    LDR     accu4, [pDat_0, #4]
    LDR     accu3, [pDat_0]
    SMULWB  accuX, accu4, val_tw
    SMULWT  accu4, accu4, val_tw
    RSB     accuX, accuX, #0
    SMLAWT  accuX, accu3, val_tw, accuX
    SMLAWB  accu4, accu3, val_tw, accu4

    LDR     accu1, [pDat_1, #-8]
    LDR     accu2, [pDat_1, #-4]

    STR     accuX, [pDat_1, #-4] !
    STR     accu4, [pDat_0], #4

    LDR     val_tw, [twiddle], inc, LSL #2    // val_tw = *twiddle; twiddle += inc

    SUBS    i, i, #1
    BNE     dct_IV_loop2
  }

  /* Last Sin and Cos value pair are the same */
  accu1 = fMultDiv2(accu1, WTC(0x5a82799a));
  accu2 = fMultDiv2(accu2, WTC(0x5a82799a));

  *--pDat_1 = accu1 + accu2;
  *pDat_0++ = accu1 - accu2;
}
Ejemplo n.º 6
0
  	LDR     accu4, [pDat_0]                   // accu4 = pDat_0[0]
  	LDR     accu3, [pDat_0, #4]               // accu3 = pDat_0[1]

    RSB     accu4, accu4, #0                  // accu4 = -accu4
    RSB     accu3, accu3, #0                  // accu3 = -accu3

    SMULWB  accu1, accu3, val_tw              // accu1 = (-accu3)*val_tw.h
    SMULWT  accu2, accu3, val_tw              // accu2 = (-accu3)*val_tw.l
    RSB     accu1, accu1, #0                  // accu1 = -(-accu3)*val_tw.h
    SMLAWT  accu3, accu4, val_tw, accu1       // accu3 = (-accu4)*val_tw.l-(-accu3)*val_tw.h
    SMLAWB  accu4, accu4, val_tw, accu2       // accu4 = (-accu3)*val_tw.l+(-accu4)*val_tw.h

    LDR     accu1, [pDat_1, #-4]              // accu1 = pDat_1[-1]
    LDR     accu2, [pDat_1]                   // accu2 = pDat_1[0]

    STR     accu3, [pDat_0], #4               // *pDat_0++ = accu3
    STR     accu4, [pDat_1], #-4              // *pDat_1-- = accu4

    SUBS    i, i, #1
    BNE     dst_IV_loop2
  }

  /* Last Sin and Cos value pair are the same */
  accu1 = fMultDiv2(-accu1, WTC(0x5a82799a));
  accu2 = fMultDiv2(-accu2, WTC(0x5a82799a));

  *pDat_0 = accu1 + accu2;
  *pDat_1 = accu1 - accu2;
}
#endif /* FUNCTION_dst_IV_func2 */
Ejemplo n.º 7
0
void pvcDecodeTimeSlot(PVC_STATIC_DATA *pPvcStaticData,
                       PVC_DYNAMIC_DATA *pPvcDynamicData,
                       FIXP_DBL **qmfSlotReal, FIXP_DBL **qmfSlotImag,
                       const int qmfExponent, const int pvcBorder0,
                       const int timeSlotNumber, FIXP_DBL predictedEsgSlot[],
                       int *predictedEsg_exp) {
  int i, band, ksg, ksg_start = 0;
  int RATE = pPvcDynamicData->RATE;
  int Esg_index = pPvcStaticData->Esg_slot_index;
  const SCHAR *sg_borders = pPvcDynamicData->sg_offset_low;
  FIXP_DBL *pEsg = pPvcStaticData->Esg[Esg_index];
  FIXP_DBL E[PVC_NBLOW] = {0};

  /* Subband grouping in QMF subbands below SBR range */
  /* Within one timeslot ( i = [0...(RATE-1)] QMF subsamples) calculate energy
     E(ib,t) and group them to Esg(ksg,t). Then transfer values to logarithmical
     domain and store them for time domain smoothing. (7.5.6.3 Subband grouping
     in QMF subbands below SBR range)
  */
  for (ksg = 0; sg_borders[ksg] < 0; ksg++) {
    pEsg[ksg] = FL2FXCONST_DBL(-10.0 / (1 << PVC_ESG_EXP)); /* 10*log10(0.1) */
    ksg_start++;
  }

  for (i = 0; i < RATE; i++) {
    FIXP_DBL *qmfR, *qmfI;
    qmfR = qmfSlotReal[i];
    qmfI = qmfSlotImag[i];
    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;
      }
    }
  }
  for (ksg = ksg_start; ksg < PVC_NBLOW; ksg++) {
    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);
      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)));
    } else {
      pEsg[ksg] =
          FL2FXCONST_DBL(-10.0 / (1 << PVC_ESG_EXP)); /* 10*log10(0.1) */
    }
  }

  /* Time domain smoothing of subband-grouped energy */
  {
    int idx = pPvcStaticData->Esg_slot_index;
    FIXP_DBL *pEsg_filt;
    FIXP_SGL SCcoeff;

    E[0] = E[1] = E[2] = (FIXP_DBL)0;
    for (i = 0; i < pPvcDynamicData->ns; i++) {
      SCcoeff = pPvcDynamicData->pSCcoeffs[i];
      pEsg_filt = pPvcStaticData->Esg[idx];
      /* Div2 is compensated by scaling of coeff table */
      E[0] = fMultAddDiv2(E[0], pEsg_filt[0], SCcoeff);
      E[1] = fMultAddDiv2(E[1], pEsg_filt[1], SCcoeff);
      E[2] = fMultAddDiv2(E[2], pEsg_filt[2], SCcoeff);
      if (i >= pPvcDynamicData->pastEsgSlotsAvail) {
        /* if past Esg values are not available use the ones from the last valid
         * slot */
        continue;
      }
      if (idx > 0) {
        idx--;
      } else {
        idx += PVC_NS_MAX - 1;
      }
    }
  }

  /* SBR envelope scalefactor prediction */
  {
    int E_high_exp[PVC_NBHIGH_MAX];
    int E_high_exp_max = 0;
    int pvcTab1ID;
    int pvcTab2ID = (int)pPvcDynamicData->pPvcID[timeSlotNumber];
    const UCHAR *pTab1, *pTab2;
    if (pvcTab2ID < pPvcDynamicData->pPVCTab1_dp[0]) {
      pvcTab1ID = 0;
    } else if (pvcTab2ID < pPvcDynamicData->pPVCTab1_dp[1]) {
      pvcTab1ID = 1;
    } else {
      pvcTab1ID = 2;
    }
    pTab1 = &(pPvcDynamicData
                  ->pPVCTab1[pvcTab1ID * PVC_NBLOW * pPvcDynamicData->nbHigh]);
    pTab2 = &(pPvcDynamicData->pPVCTab2[pvcTab2ID * pPvcDynamicData->nbHigh]);
    for (ksg = 0; ksg < pPvcDynamicData->nbHigh; ksg++) {
      FIXP_SGL predCoeff;
      FIXP_DBL accu;
      int predCoeff_exp, kb;
      E_high_exp[ksg] = 0;

      /* residual part */
      accu = ((LONG)(SCHAR)*pTab2++) << (DFRACT_BITS - 8 - PVC_ESG_EXP +
                                         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;
      }
      /* 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 */
      predictedEsgSlot[ksg] = accu;
      E_high_exp[ksg] = predCoeff_exp;
      if (predCoeff_exp > E_high_exp_max) {
        E_high_exp_max = predCoeff_exp;
      }
    }

    /* 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);
    }
    *predictedEsg_exp = E_high_exp_max;
  }

  pPvcStaticData->Esg_slot_index =
      (pPvcStaticData->Esg_slot_index + 1) & (PVC_NS_MAX - 1);
  pPvcDynamicData->pastEsgSlotsAvail =
      fMin(pPvcDynamicData->pastEsgSlotsAvail + 1, PVC_NS_MAX - 1);
  return;
}
static INVF_MODE
decisionAlgorithm(const DETECTOR_PARAMETERS *detectorParams,     /*!< Struct with the detector parameters. */
                  DETECTOR_VALUES *detectorValues,               /*!< Struct with the detector values. */
                  INT transientFlag,                             /*!< Flag indicating if there is a transient present.*/
                  INT* prevRegionSbr,                            /*!< The previous region in which the Sbr value was. */
                  INT* prevRegionOrig                            /*!< The previous region in which the Orig value was. */
                  )
{
  INT invFiltLevel, regionSbr, regionOrig, regionNrg;

  /*
   Current thresholds.
   */
  const FIXP_DBL *quantStepsSbr  = detectorParams->quantStepsSbr;
  const FIXP_DBL *quantStepsOrig = detectorParams->quantStepsOrig;
  const FIXP_DBL *nrgBorders     = detectorParams->nrgBorders;
  const INT numRegionsSbr     = detectorParams->numRegionsSbr;
  const INT numRegionsOrig    = detectorParams->numRegionsOrig;
  const INT numRegionsNrg     = detectorParams->numRegionsNrg;

  FIXP_DBL quantStepsSbrTmp[MAX_NUM_REGIONS];
  FIXP_DBL quantStepsOrigTmp[MAX_NUM_REGIONS];

  /*
   Current detector values.
   */
  FIXP_DBL origQuotaMeanFilt;
  FIXP_DBL sbrQuotaMeanFilt;
  FIXP_DBL nrg;

  /* 0.375 = 3.0 / 8.0; 0.31143075889 = log2(RELAXATION)/64.0; 0.625 = log(16)/64.0; 0.6875 = 44/64.0 */
  origQuotaMeanFilt = (fMultDiv2(FL2FXCONST_DBL(2.f*0.375f), (FIXP_DBL)(CalcLdData(max(detectorValues->origQuotaMeanFilt,(FIXP_DBL)1)) + FL2FXCONST_DBL(0.31143075889f)))) << 0;  /* scaled by 1/2^9 */
  sbrQuotaMeanFilt  = (fMultDiv2(FL2FXCONST_DBL(2.f*0.375f), (FIXP_DBL)(CalcLdData(max(detectorValues->sbrQuotaMeanFilt,(FIXP_DBL)1)) + FL2FXCONST_DBL(0.31143075889f)))) << 0;   /* scaled by 1/2^9 */
  /* If energy is zero then we will get different results for different word lengths. */
  nrg               = (fMultDiv2(FL2FXCONST_DBL(2.f*0.375f), (FIXP_DBL)(CalcLdData(detectorValues->avgNrg+(FIXP_DBL)1) + FL2FXCONST_DBL(0.0625f) + FL2FXCONST_DBL(0.6875f)))) << 0;     /* scaled by 1/2^8; 2^44 -> qmf energy scale */

  FDKmemcpy(quantStepsSbrTmp,quantStepsSbr,numRegionsSbr*sizeof(FIXP_DBL));
  FDKmemcpy(quantStepsOrigTmp,quantStepsOrig,numRegionsOrig*sizeof(FIXP_DBL));

  if(*prevRegionSbr < numRegionsSbr)
    quantStepsSbrTmp[*prevRegionSbr] = quantStepsSbr[*prevRegionSbr] + hysteresis;
  if(*prevRegionSbr > 0)
    quantStepsSbrTmp[*prevRegionSbr - 1] = quantStepsSbr[*prevRegionSbr - 1] - hysteresis;

  if(*prevRegionOrig < numRegionsOrig)
    quantStepsOrigTmp[*prevRegionOrig] = quantStepsOrig[*prevRegionOrig] + hysteresis;
  if(*prevRegionOrig > 0)
    quantStepsOrigTmp[*prevRegionOrig - 1] = quantStepsOrig[*prevRegionOrig - 1] - hysteresis;

  regionSbr  = findRegion(sbrQuotaMeanFilt, quantStepsSbrTmp, numRegionsSbr);
  regionOrig = findRegion(origQuotaMeanFilt, quantStepsOrigTmp, numRegionsOrig);
  regionNrg  = findRegion(nrg,nrgBorders,numRegionsNrg);

  *prevRegionSbr = regionSbr;
  *prevRegionOrig = regionOrig;

  /* Use different settings if a transient is present*/
  invFiltLevel = (transientFlag == 1) ? detectorParams->regionSpaceTransient[regionSbr][regionOrig]
                                      : detectorParams->regionSpace[regionSbr][regionOrig];

  /* Compensate for low energy.*/
  invFiltLevel = max(invFiltLevel + detectorParams->EnergyCompFactor[regionNrg],0);

  return (INVF_MODE) (invFiltLevel);
}
static void
calculateDetectorValues(FIXP_DBL **quotaMatrixOrig,       /*!< Matrix holding the tonality values of the original. */
                        SCHAR    *indexVector,            /*!< Index vector to obtain the patched data. */
                        FIXP_DBL *nrgVector,              /*!< Energy vector. */
                        DETECTOR_VALUES *detectorValues,  /*!< pointer to DETECTOR_VALUES struct. */
                        INT startChannel,                 /*!< Start channel. */
                        INT stopChannel,                  /*!< Stop channel. */
                        INT startIndex,                   /*!< Start index. */
                        INT stopIndex,                    /*!< Stop index. */
                        INT numberOfStrongest             /*!< The number of sorted tonal components to be considered. */
                        )
{
  INT i,temp, j;

  const FIXP_DBL* filter = *fir_table[INVF_SMOOTHING_LENGTH];
  FIXP_DBL origQuotaMeanStrongest, sbrQuotaMeanStrongest;
  FIXP_DBL origQuota, sbrQuota;
  FIXP_DBL invIndex, invChannel, invTemp;
  FIXP_DBL quotaVecOrig[64], quotaVecSbr[64];

  FDKmemclear(quotaVecOrig,64*sizeof(FIXP_DBL));
  FDKmemclear(quotaVecSbr,64*sizeof(FIXP_DBL));

  invIndex = GetInvInt(stopIndex-startIndex);
  invChannel = GetInvInt(stopChannel-startChannel);

  /*
   Calculate the mean value, over the current time segment, for the original, the HFR
   and the difference, over all channels in the current frequency range.
   NOTE: the averaging is done on the values quota/(1 - quota + RELAXATION).
   */

  /* The original, the sbr signal and the total energy */
  detectorValues->avgNrg = FL2FXCONST_DBL(0.0f);
  for(j=startIndex; j<stopIndex; j++) {
    for(i=startChannel; i<stopChannel; i++) {
      quotaVecOrig[i] += fMult(quotaMatrixOrig[j][i], invIndex);

      if(indexVector[i] != -1)
        quotaVecSbr[i] += fMult(quotaMatrixOrig[j][indexVector[i]], invIndex);
    }
    detectorValues->avgNrg += fMult(nrgVector[j], invIndex);
  }

  /*
   Calculate the mean value, over the current frequency range, for the original, the HFR
   and the difference. Also calculate the same mean values for the three vectors, but only
   includeing the x strongest copmponents.
   */

  origQuota = FL2FXCONST_DBL(0.0f);
  sbrQuota  = FL2FXCONST_DBL(0.0f);
  for(i=startChannel; i<stopChannel; i++) {
    origQuota += fMultDiv2(quotaVecOrig[i], invChannel);
    sbrQuota  += fMultDiv2(quotaVecSbr[i], invChannel);
  }

  /*
   Calculate the mean value for the x strongest components
  */
  FDKsbrEnc_Shellsort_fract(quotaVecOrig+startChannel,stopChannel-startChannel);
  FDKsbrEnc_Shellsort_fract(quotaVecSbr+startChannel,stopChannel-startChannel);

  origQuotaMeanStrongest = FL2FXCONST_DBL(0.0f);
  sbrQuotaMeanStrongest  = FL2FXCONST_DBL(0.0f);

  temp = min(stopChannel - startChannel, numberOfStrongest);
  invTemp = GetInvInt(temp);

  for(i=0; i<temp; i++) {
    origQuotaMeanStrongest += fMultDiv2(quotaVecOrig[i + stopChannel - temp], invTemp);
    sbrQuotaMeanStrongest  += fMultDiv2(quotaVecSbr[i + stopChannel - temp], invTemp);
  }

  /*
   The value for the strongest component
  */
  detectorValues->origQuotaMax = quotaVecOrig[stopChannel - 1];
  detectorValues->sbrQuotaMax  = quotaVecSbr[stopChannel - 1];

  /*
   Buffer values
  */
  FDKmemmove(detectorValues->origQuotaMean, detectorValues->origQuotaMean + 1, INVF_SMOOTHING_LENGTH*sizeof(FIXP_DBL));
  FDKmemmove(detectorValues->sbrQuotaMean, detectorValues->sbrQuotaMean + 1, INVF_SMOOTHING_LENGTH*sizeof(FIXP_DBL));
  FDKmemmove(detectorValues->origQuotaMeanStrongest, detectorValues->origQuotaMeanStrongest + 1, INVF_SMOOTHING_LENGTH*sizeof(FIXP_DBL));
  FDKmemmove(detectorValues->sbrQuotaMeanStrongest, detectorValues->sbrQuotaMeanStrongest + 1, INVF_SMOOTHING_LENGTH*sizeof(FIXP_DBL));

  detectorValues->origQuotaMean[INVF_SMOOTHING_LENGTH]          = origQuota<<1;
  detectorValues->sbrQuotaMean[INVF_SMOOTHING_LENGTH]           = sbrQuota<<1;
  detectorValues->origQuotaMeanStrongest[INVF_SMOOTHING_LENGTH] = origQuotaMeanStrongest<<1;
  detectorValues->sbrQuotaMeanStrongest[INVF_SMOOTHING_LENGTH]  = sbrQuotaMeanStrongest<<1;

  /*
   Filter values
  */
  detectorValues->origQuotaMeanFilt = FL2FXCONST_DBL(0.0f);
  detectorValues->sbrQuotaMeanFilt = FL2FXCONST_DBL(0.0f);
  detectorValues->origQuotaMeanStrongestFilt = FL2FXCONST_DBL(0.0f);
  detectorValues->sbrQuotaMeanStrongestFilt = FL2FXCONST_DBL(0.0f);

  for(i=0;i<INVF_SMOOTHING_LENGTH+1;i++) {
    detectorValues->origQuotaMeanFilt += fMult(detectorValues->origQuotaMean[i], filter[i]);
    detectorValues->sbrQuotaMeanFilt  += fMult(detectorValues->sbrQuotaMean[i], filter[i]);
    detectorValues->origQuotaMeanStrongestFilt += fMult(detectorValues->origQuotaMeanStrongest[i], filter[i]);
    detectorValues->sbrQuotaMeanStrongestFilt  += fMult(detectorValues->sbrQuotaMeanStrongest[i], filter[i]);
  }
}
Ejemplo n.º 10
0
INT CLpd_FAC_Acelp2Mdct(H_MDCT hMdct, FIXP_DBL *output, FIXP_DBL *_pSpec,
                        const SHORT spec_scale[], const int nSpec,
                        FIXP_DBL *pFac, const int fac_scale,
                        const INT fac_length, INT noOutSamples, const INT tl,
                        const FIXP_WTP *wrs, const INT fr, FIXP_LPC A[16],
                        INT A_exp, CAcelpStaticMem *acelp_mem,
                        const FIXP_DBL gain, const int last_frame_lost,
                        const int isFdFac, const UCHAR last_lpd_mode,
                        const int k, int currAliasingSymmetry) {
  FIXP_DBL *pCurr, *pOvl, *pSpec;
  const FIXP_WTP *pWindow;
  const FIXP_WTB *FacWindowZir_conceal;
  UCHAR doFacZirConceal = 0;
  int doDeemph = 1;
  const FIXP_WTB *FacWindowZir, *FacWindowSynth;
  FIXP_DBL *pOut0 = output, *pOut1;
  int w, i, fl, nl, nr, f_len, nrSamples = 0, s = 0, scale, total_gain_e;
  FIXP_DBL *pF, *pFAC_and_FAC_ZIR = NULL;
  FIXP_DBL total_gain = gain;

  FDK_ASSERT(fac_length <= 1024 / (4 * 2));
  switch (fac_length) {
    /* coreCoderFrameLength = 1024 */
    case 128:
      pWindow = SineWindow256;
      FacWindowZir = FacWindowZir128;
      FacWindowSynth = FacWindowSynth128;
      break;
    case 64:
      pWindow = SineWindow128;
      FacWindowZir = FacWindowZir64;
      FacWindowSynth = FacWindowSynth64;
      break;
    case 32:
      pWindow = SineWindow64;
      FacWindowZir = FacWindowZir32;
      FacWindowSynth = FacWindowSynth32;
      break;
    /* coreCoderFrameLength = 768 */
    case 96:
      pWindow = SineWindow192;
      FacWindowZir = FacWindowZir96;
      FacWindowSynth = FacWindowSynth96;
      break;
    case 48:
      pWindow = SineWindow96;
      FacWindowZir = FacWindowZir48;
      FacWindowSynth = FacWindowSynth48;
      break;
    default:
      FDK_ASSERT(0);
      return 0;
  }

  FacWindowZir_conceal = FacWindowSynth;
  /* Derive NR and NL */
  fl = fac_length * 2;
  nl = (tl - fl) >> 1;
  nr = (tl - fr) >> 1;

  if (noOutSamples > nrSamples) {
    /* Purge buffered output. */
    FDKmemcpy(pOut0, hMdct->overlap.time, hMdct->ov_offset * sizeof(pOut0[0]));
    nrSamples = hMdct->ov_offset;
    hMdct->ov_offset = 0;
  }

  if (nrSamples >= noOutSamples) {
    pOut1 = hMdct->overlap.time + hMdct->ov_offset;
    if (hMdct->ov_offset < fac_length) {
      pOut0 = output + nrSamples;
    } else {
      pOut0 = pOut1;
    }
    hMdct->ov_offset += fac_length + nl;
  } else {
    pOut1 = output + nrSamples;
    pOut0 = output + nrSamples;
  }

  {
    pFAC_and_FAC_ZIR = CLpd_ACELP_GetFreeExcMem(acelp_mem, 2 * fac_length);
    {
      const FIXP_DBL *pTmp1, *pTmp2;

      doFacZirConceal |= ((last_frame_lost != 0) && (k == 0));
      doDeemph &= (last_lpd_mode != 4);
      if (doFacZirConceal) {
        /* ACELP contribution in concealment case:
           Use ZIR with a modified ZIR window to preserve some more energy.
           Dont use FAC, which contains wrong information for concealed frame
           Dont use last ACELP samples, but double ZIR, instead (afterwards) */
        FDKmemclear(pFAC_and_FAC_ZIR, 2 * fac_length * sizeof(FIXP_DBL));
        FacWindowSynth = (FIXP_WTB *)pFAC_and_FAC_ZIR;
        FacWindowZir = FacWindowZir_conceal;
      } else {
        CFac_CalcFacSignal(pFAC_and_FAC_ZIR, pFac, fac_scale + s, fac_length, A,
                           A_exp, 1, isFdFac);
      }
      /* 6) Get windowed past ACELP samples and ACELP ZIR signal */

      /*
       * Get ACELP ZIR (pFac[]) and ACELP past samples (pOut0[]) and add them
       * to the FAC synth signal contribution on pOut1[].
       */
      {
        {
          CLpd_Acelp_Zir(A, A_exp, acelp_mem, fac_length, pFac, doDeemph);

          pTmp1 = pOut0;
          pTmp2 = pFac;
        }

        for (i = 0, w = 0; i < fac_length; i++) {
          FIXP_DBL x;
          /* 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;

          w++;
        }
      }

      if (doFacZirConceal) {
        /* ZIR is the only ACELP contribution, so double it */
        scaleValues(pOut1, fac_length, 1);
      }
    }
  }

  if (nrSamples < noOutSamples) {
    nrSamples += fac_length + nl;
  }

  /* Obtain transform gain */
  total_gain = gain;
  total_gain_e = 0;
  imdct_gain(&total_gain, &total_gain_e, tl);

  /* IMDCT overlap add */
  scale = total_gain_e;
  pSpec = _pSpec;

  /* Note:when comming from an LPD frame (TCX/ACELP) the previous alisaing
   * symmetry must always be 0 */
  if (currAliasingSymmetry == 0) {
    dct_IV(pSpec, tl, &scale);
  } else {
    FIXP_DBL _tmp[1024 + ALIGNMENT_DEFAULT / sizeof(FIXP_DBL)];
    FIXP_DBL *tmp = (FIXP_DBL *)ALIGN_PTR(_tmp);
    C_ALLOC_ALIGNED_REGISTER(tmp, sizeof(_tmp));
    dst_III(pSpec, tmp, tl, &scale);
    C_ALLOC_ALIGNED_UNREGISTER(tmp);
  }

  /* Optional scaling of time domain - no yet windowed - of current spectrum */
  if (total_gain != (FIXP_DBL)0) {
    for (i = 0; i < tl; i++) {
      pSpec[i] = fMult(pSpec[i], total_gain);
    }
  }
  int loc_scale = fixmin_I(spec_scale[0] + scale, (INT)DFRACT_BITS - 1);
  scaleValuesSaturate(pSpec, tl, loc_scale);

  pOut1 += fl / 2 - 1;
  pCurr = pSpec + tl - fl / 2;

  for (i = 0; i < fl / 2; i++) {
    FIXP_DBL x1;

    /* FAC signal is already on pOut1, because of that the += operator. */
    x1 = fMult(*pCurr++, pWindow[i].v.re);
    FDK_ASSERT((pOut1 >= hMdct->overlap.time &&
                pOut1 < hMdct->overlap.time + hMdct->ov_size) ||
               (pOut1 >= output && pOut1 < output + 1024));
    *pOut1 += IMDCT_SCALE_DBL(-x1);
    pOut1--;
  }

  /* NL output samples TL/2+FL/2..TL. - current[FL/2..0] */
  pOut1 += (fl / 2) + 1;

  pFAC_and_FAC_ZIR += fac_length; /* set pointer to beginning of FAC ZIR */

  if (nl == 0) {
    /* save pointer to write FAC ZIR data later */
    hMdct->pFacZir = pFAC_and_FAC_ZIR;
  } else {
    FDK_ASSERT(nl >= fac_length);
    /* FAC ZIR will be added now ... */
    hMdct->pFacZir = NULL;
  }

  pF = pFAC_and_FAC_ZIR;
  f_len = fac_length;

  pCurr = pSpec + tl - fl / 2 - 1;
  for (i = 0; i < nl; i++) {
    FIXP_DBL x = -(*pCurr--);
    /* 5) (item 4) Synthesis filter Zir component, FAC ZIR (another one). */
    if (i < f_len) {
      x += *pF++;
    }

    FDK_ASSERT((pOut1 >= hMdct->overlap.time &&
                pOut1 < hMdct->overlap.time + hMdct->ov_size) ||
               (pOut1 >= output && pOut1 < output + 1024));
    *pOut1 = IMDCT_SCALE_DBL(x);
    pOut1++;
  }

  hMdct->prev_nr = nr;
  hMdct->prev_fr = fr;
  hMdct->prev_wrs = wrs;
  hMdct->prev_tl = tl;
  hMdct->prevPrevAliasSymmetry = hMdct->prevAliasSymmetry;
  hMdct->prevAliasSymmetry = currAliasingSymmetry;
  fl = fr;
  nl = nr;

  pOvl = pSpec + tl / 2 - 1;
  pOut0 = pOut1;

  for (w = 1; w < nSpec; w++) /* for ACELP -> FD short */
  {
    const FIXP_WTP *pWindow_prev;

    /* Setup window pointers */
    pWindow_prev = hMdct->prev_wrs;

    /* Current spectrum */
    pSpec = _pSpec + w * tl;

    scale = total_gain_e;

    /* For the second, third, etc. short frames the alisaing symmetry is equal,
     * either (0,0) or (1,1) */
    if (currAliasingSymmetry == 0) {
      /* DCT IV of current spectrum */
      dct_IV(pSpec, tl, &scale);
    } else {
      dst_IV(pSpec, tl, &scale);
    }

    /* Optional scaling of time domain - no yet windowed - of current spectrum
     */
    /* and de-scale current spectrum signal (time domain, no yet windowed) */
    if (total_gain != (FIXP_DBL)0) {
      for (i = 0; i < tl; i++) {
        pSpec[i] = fMult(pSpec[i], total_gain);
      }
    }
    loc_scale = fixmin_I(spec_scale[w] + scale, (INT)DFRACT_BITS - 1);
    scaleValuesSaturate(pSpec, tl, loc_scale);

    if (noOutSamples <= nrSamples) {
      /* Divert output first half to overlap buffer if we already got enough
       * output samples. */
      pOut0 = hMdct->overlap.time + hMdct->ov_offset;
      hMdct->ov_offset += hMdct->prev_nr + fl / 2;
    } else {
      /* Account output samples */
      nrSamples += hMdct->prev_nr + fl / 2;
    }

    /* NR output samples 0 .. NR. -overlap[TL/2..TL/2-NR] */
    for (i = 0; i < hMdct->prev_nr; i++) {
      FIXP_DBL x = -(*pOvl--);
      *pOut0 = IMDCT_SCALE_DBL(x);
      pOut0++;
    }

    if (noOutSamples <= nrSamples) {
      /* Divert output second half to overlap buffer if we already got enough
       * output samples. */
      pOut1 = hMdct->overlap.time + hMdct->ov_offset + fl / 2 - 1;
      hMdct->ov_offset += fl / 2 + nl;
    } else {
      pOut1 = pOut0 + (fl - 1);
      nrSamples += fl / 2 + nl;
    }

    /* output samples before window crossing point NR .. TL/2.
     * -overlap[TL/2-NR..TL/2-NR-FL/2] + current[NR..TL/2] */
    /* output samples after window crossing point TL/2 .. TL/2+FL/2.
     * -overlap[0..FL/2] - current[TL/2..FL/2] */
    pCurr = pSpec + tl - fl / 2;
    if (currAliasingSymmetry == 0) {
      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);
        pOut0++;
        pOut1--;
      }
    } else {
      if (hMdct->prevPrevAliasSymmetry == 0) {
        /* Jump DST II -> DST IV for the second window */
        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);
          pOut0++;
          pOut1--;
        }
      } else {
        /* Jump DST IV -> DST IV from the second window on */
        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);
          pOut0++;
          pOut1--;
        }
      }
    }

    if (hMdct->pFacZir != 0) {
      /* add FAC ZIR of previous ACELP -> mdct transition */
      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]);
      }
      hMdct->pFacZir = NULL;
    }
    pOut0 += (fl / 2);

    /* NL output samples TL/2+FL/2..TL. - current[FL/2..0] */
    pOut1 += (fl / 2) + 1;
    pCurr = pSpec + tl - fl / 2 - 1;
    for (i = 0; i < nl; i++) {
      FIXP_DBL x = -(*pCurr--);
      *pOut1 = IMDCT_SCALE_DBL(x);
      pOut1++;
    }

    /* Set overlap source pointer for next window pOvl = pSpec + tl/2 - 1; */
    pOvl = pSpec + tl / 2 - 1;

    /* Previous window values. */
    hMdct->prev_nr = nr;
    hMdct->prev_fr = fr;
    hMdct->prev_tl = tl;
    hMdct->prev_wrs = pWindow_prev;
    hMdct->prevPrevAliasSymmetry = hMdct->prevAliasSymmetry;
    hMdct->prevAliasSymmetry = currAliasingSymmetry;
  }

  /* Save overlap */

  pOvl = hMdct->overlap.freq + hMdct->ov_size - tl / 2;
  FDK_ASSERT(pOvl >= hMdct->overlap.time + hMdct->ov_offset);
  FDK_ASSERT(tl / 2 <= hMdct->ov_size);
  for (i = 0; i < tl / 2; i++) {
    pOvl[i] = _pSpec[i + (w - 1) * tl];
  }

  return nrSamples;
}
Ejemplo n.º 11
0
void Pred_lt4(FIXP_DBL exc[], /* in/out: excitation buffer              */
              int T0,         /* input : integer pitch lag              */
              int frac        /* input : fraction of lag in range 0..3  */
) {
  int j;
  FIXP_DBL *x;
  const LONG *interpol;
  FIXP_DBL L_sumb, L_sumt;

  x = &exc[-T0 - L_INTERPOL2 + 1];

  /* remap frac and x:
           0 -> 3   x (unchanged)
           1 -> 0   x--
           2 -> 1   x--
           3 -> 2   x--
  */

  if (--frac < 0)
    frac += UP_SAMP;
  else
    x--;

  j = L_SUBFR + 1;
  do {
    LONG filt;
    FIXP_DBL x0, x1;
    FIXP_DBL *xi = x++;
    interpol = Pred_lt4_inter4_2[frac];
    int i = 3;

    filt = *interpol++;
    x0 = *xi++;
    x1 = *xi++;
    L_sumt = fMultDiv2(x0, (FIXP_SGL)((SHORT)(filt >> 16)));
    L_sumb = fMultDiv2(x1, (FIXP_SGL)((SHORT)filt));
    do {
      filt = *interpol++;
      x0 = *xi++;
      x1 = *xi++;
      L_sumt = fMultAddDiv2(L_sumt, x0, (FIXP_SGL)((SHORT)(filt >> 16)));
      L_sumb = fMultAddDiv2(L_sumb, x1, (FIXP_SGL)((SHORT)filt));

      filt = *interpol++;
      x0 = *xi++;
      x1 = *xi++;
      L_sumt = fMultAddDiv2(L_sumt, x0, (FIXP_SGL)((SHORT)(filt >> 16)));
      L_sumb = fMultAddDiv2(L_sumb, x1, (FIXP_SGL)((SHORT)filt));

      filt = *interpol++;
      x0 = *xi++;
      x1 = *xi++;
      L_sumt = fMultAddDiv2(L_sumt, x0, (FIXP_SGL)((SHORT)(filt >> 16)));
      L_sumb = fMultAddDiv2(L_sumb, x1, (FIXP_SGL)((SHORT)filt));

      filt = *interpol++;
      x0 = *xi++;
      x1 = *xi++;
      L_sumt = fMultAddDiv2(L_sumt, x0, (FIXP_SGL)((SHORT)(filt >> 16)));
      L_sumb = fMultAddDiv2(L_sumb, x1, (FIXP_SGL)((SHORT)filt));

      filt = *interpol++;
      x0 = *xi++;
      x1 = *xi++;
      L_sumt = fMultAddDiv2(L_sumt, x0, (FIXP_SGL)((SHORT)(filt >> 16)));
      L_sumb = fMultAddDiv2(L_sumb, x1, (FIXP_SGL)((SHORT)filt));
    } while (--i != 0);

    L_sumb <<= 1;
    L_sumb = fAddSaturate(L_sumt << 1, L_sumb);
    *exc++ = L_sumb;
  } while (--j != 0);
  return;
}
Ejemplo n.º 12
0
/*******************************************************************************
 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;
  ;
}