diff --git a/lib_com/ivas_prot_fx.h b/lib_com/ivas_prot_fx.h index a457cc575295af4c95c92b3b0e46a7b4a7af6fea..a43b0f95317ff83ddea4b8cbf0db89057c81823d 100644 --- a/lib_com/ivas_prot_fx.h +++ b/lib_com/ivas_prot_fx.h @@ -349,6 +349,21 @@ void decoder_tcx_noisefilling_fx( const Word16 frame_cnt /* i : frame counter in the super frame*/ ); +void decoder_tcx_noiseshaping_igf_fx( + Decoder_State *st, /* i/o: coder memory state */ + const Word16 L_spec, + const Word16 L_frame, + const Word16 L_frameTCX, + const Word16 left_rect, + float x[], + Word32 *x_fx, + Word16 *x_e, + const Word16 gainlpc2_fx[], + const Word16 gainlpc2_e[], + Word16 *temp_concealment_method, + const Word16 bfi /* i : Bad frame indicator */ +); + void init_tcx_info_fx( Decoder_State *st, /* i/o: coder memory state */ const Word16 L_frame_glob, /* i : global frame length */ @@ -990,7 +1005,6 @@ Word16 matrix_product_diag_fx( Word32 *Z, /* o : resulting matrix after the matrix multiplication */ Word16 *Z_e ); - // ivas_stereo_mdct_core_dec_fx.c void stereo_mdct_core_dec_fx( Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ @@ -1125,5 +1139,3 @@ void FdCngDecodeDiracMDCTStereoSID_fx( ); #endif - - diff --git a/lib_com/prot_fx2.h b/lib_com/prot_fx2.h index 554c8c49577e144427eadcf67a7e177ebd0d0b9b..6b39a956f44fbfdd0a736245dd15b552b6fac391 100644 --- a/lib_com/prot_fx2.h +++ b/lib_com/prot_fx2.h @@ -3633,6 +3633,14 @@ void mdct_shaping_16( Word16 gains_max_exp, Word32 y[] ); +void mdct_noiseShaping_ivas_fx( + Word32 x_fx[], + Word16 *x_e, + const Word16 lg, + const Word16 gains_fx[], + const Word16 gains_exp[] +); + void mdct_noiseShaping_interp( Word32 x[], const Word16 lg, @@ -5501,6 +5509,13 @@ void TonalMDCTConceal_Apply( #endif ); +void TonalMDCTConceal_Apply_ivas_fx( + TonalMDCTConcealPtr hTonalMDCTConc, /*IN */ + Word32 *mdctSpectrum, /*IN/OUT*/ + Word16 *mdctSpectrum_exp, /*IN */ + const PsychoacousticParameters *psychParamsCurrent +); + /* Conceals the lost frame using the FD signal previously stored using * TonalMDCTConceal_SaveFreqSignal. Stores the concealed noise part of * the signal in mdctSpectrum, the rest of the spectrum is unchanged. */ diff --git a/lib_com/tcx_utils_fx.c b/lib_com/tcx_utils_fx.c index a0e8bd2161d76f7b49d66c9c3e7f1dfe99f98cdc..3f0d0887cdff197b9cdb1202423a84068c595ff5 100644 --- a/lib_com/tcx_utils_fx.c +++ b/lib_com/tcx_utils_fx.c @@ -1144,6 +1144,97 @@ void mdct_shaping_16( } } +void mdct_noiseShaping_ivas_fx( + Word32 x_fx[], + Word16 *x_e, + const Word16 lg, + const Word16 gains_fx[], + const Word16 gains_exp[] + /*const Word16 nBands*/ /*Parameter added in IVAS, but always equal to FDNS_NPTS */ +) +{ + Word16 i, j, k, l; + Word16 m, n, k1, k2; + + j = 0; + /* FDNS_NPTS = 64 */ + k = shr(lg, 6); + m = s_and(lg, 0x3F); + + Word16 max_e = MIN16B; + FOR(i = 0; i < FDNS_NPTS; i++) + { + max_e = s_max(max_e, add(*x_e, gains_exp[i])); + } + + IF(m != 0) + { + IF(LE_16(m, FDNS_NPTS / 2)) + { + n = idiv1616U(FDNS_NPTS, m); + k1 = k; + move16(); + k2 = add(k, 1); + } + ELSE + { + n = idiv1616U(FDNS_NPTS,sub(FDNS_NPTS,m)); + k1 = add(k,1); + k2 = k; + move16(); + } + + i = 0; + move16(); + j = 0; + move16(); + + WHILE(LT_16(i, lg)) + { + IF ( j % n != 0 ) + { + k = k1; + move16(); + } + ELSE + { + k = k2; + move16(); + } + + /* Limit number of loops, if end is reached */ + k = s_min(k, sub(lg, i)); + + FOR(l = 0; l < k; l++) + { + x_fx[i] = Mpy_32_16_1(x_fx[i], gains_fx[j]); + x_fx[i] = L_shr(x_fx[i], sub(max_e, add(*x_e, gains_exp[j]))); + i = add(i, 1); + } + j = add(j, 1); + } + } + ELSE + { + FOR ( i = 0; i < lg; ) + { + FOR ( l = 0; l < k; l++ ) + { + x_fx[i] = Mpy_32_16_1(x_fx[i], gains_fx[j]); + x_fx[i] = L_shr(x_fx[i], sub(max_e, add(*x_e, gains_exp[j]))); + i = add(i, 1); + } + j = add(j, 1); + } + } + + *x_e = max_e; + move16(); + + return; +} + + void mdct_noiseShaping_interp( Word32 x[], const Word16 lg, diff --git a/lib_dec/dec_tcx_fx.c b/lib_dec/dec_tcx_fx.c index 0ed1b1cb359aa055cc75b16b40a8e025cfffc39a..71f4bfe905afeef1a516c106ecaf10ab8614dce4 100644 --- a/lib_dec/dec_tcx_fx.c +++ b/lib_dec/dec_tcx_fx.c @@ -2664,7 +2664,11 @@ void decoder_tcx_fx( decoder_tcx_noisefilling( st, NULL, A, L_frameTCX_glob, L_spec, L_frame, L_frameTCX, &x[0], &gainlpc2[0], &tmp_concealment_method, gain_tcx, prm_sqQ, nf_seed, bfi, 0, frame_cnt ); #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 ); +#else decoder_tcx_noiseshaping_igf( st, L_spec, L_frame, L_frameTCX, left_rect, &x[0], &gainlpc2[0], &tmp_concealment_method, bfi ); +#endif decoder_tcx_tns( st, L_frame_glob, L_spec, L_frame, L_frameTCX, &x[0], fUseTns, &tnsData, bfi, frame_cnt, 0 ); @@ -3212,7 +3216,7 @@ void decoder_tcx_invQ_fx( } /*-------------------------------------------------------------------* - * decoder_tcx_noisefilling_fx() + * decoder_tcx_noisefilling() * * TCX: core noise filling, IGF updates *-------------------------------------------------------------------*/ @@ -3604,3 +3608,195 @@ void decoder_tcx_noisefilling_fx( return; } + +/*-------------------------------------------------------------------* + * decoder_tcx_noiseshaping_igf_fx() + * + * TCX: FDNS and IGF application + *-------------------------------------------------------------------*/ + +void decoder_tcx_noiseshaping_igf_fx( + Decoder_State *st, /* i/o: coder memory state */ + const Word16 L_spec, + const Word16 L_frame, + const Word16 L_frameTCX, + const Word16 left_rect, + float x[], + Word32 *x_fx, + Word16 *x_e, + const Word16 gainlpc2_fx[], + const Word16 gainlpc2_e[], + Word16 *temp_concealment_method, + const Word16 bfi /* i : Bad frame indicator */ +) +{ + TCX_DEC_HANDLE hTcxDec = st->hTcxDec; + Word16 i; + + /*-----------------------------------------------------------* + * Noise shaping in frequency domain (1/Wz) * + *-----------------------------------------------------------*/ + + test(); + test(); + test(); + IF ( st->igf && ( !bfi || ( EQ_16(st->element_mode, IVAS_CPE_MDCT) && st->prev_bfi ) ) ) + { + test(); + IF ( ( EQ_16(L_frame, shr(st->L_frame, 1) ) ) && ( st->tcxonly ) ) + { + IGFDecCopyLPCFlatSpectrum_fx( st->hIGFDec, x_fx, *x_e, IGF_GRID_LB_SHORT ); + } + ELSE + { + IF (EQ_16(st->last_core, ACELP_CORE)) + { + IGFDecCopyLPCFlatSpectrum_fx( st->hIGFDec, x_fx, *x_e, IGF_GRID_LB_TRAN ); + } + ELSE + { + IGFDecCopyLPCFlatSpectrum_fx( st->hIGFDec, x_fx, *x_e, IGF_GRID_LB_NORM ); + } + } + } + /* LPC gains already available */ + + test(); + test(); + test(); + test(); + test(); + IF(gainlpc2_fx && gainlpc2_e && NE_16(st->element_mode, IVAS_CPE_MDCT) && (!st->enablePlcWaveadjust || !bfi || (EQ_16(*temp_concealment_method, TCX_TONAL)))) + { + Word16 spec_side_x_e, frame_side_x_e; + + spec_side_x_e = *x_e; + move16(); + + mdct_noiseShaping_ivas_fx(x_fx, x_e, L_frame, gainlpc2_fx, gainlpc2_e); + + frame_side_x_e = *x_e; + move16(); + + IF(bfi == 0) + { + FOR (i = L_frame; i < L_spec; i++) + { + x_fx[i] = Mpy_32_16_1(x_fx[i], gainlpc2_fx[FDNS_NPTS - 1]); + move32(); + } + spec_side_x_e = add(spec_side_x_e, gainlpc2_e[FDNS_NPTS-1]); + } + + IF (LT_16(spec_side_x_e, frame_side_x_e)) + { + /* If the exponent on the spec side (i>L_frame) is lesser, then shift all the values in the + spec side by the difference to make both sides have the same exponent. */ + FOR (i = L_frame; i < L_spec; i++) + { + x_fx[i] = L_shr(x_fx[i], sub(frame_side_x_e, spec_side_x_e)); + move32(); + } + } + ELSE IF (GT_16(spec_side_x_e, frame_side_x_e)) + { + /* If the exponent on the spec side (i>L_frame) is greater, then shift all the values in the + frame side (itonal_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++) + { + FOR(Word16 l = st->hTonalMDCTConc->pTCI_float->lowerIndex[i]; l <= st->hTonalMDCTConc->pTCI_float->upperIndex[i]; l++) + { + x[l] = me2f(x_fx[l], *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 ) + { + 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 ); + } + + if ( st->enablePlcWaveadjust ) + { + /* spectrum concealment */ + if ( bfi && *temp_concealment_method == TCX_NONTONAL ) + { + concealment_decode( st->core, x, st->hPlcInfo ); + } + + /* update spectrum buffer, tonality flag, etc. */ + concealment_update( bfi, st->core, st->tonality_flag, x, st->hPlcInfo ); + } + + /*-----------------------------------------------------------* + * IGF * + *-----------------------------------------------------------*/ + + if ( st->igf && !( ( L_frame == st->L_frame >> 1 ) && st->tcxonly ) ) + { + if ( 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 ); + } + } + + if ( st->igf && ( ( L_frame == st->L_frame >> 1 ) && st->tcxonly ) ) + { + if ( st->element_mode != IVAS_CPE_MDCT ) + { + IGFDecApplyMono_flt( st->hIGFDec, x, IGF_GRID_LB_SHORT, bfi, st->element_mode ); + } + } + + return; +} \ No newline at end of file diff --git a/lib_dec/igf_dec_fx.c b/lib_dec/igf_dec_fx.c index 90c044cee21f947b3ddc52ff6869c8dcbd090bfe..2bad8bcdba6b45a451a3cc160f629a248bec94cc 100644 --- a/lib_dec/igf_dec_fx.c +++ b/lib_dec/igf_dec_fx.c @@ -2007,7 +2007,7 @@ void IGFDecCopyLPCFlatSpectrum_fx( /* TODO: remove float dependency */ for ( i = hGrid->minSrcSubband - IGF_MID_WHITENING_LEVEL2; i < hGrid->startLine; i++ ) { - hPrivateData->pSpecFlat_float[i] = fix_to_float( hPrivateData->pSpecFlat[i], 31 - hPrivateData->pSpecFlat_exp ) * 1024.f; + hPrivateData->pSpecFlat_float[i] = me2f( hPrivateData->pSpecFlat[i], hPrivateData->pSpecFlat_exp ); } } } diff --git a/lib_dec/ivas_mdct_core_dec.c b/lib_dec/ivas_mdct_core_dec.c index 1fdefee69a8d4adbea9771b44730aeaef5ae33f7..c7eb5395debcc9b09bc1f72c36094122e96d35bd 100644 --- a/lib_dec/ivas_mdct_core_dec.c +++ b/lib_dec/ivas_mdct_core_dec.c @@ -1280,7 +1280,11 @@ void ivas_mdct_core_invQ( decoder_tcx_noisefilling( st, concealment_noise[ch], Aq[ch], L_frameTCX_global[ch], L_spec[ch], L_frame[ch], L_frameTCX[ch], x[ch][k], NULL, &tmp_concealment_method, gain_tcx, prm_sqQ, nf_seed, bfi, MCT_flag, k ); #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 ); +#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 } } } @@ -1656,7 +1660,46 @@ void ivas_mdct_core_tns_ns( if ( bfi && st->tonal_mdct_plc_active ) { +#ifdef IVAS_FLOAT_FIXED + // Float to fixed + 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]; + 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]); + } + TonalMDCTConceal_Apply_ivas_fx( st->hTonalMDCTConc, x_fx, &x_e, st->hTcxCfg->psychParamsCurrent ); + // Fix to float + FOR(Word16 i = 0; i < st->hTonalMDCTConc->pTCI_float->numIndexes; i++) + { + FOR(Word16 l = st->hTonalMDCTConc->pTCI_float->lowerIndex[i]; l <= st->hTonalMDCTConc->pTCI_float->upperIndex[i]; l++) + { + x[ch][0][l] = me2f(x_fx[l], x_e); + } + } + st->hTonalMDCTConc->nFramesLost_float = fix16_to_float(st->hTonalMDCTConc->nFramesLost, Q1); +#else TonalMDCTConceal_Apply_ivas( st->hTonalMDCTConc, x[ch][0], st->hTcxCfg->psychParamsCurrent ); +#endif } if ( ( bfi || MCT_flag ) && st->hTonalMDCTConc != NULL ) diff --git a/lib_dec/stat_dec.h b/lib_dec/stat_dec.h index 1ef29c3829e150bc8caa085e3931835931358b4e..c07876dee93463d575fd9621313c2127d823ffbd 100644 --- a/lib_dec/stat_dec.h +++ b/lib_dec/stat_dec.h @@ -308,9 +308,9 @@ typedef struct Word16 lowerIndex[MAX_NUMBER_OF_IDX]; Word16 upperIndex[MAX_NUMBER_OF_IDX]; - Word16 phaseDiff[MAX_NUMBER_OF_IDX]; /* This one can be stored with 16 bits in range 0..2*PI */ + Word16 phaseDiff[MAX_NUMBER_OF_IDX]; // Q12 /* This one can be stored with 16 bits in range 0..2*PI */ - Word16 phase_currentFramePredicted[MAX_NUMBER_OF_IDX*GROUP_LENGTH]; /* This one can be stored with 16 bits in range [-pi;pi] 2Q13, but the code has to be adapted to use moduo(2*PI) after adding */ + Word16 phase_currentFramePredicted[MAX_NUMBER_OF_IDX*GROUP_LENGTH]; // Q13 /* This one can be stored with 16 bits in range [-pi;pi] 2Q13, but the code has to be adapted to use moduo(2*PI) after adding */ } TonalComponentsInfo_fix; diff --git a/lib_dec/tonalMDCTconcealment_fx.c b/lib_dec/tonalMDCTconcealment_fx.c index 9da79f6fa070857182196e3d67962a8daf5c2fc9..c5fcf41492de199e2cf066d19cae4ce0e4638965 100644 --- a/lib_dec/tonalMDCTconcealment_fx.c +++ b/lib_dec/tonalMDCTconcealment_fx.c @@ -6,6 +6,7 @@ #include #include +#include #include "options.h" #include "basop_util.h" #include "options.h" @@ -15,6 +16,7 @@ #include "prot_fx2.h" #include "stat_com.h" #include "prot.h" +#include "ivas_prot_fx.h" #define CROSSFADE_THRESHOLD (32762) // close to 1.0f in Q15 such that (x == 1.0f) is true @@ -152,6 +154,8 @@ ivas_error TonalMDCTConceal_Init_ivas_fx( move16(); hTonalMDCTConc->secondLastPowerSpectrum = hTonalMDCTConc->secondLastBlockData.spectralData; move16(); + hTonalMDCTConc->secondLastPowerSpectrum_exp = hTonalMDCTConc->secondLastBlockData.spectralData_exp; + move16(); hTonalMDCTConc->lastBlockData.scaleFactors = hTonalMDCTConc->scaleFactorsBuffers[0]; move16(); hTonalMDCTConc->secondLastBlockData.scaleFactors = hTonalMDCTConc->scaleFactorsBuffers[1]; @@ -2458,6 +2462,184 @@ void TonalMDCTConceal_Apply( return ; } +#ifdef IVAS_FLOAT_FIXED +void TonalMDCTConceal_Apply_ivas_fx( + TonalMDCTConcealPtr hTonalMDCTConc, /*IN */ + Word32 *mdctSpectrum, /*IN/OUT*/ + Word16 *mdctSpectrum_exp, /*IN */ + const PsychoacousticParameters *psychParamsCurrent ) + +{ + /* TODO: change pTCI_float to pTCI_fix in this function. */ + + Word16 i, l; + Word16 *phaseDiff, *pCurrentPhase; + Word32 phaseToAdd; + Word32 powerSpectrum[L_FRAME_MAX]; + Word16 powerSpectrum_exp; + Word32 scaleFactors[FDNS_NPTS]; + Word16 nSamples; + Word16 nBands; + + /* TODO: remove this later. */ + Word16 *tmp_secondLastPowerSpectrum = (Word16 *)malloc(hTonalMDCTConc->nNonZeroSamples * sizeof(Word16)); + Word16 tmp_secondLastPowerSpectrum_exp; + f2me_buf_16(hTonalMDCTConc->secondLastPowerSpectrum_float, tmp_secondLastPowerSpectrum, &tmp_secondLastPowerSpectrum_exp, hTonalMDCTConc->nNonZeroSamples); + + Word16 max_nSamples = s_max(hTonalMDCTConc->nNonZeroSamples, hTonalMDCTConc->nSamplesCore); + + // To avoid garbage values + set32_fx(powerSpectrum, 0, L_FRAME_MAX); + + /* Creating 32-bit scaleFactors with common exponent. */ + FOR(i = 0; i < FDNS_NPTS; i++) + { + scaleFactors[i] = L_shr(L_deposit_h(hTonalMDCTConc->secondLastBlockData.scaleFactors[i]), sub(hTonalMDCTConc->secondLastBlockData.scaleFactors_max_e, hTonalMDCTConc->secondLastBlockData.scaleFactors_exp[i])); + } + + IF ( hTonalMDCTConc->lastBlockData.blockIsValid & hTonalMDCTConc->secondLastBlockData.blockIsValid ) + { + assert( hTonalMDCTConc->pTCI_float->numIndexes > 0 ); + + nSamples = hTonalMDCTConc->nNonZeroSamples; + move16(); + assert( hTonalMDCTConc->pTCI_float->upperIndex[hTonalMDCTConc->pTCI_float->numIndexes - 1] < nSamples ); + //mvr2r( hTonalMDCTConc->secondLastPowerSpectrum_float, powerSpectrum_flt, nSamples ); /* Convert from 16 bits to 32 bits */ + FOR (i = 0; i < nSamples; i++) + { + powerSpectrum[i] = L_deposit_h(tmp_secondLastPowerSpectrum[i]); + move16(); + } + powerSpectrum_exp = tmp_secondLastPowerSpectrum_exp; + move16(); + + Word16 exp1 = powerSpectrum_exp; + + IF ( psychParamsCurrent == NULL ) + { + nBands = FDNS_NPTS; + move16(); + mdct_noiseShaping_ivas_fx(powerSpectrum, &powerSpectrum_exp, hTonalMDCTConc->nSamplesCore, hTonalMDCTConc->secondLastBlockData.scaleFactors, + hTonalMDCTConc->secondLastBlockData.scaleFactors_exp); + } + ELSE + { + Word16 q_ps, q_sf; + q_ps = sub(31, powerSpectrum_exp); + q_sf = sub(31, hTonalMDCTConc->secondLastBlockData.scaleFactors_max_e); + + /* adding guard bit */ + q_ps = sub(q_ps, 1); + FOR( Word16 c = 0; c < hTonalMDCTConc->nSamplesCore; c++ ) + { + powerSpectrum[c] = L_shr(powerSpectrum[c], 1); + } + + /* adding guard bit */ + q_sf = sub(q_sf, 1); + FOR(Word16 c = 0; c < FDNS_NPTS; c++) + { + scaleFactors[c] = L_shr(scaleFactors[c], 1); + } + + sns_shape_spectrum_fx( powerSpectrum, &q_ps, psychParamsCurrent, scaleFactors, q_sf, hTonalMDCTConc->nSamplesCore ); + + powerSpectrum_exp = sub(31, add(q_ps, 1)); + + nBands = psychParamsCurrent->nBands; + move16(); + } + + Word16 exp_left = powerSpectrum_exp; + Word16 exp_right = exp1; + + FOR (Word16 c = hTonalMDCTConc->nSamplesCore; c < nSamples; c++) + { + powerSpectrum[c] = Mpy_32_16_1(powerSpectrum[c], hTonalMDCTConc->secondLastBlockData.scaleFactors[nBands - 1]); + } + exp_right = add(exp_right, hTonalMDCTConc->secondLastBlockData.scaleFactors_exp[nBands - 1]); + + Word16 max_e = s_max(exp_right, exp_left); + FOR (Word16 c = 0; c < max_nSamples; c++) + { + test(); test(); test(); test(); + IF (GE_16(c, hTonalMDCTConc->nSamplesCore) && LT_16(c, nSamples) && GT_16(max_e, exp_right)) + { + powerSpectrum[c] = L_shr(powerSpectrum[c], sub(max_e, exp_right)); + move32(); + } + ELSE IF ((LT_16(c, hTonalMDCTConc->nSamplesCore) || GT_16(c, nSamples)) && GT_16(max_e, exp_left)) + { + powerSpectrum[c] = L_shr(powerSpectrum[c], sub(max_e, exp_left)); + move32(); + } + } + powerSpectrum_exp = max_e; + move16(); + + phaseDiff = hTonalMDCTConc->pTCI_fix->phaseDiff; /* if multiple frame loss occurs use the phase from the last frame and continue rotating */ + pCurrentPhase = hTonalMDCTConc->pTCI_fix->phase_currentFramePredicted; + + IF(!hTonalMDCTConc->lastBlockData.blockIsConcealed) + { + IF (hTonalMDCTConc->secondLastBlockData.tonalConcealmentActive != 0) + { + hTonalMDCTConc->nFramesLost = add(hTonalMDCTConc->nFramesLost, 2); /*Q1*/ + move16(); + } + IF (hTonalMDCTConc->secondLastBlockData.tonalConcealmentActive == 0) + { + hTonalMDCTConc->nFramesLost = 3; /*Q1*/ + move16(); + } + } + + /* for each index group */ + FOR ( i = 0; i < hTonalMDCTConc->pTCI_float->numIndexes; i++ ) + { + phaseToAdd = L_mult0(hTonalMDCTConc->nFramesLost, phaseDiff[i]); /*Q1*3Q12=2Q13*/ + + /* Move phaseToAdd to range -PI..PI */ + WHILE(GT_32(phaseToAdd, 25736l/*EVS_PI Q13*/)) + { + phaseToAdd = L_sub(phaseToAdd, 51472l/*2*EVS_PI Q13*/); + } + WHILE(LT_32(phaseToAdd, -25736l/*-EVS_PI Q13*/)) + { + phaseToAdd = L_add(phaseToAdd, 51472l/*2*EVS_PI Q13*/); + } + + FOR ( l = hTonalMDCTConc->pTCI_float->lowerIndex[i]; l <= hTonalMDCTConc->pTCI_float->upperIndex[i]; l++ ) + { + /* *pCurrentPhase and phaseToAdd are in range -PI..PI */ + Word32 currentPhase = L_mac0(phaseToAdd, ( *pCurrentPhase++ ), 1); /*2Q13+2Q13=3Q13*/ + IF (GT_32(currentPhase, 25736l/*EVS_PI Q13*/)) + { + currentPhase = L_sub(currentPhase, 51472l/*2*EVS_PI Q13*/); + } + IF(LT_32(currentPhase, -25736l/*-EVS_PI Q13*/)) + { + currentPhase = L_add(currentPhase, 51472l/*2*EVS_PI Q13*/); + } + + /* getCosWord16 returns 1Q14*/ + mdctSpectrum[l] = Mpy_32_16_1(powerSpectrum[l], getCosWord16(extract_l(currentPhase))); + move32(); + *mdctSpectrum_exp = add(powerSpectrum_exp, 1); // getCosWord16 returns Q14 (exp is 1) + } + } + } + + /* TODO: remove this later. */ + free(tmp_secondLastPowerSpectrum); + + hTonalMDCTConc->nFramesLost = add(hTonalMDCTConc->nFramesLost, 2); /*Q1*/ + move16(); + + return; +} +#endif + void TonalMDCTConceal_SaveTimeSignal( TonalMDCTConcealPtr hTonalMDCTConc, Word16* timeSignal,