/*! \brief Convert from coupled channels to independent L/R data */ static void sbr_envelope_unmapping (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ HANDLE_SBR_FRAME_DATA h_data_left, /*!< pointer to left channel */ HANDLE_SBR_FRAME_DATA h_data_right) /*!< pointer to right channel */ { int i; FIXP_SGL tempL_m, tempR_m, tempRplus1_m, newL_m, newR_m; SCHAR tempL_e, tempR_e, tempRplus1_e, newL_e, newR_e; /* 1. Unmap (already dequantized) coupled envelope energies */ for (i = 0; i < h_data_left->nScaleFactors; i++) { tempR_m = (FIXP_SGL)((LONG)h_data_right->iEnvelope[i] & MASK_M); tempR_e = (SCHAR)((LONG)h_data_right->iEnvelope[i] & MASK_E); tempR_e -= (18 + NRG_EXP_OFFSET); /* -18 = ld(UNMAPPING_SCALE / h_data_right->nChannels) */ tempL_m = (FIXP_SGL)((LONG)h_data_left->iEnvelope[i] & MASK_M); tempL_e = (SCHAR)((LONG)h_data_left->iEnvelope[i] & MASK_E); tempL_e -= NRG_EXP_OFFSET; /* Calculate tempRight+1 */ FDK_add_MantExp( tempR_m, tempR_e, FL2FXCONST_SGL(0.5f), 1, /* 1.0 */ &tempRplus1_m, &tempRplus1_e); FDK_divide_MantExp( tempL_m, tempL_e+1, /* 2 * tempLeft */ tempRplus1_m, tempRplus1_e, &newR_m, &newR_e ); if (newR_m >= ((FIXP_SGL)MAXVAL_SGL - ROUNDING)) { newR_m >>= 1; newR_e += 1; } newL_m = FX_DBL2FX_SGL(fMult(tempR_m,newR_m)); newL_e = tempR_e + newR_e; h_data_right->iEnvelope[i] = ((FIXP_SGL)((SHORT)(FIXP_SGL)(newR_m + ROUNDING) & MASK_M)) + (FIXP_SGL)((SHORT)(FIXP_SGL)(newR_e + NRG_EXP_OFFSET) & MASK_E); h_data_left->iEnvelope[i] = ((FIXP_SGL)((SHORT)(FIXP_SGL)(newL_m + ROUNDING) & MASK_M)) + (FIXP_SGL)((SHORT)(FIXP_SGL)(newL_e + NRG_EXP_OFFSET) & MASK_E); }
INT sfbCnt, const INT *RESTRICT sfbOffset, FIXP_DBL *RESTRICT sfbEnergyLD64 ); void FDKaacEnc_CalculateFullTonality(FIXP_DBL *RESTRICT spectrum, INT *RESTRICT sfbMaxScaleSpec, FIXP_DBL *RESTRICT sfbEnergyLD64, FIXP_SGL *RESTRICT sfbTonality, INT sfbCnt, const INT *sfbOffset, INT usePns) { INT j; #if defined(ARCH_PREFER_MULT_32x16) FIXP_SGL alpha_0 = FL2FXCONST_SGL(0.25f); /* used in smooth ChaosMeasure */ FIXP_SGL alpha_1 = FL2FXCONST_SGL(1.0f-0.25f); /* used in smooth ChaosMeasure */ #else FIXP_DBL alpha_0 = FL2FXCONST_DBL(0.25f); /* used in smooth ChaosMeasure */ FIXP_DBL alpha_1 = FL2FXCONST_DBL(1.0f-0.25f); /* used in smooth ChaosMeasure */ #endif INT numberOfLines = sfbOffset[sfbCnt]; if (!usePns) return; C_ALLOC_SCRATCH_START(chaosMeasurePerLine, FIXP_DBL, (1024)); /* calculate chaos measure */ FDKaacEnc_CalculateChaosMeasure(spectrum, numberOfLines, chaosMeasurePerLine);
/***************************************************************************** functionname: FDKaacEnc_PnsDetect description: do decision, if PNS shall used or not returns: input: pns config structure pns data structure (modified), lastWindowSequence (long or short blocks) sfbActive pointer to Sfb Energy, Threshold, Offset pointer to mdct Spectrum length of each group pointer to tonality calculated in chaosmeasure tns order and prediction gain calculated noiseNrg at active PNS output: pnsFlag in pns data structure *****************************************************************************/ void FDKaacEnc_PnsDetect(PNS_CONFIG *pnsConf, PNS_DATA *pnsData, const INT lastWindowSequence, const INT sfbActive, const INT maxSfbPerGroup, FIXP_DBL *sfbThresholdLdData, const INT *sfbOffset, FIXP_DBL *mdctSpectrum, INT *sfbMaxScaleSpec, FIXP_SGL *sfbtonality, INT tnsOrder, INT tnsPredictionGain, INT tnsActive, FIXP_DBL *sfbEnergyLdData, INT *noiseNrg ) { int sfb; int startNoiseSfb; if (pnsConf->np.detectionAlgorithmFlags & IS_LOW_COMLEXITY) { if ( (!pnsConf->usePns) || /* pns enabled? */ (lastWindowSequence == SHORT_WINDOW) ) /* currently only long blocks */ { FDKmemclear(pnsData->pnsFlag, MAX_GROUPED_SFB*sizeof(INT)); /* clear all pnsFlags */ for (sfb=0; sfb<MAX_GROUPED_SFB; sfb++) { noiseNrg[sfb] = NO_NOISE_PNS; /* clear nrg's of previous frame */ } return; } } else { if(!pnsConf->usePns) return; /* PNS only for long Windows */ if (pnsConf->np.detectionAlgorithmFlags & JUST_LONG_WINDOW) { if(lastWindowSequence != LONG_WINDOW) { for (sfb = 0; sfb < sfbActive; sfb++) { pnsData->pnsFlag[sfb] = 0; /* clear all pnsFlags */ } return; } } } /* call noise detection */ FDKaacEnc_FDKaacEnc_noiseDetection( pnsConf, pnsData, sfbActive, sfbOffset, tnsOrder, tnsPredictionGain, tnsActive, mdctSpectrum, sfbMaxScaleSpec, sfbtonality ); /* set startNoiseSfb (long) */ startNoiseSfb = pnsConf->np.startSfb; /* Set noise substitution status */ for(sfb = 0; sfb < sfbActive; sfb++) { /* No PNS below startNoiseSfb */ if(sfb < startNoiseSfb){ pnsData->pnsFlag[sfb] = 0; continue; } /* do noise substitution if fuzzy measure is high enough sfb freq > minimum sfb freq signal in coder band is not masked */ if((pnsData->noiseFuzzyMeasure[sfb] > FL2FXCONST_SGL(0.5)) && ( (sfbThresholdLdData[sfb] + FL2FXCONST_DBL(0.5849625f/64.0f)) /* thr * 1.5 = thrLd +ld(1.5)/64 */ < sfbEnergyLdData[sfb] ) ) { /* mark in psyout flag array that we will code this band with PNS */ pnsData->pnsFlag[sfb] = 1; /* PNS_ON */ } else{ pnsData->pnsFlag[sfb] = 0; /* PNS_OFF */ } /* no PNS if LTP is active */ } /* avoid PNS holes */ if((pnsData->noiseFuzzyMeasure[0]>FL2FXCONST_SGL(0.5f)) && (pnsData->pnsFlag[1])) { pnsData->pnsFlag[0] = 1; } for(sfb=1; sfb<maxSfbPerGroup-1; sfb++) { if((pnsData->noiseFuzzyMeasure[sfb]>pnsConf->np.gapFillThr) && (pnsData->pnsFlag[sfb-1]) && (pnsData->pnsFlag[sfb+1])) { pnsData->pnsFlag[sfb] = 1; } } if(maxSfbPerGroup>0) { /* avoid PNS hole */ if((pnsData->noiseFuzzyMeasure[maxSfbPerGroup-1]>pnsConf->np.gapFillThr) && (pnsData->pnsFlag[maxSfbPerGroup-2])) { pnsData->pnsFlag[maxSfbPerGroup-1] = 1; } /* avoid single PNS band */ if(pnsData->pnsFlag[maxSfbPerGroup-2]==0) { pnsData->pnsFlag[maxSfbPerGroup-1] = 0; } } /* avoid single PNS bands */ if(pnsData->pnsFlag[1]==0) { pnsData->pnsFlag[0] = 0; } for(sfb=1; sfb<maxSfbPerGroup-1; sfb++) { if((pnsData->pnsFlag[sfb-1]==0)&&(pnsData->pnsFlag[sfb+1]==0)) { pnsData->pnsFlag[sfb] = 0; } } /* calculate noiseNrg's */ FDKaacEnc_CalcNoiseNrgs( sfbActive, pnsData->pnsFlag, sfbEnergyLdData, noiseNrg ); }
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; }
{1, 2}, {3, 4}, {-63, -65}, {5, -66}, {-64, 6}, {-80, 7}, {8, 9}, {-68, 10}, {11, 12}, {-56, -67}, {-61, 13}, {-62, -69}, {14, 15}, {16, -72}, {-71, 17}, {-70, -60}, {18, -59}, {19, 20}, {21, -79}, {-57, -73}, {22, -58}, {-76, 23}, {-75, -74}, {-78, -77}}; const SCHAR deltaGain_codingProfile_2_huffman[48][2] = { {1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}, {13, -65}, {14, -64}, {15, -66}, {16, -67}, {17, 18}, {19, -68}, {20, -63}, {-69, 21}, {-59, 22}, {-61, -62}, {-60, 23}, {24, -58}, {-70, -57}, {-56, -71}, {25, 26}, {27, -55}, {-72, 28}, {-54, 29}, {-53, 30}, {-73, -52}, {31, -74}, {32, 33}, {-75, 34}, {-76, 35}, {-51, 36}, {-78, 37}, {-77, 38}, {-96, 39}, {-48, 40}, {-50, -79}, {41, 42}, {-80, -81}, {-82, 43}, {44, -49}, {45, -84}, {-83, -89}, {-86, 46}, {-90, -85}, {-91, -93}, {-92, 47}, {-88, -87}, {-95, -94}}; const FIXP_SGL slopeSteepness[] = {FL2FXCONST_SGL(-3.0518f / (float)(1 << 2)), FL2FXCONST_SGL(-1.2207f / (float)(1 << 2)), FL2FXCONST_SGL(-0.4883f / (float)(1 << 2)), FL2FXCONST_SGL(-0.1953f / (float)(1 << 2)), FL2FXCONST_SGL(-0.0781f / (float)(1 << 2)), FL2FXCONST_SGL(-0.0312f / (float)(1 << 2)), FL2FXCONST_SGL(-0.005f / (float)(1 << 2)), FL2FXCONST_SGL(0.0f / (float)(1 << 2)), FL2FXCONST_SGL(0.005f / (float)(1 << 2)), FL2FXCONST_SGL(0.0312f / (float)(1 << 2)), FL2FXCONST_SGL(0.0781f / (float)(1 << 2)), FL2FXCONST_SGL(0.1953f / (float)(1 << 2)), FL2FXCONST_SGL(0.4883f / (float)(1 << 2)), FL2FXCONST_SGL(1.2207f / (float)(1 << 2)), FL2FXCONST_SGL(3.0518f / (float)(1 << 2))};