diff --git a/lib_com/igf_base_fx.c b/lib_com/igf_base_fx.c index 3bcc9dc9ba2ba97df2e19a6bef537ba7a8932cf6..c10429a844af295aaafb1c68cc9ee7e9627feedd 100644 --- a/lib_com/igf_base_fx.c +++ b/lib_com/igf_base_fx.c @@ -1124,6 +1124,44 @@ void IGFCommonFuncsMDCTSquareSpec(const Word16 sqrtBgn, } +/**********************************************************************/ /* +calculate the MDCT square spectrum in the IGF range (for IVAS) +**************************************************************************/ +void IGFCommonFuncsMDCTSquareSpec_ivas( const Word16 sqrtBgn, /**< in: Q0 | start MDCT subband index */ + const Word16 sqrtEnd, /**< in: Q0 | stop MDCT subband index */ + const Word32 *mdctSpec, /**< in: Q31 | MDCT spectrum to square */ + const Word16 mdctSpec_e, /**< in: | exponent of mdctSpectrum */ + Word32 *mdctSquareSpec, /**< out:Q31 | MDCT square spectrum */ + Word16 *mdctSquareSpec_e, /**< out: | exponent of mdctSquareSpec */ + Word16 indexOffset /**< in: Q0 | index offset */ +) +{ + Word16 i; + Word16 j; + Word16 s1; + Word16 tmp; + + + /* get headroom, only in IGF range */ + s1 = getScaleFactor32( mdctSpec + sqrtBgn, sub( sqrtEnd, sqrtBgn ) ); + + /* set new exponent */ + *mdctSquareSpec_e = add( shl( sub( mdctSpec_e, s1 ), 1 ), 1 ); + move16(); + + /* MDCT square spectrum: MDCT^2 */ + j = add( sqrtBgn, indexOffset ); /* handle indexOffset with care, otherwise memory overruns may occur! */ + + + FOR( i = sqrtBgn; i < sqrtEnd; i++ ) + { + tmp = extract_h( L_shl( mdctSpec[i], s1 ) ); + mdctSquareSpec[j++] = L_mult0( tmp, tmp ); + move32(); + } +} + + /**********************************************************************/ /* write bits to stream **************************************************************************/ diff --git a/lib_com/ivas_prot_fx.h b/lib_com/ivas_prot_fx.h index 6bf289f396ec25400315450d5606c1326c813cf4..c070332087e9b838a2618ba88feb19e62f95a88d 100644 --- a/lib_com/ivas_prot_fx.h +++ b/lib_com/ivas_prot_fx.h @@ -355,9 +355,9 @@ void decoder_tcx_noiseshaping_igf_fx( const Word16 L_frame, const Word16 L_frameTCX, const Word16 left_rect, - float x[], Word32 *x_fx, Word16 *x_e, + Word16 *x_len, const Word16 gainlpc2_fx[], const Word16 gainlpc2_e[], Word16 *temp_concealment_method, diff --git a/lib_com/prot_fx2.h b/lib_com/prot_fx2.h index f28e18fa1b29cb3588fd527fd2bca1a13b070d55..354cf5cf989118c9310c30a335e587c694f1d607 100644 --- a/lib_com/prot_fx2.h +++ b/lib_com/prot_fx2.h @@ -5169,6 +5169,16 @@ void IGFCommonFuncsMDCTSquareSpec(const Word16 sqrtBgn, Word16 indexOffset /**< in: Q0 | index offset */ ); +void IGFCommonFuncsMDCTSquareSpec_ivas( + const Word16 sqrtBgn, /**< in: Q0 | start MDCT subband index */ + const Word16 sqrtEnd, /**< in: Q0 | stop MDCT subband index */ + const Word32 *mdctSpec, /**< in: Q31 | MDCT spectrum to square */ + const Word16 mdctSpec_e, /**< in: | exponent of mdctSpectrum */ + Word32 *mdctSquareSpec, /**< out:Q31 | MDCT square spectrum */ + Word16 *mdctSquareSpec_e, /**< out: | exponent of mdctSquareSpec */ + Word16 indexOffset /**< in: Q0 | index offset */ +); + void IGFCommonFuncsWriteSerialBit( BSTR_ENC_HANDLE hBstr, /* i/o: encoder bitstream handle */ Word16* pBitOffset, /**< out: Q0 | bit offset */ @@ -7977,6 +7987,16 @@ void IGFDecApplyMono(const IGF_DEC_INSTANCE_HANDLE hInstance, Word16 bfi /**< in: | frame loss == 1, frame good == 0 */ ); + +void IGFDecApplyMono_ivas( + const IGF_DEC_INSTANCE_HANDLE hInstance, /**< in: | instance handle of IGF Decoder */ + Word32 *spectrum, /**< in/out: | MDCT spectrum */ + Word16 *spectrum_e, /**< in/out: | exponent of spectrum */ + const Word16 igfGridIdx, /**< in: | in case of CELP->TCX switching, use 1.25 framelength */ + Word16 bfi, /**< in: | frame loss == 1, frame good == 0 */ + Word16 element_mode /**< in: | IVAS element mode */ +); + void IGFDecSetMode( const IGF_DEC_INSTANCE_HANDLE hIGFDec, /* o : instance handle of IGF Decoder */ const Word32 total_brate, /* i : bitrate */ diff --git a/lib_dec/dec_tcx.c b/lib_dec/dec_tcx.c index 1f7aae46999e6253bf119e523ae7cdede127e529..36ddb05ec6d9b57627224295d826ebe9fb7589b8 100644 --- a/lib_dec/dec_tcx.c +++ b/lib_dec/dec_tcx.c @@ -2524,7 +2524,38 @@ void decoder_tcx_IGF_mono( igfGridIdx = ( st->last_core == ACELP_CORE || ( left_rect && bfi ) ) ? IGF_GRID_LB_TRAN : IGF_GRID_LB_NORM; } +#ifdef IVAS_FLOAT_FIXED + Word16 len; + Word32 x_fx[N_MAX]; + Word16 x_e; + len = ((igfGridIdx == IGF_GRID_LB_SHORT) ? (N_MAX_TCX - IGF_START_MN) / 2 : (N_MAX_TCX - IGF_START_MN)); + IGF_GRID *hGrid = &st->hIGFDec->igfData.igfInfo.grid[igfGridIdx]; + Word16 stop = hGrid->stopLine; + + // Float to fixed + f2me_buf(x, x_fx, &x_e, stop); + hGrid->fFactor = float_to_fix16(hGrid->fFactor_flt, Q14); + hGrid->lFactor = float_to_fix16(hGrid->lFactor_flt, Q14); + hGrid->gFactor = float_to_fix16(hGrid->gFactor_flt, Q14); + // u8bit to 16bit + FOR(int l = 0; l < IGF_START_MX; l++) + { + st->hIGFDec->infoTCXNoise_evs[l] = (Word16)st->hIGFDec->infoTCXNoise[l]; + } + + IGFDecApplyMono_ivas( st->hIGFDec, x_fx, &x_e, igfGridIdx, bfi, st->element_mode ); + + // Fixed to float + me2f_buf(x_fx, x_e, x, stop); + me2f_buf(st->hIGFDec->virtualSpec, st->hIGFDec->virtualSpec_e, st->hIGFDec->virtualSpec_float, len); + // 16bit to u8bit + FOR(Word16 l = 0; l < IGF_START_MX; l++) + { + st->hIGFDec->infoTCXNoise[l] = (uint8_t)st->hIGFDec->infoTCXNoise_evs[l]; + } +#else IGFDecApplyMono_flt( st->hIGFDec, x, igfGridIdx, bfi, st->element_mode ); +#endif } return; diff --git a/lib_dec/dec_tcx_fx.c b/lib_dec/dec_tcx_fx.c index 2843132ed50e2ae28cf9ca376c78ccdede2d24d5..4249fd1b690169deb09a07d14e17e15743598073 100644 --- a/lib_dec/dec_tcx_fx.c +++ b/lib_dec/dec_tcx_fx.c @@ -2635,7 +2635,58 @@ void decoder_tcx_fx( #endif #ifdef IVAS_FLOAT_FIXED - decoder_tcx_noiseshaping_igf_fx( st, L_spec, L_frame, L_frameTCX, left_rect, &x[0], x_fx, &x_e, gainlpc2_fx, gainlpc2_e, &tmp_concealment_method, bfi ); + // Float to fix starts here + Word16 x_len; + IF(bfi && st->tonal_mdct_plc_active && NE_16(st->element_mode, IVAS_CPE_MDCT)) + { + FOR(Word16 i = 0; i < st->hTonalMDCTConc->pTCI_float->numIndexes; i++) + { + float pd = st->hTonalMDCTConc->pTCI_float->phaseDiff_float[i]; + if (pd >= PI2) + pd = fmodf(pd, PI2) - PI2; + st->hTonalMDCTConc->pTCI_fix->phaseDiff[i] = float_to_fix16(pd, Q12); + } + FOR(Word16 i = 0; i < MAX_NUMBER_OF_IDX * GROUP_LENGTH; i++) + { + float pd = st->hTonalMDCTConc->pTCI_float->phase_currentFramePredicted_float[i]; + pd = fmodf(pd, PI2); + st->hTonalMDCTConc->pTCI_fix->phase_currentFramePredicted[i] = (Word16)(pd * (1u << Q13)); + } + FOR(Word16 i = 0; i < FDNS_NPTS; i++) + { + f2me_16(st->hTonalMDCTConc->secondLastBlockData.scaleFactors_float[i], &st->hTonalMDCTConc->secondLastBlockData.scaleFactors[i], &st->hTonalMDCTConc->secondLastBlockData.scaleFactors_exp[i]); + st->hTonalMDCTConc->secondLastBlockData.scaleFactors_max_e = s_max(st->hTonalMDCTConc->secondLastBlockData.scaleFactors_max_e, st->hTonalMDCTConc->secondLastBlockData.scaleFactors_exp[i]); + } + } + st->hTcxDec->tcxltp_last_gain_unmodified = float_to_fix16(st->hTcxDec->tcxltp_last_gain_unmodified_float, Q15); + st->old_fpitch = float_to_fix(st->old_fpitch_float, Q16); + st->hTonalMDCTConc->lastPitchLag = float_to_fix(st->hTonalMDCTConc->lastPitchLag_float, Q16); + + IF(st->enablePlcWaveadjust) + { + f2me_buf(st->hPlcInfo->data_reci2, st->hPlcInfo->data_reci2_fx, &st->hPlcInfo->data_reci2_scale, st->hPlcInfo->L_frameTCX); + } + + // u8bit to 16bit + FOR(int l = 0; l < IGF_START_MX; l++) + { + st->hIGFDec->infoTCXNoise_evs[l] = (Word16)st->hIGFDec->infoTCXNoise[l]; + } + // Float to fix ends here + + decoder_tcx_noiseshaping_igf_fx( st, L_spec, L_frame, L_frameTCX, left_rect, x_fx, &x_e, &x_len, gainlpc2_fx, gainlpc2_e, &tmp_concealment_method, bfi ); + + // Fixed to float starts here + st->hTonalMDCTConc->lastPitchLag_float = fix_to_float(st->hTonalMDCTConc->lastPitchLag, Q16); + st->hTonalMDCTConc->nFramesLost_float = fix16_to_float(st->hTonalMDCTConc->nFramesLost, Q1); + // 16bit to u8bit + FOR(Word16 l = 0; l < IGF_START_MX; l++) + { + st->hIGFDec->infoTCXNoise[l] = (uint8_t)st->hIGFDec->infoTCXNoise_evs[l]; + } + me2f_buf(st->hIGFDec->virtualSpec, st->hIGFDec->virtualSpec_e, st->hIGFDec->virtualSpec_float, (N_MAX_TCX - IGF_START_MN)); + me2f_buf(x_fx, x_e, x, x_len); + // Fixed to float ends here #else decoder_tcx_noiseshaping_igf( st, L_spec, L_frame, L_frameTCX, left_rect, &x[0], &gainlpc2[0], &tmp_concealment_method, bfi ); #endif @@ -3591,9 +3642,9 @@ void decoder_tcx_noiseshaping_igf_fx( const Word16 L_frame, const Word16 L_frameTCX, const Word16 left_rect, - float x[], Word32 *x_fx, Word16 *x_e, + Word16 *x_len, const Word16 gainlpc2_fx[], const Word16 gainlpc2_e[], Word16 *temp_concealment_method, @@ -3602,6 +3653,8 @@ void decoder_tcx_noiseshaping_igf_fx( { TCX_DEC_HANDLE hTcxDec = st->hTcxDec; Word16 i; + Word32 tmp32; + Word8 tmp8; /*-----------------------------------------------------------* * Noise shaping in frequency domain (1/Wz) * @@ -3643,6 +3696,7 @@ void decoder_tcx_noiseshaping_igf_fx( spec_side_x_e = *x_e; move16(); + /* NOTE: this function updates x till L_frame. From L_frame to L_spec, the exponent needs to be updated. */ mdct_noiseShaping_ivas_fx(x_fx, x_e, L_frame, gainlpc2_fx, gainlpc2_e); frame_side_x_e = *x_e; @@ -3683,88 +3737,123 @@ void decoder_tcx_noiseshaping_igf_fx( set32_fx(x_fx + L_spec, 0, sub(L_frameTCX, L_spec)); } - me2f_buf(x_fx, *x_e, x, L_frameTCX); + + Word16 prev_x_e, curr_x_e; + prev_x_e = *x_e; + move16(); /* PLC: [TCX: Tonal Concealment] */ test(); test(); IF ( bfi && st->tonal_mdct_plc_active && NE_16(st->element_mode, IVAS_CPE_MDCT) ) { -#if 1 - // Float to fixed - IF(!st->hTonalMDCTConc->lastBlockData.blockIsConcealed && st->hTonalMDCTConc->secondLastBlockData.tonalConcealmentActive != 0) - { - st->hTonalMDCTConc->nFramesLost = float_to_fix16(st->hTonalMDCTConc->nFramesLost_float, Q1); - } - FOR (i = 0; i < st->hTonalMDCTConc->pTCI_float->numIndexes; i++) - { - float pd = st->hTonalMDCTConc->pTCI_float->phaseDiff_float[i]; - if (pd >= PI2) - pd = fmodf(pd, PI2) - PI2; - st->hTonalMDCTConc->pTCI_fix->phaseDiff[i] = float_to_fix16(pd, Q12); - } - FOR (i = 0; i < MAX_NUMBER_OF_IDX * GROUP_LENGTH; i++) - { - float pd = st->hTonalMDCTConc->pTCI_float->phase_currentFramePredicted_float[i]; - pd = fmodf(pd, PI2); - st->hTonalMDCTConc->pTCI_fix->phase_currentFramePredicted[i] = (Word16)(pd * (1u << Q13)); - } - FOR(i = 0; i < FDNS_NPTS; i++) - { - f2me_16(st->hTonalMDCTConc->secondLastBlockData.scaleFactors_float[i], &st->hTonalMDCTConc->secondLastBlockData.scaleFactors[i], &st->hTonalMDCTConc->secondLastBlockData.scaleFactors_exp[i]); - st->hTonalMDCTConc->secondLastBlockData.scaleFactors_max_e = s_max(st->hTonalMDCTConc->secondLastBlockData.scaleFactors_max_e, st->hTonalMDCTConc->secondLastBlockData.scaleFactors_exp[i]); - } - TonalMDCTConceal_Apply_ivas_fx( st->hTonalMDCTConc, x_fx, x_e, st->hTcxCfg->psychParamsCurrent ); - // Fix to float - FOR(i = 0; i < st->hTonalMDCTConc->pTCI_float->numIndexes; i++) + /* If exponent has been updated after TonalMDCTConceal_Apply, then shift the spectrum to common exponent. */ + curr_x_e = *x_e; + move16(); + IF(NE_16(curr_x_e, prev_x_e)) { - FOR(Word16 l = st->hTonalMDCTConc->pTCI_float->lowerIndex[i]; l <= st->hTonalMDCTConc->pTCI_float->upperIndex[i]; l++) + *x_e = s_max(curr_x_e, prev_x_e); + FOR(i = 0; i < L_frameTCX; i++) { - x[l] = me2f(x_fx[l], *x_e); + Word16 n_idx = st->hTonalMDCTConc->pTCI_float->numIndexes; + Word16 l_idx = st->hTonalMDCTConc->pTCI_float->lowerIndex[0]; + Word16 u_idx = st->hTonalMDCTConc->pTCI_float->upperIndex[n_idx - 1]; + test(); + IF(GE_16(i, l_idx) && LE_16(i, u_idx)) + { + x_fx[i] = L_shr(x_fx[i], sub(*x_e, curr_x_e)); + } + ELSE + { + x_fx[i] = L_shr(x_fx[i], sub(*x_e, prev_x_e)); + } } } - st->hTonalMDCTConc->nFramesLost_float = fix16_to_float(st->hTonalMDCTConc->nFramesLost, Q1); -#else - TonalMDCTConceal_Apply_ivas( st->hTonalMDCTConc, x, st->hTcxCfg->psychParamsCurrent ); -#endif } - if ( st->hTonalMDCTConc != NULL && st->element_mode != IVAS_CPE_MDCT ) + test(); + IF ( st->hTonalMDCTConc != NULL && NE_16(st->element_mode, IVAS_CPE_MDCT) ) { - TonalMDCTConceal_UpdateState_ivas( st->hTonalMDCTConc, L_frameTCX, ( hTcxDec->tcxltp_last_gain_unmodified_float > 0 ) ? st->old_fpitch_float : 0, bfi, bfi && st->tonal_mdct_plc_active ); + tmp32 = L_deposit_h(0); + IF(GT_16(hTcxDec->tcxltp_last_gain_unmodified, 0)) + { + tmp32 = st->old_fpitch; + move32(); + } + + tmp8 = 0; + move16(); + test(); + IF (bfi && st->tonal_mdct_plc_active) + { + tmp8 = 1; + move16(); + } + + TonalMDCTConceal_UpdateState( st->hTonalMDCTConc, + L_frameTCX, + tmp32, + bfi, + tmp8 ); } - if ( st->enablePlcWaveadjust ) + *x_len = L_frameTCX; + move16(); + + IF ( st->enablePlcWaveadjust != 0 ) { + test(); /* spectrum concealment */ - if ( bfi && *temp_concealment_method == TCX_NONTONAL ) + IF ( bfi && EQ_16(*temp_concealment_method, TCX_NONTONAL) ) { - concealment_decode( st->core, x, st->hPlcInfo ); + concealment_decode_fix( st->core, x_fx, x_e, &st->hPlcInfo ); } /* update spectrum buffer, tonality flag, etc. */ - concealment_update( bfi, st->core, st->tonality_flag, x, st->hPlcInfo ); + concealment_update_x( bfi, st->core, st->tonality_flag, x_fx, x_e, &st->hPlcInfo ); + + *x_len = s_max(*x_len, st->hPlcInfo->L_frameTCX); } /*-----------------------------------------------------------* * IGF * *-----------------------------------------------------------*/ - if ( st->igf && !( ( L_frame == st->L_frame >> 1 ) && st->tcxonly ) ) + test(); + test(); + IF(st->igf && !((EQ_16(L_frame, shr(st->L_frame, 1))) && (st->tcxonly))) { - if ( st->element_mode != IVAS_CPE_MDCT ) + IF ( NE_16(st->element_mode, IVAS_CPE_MDCT) ) { - IGFDecApplyMono_flt( st->hIGFDec, x, ( st->last_core == ACELP_CORE || ( left_rect && bfi ) ) ? IGF_GRID_LB_TRAN : IGF_GRID_LB_NORM, bfi, st->element_mode ); + Word16 igfGridIdx; + + test(); + test(); + IF((EQ_16(st->last_core, ACELP_CORE)) || (left_rect&&bfi)) + { + /* packet loss after first TCX must be handled like transition frame */ + igfGridIdx = IGF_GRID_LB_TRAN; + } + ELSE + { + igfGridIdx = IGF_GRID_LB_NORM; + } + + IGFDecApplyMono_ivas(st->hIGFDec, x_fx, x_e, igfGridIdx, bfi, st->element_mode); + + *x_len = s_max(*x_len, st->hIGFDec->igfData.igfInfo.grid[igfGridIdx].stopLine); } } - if ( st->igf && ( ( L_frame == st->L_frame >> 1 ) && st->tcxonly ) ) + IF(st->igf && ((EQ_16(L_frame, shr(st->L_frame, 1))) && (st->tcxonly))) { - if ( st->element_mode != IVAS_CPE_MDCT ) + IF(NE_16(st->element_mode, IVAS_CPE_MDCT)) { - IGFDecApplyMono_flt( st->hIGFDec, x, IGF_GRID_LB_SHORT, bfi, st->element_mode ); + IGFDecApplyMono_ivas(st->hIGFDec, x_fx, x_e, IGF_GRID_LB_SHORT, bfi, st->element_mode); + + *x_len = s_max(*x_len, st->hIGFDec->igfData.igfInfo.grid[IGF_GRID_LB_SHORT].stopLine); } } diff --git a/lib_dec/igf_dec.c b/lib_dec/igf_dec.c index 893d6acda96b17d9e1cde55ce075e0049dba8f91..f89e6c054f8f0b322db5fd1fd21a87df2be7d6ea 100644 --- a/lib_dec/igf_dec.c +++ b/lib_dec/igf_dec.c @@ -43,6 +43,9 @@ #include "stat_dec.h" #include "ivas_prot.h" #include "wmc_auto.h" +#ifdef IVAS_FLOAT_FIXED +#include "prot_fx2.h" +#endif /*-------------------------------------------------------------------* @@ -1401,6 +1404,9 @@ void IGFDecSetMode_flt( hIGFDec->virtualSpec_fx = &hIGFDec->virtualSpec[0]; #endif hIGFDec->igfData.pSpecFlat_float = &hIGFDec->igfData.pSpecFlatBuf[0]; +#ifdef IVAS_FLOAT_FIXED + hIGFDec->igfData.pSpecFlat = &hIGFDec->igfData.pSpecFlatBuf_fx[0]; +#endif hIGFDec->igfData.igfInfo.nfSeed = &hIGFDec->igfData.igfInfo.nfSeedBuf[0]; return; @@ -1429,6 +1435,9 @@ void IGFDecUpdateInfo_flt( hIGFDec->virtualSpec_fx = &hIGFDec->virtualSpec[0]; #endif hIGFDec->igfData.pSpecFlat_float = &hIGFDec->igfData.pSpecFlatBuf[0]; +#ifdef IVAS_FLOAT_FIXED + hIGFDec->igfData.pSpecFlat = &hIGFDec->igfData.pSpecFlatBuf_fx[0]; +#endif hIGFDec->igfData.igfInfo.nfSeed = &hIGFDec->igfData.igfInfo.nfSeedBuf[0]; if ( igfGridIdx == IGF_GRID_LB_SHORT ) @@ -1464,6 +1473,9 @@ void IGFDecReplicateTCX10State_flt( mvc2c( &hIGFDec->infoTCXNoiseBuf[( IGF_START_MX ) / 2], &hIGFDec->infoTCXNoiseBuf[0], ( IGF_START_MX ) / 2 ); mvr2r( &hIGFDec->virtualSpecBuf[( N_MAX_TCX - IGF_START_MN ) / 2], &hIGFDec->virtualSpecBuf[0], ( N_MAX_TCX - IGF_START_MN ) / 2 ); mvr2r( &hIGFDec->igfData.pSpecFlatBuf[IGF_START_MX / 2], &hIGFDec->igfData.pSpecFlatBuf[0], IGF_START_MX / 2 ); +#ifdef IVAS_FLOAT_FIXED + Copy32(&hIGFDec->igfData.pSpecFlatBuf_fx[IGF_START_MX / 2], &hIGFDec->igfData.pSpecFlatBuf_fx[0], IGF_START_MX / 2); +#endif hIGFDec->igfData.igfInfo.nfSeedBuf[0] = hIGFDec->igfData.igfInfo.nfSeedBuf[1]; @@ -1564,6 +1576,9 @@ void IGFDecRestoreTCX10SubFrameData_flt( hIGFDec->virtualSpec_fx = &hIGFDec->virtualSpec[0]; #endif hIGFDec->igfData.pSpecFlat_float = &hIGFDec->igfData.pSpecFlatBuf[subFrameIdx * IGF_START_MX / 2]; +#ifdef IVAS_FLOAT_FIXED + hIGFDec->igfData.pSpecFlat = &hIGFDec->igfData.pSpecFlatBuf_fx[subFrameIdx * IGF_START_MX / 2]; +#endif hIGFDec->igfData.igfInfo.nfSeed = &hIGFDec->igfData.igfInfo.nfSeedBuf[subFrameIdx]; return; @@ -1581,6 +1596,9 @@ void init_igf_dec_flt( { set_c( (int8_t *) ( hIGFDec->infoTCXNoiseBuf ), 0, IGF_START_MX ); set_f( hIGFDec->igfData.pSpecFlatBuf, 0, IGF_START_MX ); +#ifdef IVAS_FLOAT_FIXED + set32_fx( hIGFDec->igfData.pSpecFlatBuf_fx, 0, IGF_START_MX ); +#endif hIGFDec->igfData.igfInfo.nfSeedBuf[0] = 9733; hIGFDec->igfData.igfInfo.nfSeedBuf[1] = 9733; hIGFDec->igfData.igfInfo.nfSeed = &hIGFDec->igfData.igfInfo.nfSeedBuf[0]; diff --git a/lib_dec/igf_dec_fx.c b/lib_dec/igf_dec_fx.c index 2bad8bcdba6b45a451a3cc160f629a248bec94cc..3fc8fe0956034c22472a5c4216ec5f2829a7e06f 100644 --- a/lib_dec/igf_dec_fx.c +++ b/lib_dec/igf_dec_fx.c @@ -212,6 +212,86 @@ static void IGF_replaceTCXNoise_2(Word32 *in, } +/**********************************************************************/ /* +replaces TCX noise with noise band ratio (for IVAS) +**************************************************************************/ +static void IGF_replaceTCXNoise_2_new_ivas( Word32 *in, /**< in/out: | MDCT spectrum */ + const Word16 in_e, /**< in: | MDCT spectrum exp */ + const Word16 *TCXNoise, /**< in: Q0 | tcx noise indicator vector */ + const Word16 start, /**< in: Q0 | start MDCT subband index */ + const Word16 stop, /**< in: Q0 | stop MDCT subband index */ + Word32 totalNoiseNrg, /**< in: | measured noise energy */ + Word16 totalNoiseNrg_e, /**< in: | measured noise energy exp */ + const Word16 n_noise_bands, /**< in: | number of noise bands in src */ + Word16 *nfSeed /**< in: | random generator noise seed */ +) +{ + Word16 sb; + Word16 g; + Word16 val; + Word32 rE; + Word32 L_tmp; + Word16 n_noise_bands_tile; + Word16 noise_band_ratio; + + n_noise_bands_tile = 0; + move16(); + val = 0; + move16(); + rE = 0; + move32(); + + FOR( sb = start; sb < stop; sb++ ) + { + IF ( TCXNoise[sb] ) + { + val = Random( nfSeed ); + move16(); + in[sb] = L_deposit_l( val ); + move32(); + val = shr( val, 5 ); + rE = L_mac( rE, val, val ); + n_noise_bands_tile = add( n_noise_bands_tile, 1 ); + } + } + + + IF( n_noise_bands_tile != 0 ) + { + noise_band_ratio = div_s( n_noise_bands_tile, n_noise_bands ); // Q15 + + /* make sure that rE is never 0 */ + if ( rE == 0 ) + { + rE = L_add( totalNoiseNrg, 0 ); /* save move32() -> use L_add(x, 0) = x; */ + } + + /* if totalNoiseNrg == 0, then rE must be at least 0x00010000, otherwise division by 0 will occur */ + if ( totalNoiseNrg == 0 ) + { + rE = L_max( rE, 0x00010000 ); + } + + Word16 tmp, tmp_e; + L_tmp = Mpy_32_16_1( totalNoiseNrg, noise_band_ratio ); + tmp = BASOP_Util_Divide3232_Scale( L_tmp, rE, &tmp_e ); + tmp_e = add( tmp_e, sub( totalNoiseNrg_e, 40 ) ); + g = Sqrt16( tmp, &tmp_e ); + + FOR( sb = start; sb < stop; sb++ ) + { + IF ( TCXNoise[sb] ) + { + Word16 nrm = norm_l( in[sb] ); + in[sb] = L_shl( in[sb], nrm ); // exp: 31 - tmp + in[sb] = Mpy_32_16_1( in[sb], g ); // exp: 31 - tmp + tmp_e + in[sb] = L_shr( in[sb], sub( in_e, 31 - nrm + tmp_e ) ); // Making the exponent same as original + move32(); + } + } + } +} + /**********************************************************************/ /* reads whitening levels **************************************************************************/ @@ -432,6 +512,212 @@ static void IGF_prep(IGF_DEC_PRIVATE_DATA_HANDLE hPrivate } +/**********************************************************************/ /* +prepare IGF spectrum (for IVAS) +**************************************************************************/ +static void IGF_prep_ivas( IGF_DEC_PRIVATE_DATA_HANDLE hPrivateData, /**< in: | IGF private data handle */ + const Word16 igfGridIdx, /**< in: Q0 | in case of CELP->TCX switching, use 1.25 framelength */ + const Word16 *TCXNoise, /**< in: Q0 | TCX noise vector */ + Word32 *igf_spec, /**< in/out: | prepared IGF spectrum */ + Word16 *igf_spec_e, /**< in/out: | array exponents of igf_spec, one exponent per tile */ + Word32 *src_spec, /**< in/out: | source spectrum */ + const Word16 src_spec_e, /**< in: | exponent of src_spec, whitening off */ + const Word16 specMed_e, /**< in: | exponent of medium flattening level */ + const Word16 element_mode /**< in: | element mode */ +) +{ + H_IGF_GRID hGrid; + H_IGF_INFO hInfo; + Word16 i; + Word16 tb; + Word16 sfb; + Word16 nTiles; + Word16 n_noise_bands; + Word16 n_noise_bands_off; + Word16 strt_cpy; + Word16 startLine; + Word16 minSrcSubband; + Word16 tile_idx; + Word32 totalNoiseNrg; + Word32 totalNoiseNrg_off; + Word16 totalNoiseNrg_exp; + Word16 totalNoiseNrg_off_exp; + const Word32 *sel_spec; + + /* initialize variables */ + hInfo = &hPrivateData->igfInfo; + hGrid = &hPrivateData->igfInfo.grid[igfGridIdx]; + n_noise_bands = hPrivateData->n_noise_bands; + move16(); + n_noise_bands_off = hPrivateData->n_noise_bands_off; + move16(); + totalNoiseNrg = hPrivateData->totalNoiseNrg; + move32(); + totalNoiseNrg_off = hPrivateData->totalNoiseNrg_off; + move32(); + totalNoiseNrg_exp = hPrivateData->totalNoiseNrg_exp; + move16(); + totalNoiseNrg_off_exp = hPrivateData->totalNoiseNrg_off_exp; + move16(); + nTiles = hGrid->nTiles; + move16(); + startLine = hGrid->startLine; + move16(); + minSrcSubband = hGrid->minSrcSubband; + move16(); + tile_idx = 0; + move16(); + + FOR( tile_idx = 0; tile_idx < nTiles; tile_idx++ ) + { + Word16 tile_width, stop; + + strt_cpy = hGrid->sbWrap[tile_idx]; + move16(); + + IF( GT_16( element_mode, EVS_MONO ) ) + { + tile_width = hGrid->swb_offset[hGrid->sfbWrap[tile_idx + 1]] - hGrid->swb_offset[hGrid->sfbWrap[tile_idx]]; + stop = add( strt_cpy, tile_width ); + } + ELSE + { + stop = hGrid->startLine; + move16(); + } + + /* strong whitening detected */ + IF( EQ_16( IGF_WHITENING_STRONG, hPrivateData->currWhiteningLevel[tile_idx] ) ) + { + Word32 abs_sum; + abs_sum = 0; + move32(); + + FOR( i = strt_cpy; i < stop; i++ ) + { + abs_sum = L_add_sat( abs_sum, L_abs( src_spec[i] ) ); /* saturation since it just checks if abs_sum is greater than zero*/ + } + + /* fill igf_spec with random noise */ + tb = hGrid->swb_offset[hGrid->sfbWrap[tile_idx]]; + move16(); + + IF( abs_sum != 0 ) + { + FOR( i = strt_cpy; i < stop; i++ ) + { + igf_spec[tb++] = L_deposit_l( Random( hInfo->nfSeed ) ); /* 31Q0, fill LSBs */ + } + } + ELSE + { + FOR( i = strt_cpy; i < stop; i++ ) + { + igf_spec[tb++] = 0; + move32(); + } + } + + /* set exponent of the current tile, random noise is 31Q0 */ + igf_spec_e[tile_idx] = 31; + move16(); + } + ELSE + { + /* medium whitening detected */ + IF( EQ_16( IGF_WHITENING_MID, hPrivateData->currWhiteningLevel[tile_idx] ) ) + { + IF( GT_16( element_mode, EVS_MONO ) ) + { + IF( n_noise_bands != 0 ) + { + IGF_replaceTCXNoise_2_new_ivas( igf_spec, + specMed_e, + TCXNoise, + strt_cpy, + stop, + totalNoiseNrg, + totalNoiseNrg_exp, + hPrivateData->n_noise_bands, + hInfo->nfSeed ); + } + } + ELSE + { + IF( n_noise_bands != 0 ) + { + IGF_replaceTCXNoise_2( igf_spec, + TCXNoise, + minSrcSubband, + startLine, + totalNoiseNrg, + hPrivateData->headroom_TCX_noise_white, + hInfo->nfSeed ); + } + } + + /* selected source spectrum is igf_spec, igf_spec contains the whitened signal in the core region */ + sel_spec = igf_spec; + move16(); + + /* set exponent of the current tile */ + igf_spec_e[tile_idx] = specMed_e; + move16(); + } + /* off whitening detectded */ + ELSE + { + + IF( GT_16( element_mode, EVS_MONO ) ) + { + IF( n_noise_bands_off != 0 ) + { + IGF_replaceTCXNoise_2_new_ivas( src_spec, + src_spec_e, + TCXNoise, + strt_cpy, + stop, + totalNoiseNrg_off, + totalNoiseNrg_off_exp, + hPrivateData->n_noise_bands_off, + hInfo->nfSeed ); + } + } + ELSE + { + IF( n_noise_bands_off != 0 ) + { + IGF_replaceTCXNoise_2( src_spec, + TCXNoise, + minSrcSubband, + startLine, + totalNoiseNrg_off, + hPrivateData->headroom_TCX_noise, + hInfo->nfSeed ); + } + } + /* selected source spectrum is pSpecFlat, pSpecFlat contains the signal before the LPC reshaping */ + sel_spec = src_spec; + move16(); + + /* set exponent of the current tile */ + igf_spec_e[tile_idx] = src_spec_e; + move16(); + } + /* generate the raw IGF spectrum out if the selected spectrum */ + FOR( sfb = hGrid->sfbWrap[tile_idx]; sfb < hGrid->sfbWrap[tile_idx + 1]; sfb++ ) + { + FOR( tb = hGrid->swb_offset[sfb]; tb < hGrid->swb_offset[sfb + 1]; tb++ ) + { + igf_spec[tb] = sel_spec[strt_cpy]; + move32(); + strt_cpy = add( strt_cpy, 1 ); + } + } + } + } +} + /**********************************************************************/ /* calculates IGF energies **************************************************************************/ @@ -511,6 +797,85 @@ static void IGF_calc(IGF_DEC_PRIVATE_DATA_HANDLE hPrivate } + +/**********************************************************************/ /* +calculates IGF energies (for IVAS) +**************************************************************************/ +static void IGF_calc_ivas( IGF_DEC_PRIVATE_DATA_HANDLE hPrivateData, /**< in: | IGF private data handle */ + const Word16 igfGridIdx, /**< in: Q0 | in case of CELP->TCX switching, use 1.25 framelength */ + const Word32 *spectrum, /**< in: Q31 | MDCT spectrum */ + const Word16 spectrum_e, /**< in: | exponent of pSpectralData */ + Word32 *igf_spec, /**< in: Q31 | prepared IGF spectrum */ + Word16 *igf_spec_e /**< in: | array exponents of igf_spec, one exponent per tile */ +) +{ + H_IGF_GRID hGrid; + Word16 i; + Word32 *igf_pN; /* Q31 | processed energy */ + Word16 *igf_pN_e; /* | exponents of igf_pN, one for each entry of igf_pN */ + Word32 *igf_sN; /* Q31 | survived energy */ + Word16 *igf_sN_e; /* | exponents of igf_sN, one for each entry of igf_sN */ + Word32 squaredSpectra[IGF_MAX_GRANULE_LEN]; /* Q31 | MDCT^2 spectra */ + Word16 squaredSpectra_e[IGF_MAX_TILES]; /* | exponents of squaredSpectra, one exponent per tile! */ + + + /* initialize variables */ + hGrid = &hPrivateData->igfInfo.grid[igfGridIdx]; + igf_pN = hPrivateData->igf_pN; + igf_pN_e = hPrivateData->igf_pN_e; + igf_sN = hPrivateData->igf_sN; + igf_sN_e = hPrivateData->igf_sN_e; + + set32_fx( squaredSpectra, 0, IGF_MAX_GRANULE_LEN ); + set16_fx( squaredSpectra_e, 0, IGF_MAX_TILES ); + + /* square the original spectrum */ + IGFCommonFuncsMDCTSquareSpec_ivas( hGrid->startLine, + hGrid->stopLine, + spectrum, + spectrum_e, + squaredSpectra, + squaredSpectra_e, + 0 ); + + /* calculate the energy per SFB of the survied subbands */ + IGFCommonFuncsCalcSfbEnergyPowerSpec( hGrid->startSfb, + hGrid->stopSfb, + hGrid->swb_offset, + squaredSpectra, + squaredSpectra_e, + igf_sN, + igf_sN_e ); + + /* loop over tiles, every tile has his own exponent! */ + FOR( i = 0; i < hGrid->nTiles; i++ ) + { + /* square the prepared IGF spectrum */ + IGFCommonFuncsMDCTSquareSpec_ivas( hGrid->tile[i], + hGrid->tile[i + 1], + igf_spec, + igf_spec_e[i], + squaredSpectra, + &squaredSpectra_e[i], + 0 ); + + /* set all squared values to 0, if the core contains survied lines */ + IGF_setLinesToZero( hGrid->tile[i], + hGrid->tile[i + 1], + spectrum, + squaredSpectra ); + + /* calculate the energy per SFB of the processed subbands */ + IGFCommonFuncsCalcSfbEnergyPowerSpec( hGrid->sfbWrap[i], + hGrid->sfbWrap[i + 1], + hGrid->swb_offset, + squaredSpectra, + &squaredSpectra_e[i], + igf_pN, + igf_pN_e ); + } +} + /**********************************************************************/ /* apply IGF **************************************************************************/ @@ -1199,42 +1564,707 @@ static void IGF_appl(IGF_DEC_PRIVATE_DATA_HANDLE hPrivate } /**********************************************************************/ /* -spectral whitening +apply IGF (for IVAS) **************************************************************************/ -static void IGF_getWhiteSpectralData(const Word32 *in, /**< in: Q31 | MDCT spectrum */ - Word16 s_l, /**< in: Q0 | getScaleFactor32() of in */ - Word32 *out, /**< out: Q31| whitened spectrum */ - const Word16 start, /**< in: Q0 | start MDCT subband index */ - const Word16 stop, /**< in: Q0 | stop MDCT subband index */ - const Word16 level /**< in: Q0 | whitening strength */ - ) +static void IGF_appl_ivas( IGF_DEC_PRIVATE_DATA_HANDLE hPrivateData, /**< in: | IGF private data handle */ + const Word16 igfGridIdx, /**< in: Q0 | in case of CELP->TCX switching, use 1.25 framelength */ + Word32 *spectrum, /**< in: Q31 | MDCT spectrum */ + Word16 *spectrum_e, /**< in: | exponent of pSpectralData */ + const Word32 *igf_spec, /**< in: Q31 | prepared IGF spectrum */ + const Word16 *igf_spec_e, /**< in: | array exponents of igf_spec, one exponent per tile */ + Word32 *virtualSpec, /**< out:Q31 | virtual IGF spectrum, used for temp flattening */ + Word16 *virtualSpec_e, /**< out: | exponent of virtualSpec */ + Word16 *flag_sparse, /**< out: Q0 | temp flattening indicator */ + Word16 bfi_apply_damping /**< in: | bfi apply damping */ +) { - Word16 j; - Word32 ak; /* moving average */ - Word32 ak_norm; - Word16 tmp_16; - Word16 div; - Word16 nrm_i; - Word16 nrm_tab[] = {2341 /* 1/14 */, 2521 /* 1/13 */, 2731 /* 1/12 */, 2979 /* 1/11 */, 3277 /* 1/10 */, 3641 /* 1/9 */, 4096 /* 1/8 */, 4681 /* 1/7 */}; + H_IGF_GRID hGrid; + Word16 i; + Word16 tb; + Word16 sfb; + Word16 shift; + Word16 s; + Word16 s_sfb; + Word16 start_sfb; + Word16 stop_sfb; + Word16 sfb_p1; + Word16 sfb_m1; + Word16 hopsize; + Word16 sum; + Word16 tileIdx; + Word16 width; /* Q0 | width of the current sfb */ + Word16 width_e; /* | exponent of widthent sfb, initialized as 15! */ + Word16 gFactor; /* 1Q14 | general SCF adaption */ + Word16 fFactor; /* 1Q14 | first SCF adaption */ + Word16 lFactor; /* 1Q14 | last SCF adaption */ + Word16 w0; /* Q15 | float value: 0.201f */ + Word16 w1; /* Q15 | float value: 0.389f */ + Word16 w2; /* Q15 | float value: 0.410f */ + Word16 dE; /* Q31 | energy below igfBgn */ + Word16 dE_e; /* | exponent of dE */ + Word16 gn; /* Q0 | gain read from bitstream + processing */ + Word16 gn_e; /* | exponent of gn */ + Word16 maxGain_e; /* | maximal gain exponent over sfbs */ + Word16 tmp; + Word16 tmp_e; + Word16 tmp_loop; + Word32 L_tmp; + Word16 L_tmp_e; + Word32 L_tmp2; + Word32 sNlocal; + Word16 sNlocal_e; + Word32 dNlocal; + Word16 dNlocal_e; + Word32 E; + Word16 E_e; + Word32 *sN; + Word16 *sN_e; + Word32 *pN; + Word16 *pN_e; + Word16 gain[IGF_MAX_SFB]; + Word16 gain_e[IGF_MAX_SFB]; + Word16 dN[IGF_MAX_SFB + 1]; + Word16 dN_e[IGF_MAX_SFB + 1]; + Word16 dS[IGF_MAX_SFB]; + Word16 dS_e[IGF_MAX_SFB]; + Word32 energyTmp[24]; + Word32 L_c; + Word16 spec_e_arr[N_MAX]; + Word16 vspec_e_arr[N_MAX_TCX - IGF_START_MN]; +#ifdef BASOP_NOGLOB_DECLARE_LOCAL + Flag Overflow = 0; + Flag Carry = 0; +#endif - /* inits */ - div = 0; + /* initialize variables */ + w0 = 6586; move16(); - s_l = sub(s_l, 2); - ak = 0; - move32(); - - - FOR (j = start - level; j < start + level; j++) - { - tmp_16 = extract_h(L_shl(in[j], s_l)); - ak = L_mac(ak, tmp_16, tmp_16); - } - FOR (j = start; j < stop - level; j++) - { - tmp_16 = extract_h(L_shl(in[j + level], s_l)); - ak = L_mac(ak, tmp_16, tmp_16); + w1 = 12747; + move16(); + w2 = 13435; + move16(); + dE = 0; + move16(); + dE_e = 0; + move16(); + tmp = 0; + move16(); + s = 0; + move16(); + tmp_e = 0; + move16(); + gn = 0; + move16(); + gn_e = 0; + move16(); + maxGain_e = 0; + move16(); + L_tmp_e = 0; + move16(); + dNlocal_e = 0; + move16(); + L_tmp = 0; + move32(); + dNlocal = 0; + move32(); + + set16_fx( gain, 0, IGF_MAX_SFB ); + set16_fx( gain_e, 0, IGF_MAX_SFB ); + set16_fx( dN, 0, add( IGF_MAX_SFB, 1 ) ); + set16_fx( dN_e, 0, add( IGF_MAX_SFB, 1 ) ); + set16_fx( dS, 0, IGF_MAX_SFB ); + set16_fx( dS_e, 0, IGF_MAX_SFB ); + set32_fx( energyTmp, 0, 24 ); + set16_fx( spec_e_arr, *spectrum_e, N_MAX ); + set16_fx( vspec_e_arr, 0, N_MAX_TCX - IGF_START_MN ); + + /* more inits */ + hGrid = &hPrivateData->igfInfo.grid[igfGridIdx]; + sN = hPrivateData->igf_sN; + sN_e = hPrivateData->igf_sN_e; + pN = hPrivateData->igf_pN; + pN_e = hPrivateData->igf_pN_e; + start_sfb = hGrid->startSfb; + move16(); + stop_sfb = hGrid->stopSfb; + move16(); + gFactor = hGrid->gFactor; + move16(); + fFactor = hGrid->fFactor; + move16(); + lFactor = hGrid->lFactor; + move16(); + + /* reset virtual spec */ + set16_fx( flag_sparse, 0, N_MAX_TCX - IGF_START_MN ); + set32_fx( virtualSpec, 0, N_MAX_TCX - IGF_START_MN ); + *virtualSpec_e = *spectrum_e; + move16(); + + /* collect energy below hGrid->startLine: */ + tmp = sub( hGrid->startLine, 24 ); + IGFCommonFuncsMDCTSquareSpec_ivas( tmp, + hGrid->startLine, + spectrum, + *spectrum_e, + energyTmp, + &dE_e, + negate( tmp ) ); + + L_c = 0; + move32(); + FOR( tb = 0; tb < 24; tb++ ) + { + Carry = 0; +#ifdef BASOP_NOGLOB /* Critical Carry/Overflow*/ + L_tmp = L_add_co( L_tmp, energyTmp[tb], &Carry, &Overflow ); + Overflow = 0; + L_c = L_macNs_co( L_c, 0, 0, &Carry, &Overflow ); +#else + L_tmp = L_add_c( L_tmp, energyTmp[tb] ); + Overflow = 0; + L_c = L_macNs( L_c, 0, 0 ); +#endif + } + L_tmp = norm_llQ31( L_c, L_tmp, &shift ); + /* float: dE = (float)sqrt(dE / 24.f); basop: */ + shift = add( sub( shift, 4 ), dE_e ); /* x/24 = (x >> 4) * 1/1.5 */ + dE = Sqrt16norm( extract_h( L_tmp ), &shift ); + dE = mult_r( dE, 26755 /*0.81649658092772603273242802490196f Q15*/ ); /* 0.81649658092772603273242802490196f = sqrt(1/1.5)) */ + dE_e = shift; + move16(); + + /* select correct hopsize for envelope refinement */ + hopsize = 2; + move16(); + if ( EQ_16( hPrivateData->currWhiteningLevel[0], IGF_WHITENING_OFF ) ) + { + hopsize = 4; + move16(); + } + if ( EQ_16( hPrivateData->currWhiteningLevel[0], IGF_WHITENING_STRONG ) ) + { + hopsize = 1; + move16(); + } + hopsize = s_min( hopsize, hPrivateData->igfInfo.maxHopsize ); + IF( hPrivateData->restrict_hopsize ) + { + hopsize = s_min( hopsize, 2 ); + } + + IF( hopsize > 1 ) + { + FOR( sfb = start_sfb; sfb < stop_sfb; sfb += hopsize ) + { + tmp_loop = s_min( add( sfb, hopsize ), stop_sfb ); + FOR( tb = add( sfb, 1 ); tb < tmp_loop; tb++ ) + { + sN[sfb] = BASOP_Util_Add_Mant32Exp( sN[sfb], + sN_e[sfb], + sN[tb], + sN_e[tb], + &sN_e[sfb] ); + move32(); + pN[sfb] = BASOP_Util_Add_Mant32Exp( pN[sfb], + pN_e[sfb], + pN[tb], + pN_e[tb], + &pN_e[sfb] ); + move32(); + sN[tb] = L_deposit_l( 0 ); + pN[tb] = L_deposit_l( 0 ); + } + } + } + + /* IGF_rescale_SCF */ + IF( hGrid->infoIsRefined != 0 ) + { + FOR( sfb = start_sfb; sfb < stop_sfb; sfb += 2 ) + { + /* calculate and normalize the width of the current sfb */ + width = sub( hGrid->swb_offset[sfb + 2], hGrid->swb_offset[sfb] ); + shift = norm_s( width ); + width = shl( width, shift ); + width_e = sub( 15, shift ); /* initial value of width_e is 15, -> width = 15Q0 */ + + /* float: gn = 0.25f * igf_curr - 4.f; basop: */ + gn = hPrivateData->igf_curr[shr( sfb, 1 )]; + move16(); + move16(); + gn_e = 13; /* set exponent of igf_curr to 13 = 15 - 2; -> igf_curr = igf_curr * 0.25, virtual division by 4 */ + gn = sub( gn, 16 ); /* 13Q2 | 4 = 16 * 2^(-15 + 13); ("4" has same exponent as igf_curr now) */ + + /* float: tmp = pow(2.f, gn); basop: */ + L_tmp = BASOP_util_Pow2( L_deposit_h( gn ), gn_e, &L_tmp_e ); + + /* float: tmp = tmp * tmp; basop: */ + tmp = round_fx( L_tmp ); + L_tmp = L_mult( tmp, tmp ); + L_tmp_e = add( L_tmp_e, L_tmp_e ); + + /* get sNlocal | float: sNlocal = sN[ sfb ] + sN[ sfb+ 1 ]; basop: */ + sNlocal = BASOP_Util_Add_Mant32Exp( sN[sfb], + sN_e[sfb], + sN[sfb + 1], + sN_e[sfb + 1], + &sNlocal_e ); + + /* float: sNlocal /= width; basop: */ + shift = sub( norm_l( sNlocal ), 1 ); /* leave MSB empty, so in the division sNlocal is always smaller than width */ + sNlocal = L_deposit_h( div_s( extract_h( L_shl( sNlocal, shift ) ), width ) ); + sNlocal_e = sub( sub( sNlocal_e, shift ), width_e ); + + /* float: tmp = max(0.001 * sNlocal, tmp - sNlocal); basop: */ + L_tmp = BASOP_Util_Add_Mant32Exp( L_tmp, + L_tmp_e, + L_negate( sNlocal ), + sNlocal_e, + &L_tmp_e ); /* float: tmp = tmp - sNlocal */ + + /* max(0.001 * sNlocal, L_tmp) */ + /* Build a threshold and compare with L_tmp. + Build negated threshold and compare with negated L_tmp to cover also fullscale L_tmp case */ + BASOP_SATURATE_WARNING_OFF_EVS +#ifdef BASOP_NOGLOB + L_tmp2 = L_shl_sat( L_negate( Mpy_32_16_1( sNlocal, 33 /*0.001f Q15*/ ) ), sub( sNlocal_e, L_tmp_e ) ); + L_tmp2 = L_sub_sat( L_tmp2, L_negate( L_tmp ) ); +#else + L_tmp2 = L_shl( L_negate( Mpy_32_16_1( sNlocal, 33 /*0.001f Q15*/ ) ), sub( sNlocal_e, L_tmp_e ) ); + L_tmp2 = L_sub( L_tmp2, L_negate( L_tmp ) ); +#endif + BASOP_SATURATE_WARNING_ON_EVS + + IF( L_tmp2 < 0 ) + { + L_tmp = Mpy_32_16_1( sNlocal, 33 /*0.001f Q15*/ ); + L_tmp_e = sNlocal_e; + move16(); + } + + /* calc square root of L_tmp and store result in dN */ + L_tmp = Sqrt32( L_tmp, &L_tmp_e ); + dN[sfb] = extract_h( L_tmp ); + dN_e[sfb] = L_tmp_e; + move16(); + dN[sfb + 1] = dN[sfb]; + move16(); + dN_e[sfb + 1] = dN_e[sfb]; + move16(); + } + } + ELSE + { + FOR( sfb = start_sfb; sfb < stop_sfb; sfb++ ) + { + /* calculate and normalize the width of the current sfb */ + width = sub( hGrid->swb_offset[sfb + 1], hGrid->swb_offset[sfb] ); + shift = norm_s( width ); + width = shl( width, shift ); + width_e = sub( 15, shift ); /* initial value of width_e is 15, -> width = 15Q0 */ + + /* float: gn = 0.25f * igf_curr - 4.f; basop: */ + gn = hPrivateData->igf_curr[sfb]; + move16(); + move16(); + gn_e = 13; /* set exponent of igf_curr to 13 = 15 - 2; -> igf_curr = igf_curr * 0.25, virtual division by 4 */ + gn = sub( gn, 16 ); /* 13Q2 | 4 = 16 * 2^(-15 + 13); ("4" has same exponent as igf_curr now) */ + + /* float: tmp = pow(2.f, gn); basop: */ + L_tmp = BASOP_util_Pow2( L_deposit_h( gn ), gn_e, &L_tmp_e ); + + /* float: tmp = tmp * tmp; basop: */ + tmp = round_fx( L_tmp ); + L_tmp = L_mult( tmp, tmp ); + L_tmp_e = add( L_tmp_e, L_tmp_e ); + + /* get sNlocal */ + sNlocal = sN[sfb]; + move32(); + sNlocal_e = sN_e[sfb]; + move16(); + + /* float: sNlocal /= width; basop: */ + shift = sub( norm_l( sNlocal ), 1 ); /* leave MSB empty, so in the division sNlocal is always smaller than width */ + sNlocal = L_deposit_h( div_s( extract_h( L_shl( sNlocal, shift ) ), width ) ); + sNlocal_e = sub( sub( sNlocal_e, shift ), width_e ); + + /* float: tmp = max(0.001 * sNlocal, tmp - sNlocal); basop: */ + L_tmp = BASOP_Util_Add_Mant32Exp( L_tmp, + L_tmp_e, + L_negate( sNlocal ), + sNlocal_e, + &L_tmp_e ); /* float: tmp = tmp - sNlocal */ + + /* max(0.001 * sNlocal, L_tmp) */ + /* Build a threshold and compare with L_tmp. + Build negated threshold and compare with negated L_tmp to cover also fullscale L_tmp case */ + L_tmp2 = L_shl_sat( L_negate( Mpy_32_16_1( sNlocal, 33 /*0.001f Q15*/ ) ), sub( sNlocal_e, L_tmp_e ) ); + L_tmp2 = L_sub_sat( L_tmp2, L_negate( L_tmp ) ); + + IF( L_tmp2 < 0 ) + { + L_tmp = Mpy_32_16_1( sNlocal, 33 /*0.001f Q15*/ ); + L_tmp_e = sNlocal_e; + } + + /* calc square root of L_tmp and store result in dN */ + L_tmp = Sqrt32( L_tmp, &L_tmp_e ); + dN[sfb] = round_fx( L_tmp ); + dN_e[sfb] = L_tmp_e; + move16(); + } + } + + dS[start_sfb] = dN[start_sfb]; + move16(); + dS_e[start_sfb] = dN_e[start_sfb]; + move16(); + + /* first value with adaption to core energy: */ + tmp_e = BASOP_Util_Add_MantExp( dE, + dE_e, + negate( dN[start_sfb] ), + dN_e[start_sfb], + &tmp ); /* float: tmp = dE - dN[start_sfb] */ + IF( tmp < 0 ) + { + /* float: dS[start_sfb] = dN[start_sfb] + fFactor * (dE-dN[start_sfb]); basop: */ + L_tmp = L_mult( fFactor, tmp ); + L_tmp_e = add( tmp_e, 1 ); /* 1Q14 | fFactor is 1Q14 */ + dS_e[start_sfb] = BASOP_Util_Add_MantExp( dN[start_sfb], + dN_e[start_sfb], + round_fx( L_tmp ), + L_tmp_e, + &dS[start_sfb] ); + move16(); + } + /* last value with less energy: */ + dS[stop_sfb - 1] = mult_r( lFactor, dN[stop_sfb - 1] ); + move16(); + move16(); + dS_e[stop_sfb - 1] = add( dN_e[stop_sfb - 1], 1 ); /* 1Q14 | lFactor is 1Q14 */ + + sfb_p1 = add( start_sfb, 1 ); + sfb_m1 = sub( stop_sfb, 1 ); + test(); + IF( hGrid->infoIsRefined != 0 && EQ_16( hopsize, 1 ) ) + { + /* apply filter to absolute energy values: */ + FOR( sfb = sfb_p1; sfb < sfb_m1; sfb++ ) + { + /* float: dS[sfb] = w0 * dN[sfb-1] + w1 * dN[sfb+0] + w2 * dN[sfb+1]; basop: */ + L_tmp = L_mult( w0, dN[sfb - 1] ); + dS[sfb] = round_fx( L_tmp ); + move16(); + dS_e[sfb] = dN_e[sfb - 1]; /* w0 is Q15, so no need to add an exponent */ + L_tmp = L_mult( w1, dN[sfb] ); + dS_e[sfb] = BASOP_Util_Add_MantExp( dS[sfb], + dS_e[sfb], + round_fx( L_tmp ), + dN_e[sfb], /* w1 is Q15, so no need to add an exponent */ + &tmp ); + move16(); + dS[sfb] = tmp; + move16(); + L_tmp = L_mult( w2, dN[sfb + 1] ); + dS_e[sfb] = BASOP_Util_Add_MantExp( dS[sfb], + dS_e[sfb], + round_fx( L_tmp ), + dN_e[sfb + 1], /* w2 is Q15, so no need to add an exponent */ + &tmp ); + move16(); + dS[sfb] = tmp; + move16(); + } + } + ELSE + { + FOR( sfb = sfb_p1; sfb < sfb_m1; sfb++ ) + { + dS[sfb] = dN[sfb]; + move16(); + dS_e[sfb] = dN_e[sfb]; + move16(); + } + } + + tileIdx = -1; + move16(); + FOR( sfb = start_sfb; sfb < stop_sfb; sfb += hopsize ) + { + E = 0; + move32(); + E_e = 0; + move16(); + sum = 0; + move16(); + + FOR( tb = 0; tb < hopsize; tb++ ) + { + /* calculate of the current sfb width */ + width = sub( hGrid->swb_offset[s_min( add( add( sfb, tb ), 1 ), stop_sfb )], /* 15Q0 | width is Q0 */ + hGrid->swb_offset[s_min( add( sfb, tb ), stop_sfb )] ); + + tmp = dS[s_min( add( sfb, tb ), sub( stop_sfb, 1 ) )]; + tmp_e = dS_e[s_min( add( sfb, tb ), sub( stop_sfb, 1 ) )]; + + /* square tmp */ + L_tmp = L_mult( tmp, tmp ); + L_tmp_e = add( tmp_e, tmp_e ); + + /* mult L_tmp times width */ + L_tmp = L_mult( round_fx( L_tmp ), width ); + L_tmp_e = add( L_tmp_e, 15 ); /* 15Q0 | width is Q0 */ + + /* calculate resulting energy */ + E = BASOP_Util_Add_Mant32Exp( E, + E_e, + L_tmp, + L_tmp_e, + &E_e ); + sum = add( sum, width ); /* 15Q0 | sum shares its exponent with width */ + } + + /* normalize sum for the following division */ + shift = norm_s( sum ); + sum = shl( sum, shift ); /* exponent of sum: sub(15, shift) */ + + /* divide E by sum */ +#ifdef BASOP_NOGLOB /* Critical Carry/Overflow*/ + tmp = div_s( shr( round_fx_o( E, &Overflow ), 1 ), sum ); /* shift E 1 bit to the right in order to make it smaller than sum */ +#else + tmp = div_s( shr( round_fx( E ), 1 ), sum ); /* shift E 1 bit to the right in order to make it smaller than sum */ +#endif + tmp_e = sub( add( E_e, 1 ), sub( 15, shift ) ); /* 15Q0 | sum is 15Q0 */ + + /* multiply the result by the hopsize */ + L_tmp = L_mult( tmp, hopsize ); + L_tmp_e = add( tmp_e, 15 ); /* 15Q0 | hopsize is 15Q0 */ + + /* take the square root and store the result in dS */ + L_tmp = Sqrt32( L_tmp, &L_tmp_e ); + dS[sfb] = round_fx( L_tmp ); + dS_e[sfb] = L_tmp_e; + move16(); + + /* calculate the new dN */ + dN[sfb] = mult_r( gFactor, dS[sfb] ); + move16(); + move16(); + dN_e[sfb] = add( dS_e[sfb], 1 ); /* 1Q14 | gFactor is 1Q14 */ + + /* calculate of the current sfb width */ + width = sub( hGrid->swb_offset[sfb + 1], /* 15Q0 | width is Q0 */ + hGrid->swb_offset[sfb] ); + + /* square dN */ + L_tmp = L_mult( dN[sfb], dN[sfb] ); + L_tmp_e = add( dN_e[sfb], dN_e[sfb] ); + + /* mult L_tmp times width */ + shift = norm_l( L_tmp ); + L_tmp = L_shl( L_tmp, shift ); + L_tmp = L_mult( round_fx( L_tmp ), width ); + L_tmp_e = sub( add( L_tmp_e, 15 ), shift ); /* 15Q0 | width is Q0 */ + shift = norm_l( L_tmp ); + + /* store normalized result */ + dNlocal = L_shl( L_tmp, shift ); + dNlocal_e = sub( L_tmp_e, shift ); + + /* gain calculation */ + gain[sfb] = 0; + move16(); + IF( pN[sfb] != 0 ) + { + tmp = BASOP_Util_Divide3232_Scale( dNlocal, pN[sfb], &s ); + s = sub( add( s, dNlocal_e ), pN_e[sfb] ); + gain[sfb] = Sqrt16( tmp, &s ); + move16(); + gain_e[sfb] = s; + move16(); + + + /* get the maximal exponent of the gain array, needed for exponent adjustment of the spectrum */ + maxGain_e = s_max( maxGain_e, gain_e[sfb] ); + } + sfb_p1 = add( sfb, 1 ); + sfb_m1 = s_min( add( sfb, hopsize ), stop_sfb ); + FOR( s_sfb = sfb_p1; s_sfb < sfb_m1; s_sfb++ ) + { + gain[s_sfb] = gain[sfb]; + move16(); + gain_e[s_sfb] = gain_e[sfb]; + move16(); + } + } + + /* tiling */ + tileIdx = -1; + move16(); + FOR( sfb = start_sfb; sfb < stop_sfb; sfb++ ) + { + /* get tile index */ + if ( EQ_16( hGrid->sfbWrap[tileIdx + 1], sfb ) ) + { + tileIdx = add( tileIdx, 1 ); + } + + test(); + IF( bfi_apply_damping && hPrivateData->frameLossCounter > 0 ) + { + /* normalize gain */ + tmp = norm_s( gain[sfb] ); + gain[sfb] = shl( gain[sfb], tmp ); + gain_e[sfb] = sub( gain_e[sfb], tmp ); + + /* gain[sfb] = min(gain[sfb], 12.f); */ + BASOP_SATURATE_WARNING_OFF_EVS /* threshold, may overflow */ + tmp = shl( gain[sfb], sub( gain_e[sfb], 15 - 5 ) ); /* 10Q5 | tmp is in 10Q5 */ + BASOP_SATURATE_WARNING_ON_EVS + + IF( tmp > 384 ) /* 10Q5 | 384 = 12 in 10Q5 */ + { + gain[sfb] = 384; + move16(); + gain_e[sfb] = 10; + move16(); + } + + IF( LT_16( hPrivateData->frameLossCounter, 5 ) ) + { + /* gain[sfb] -= gain[sfb] / 8 * hPrivateData->frameLossCounter; -> multiply with 0Q15 -> adaption of the exponent not needed */ + IF( EQ_16( hPrivateData->frameLossCounter, 1 ) ) + { + /* 0Q15 | >> 3 ^= * 0.125 = 1 / 8 */ + gain[sfb] = sub( gain[sfb], shr_r( gain[sfb], 3 ) ); + move16(); + } + ELSE IF( EQ_16( hPrivateData->frameLossCounter, 2 ) ) + { + /* 0Q15 | >> 2 ^= * 0.25 = 2 / 8 */ + gain[sfb] = sub( gain[sfb], shr_r( gain[sfb], 2 ) ); + move16(); + } + ELSE IF( EQ_16( hPrivateData->frameLossCounter, 3 ) ) + { + /* 0Q15 | * 12288 ^= * 0.3750 = 3 / 8 */ + gain[sfb] = sub( gain[sfb], mult_r( gain[sfb], 12288 ) ); + move16(); + } + ELSE + { + /* 0Q15 | >> 1 ^= * 0.5 = 4 / 8 */ + gain[sfb] = sub( gain[sfb], shr_r( gain[sfb], 1 ) ); + move16(); + } + } + ELSE + { + /* gain[sfb] /= 2; -> reduce exponent by 1 */ + gain_e[sfb] = sub( gain_e[sfb], 1 ); + move16(); + } + } + + FOR( tb = hGrid->swb_offset[sfb]; tb < hGrid->swb_offset[sfb + 1]; tb++ ) + { + /* multiply the prepared IGF spectrum with the gain */ + L_tmp2 = 0; /* set L_tmp2 to default value */ + move32(); + L_tmp = Mpy_32_16_1( igf_spec[tb], gain[sfb] ); + L_tmp_e = add( igf_spec_e[tileIdx], gain_e[sfb] ); + + /* store the finalized IGF spectrum */ + IF( spectrum[tb] == 0 ) + { + spectrum[tb] = L_tmp; + move32(); + spec_e_arr[tb] = L_tmp_e; + move16(); + flag_sparse[tb - IGF_START_MN] = 1; + move16(); + } + ELSE + { + virtualSpec[tb - IGF_START_MN] = L_tmp; + move32(); + vspec_e_arr[tb - IGF_START_MN] = L_tmp_e; + move16(); + flag_sparse[tb - IGF_START_MN] = 2; + move16(); + } + } + } + + Word16 max_e; + max_e = MIN16B; + move16(); + FOR( i = 0; i < hGrid->stopLine; i++ ) + { + max_e = s_max( max_e, spec_e_arr[i] ); + } + FOR( i = 0; i < hGrid->stopLine; i++ ) + { + spectrum[i] = L_shr( spectrum[i], sub( max_e, spec_e_arr[i] ) ); + move16(); + } + *spectrum_e = max_e; + move16(); + + max_e = MIN16B; + move16(); + FOR( i = hGrid->startLine - IGF_START_MN; i < hGrid->stopLine - IGF_START_MN; i++ ) + { + max_e = s_max( max_e, vspec_e_arr[i] ); + } + FOR( i = hGrid->startLine - IGF_START_MN; i < hGrid->stopLine - IGF_START_MN; i++ ) + { + virtualSpec[i] = L_shr( virtualSpec[i], sub( max_e, vspec_e_arr[i] ) ); + move16(); + } + *virtualSpec_e = max_e; + move16(); +} + +/**********************************************************************/ /* +spectral whitening +**************************************************************************/ +static void IGF_getWhiteSpectralData(const Word32 *in, /**< in: Q31 | MDCT spectrum */ + Word16 s_l, /**< in: Q0 | getScaleFactor32() of in */ + Word32 *out, /**< out: Q31| whitened spectrum */ + const Word16 start, /**< in: Q0 | start MDCT subband index */ + const Word16 stop, /**< in: Q0 | stop MDCT subband index */ + const Word16 level /**< in: Q0 | whitening strength */ + ) +{ + Word16 j; + Word32 ak; /* moving average */ + Word32 ak_norm; + Word16 tmp_16; + Word16 div; + Word16 nrm_i; + Word16 nrm_tab[] = {2341 /* 1/14 */, 2521 /* 1/13 */, 2731 /* 1/12 */, 2979 /* 1/11 */, 3277 /* 1/10 */, 3641 /* 1/9 */, 4096 /* 1/8 */, 4681 /* 1/7 */}; + + /* inits */ + div = 0; + move16(); + s_l = sub(s_l, 2); + ak = 0; + move32(); + + FOR (j = start - level; j < start + level; j++) + { + tmp_16 = extract_h(L_shl(in[j], s_l)); // e: in_e - s_l + ak = L_mac(ak, tmp_16, tmp_16); // e: 2 * (in_e - s_l) + } + FOR (j = start; j < stop - level; j++) + { + tmp_16 = extract_h(L_shl(in[j + level], s_l)); // in_e - s_l + ak = L_mac(ak, tmp_16, tmp_16); // 2 * (in_e - s_l) ak_norm = Mpy_32_16_r(ak, 2185); tmp_16 = sub(31, norm_l(ak_norm)); @@ -1284,6 +2314,98 @@ static void IGF_getWhiteSpectralData(const Word32 *in, } +/*-------------------------------------------------------------------* + * IGF_getWhiteSpectralData_ivas() + * + * spectral whitening + *-------------------------------------------------------------------*/ + +static void IGF_getWhiteSpectralData_ivas( + const Word32 *in, /* i : MDCT spectrum */ + const Word16 in_e, /* i : MDCT spectrum exp */ + Word16 s_l, /* i : getScaleFactor32() of in */ + Word32 *out, /* o : whitened spectrum */ + Word16 *out_e, /* o : whitened spectrum exp */ + const Word16 start, /* i : start MDCT subband index */ + const Word16 stop, /* i : stop MDCT subband index */ + const Word16 level /* i : whitening strength */ +) +{ + Word16 i; + Word16 n; + Word16 j; + Word32 ak; + Word16 ak_e; + Word16 tmp_16; + Word16 tmp_e; + Word16 out_e_arr[IGF_START_MX + MAX_IGF_SFB_LEN]; + Word16 max_out_e; + assert( LT_16( stop, IGF_START_MX + MAX_IGF_SFB_LEN ) ); + + /* inits */ + ak = 0; + move16(); + ak_e = 0; + move16(); + tmp_e = 0; + move16(); + max_out_e = 0; + move16(); + s_l = sub( s_l, 2 ); + + FOR( i = start; i < stop - level; i++ ) + { + ak = 0; + ak_e = 0; + FOR( j = i - level; j < i + level + 1; j++ ) + { + tmp_16 = extract_h( L_shl( in[j], s_l ) ); + ak = L_mac( ak, tmp_16, tmp_16 ); + } + ak = L_deposit_h( BASOP_Util_Divide3216_Scale( ak, add( shl( level, 1 ), 1 ), &tmp_e ) ); + ak_e = add( tmp_e, sub( shl( sub( in_e, s_l ), 1 ), 15 ) ); // tmp_e + 2 * (in_e - s_l) - 15 + + n = sub( 30, add( norm_l( ak ), sub( 31, ak_e ) ) ); + n = shr( n, 1 ); + + out_e_arr[i] = add( sub( 21, n ), in_e ); + move16(); + max_out_e = s_max( max_out_e, out_e_arr[i] ); + } + + FOR( ; i < stop; i++ ) + { + ak = 0; + ak_e = 0; + + FOR( j = i - level; j < stop; j++ ) + { + tmp_16 = extract_h( L_shl( in[j], s_l ) ); + ak = L_mac( ak, tmp_16, tmp_16 ); + } + ak = L_deposit_h( BASOP_Util_Divide3216_Scale( ak, sub( stop, sub( i, level ) ), &tmp_e ) ); + ak_e = add( tmp_e, sub( shl( sub( in_e, s_l ), 1 ), 15 ) ); // tmp_e + 2 * (in_e - s_l) - 15 + + n = sub( 30, add( norm_l( ak ), sub( 31, ak_e ) ) ); + n = shr( n, 1 ); + + out_e_arr[i] = add( sub( 21, n ), in_e ); + move16(); + max_out_e = s_max( max_out_e, out_e_arr[i] ); + } + + *out_e = max_out_e; + move16(); + FOR( i = start; i < stop; i++ ) + { + out[i] = L_shr( in[i], *out_e - out_e_arr[i] ); + move32(); + } + + return; +} + + /**********************************************************************/ /* refines the IGF grid **************************************************************************/ @@ -1738,6 +2860,198 @@ void IGFDecApplyMono(const IGF_DEC_INSTANCE_HANDLE hInstance, } +/**********************************************************************/ /* +apply the IGF decoder (for IVAS) +**************************************************************************/ +void IGFDecApplyMono_ivas( const IGF_DEC_INSTANCE_HANDLE hInstance, /**< in: | instance handle of IGF Decoder */ + Word32 *spectrum, /**< in/out: | MDCT spectrum */ + Word16 *spectrum_e, /**< in/out: | exponent of spectrum */ + const Word16 igfGridIdx, /**< in: | in case of CELP->TCX switching, use 1.25 framelength */ + Word16 bfi, /**< in: | frame loss == 1, frame good == 0 */ + Word16 element_mode /**< in: | IVAS element mode */ +) +{ + IGF_DEC_PRIVATE_DATA_HANDLE hPrivateData; + H_IGF_GRID hGrid; + Word16 i; + Word16 whiteningLevel; + Word16 s_l; /* | headroom of pSpecFlat */ + Word16 specMed_e; /* | exponent of the medium whitened spectrum */ + Word32 igf_spec[IGF_MAX_GRANULE_LEN]; /* Q31 | prepared IGF spectrum */ + Word16 igf_spec_e[IGF_MAX_TILES]; /* | exponents of igf_spec, one exponent per tile */ + Word16 len; + + hPrivateData = &hInstance->igfData; + hGrid = &hPrivateData->igfInfo.grid[igfGridIdx]; + + /* initialize variables */ + + IF( GT_16( element_mode, EVS_MONO ) ) + { + whiteningLevel = IGF_MID_WHITENING_LEVEL2; + move16(); + } + ELSE + { + whiteningLevel = IGF_MID_WHITENING_LEVEL; + move16(); + } + + IF( EQ_16( igfGridIdx, IGF_GRID_LB_SHORT ) ) + { + len = ( N_MAX_TCX - IGF_START_MN ) / 2; + move16(); + } + ELSE + { + len = ( N_MAX_TCX - IGF_START_MN ); + move16(); + } + + set16_fx( hInstance->flag_sparse, 0, len ); + set32_fx( hInstance->virtualSpec_fx, 0, len ); + hInstance->virtualSpec_e = 0; + move16(); + + specMed_e = 0; + move16(); + hPrivateData->n_noise_bands = 0; + move16(); + hPrivateData->n_noise_bands_off = 0; + move16(); + hPrivateData->headroom_TCX_noise_white = 0; + move16(); + hPrivateData->headroom_TCX_noise = 0; + move16(); + hPrivateData->totalNoiseNrg = 0; + move32(); + hPrivateData->totalNoiseNrg_off = 0; + move32(); + hPrivateData->restrict_hopsize = 0; + move16(); + + set32_fx( igf_spec, 0, IGF_MAX_GRANULE_LEN ); + set16_fx( igf_spec_e, 0, IGF_MAX_TILES ); + + /* concealment counter */ + IF( bfi != 0 ) + { + hPrivateData->frameLossCounter = add( hPrivateData->frameLossCounter, 1 ); + } + ELSE + { + hPrivateData->frameLossCounter = 0; + move16(); + } + + /* skip IGF processing if all IGF levels are zero */ + IF( hInstance->infoIGFAllZero == 0 ) + { + FOR( i = 0; i < hGrid->nTiles; i++ ) + { + IF( EQ_16( hPrivateData->currWhiteningLevel[i], IGF_WHITENING_MID ) ) + { + test(); + IF( EQ_16( element_mode, EVS_MONO ) || !bfi ) + { + s_l = getScaleFactor32( hPrivateData->pSpecFlat + hGrid->minSrcSubband - whiteningLevel, + add( sub( hGrid->startLine, hGrid->minSrcSubband ), whiteningLevel ) ); + + IGF_getWhiteSpectralData_ivas( hPrivateData->pSpecFlat, + hPrivateData->pSpecFlat_exp, + s_l, + igf_spec, + &igf_spec_e[i], + hGrid->minSrcSubband, + hGrid->startLine, + whiteningLevel ); + } + ELSE + { + Copy32( hPrivateData->pSpecFlat, igf_spec, hGrid->startLine ); + igf_spec_e[i] = hPrivateData->pSpecFlat_exp, + move16(); + } + specMed_e = igf_spec_e[i]; + move16(); + + /*14 seems to be precise enough*/ + hPrivateData->headroom_TCX_noise_white = IGF_getScaleFactor32Cond( + hInstance->infoTCXNoise_evs + hGrid->minSrcSubband, + igf_spec + hGrid->minSrcSubband, + sub( hGrid->startLine, hGrid->minSrcSubband ) ); + hPrivateData->n_noise_bands = IGF_replaceTCXNoise_1( igf_spec, + hPrivateData->headroom_TCX_noise_white, + hInstance->infoTCXNoise_evs, + hGrid->minSrcSubband, + hGrid->startLine, + &hPrivateData->totalNoiseNrg ); + + hPrivateData->totalNoiseNrg_exp = shl( sub( igf_spec_e[i], sub( hPrivateData->headroom_TCX_noise_white, 5 ) ), 1 ); + + BREAK; + } + } + + + FOR( i = 0; i < hGrid->nTiles; i++ ) + { + IF( hPrivateData->currWhiteningLevel[i] == IGF_WHITENING_OFF ) + { + hPrivateData->headroom_TCX_noise = IGF_getScaleFactor32Cond( + hInstance->infoTCXNoise_evs + hGrid->minSrcSubband, + hPrivateData->pSpecFlat + hGrid->minSrcSubband, + sub( hGrid->startLine, hGrid->minSrcSubband ) ); + + hPrivateData->n_noise_bands_off = IGF_replaceTCXNoise_1( hPrivateData->pSpecFlat, + hPrivateData->headroom_TCX_noise, + hInstance->infoTCXNoise_evs, + hGrid->minSrcSubband, + hGrid->startLine, + &hPrivateData->totalNoiseNrg_off ); + hPrivateData->totalNoiseNrg_off_exp = shl( sub( hPrivateData->pSpecFlat_exp, sub( hPrivateData->headroom_TCX_noise, 5 ) ), 1 ); + BREAK; + } + } + + IGF_prep_ivas( hPrivateData, + igfGridIdx, + hInstance->infoTCXNoise_evs, + igf_spec, + igf_spec_e, + hPrivateData->pSpecFlat, + hPrivateData->pSpecFlat_exp, + specMed_e, + element_mode ); + IGF_calc_ivas( hPrivateData, + igfGridIdx, + spectrum, + *spectrum_e, + igf_spec, + igf_spec_e ); + IGF_appl_ivas( hPrivateData, + igfGridIdx, + spectrum, + spectrum_e, + igf_spec, + igf_spec_e, + hInstance->virtualSpec, + &hInstance->virtualSpec_e, + hInstance->flag_sparseBuf, + 1 ); + } + + /* reset TCX noise indicator vector */ + IF( EQ_16( igfGridIdx, IGF_GRID_LB_SHORT ) ) + { + set16_fx( hInstance->infoTCXNoise_evs, 0, IGF_START_MX / 2 ); + } + ELSE + { + set16_fx( hInstance->infoTCXNoise_evs, 0, IGF_START_MX ); + } +} + /**********************************************************************/ /* set mode is used to init the IGF dec with a new bitrate **************************************************************************/ @@ -1906,7 +3220,7 @@ void IGFDecUpdateInfo_fx( hIGFDec->infoTCXNoise = &hIGFDec->infoTCXNoiseBuf[0]; hIGFDec->virtualSpec_fx = &hIGFDec->virtualSpec[0]; - hIGFDec->igfData.pSpecFlat_fx = &hIGFDec->igfData.pSpecFlat[0]; + hIGFDec->igfData.pSpecFlat = &hIGFDec->igfData.pSpecFlatBuf_fx[0]; /* TODO: remove float init */ hIGFDec->virtualSpec_float = &hIGFDec->virtualSpecBuf[0]; @@ -1944,7 +3258,7 @@ void IGFDecReplicateTCX10State_fx( mvr2r( &hIGFDec->igfData.pSpecFlatBuf[IGF_START_MX / 2], &hIGFDec->igfData.pSpecFlatBuf[0], IGF_START_MX / 2 ); Copy32( &hIGFDec->virtualSpec[( N_MAX_TCX - IGF_START_MN ) / 2], &hIGFDec->virtualSpec[0], ( N_MAX_TCX - IGF_START_MN ) / 2 ); - Copy32( &hIGFDec->igfData.pSpecFlat[IGF_START_MX / 2], &hIGFDec->igfData.pSpecFlat[0], IGF_START_MX / 2 ); + Copy32( &hIGFDec->igfData.pSpecFlatBuf_fx[IGF_START_MX / 2], &hIGFDec->igfData.pSpecFlatBuf_fx[0], IGF_START_MX / 2 ); hIGFDec->igfData.igfInfo.nfSeedBuf[0] = hIGFDec->igfData.igfInfo.nfSeedBuf[1]; move16(); @@ -2085,7 +3399,7 @@ void IGFDecRestoreTCX10SubFrameData_fx( hIGFDec->infoTCXNoise = &hIGFDec->infoTCXNoiseBuf[subFrameIdx * ( IGF_START_MX ) / 2]; hIGFDec->virtualSpec_fx = &hIGFDec->virtualSpec[subFrameIdx * ( N_MAX_TCX - IGF_START_MN ) / 2]; - hIGFDec->igfData.pSpecFlat_fx = &hIGFDec->igfData.pSpecFlat[subFrameIdx * IGF_START_MX / 2]; + hIGFDec->igfData.pSpecFlat = &hIGFDec->igfData.pSpecFlatBuf_fx[subFrameIdx * IGF_START_MX / 2]; /* TODO: remove float init */ hIGFDec->virtualSpec_float = &hIGFDec->virtualSpecBuf[subFrameIdx * ( N_MAX_TCX - IGF_START_MN ) / 2]; diff --git a/lib_dec/ivas_mdct_core_dec.c b/lib_dec/ivas_mdct_core_dec.c index 4eaf61668138f6af4ffd7c87940843ca134ef1d7..c945d029b26ef32fd154d4fcb1e0ff79015aa32d 100644 --- a/lib_dec/ivas_mdct_core_dec.c +++ b/lib_dec/ivas_mdct_core_dec.c @@ -1278,7 +1278,56 @@ void ivas_mdct_core_invQ( #endif #ifdef IVAS_FLOAT_FIXED - decoder_tcx_noiseshaping_igf_fx( st, L_spec[ch], L_frame[ch], L_frameTCX[ch], left_rect[ch], x[ch][k], x_fx, &x_e, NULL, NULL, &tmp_concealment_method, bfi ); + // Float to fix starts here + Word16 x_len; + IF(bfi && st->tonal_mdct_plc_active && NE_16(st->element_mode, IVAS_CPE_MDCT)) + { + FOR(Word16 i = 0; i < st->hTonalMDCTConc->pTCI_float->numIndexes; i++) + { + float pd = st->hTonalMDCTConc->pTCI_float->phaseDiff_float[i]; + if (pd >= PI2) + pd = fmodf(pd, PI2) - PI2; + st->hTonalMDCTConc->pTCI_fix->phaseDiff[i] = float_to_fix16(pd, Q12); + } + FOR(Word16 i = 0; i < MAX_NUMBER_OF_IDX * GROUP_LENGTH; i++) + { + float pd = st->hTonalMDCTConc->pTCI_float->phase_currentFramePredicted_float[i]; + pd = fmodf(pd, PI2); + st->hTonalMDCTConc->pTCI_fix->phase_currentFramePredicted[i] = (Word16)(pd * (1u << Q13)); + } + FOR(Word16 i = 0; i < FDNS_NPTS; i++) + { + f2me_16(st->hTonalMDCTConc->secondLastBlockData.scaleFactors_float[i], &st->hTonalMDCTConc->secondLastBlockData.scaleFactors[i], &st->hTonalMDCTConc->secondLastBlockData.scaleFactors_exp[i]); + st->hTonalMDCTConc->secondLastBlockData.scaleFactors_max_e = s_max(st->hTonalMDCTConc->secondLastBlockData.scaleFactors_max_e, st->hTonalMDCTConc->secondLastBlockData.scaleFactors_exp[i]); + } + } + st->hTcxDec->tcxltp_last_gain_unmodified = float_to_fix16(st->hTcxDec->tcxltp_last_gain_unmodified_float, Q15); + st->old_fpitch = float_to_fix(st->old_fpitch_float, Q16); + st->hTonalMDCTConc->lastPitchLag = float_to_fix(st->hTonalMDCTConc->lastPitchLag_float, Q16); + IF(st->enablePlcWaveadjust) + { + f2me_buf(st->hPlcInfo->data_reci2, st->hPlcInfo->data_reci2_fx, &st->hPlcInfo->data_reci2_scale, st->hPlcInfo->L_frameTCX); + } + // u8bit to 16bit + FOR(int l = 0; l < IGF_START_MX; l++) + { + st->hIGFDec->infoTCXNoise_evs[l] = (Word16)st->hIGFDec->infoTCXNoise[l]; + } + // Float to fix ends here + + decoder_tcx_noiseshaping_igf_fx( st, L_spec[ch], L_frame[ch], L_frameTCX[ch], left_rect[ch], x_fx, &x_e, &x_len, NULL, NULL, &tmp_concealment_method, bfi ); + + // Fixed to float starts here + st->hTonalMDCTConc->lastPitchLag_float = fix_to_float(st->hTonalMDCTConc->lastPitchLag, Q16); + st->hTonalMDCTConc->nFramesLost_float = fix16_to_float(st->hTonalMDCTConc->nFramesLost, Q1); + // 16bit to u8bit + FOR(Word16 l = 0; l < IGF_START_MX; l++) + { + st->hIGFDec->infoTCXNoise[l] = (uint8_t)st->hIGFDec->infoTCXNoise_evs[l]; + } + me2f_buf(st->hIGFDec->virtualSpec, st->hIGFDec->virtualSpec_e, st->hIGFDec->virtualSpec_float, (N_MAX_TCX - IGF_START_MN)); + me2f_buf(x_fx, x_e, x[ch][k], x_len); + // Fixed to float ends here #else decoder_tcx_noiseshaping_igf( st, L_spec[ch], L_frame[ch], L_frameTCX[ch], left_rect[ch], x[ch][k], NULL, &tmp_concealment_method, bfi ); #endif @@ -1696,10 +1745,6 @@ void ivas_mdct_core_tns_ns( Word32 x_fx[N_MAX]; Word16 x_e; f2me_buf(x[ch][0], x_fx, &x_e, st->hTonalMDCTConc->pTCI_float->upperIndex[st->hTonalMDCTConc->pTCI_float->numIndexes - 1]); - IF(!st->hTonalMDCTConc->lastBlockData.blockIsConcealed && st->hTonalMDCTConc->secondLastBlockData.tonalConcealmentActive != 0) - { - st->hTonalMDCTConc->nFramesLost = float_to_fix16(st->hTonalMDCTConc->nFramesLost_float, Q1); - } FOR(Word16 i = 0; i < st->hTonalMDCTConc->pTCI_float->numIndexes; i++) { float pd = st->hTonalMDCTConc->pTCI_float->phaseDiff_float[i]; diff --git a/lib_dec/stat_dec.h b/lib_dec/stat_dec.h index 4aece7ae7313b1bf0a774be9455cfde068ff1f48..5468047c15b1070cfe95477012ff710d6abb71e9 100644 --- a/lib_dec/stat_dec.h +++ b/lib_dec/stat_dec.h @@ -443,8 +443,8 @@ typedef struct igfdec_private_data_struct /* spectral whitening: */ float *pSpecFlat_float; float pSpecFlatBuf[IGF_START_MX]; - Word32 *pSpecFlat_fx; - Word32 pSpecFlat[IGF_START_MX]; /* Q31 | MDCT spectrum before LPC shaping */ + Word32 *pSpecFlat; + Word32 pSpecFlatBuf_fx[IGF_START_MX]; /* Q31 | MDCT spectrum before LPC shaping */ Word16 pSpecFlat_exp; int16_t restrict_hopsize; @@ -456,6 +456,7 @@ typedef struct igfdec_private_data_struct float totalNoiseNrg_float; Word32 totalNoiseNrg; + Word16 totalNoiseNrg_exp; int16_t n_noise_bands; @@ -464,6 +465,7 @@ typedef struct igfdec_private_data_struct float totalNoiseNrg_off_float; Word32 totalNoiseNrg_off; + Word16 totalNoiseNrg_off_exp; int16_t n_noise_bands_off;