/*==================================================================================== EVS Codec 3GPP TS26.443 Jun 30, 2015. Version CR 26.443-0006 ====================================================================================*/ #include "cnst.h" #include #include #include #include #include "prot.h" /*-------------------------------------------------------------------* * HBAutocorrelation() * * *-------------------------------------------------------------------*/ void HBAutocorrelation( TCX_config *tcx_cfg, /* input: configuration of TCX */ int left_overlap_mode, /* input: overlap mode of left window half */ int right_overlap_mode, /* input: overlap mode of right window half */ float speech[], /* input: synthesis */ int L_frame, /* input: frame length */ float *r, /* output: autocorrelations vector */ int m /* input : order of LP filter */ ) { int i, j, left_overlap, right_overlap; float s; float xn_buf[L_MDCT_OVLP_MAX+L_FRAME_PLUS+L_MDCT_OVLP_MAX]; /*-----------------------------------------------------------* * Windowing * *-----------------------------------------------------------*/ WindowSignal( tcx_cfg, tcx_cfg->tcx_offset, left_overlap_mode, right_overlap_mode, &left_overlap, &right_overlap, speech, &L_frame, xn_buf, 0 ); /*-----------------------------------------------------------* * Autocorrelation * *-----------------------------------------------------------*/ for (i = 0; i <= m; i++) { s = 0.0; for (j = 0; j < L_frame+(left_overlap+right_overlap)/2-i; j++) { s += xn_buf[j]*xn_buf[j+i]; } r[i] = s; } if (r[0] < 100.0) { r[0] = 100.0; } return; } /*-------------------------------------------------------------------* * TNSAnalysis() * * *-------------------------------------------------------------------*/ void TNSAnalysis( TCX_config *tcx_cfg, /* input: configuration of TCX */ int L_frame, /* input: frame length */ int L_spec, const short tcxMode, /* input: TCX mode for the frame/subframe - TCX20 | TCX10 | TCX 5 (meaning 2 x TCX 5) */ int isAfterACELP, /* input: Flag indicating if the last frame was ACELP. For the second TCX subframe it should be 0 */ float spectrum[], /* input: MDCT spectrum of the subframe */ STnsData * pTnsData, /* output: Tns data */ int * pfUseTns, /* output: Flag indicating if TNS is used */ float* predictionGain ) { float buff[8]; /* Buffer for the rearrangement of LF TCX5 */ /* Init TNS */ *pfUseTns = 0; if (tcx_cfg->fIsTNSAllowed) { tcx_cfg->pCurrentTnsConfig = &tcx_cfg->tnsConfig[tcxMode == TCX_20][isAfterACELP]; L_spec = tcx_cfg->pCurrentTnsConfig->iFilterBorders[0]; /*-----------------------------------------------------------* * Temporal Noise Shaping analysis * *-----------------------------------------------------------*/ if (tcxMode == TCX_5) { /* rearrange LF sub-window lines prior to TNS analysis & filtering */ if (L_spec < L_frame/2) { mvr2r(spectrum+8, spectrum+16, L_spec/2-8); mvr2r(spectrum+L_frame/4, spectrum+8, 8); mvr2r(spectrum+L_frame/4+8, spectrum+L_spec/2+8, L_spec/2-8); } else { mvr2r(spectrum+L_frame/4, buff, 8); mvr2r(spectrum+8, spectrum+16, L_frame/4-8); mvr2r(buff, spectrum+8, 8); } } *pfUseTns = DetectTnsFilt(tcx_cfg->pCurrentTnsConfig, spectrum, pTnsData, predictionGain); /* If TNS should be used then get the residual after applying it inplace in the spectrum */ if (*pfUseTns) { ApplyTnsFilter(tcx_cfg->pCurrentTnsConfig, pTnsData, spectrum, 1); } if (tcxMode == TCX_5) { /* undo rearrangement of LF sub-window lines prior to TNS analysis */ if (L_spec < L_frame/2) { mvr2r(spectrum+L_spec/2+8, spectrum+L_frame/4+8, L_spec/2-8); mvr2r(spectrum+8, spectrum+L_frame/4, 8); mvr2r(spectrum+16, spectrum+8, L_spec/2-8); set_zero(spectrum+L_spec/2, L_frame/4-L_spec/2); set_zero(spectrum+L_frame/4+L_spec/2, L_frame/4-L_spec/2); } else { mvr2r(spectrum+8, buff, 8); mvr2r(spectrum+16, spectrum+8, L_frame/4-8); mvr2r(buff, spectrum+L_frame/4, 8); } } } return; } /*-------------------------------------------------------------------* * ShapeSpectrum() * * *-------------------------------------------------------------------*/ void ShapeSpectrum( TCX_config *tcx_cfg,/*input: configuration of TCX */ float A[], /* input: quantized coefficients NxAz_q[M+1] */ float gainlpc[], /* output: MDCT gains for the previous frame */ int L_frame_glob, /* input: frame length */ int L_spec, float spectrum[], /* i/o: MDCT spectrum */ int fUseTns, /* output: Flag indicating if TNS is used */ Encoder_State *st ) { int L_frame; int tcx_offset; float Ap[M+2]; float gamma1; /*-----------------------------------------------------------* * Init * *-----------------------------------------------------------*/ /* Init lengths */ L_frame = L_frame_glob; tcx_offset = tcx_cfg->tcx_offset; gamma1 = st->gamma; if (st->enableTcxLpc) { gamma1 = 1.0f; } /* if past frame is ACELP */ if (st->last_core == 0) { L_frame += tcx_offset; L_spec += tcx_cfg->tcx_coded_lines >> 2; if(tcx_cfg->lfacNext<0) { L_frame -= tcx_cfg->lfacNext; } } tcxGetNoiseFillingTilt( A, L_frame, (st->total_brate >= ACELP_13k20 && !st->rf_mode), &st->noiseTiltFactor ); /* Calculate Spectrum Flatness Measure for the TCX Concealment */ if( st->enablePlcWaveadjust ) { tcx_cfg->SFM2 = SFM_Cal(spectrum, min(200, L_frame)); } /*-----------------------------------------------------------* * Pre-shaping in frequency domain using weighted LPC (Wz) * *-----------------------------------------------------------*/ weight_a(A, Ap, gamma1, M); lpc2mdct(Ap, M, gainlpc); mdct_preShaping(spectrum, L_frame, gainlpc); v_multc(spectrum+L_frame, 1.f/gainlpc[FDNS_NPTS-1], spectrum+L_frame, L_spec-L_frame); if (st->tcxonly && st->tcxltp && (st->tcxltp_gain > 0.0f) && !fUseTns ) { PsychAdaptLowFreqEmph(spectrum, gainlpc); } return; } /*-------------------------------------------------------------------* * QuantizeSpectrum() * * *-------------------------------------------------------------------*/ void QuantizeSpectrum( TCX_config *tcx_cfg,/*input: configuration of TCX*/ float A[], /* input: quantized coefficients NxAz_q[M+1] */ Word16 Aqind[], /* input: frame-independent quantized coefficients (M+1) */ float gainlpc[], /* input: MDCT gains of the previous frame */ float synth[], int L_frame_glob, /* input: frame length */ int L_frameTCX_glob, int L_spec, int nb_bits, /*input: bit budget*/ int tcxonly, /*input: only TCX flag*/ float spectrum[], /* i/o: MDCT spectrum, input is shaped MDCT spectrum */ STnsData * pTnsData,/* input: Tns data */ int fUseTns, /* input: Flag indicating if TNS is used */ int tnsSize, /* input: number of tns parameters put into prm */ LPD_state *LPDmem, /*i/o: memories*/ int prm[], /* output: tcx parameters */ int frame_cnt, /* input: frame counter in the super_frame */ Encoder_State *st, CONTEXT_HM_CONFIG *hm_cfg ) { int i, sqTargetBits, L_frame, tcx_offset, stop; int L_frameTCX; float fac_ns, ener, gain_tcx, gain_tcx_opt; float xn_buf[L_MDCT_OVLP_MAX+L_FRAME_PLUS+L_MDCT_OVLP_MAX]; float x_orig[N_MAX]; float sqGain = 1.0f; int sqBits; int sqBits_noStop; int overlap; int noiseFillingSize; int noiseTransWidth = MIN_NOISE_FILLING_HOLE; int nEncoded; int *sqQ; short LtpPitchLag; int ctxHmBits; int resQBits; int resQTargetBits = 0; short nf_seed = 0; int PeriodicityIndex, NumIndexBits; float *OriginalSpectrum; int nEncodedCtxHm, stopCtxHm, sqBitsCtxHm, Selector; int lastnz, lastnzCtxHm; float RelativeScore; int *signs; int signaling_bits; int *prm_ltp, *prm_tns, *prm_hm, *prm_lastnz, *prm_target; float SFM; float K, K2; float Aq_old[M+1]; short aldo; /* ALDO flag in current frame*/ short nz; /* non-zero length in ALDO window*/ int maxNfCalcBw; /*-----------------------------------------------------------* * Init * *-----------------------------------------------------------*/ /* Init lengths */ L_frame = L_frame_glob; L_frameTCX = L_frameTCX_glob; overlap = tcx_cfg->tcx_mdct_window_length; aldo=0; nz=NS2SA(st->sr_core, N_ZERO_MDCT_NS); tcx_offset = tcx_cfg->tcx_offset; OriginalSpectrum = NULL; signs = NULL; /* silence warning */ NumIndexBits = 0; sqBits = 0; ctxHmBits = 0; resQBits=0; prm_ltp = &prm[1+NOISE_FILL_RANGES]; prm_tns = prm_ltp + LTPSIZE; prm_hm = prm_tns + tnsSize; prm_lastnz = prm_hm + 2; sqQ = prm_hm + NPRM_CTX_HM; /* if past frame is ACELP */ if (st->last_core == 0) { tcx_cfg->last_aldo=0; L_frame += tcx_offset; L_frameTCX += tcx_cfg->tcx_offsetFB; L_spec += tcx_cfg->tcx_coded_lines >> 2; if(tcx_cfg->lfacNext<0) { L_frame -= tcx_cfg->lfacNext; L_frameTCX -= tcx_cfg->lfacNextFB; tcx_offset = tcx_cfg->lfacNext; } else { tcx_offset = 0; } st->noiseLevelMemory = 0; } lsp2a_stab( st->lsp_old, Aq_old, M ); /* target bitrate for SQ */ sqTargetBits = nb_bits-7-NBITS_NOISE_FILL_LEVEL; /*Unquantized spectrum here*/ if(st->enablePlcWaveadjust) { SFM = SFM_Cal(spectrum, min(200, L_frame_glob)); if (L_frame_glob <= 256) { K = 0.4f; K2 = 0.1f; } else if (L_frame_glob == 320 || L_frame_glob == 512) { K = 0.4f; K2 = 0.1f; } else /*FrameSize_Core == 640*/ { K = 0.35f; K2 = 0.04f; } if (SFM < K) { st->Tonal_SideInfo = 1; } else { st->Tonal_SideInfo = 0; } if (tcx_cfg->SFM2 < K2) { st->Tonal_SideInfo = 1; } } /* Save pre-shaped spectrum*/ mvr2r(spectrum, x_orig, L_spec); /*-----------------------------------------------------------* * Bandwidth Limitation * *-----------------------------------------------------------*/ noiseFillingSize = L_spec; if (st->igf) { noiseFillingSize = (&st->hIGFEnc)->infoStartLine; } else { (&st->hIGFEnc)->infoStopLine = noiseFillingSize; } for (i=(&st->hIGFEnc)->infoStopLine; i < max(L_frame, L_frameTCX); i++) { spectrum[i] = 0.0f; } /*-----------------------------------------------------------* * Quantization * *-----------------------------------------------------------*/ if (!st->tcx_lpc_shaped_ari) { /* context based arithmetic coder */ /* Fast estimation of the scalar quantizer step size */ if (tcx_cfg->ctx_hm && (st->last_core != 0) ) { LtpPitchLag = ((!tcxonly) && (st->tcxltp_pitch_int < st->L_frame) ? ((2 * st->L_frame * st->pit_res_max) << kLtpHmFractionalResolution) / (st->tcxltp_pitch_int * st->pit_res_max + st->tcxltp_pitch_fr): -1); ++ctxHmBits; /* ContextHM flag */ --sqTargetBits; /* ContextHM flag */ OriginalSpectrum = spectrum; PeriodicityIndex = SearchPeriodicityIndex( OriginalSpectrum, NULL, L_spec, sqTargetBits, LtpPitchLag, st->tcxltp ? st->tcxltp_gain : -1.0f, &RelativeScore ); ConfigureContextHm( L_spec, sqTargetBits, PeriodicityIndex, LtpPitchLag, hm_cfg ); NumIndexBits = CountIndexBits( L_spec >= 256, PeriodicityIndex ); /* Quantize original spectrum */ sqGain = SQ_gain( OriginalSpectrum, (int)(LPDmem->tcx_target_bits_fac * (float)sqTargetBits), L_spec ); tcx_scalar_quantization( OriginalSpectrum, sqQ, L_spec, sqGain, tcx_cfg->sq_rounding, st->memQuantZeros, tcxonly ); /* Estimate original bitrate */ stop = 0; sqBits = ACcontextMapping_encode2_estimate_no_mem_s17_LC( sqQ, L_spec, &lastnz, &nEncoded, sqTargetBits, &stop, NULL ); /* Estimate context mapped bitrate */ stopCtxHm = 0; /* Context Mapping */ sqBitsCtxHm = ACcontextMapping_encode2_estimate_no_mem_s17_LC( sqQ, L_spec, &lastnzCtxHm, &nEncodedCtxHm, sqTargetBits - NumIndexBits, &stopCtxHm, hm_cfg ); /* Decide whether or not to use context mapping */ Selector = max(stop, sqBits) - (max(stopCtxHm, sqBitsCtxHm) + NumIndexBits); if (Selector > 2 || (abs(Selector) <= 2 && kCtxHmOlRSThr < RelativeScore)) { /* CtxHm is likely better */ sqTargetBits -= NumIndexBits; ctxHmBits += NumIndexBits; prm_hm[0] = 1; prm_hm[1] = PeriodicityIndex; *prm_lastnz = lastnzCtxHm; sqBits_noStop = sqBits = sqBitsCtxHm; nEncoded = nEncodedCtxHm; stop = stopCtxHm; } else { /* Original is better or not much difference */ prm_hm[0] = 0; prm_hm[1] = PeriodicityIndex; *prm_lastnz = lastnz; PeriodicityIndex = -1; sqBits_noStop = sqBits; } if (stop != 0) { sqBits = stop; } } else { /* no context hm*/ PeriodicityIndex = -1; sqGain = SQ_gain(spectrum, (int)(LPDmem->tcx_target_bits_fac * (float)sqTargetBits), L_spec); /* Quantize spectrum */ tcx_scalar_quantization( spectrum, sqQ, L_spec, sqGain, tcx_cfg->sq_rounding, st->memQuantZeros, tcxonly ); /* Estimate bitrate */ stop = 0; sqBits_noStop = sqBits = ACcontextMapping_encode2_estimate_no_mem_s17_LC( sqQ, L_spec, prm_lastnz, &nEncoded, sqTargetBits, &stop, NULL); if(stop!=0) { sqBits=stop; } } /* end of if (ctx_hm) */ /* Adjust correction factor */ if ((L_spec & (L_spec - 1)) == 0) { /* power-of-2 */ LPDmem->tcx_target_bits_fac *= (float)sqTargetBits / (float)(sqBits + 1); } else { LPDmem->tcx_target_bits_fac *= (float)sqTargetBits / (float)sqBits; } if (LPDmem->tcx_target_bits_fac>1.25) { LPDmem->tcx_target_bits_fac = 1.25; } if (LPDmem->tcx_target_bits_fac<0.75) { LPDmem->tcx_target_bits_fac = 0.75; } /* Refine quantizer step size with a rate-control-loop (optional) */ sqBits = tcx_scalar_quantization_rateloop( spectrum, sqQ, L_spec, &sqGain, tcx_cfg->sq_rounding, st->memQuantZeros, prm_lastnz, /* lastnz */ sqTargetBits, &nEncoded, &stop, sqBits_noStop, sqBits, tcx_cfg->tcxRateLoopOpt, tcxonly, PeriodicityIndex >= 0 ? hm_cfg : NULL ); if (ctxHmBits > 0) { /* Mapping tool is enabled */ /* Truncate spectrum */ for (i=nEncoded; i= 0) { /* Mapping is used */ /* Estimate non-mapped bitrate */ stopCtxHm = 1; sqBitsCtxHm = ACcontextMapping_encode2_estimate_no_mem_s17_LC(sqQ, L_spec, &lastnz, &nEncodedCtxHm, sqTargetBits, &stopCtxHm, NULL); /* Decide whether or not to revert mapping */ Selector = sqBits - (sqBitsCtxHm + NumIndexBits); if (stopCtxHm == 0 && Selector > 0) { /* Non-mapped is better */ sqTargetBits += NumIndexBits; ctxHmBits -= NumIndexBits; prm_hm[0] = 0; *prm_lastnz = lastnz; PeriodicityIndex = -1; sqBits_noStop = sqBits = sqBitsCtxHm; nEncoded = nEncodedCtxHm; stop = stopCtxHm; } } else { /* Mapping is not used */ /* Estimate mapped bitrate */ stopCtxHm = 1; sqBitsCtxHm = ACcontextMapping_encode2_estimate_no_mem_s17_LC( sqQ, L_spec, &lastnzCtxHm, &nEncodedCtxHm, sqTargetBits - NumIndexBits, &stopCtxHm, hm_cfg ); /* Decide whether or not to use mapping */ Selector = sqBits - (sqBitsCtxHm + NumIndexBits); if (stopCtxHm == 0 && Selector > 0) { /* Mapped is better */ sqTargetBits -= NumIndexBits; ctxHmBits += NumIndexBits; prm_hm[0] = 1; *prm_lastnz = lastnzCtxHm; PeriodicityIndex = prm_hm[1]; sqBits_noStop = sqBits = sqBitsCtxHm; nEncoded = nEncodedCtxHm; stop = stopCtxHm; } } } /* Limit low sqGain for avoiding saturation of the gain quantizer*/ if(sqGain < sqrt((float)NORM_MDCT_FACTOR / (float)L_spec)) { sqGain = (float)sqrt((float)NORM_MDCT_FACTOR / (float)L_spec); tcx_scalar_quantization( spectrum, sqQ, L_spec, sqGain, tcx_cfg->sq_rounding, st->memQuantZeros, tcxonly ); stop=1; sqBits = ACcontextMapping_encode2_estimate_no_mem_s17_LC( sqQ, L_spec, prm_lastnz, &nEncoded, sqTargetBits, &stop, PeriodicityIndex >= 0 ? hm_cfg : NULL); } /* Truncate spectrum (for CBR) */ if ( stop ) { for (i=nEncoded; iindexBuffer; LtpPitchLag = ((st->tcxltp_pitch_int < st->L_frame) ? ((2 * st->L_frame * st->pit_res_max) << kLtpHmFractionalResolution) / (st->tcxltp_pitch_int * st->pit_res_max + st->tcxltp_pitch_fr): -1); tcx_arith_encode_envelope( spectrum, signs, L_frame, L_spec, st, Aqind, sqTargetBits, sqQ, st->last_core != ACELP_CORE, prm_hm, /* HM parameter area */ LtpPitchLag, &sqBits, &signaling_bits ,(st->bwidth > WB)?1:0 ); sqTargetBits -= signaling_bits; *prm_target = sqTargetBits; /* Noise filling seed */ for (i=0; itcx_lpc_shaped_ari, gainlpc, L_frame, xn_buf /* LF deemphasis factors */ ); } gain_tcx_opt = get_gain(x_orig, spectrum, L_spec, &ener); if (gain_tcx_opt <= 0.0f) { gain_tcx_opt = sqGain; } gain_tcx = gain_tcx_opt; /*-----------------------------------------------------------* * Quantize TCX gain * *-----------------------------------------------------------*/ /* gain quantization here in case of VBR unvoiced coding; fixes problems of uninitialized global gain values */ if (st->total_brate >= ACELP_13k20 && !st->rf_mode) { QuantizeGain(L_spec, &gain_tcx, &prm[0]); } /*-----------------------------------------------------------* * Residual Quantization * *-----------------------------------------------------------*/ if (tcx_cfg->resq) { resQTargetBits = sqTargetBits-sqBits; if (st->tcx_lpc_shaped_ari) { /* envelope based arithmetic coder */ int *prm_resq; prm_resq = sqQ + sqTargetBits - resQTargetBits; resQBits = tcx_ari_res_Q_spec( x_orig, signs, spectrum, L_spec, gain_tcx, prm_resq, resQTargetBits, resQBits, tcx_cfg->sq_rounding, xn_buf /* LF deemphasis factors */ ); /* Transmit zeros when there bits remain after RESQ */ for (i=resQBits; isq_rounding, tcxonly ? NULL : xn_buf /* LF deemphasis factors */ ); } } /*-----------------------------------------------------------* * ALFE tcx only bitrates * *-----------------------------------------------------------*/ if (st->tcxonly) { if (st->tcxltp && (st->tcxltp_gain > 0.0f) && !fUseTns) { PsychAdaptLowFreqDeemph( spectrum, gainlpc, NULL ); } } /*-----------------------------------------------------------* * TCX SNR for Analysis purposes * *-----------------------------------------------------------*/ maxNfCalcBw = min(noiseFillingSize, (int)(st->measuredBwRatio * (float)L_frame + 0.5f)); /*-----------------------------------------------------------* * Estimate and quantize noise factor * *-----------------------------------------------------------*/ if (st->total_brate >= HQ_96k) { fac_ns = 0.0f; prm[1] = 0; } else { i = L_frame / ((st->total_brate >= ACELP_13k20 && !st->rf_mode) ? 6 : 8); /* noise filling start bin*/ if (tcxonly) { noiseTransWidth = HOLE_SIZE_FROM_LTP(max(st->tcxltp_gain,(tcx_cfg->ctx_hm && st->last_core != 0) ? 0.3125f*prm_hm[0] : 0)); if (L_frame == st->L_frame >> 1) { noiseTransWidth = 3; /* minimum transition for noise filling in TCX-10 */ } } tcx_noise_factor( x_orig, spectrum, i, maxNfCalcBw, noiseTransWidth, L_frame, gain_tcx, st->noiseTiltFactor, &fac_ns, &prm[NOISE_FILL_RANGES] ); /* hysteresis for very tonal passages (more stationary noise filling level) */ if (prm[1] == 1) { st->noiseLevelMemory = 1 + abs(st->noiseLevelMemory); /* update counter */ } else { if ((prm[1] == 2) && (abs(st->noiseLevelMemory) > 5)) { prm[1] = 1; /* reduce noise filling level by one step */ fac_ns = 0.75f / (1<noiseLevelMemory = (st->noiseLevelMemory < 0) ? 5 : -1 - st->noiseLevelMemory; } else { st->noiseLevelMemory = 0; /* reset memory since level is too different */ } } } /* bitrate */ /*-----------------------------------------------------------* * Internal TCX decoder * *-----------------------------------------------------------*/ /*-----------------------------------------------------------* * Noise Filling. * *-----------------------------------------------------------*/ /* Replication of ACELP formant enhancement for low rates */ if ( st->total_brate < ACELP_13k20 || st->rf_mode ) { tcxFormantEnhancement(xn_buf, gainlpc, spectrum, L_frame); } if (fac_ns > 0.0f) { i = tcxGetNoiseFillingTilt( A, L_frame, (st->total_brate >= ACELP_13k20 && !st->rf_mode), &st->noiseTiltFactor); tcx_noise_filling( spectrum, nf_seed, i, noiseFillingSize, noiseTransWidth, L_frame, st->noiseTiltFactor, fac_ns, NULL ); } if (st->total_brate < ACELP_13k20 || st->rf_mode) { /* partially recompute global gain (energy part), taking noise filling and formant enhancement into account */ gain_tcx_opt = 1e-6f; for (i = 0; i < L_spec; i++) { gain_tcx_opt += spectrum[i] * spectrum[i]; } gain_tcx *= (float)sqrt(ener / gain_tcx_opt); QuantizeGain(L_spec, &gain_tcx, &prm[0]); } /*end of noise filling*/ /*-----------------------------------------------------------* * Noise shaping in frequency domain (1/Wz) * *-----------------------------------------------------------*/ /* LPC gains already available */ mdct_noiseShaping( spectrum, L_frame, gainlpc ); /*-----------------------------------------------------------* * Apply gain * *-----------------------------------------------------------*/ if( st->tcx_cfg.coder_type == INACTIVE ) { gain_tcx *= tcx_cfg->na_scale; } v_multc( spectrum, gain_tcx, spectrum, L_spec); stop = tcx_cfg->tcx_last_overlap_mode; /* backup last TCX overlap mode */ if ((L_frame == st->L_frame >> 1) && tcxonly) { int L = L_frame; if ((tcx_cfg->fIsTNSAllowed && fUseTns != 0) || (L_spec > L_frame)) L = L_spec; tcxInvertWindowGrouping( tcx_cfg, xn_buf, spectrum, L, fUseTns, st->last_core, stop, frame_cnt, 0); } /*-----------------------------------------------------------* * Temporal Noise Shaping Synthesis * *-----------------------------------------------------------*/ if (tcx_cfg->fIsTNSAllowed) { SetTnsConfig(tcx_cfg, L_frame_glob == st->L_frame, (st->last_core == 0) && (frame_cnt == 0)); /* Apply TNS to get the reconstructed signal */ if (fUseTns != 0) { ApplyTnsFilter(tcx_cfg->pCurrentTnsConfig, pTnsData, spectrum, 0); if ((L_frame == st->L_frame >> 1) && (tcxonly)) { if ((tcx_cfg->tcx_last_overlap_mode != FULL_OVERLAP) || ((tcx_cfg->tcx_curr_overlap_mode == FULL_OVERLAP) && (frame_cnt == 0) && (stop == 0)) ) { const int L_win = L_spec >> 1; /* undo rearrangement of LF sub-window lines for TNS synthesis filter */ if (L_frame > L_spec) { assert(0); } else { mvr2r(spectrum+8, xn_buf, L_win); mvr2r(xn_buf, spectrum+L_win, 8); mvr2r(xn_buf+8, spectrum+8, L_win-8); } } } } } /*-----------------------------------------------------------* * Compute inverse MDCT of spectrum[]. * *-----------------------------------------------------------*/ if ((L_frame == st->L_frame >> 1) && (tcxonly)) { if (tcx_cfg->tcx_last_overlap_mode != FULL_OVERLAP) { /* minimum or half overlap, two transforms, grouping into one window */ float win[(L_FRAME_PLUS+L_MDCT_OVLP_MAX)/2]; const int L_win = L_frame >> 1; const int L_spec_TCX5 = max(L_frame, L_spec) >> 1; const int L_ola = (tcx_cfg->tcx_last_overlap_mode == MIN_OVERLAP) ? tcx_cfg->tcx_mdct_window_min_length : tcx_cfg->tcx_mdct_window_half_length; int w; set_f( win, 0, (L_FRAME_PLUS+L_MDCT_OVLP_MAX)/2 ); set_zero(xn_buf, tcx_offset+(L_ola>>1)); /* zero left end of buffer */ for (w = 0; w < 2; w++) { if (tcx_cfg->tcx_last_overlap_mode == MIN_OVERLAP) { TCX_MDCT_Inverse(spectrum+w*L_spec_TCX5, win, L_ola, L_win-L_ola, L_ola); } else { TCX_MDCT_Inverse(spectrum+w*L_spec_TCX5, win, L_ola, L_win-L_ola, L_ola); } tcx_windowing_synthesis_current_frame( win, tcx_cfg->tcx_aldo_window_2, tcx_cfg->tcx_mdct_window_half, tcx_cfg->tcx_mdct_window_minimum, L_ola, tcx_cfg->tcx_mdct_window_half_length, tcx_cfg->tcx_mdct_window_min_length, w==0 && st->last_core==0, (w > 0) || (w == 0 && stop == 2) ? MIN_OVERLAP : tcx_cfg->tcx_last_overlap_mode, LPDmem->acelp_zir, st->LPDmem.Txnq, NULL, Aq_old, tcx_cfg->tcx_mdct_window_trans, L_win, tcx_offset<0?-tcx_offset:0, (w > 0) ? 1 : st->last_core, 0, 0 ); if (w > 0) { tcx_windowing_synthesis_past_frame( xn_buf+tcx_offset-(L_ola>>1)+w*L_win, tcx_cfg->tcx_aldo_window_1_trunc, tcx_cfg->tcx_mdct_window_half, tcx_cfg->tcx_mdct_window_minimum, L_ola, tcx_cfg->tcx_mdct_window_half_length, tcx_cfg->tcx_mdct_window_min_length, 2 ); } /* add part of current sub-window overlapping with previous window */ v_add(win, xn_buf+tcx_offset-(L_ola>>1)+w*L_win, xn_buf+tcx_offset-(L_ola>>1)+w*L_win, L_ola); /* copy new sub-window region not overlapping with previous window */ mvr2r(win+L_ola, xn_buf+tcx_offset+(L_ola>>1)+w*L_win, L_win); } /* To assure that no garbage values are copied to LPDmem->Txnq */ set_zero(xn_buf+L_frame+tcx_offset+(L_ola>>1), overlap-tcx_offset-(L_ola>>1)); } else if ((frame_cnt == 0) && (tcx_cfg->tcx_curr_overlap_mode == FULL_OVERLAP)) { /* special overlap attempt, two transforms, grouping into one window */ float win[(L_FRAME_PLUS+L_MDCT_OVLP_MAX)/2]; const int L_win = L_frame >> 1; const int L_spec_TCX5 = max(L_frame, L_spec) >> 1; const int L_ola = tcx_cfg->tcx_mdct_window_min_length; int w; set_f( win, 0, (L_FRAME_PLUS+L_MDCT_OVLP_MAX)/2 ); /* Resize overlap (affect only asymmetric window)*/ overlap = st->tcx_cfg.tcx_mdct_window_delay; /* 1st TCX-5 window, special MDCT with minimum overlap on right side */ TCX_MDCT_Inverse(spectrum, win+L_win, 0, L_win-(L_ola>>1), L_ola); /* copy new sub-window region not overlapping with previous window */ mvr2r(win+L_win, xn_buf+(overlap>>1), L_win+(L_ola>>1)); /* 2nd TCX-5 window, regular MDCT with minimum overlap on both sides */ TCX_MDCT_Inverse(spectrum+L_spec_TCX5, win, L_ola, L_win-L_ola, L_ola); tcx_windowing_synthesis_current_frame( win, tcx_cfg->tcx_aldo_window_2, tcx_cfg->tcx_mdct_window_half, tcx_cfg->tcx_mdct_window_minimum, L_ola, tcx_cfg->tcx_mdct_window_half_length, tcx_cfg->tcx_mdct_window_min_length, 0, /* left_rect */ 2, /* left_mode */ LPDmem->acelp_zir, st->LPDmem.Txnq, NULL, Aq_old, tcx_cfg->tcx_mdct_window_trans, L_win, tcx_offset<0?-tcx_offset:0, 1, /* not st->last_core */ 0 ,0 ); tcx_windowing_synthesis_past_frame( xn_buf+(overlap>>1)+L_win-(L_ola>>1), tcx_cfg->tcx_aldo_window_1_trunc, tcx_cfg->tcx_mdct_window_half, tcx_cfg->tcx_mdct_window_minimum, L_ola, tcx_cfg->tcx_mdct_window_half_length, tcx_cfg->tcx_mdct_window_min_length, 2 ); /* add part of current sub-window overlapping with previous window */ v_add(win, xn_buf+(overlap>>1)+L_win-(L_ola>>1), xn_buf+(overlap>>1)+L_win-(L_ola>>1), L_ola); /* copy new sub-window region not overlapping with previous window */ mvr2r(win+L_ola, xn_buf+(overlap>>1)+L_win+(L_ola>>1), L_win); /* extra folding-out on left side of win, for perfect reconstruction */ for (w = (overlap>>1); w < overlap; w++) { xn_buf[overlap-1-w] = -1.0f * xn_buf[w]; } tcx_windowing_synthesis_current_frame( xn_buf, tcx_cfg->tcx_aldo_window_2, tcx_cfg->tcx_mdct_window_half, tcx_cfg->tcx_mdct_window_minimum, overlap, /*tcx_cfg->tcx_mdct_window_length*/ tcx_cfg->tcx_mdct_window_half_length, tcx_cfg->tcx_mdct_window_min_length, st->last_core == ACELP_CORE, 0, /* left_mode */ LPDmem->acelp_zir, st->LPDmem.Txnq, NULL, Aq_old, tcx_cfg->tcx_mdct_window_trans, L_win, tcx_offset<0?-tcx_offset:0, st->last_core, 0, 0 ); } else { /* default, i.e. maximum overlap, single transform, no grouping */ TCX_MDCT_Inverse(spectrum, xn_buf, overlap, L_frame-overlap, overlap); tcx_windowing_synthesis_current_frame( xn_buf, tcx_cfg->tcx_aldo_window_2, tcx_cfg->tcx_mdct_window_half, tcx_cfg->tcx_mdct_window_minimum, overlap, /*tcx_cfg->tcx_mdct_window_length*/ tcx_cfg->tcx_mdct_window_half_length, tcx_cfg->tcx_mdct_window_min_length, st->last_core == ACELP_CORE, (frame_cnt > 0) && (stop == 0) && (st->last_core!=0) ? 2 : stop, LPDmem->acelp_zir, st->LPDmem.Txnq, NULL, Aq_old, tcx_cfg->tcx_mdct_window_trans, L_frame_glob >> 1, tcx_offset<0?-tcx_offset:0, st->last_core, 0, 0 ); } /* tcx_last_overlap_mode != FULL_OVERLAP */ } else { /* frame is TCX-20 or not TCX-only */ if (st->tcx_cfg.tcx_last_overlap_mode != TRANSITION_OVERLAP) { float tmp[L_FRAME_PLUS]; edct(spectrum, xn_buf+overlap/2+nz, L_frame); v_multc( xn_buf+overlap/2+nz, (float)sqrt((float)L_frame / NORM_MDCT_FACTOR), tmp, L_frame); window_ola( tmp, xn_buf, st->old_out, L_frame, tcx_cfg->tcx_last_overlap_mode, tcx_cfg->tcx_curr_overlap_mode, 0, 0, NULL ); aldo = 1; } else { TCX_MDCT_Inverse(spectrum, xn_buf, overlap, L_frame-overlap, overlap); /*-----------------------------------------------------------* * Windowing, overlap and add * *-----------------------------------------------------------*/ /* Window current frame */ tcx_windowing_synthesis_current_frame( xn_buf, tcx_cfg->tcx_aldo_window_2, tcx_cfg->tcx_mdct_window_half, tcx_cfg->tcx_mdct_window_minimum, overlap, /*tcx_cfg->tcx_mdct_window_length*/ tcx_cfg->tcx_mdct_window_half_length, tcx_cfg->tcx_mdct_window_min_length, st->last_core == ACELP_CORE, tcx_cfg->tcx_last_overlap_mode, /*left mode*/ LPDmem->acelp_zir, st->LPDmem.Txnq, NULL, Aq_old, tcx_cfg->tcx_mdct_window_trans, L_frame_glob >> 1, tcx_offset<0?-tcx_offset:0, st->last_core, 0, 0 ); } } /* TCX-20/TCX-10 and TCX-only */ /* Window and overlap-add past frame if past frame is TCX */ if ((st->last_core > 0) && (((L_frameTCX == st->L_frameTCX >> 1) && (st->tcxonly)) || (st->tcx_cfg.tcx_last_overlap_mode == TRANSITION_OVERLAP)) ) { if (tcx_cfg->last_aldo) { for (i=0; i < overlap - tcx_cfg->tcx_mdct_window_min_length; i++) { xn_buf[i] += st->old_out[i+nz]; } /* fade truncated ALDO window */ for ( ; i < overlap; i++) { xn_buf[i] += st->old_out[i+nz] * tcx_cfg->tcx_mdct_window_minimum[overlap-1-i]; } } else { if ((frame_cnt > 0) && (stop == 0) && (tcx_cfg->tcx_curr_overlap_mode == FULL_OVERLAP)&& (st->last_core!=0)) { stop = 2; /* use minimum overlap between the two TCX-10 windows */ } tcx_windowing_synthesis_past_frame( LPDmem->Txnq , tcx_cfg->tcx_aldo_window_1_trunc, tcx_cfg->tcx_mdct_window_half, tcx_cfg->tcx_mdct_window_minimum, overlap, tcx_cfg->tcx_mdct_window_half_length, tcx_cfg->tcx_mdct_window_min_length, (stop == 0 || tcx_cfg->tcx_last_overlap_mode == MIN_OVERLAP) ? tcx_cfg->tcx_last_overlap_mode : stop ); for (i=0; iTxnq[i]; } } } if(!aldo && (((L_frameTCX == st->L_frameTCX >> 1)&&frame_cnt > 0) || L_frameTCX != (st->L_frameTCX >> 1))) { /*Compute windowed synthesis in case of switching to ALDO windows in next frame*/ mvr2r(xn_buf+L_frame-nz, st->old_out, nz+overlap); set_zero(st->old_out+nz+overlap, nz); tcx_windowing_synthesis_past_frame( st->old_out+nz, tcx_cfg->tcx_aldo_window_1_trunc, tcx_cfg->tcx_mdct_window_half, tcx_cfg->tcx_mdct_window_minimum, overlap, tcx_cfg->tcx_mdct_window_half_length, tcx_cfg->tcx_mdct_window_min_length, tcx_cfg->tcx_curr_overlap_mode ); if(tcx_cfg->tcx_curr_overlap_mode==FULL_OVERLAP) { for (i=0; iold_out[nz+overlap+i]=xn_buf[L_frame-1-i]*tcx_cfg->tcx_aldo_window_1_trunc[-1-i]; } tcx_cfg->tcx_curr_overlap_mode=ALDO_WINDOW; } } tcx_cfg->last_aldo=aldo; /* Update Txnq */ if (!tcx_cfg->last_aldo) { mvr2r(xn_buf+L_frame, LPDmem->Txnq, overlap); } /* Output */ mvr2r( xn_buf+(overlap>>1)-tcx_offset, synth, L_frame_glob ); /* Update L_frame_past */ st->L_frame_past = L_frame; return; } /*-------------------------------------------------------------------* * coder_tcx() * * *-------------------------------------------------------------------*/ void coder_tcx( int n, TCX_config *tcx_cfg, /*input: configuration of TCX*/ float A[], /* input: quantized coefficients NxAz_q[M+1] */ Word16 Aqind[], /* input: frame-independent quantized coefficients (M+1) */ float synth[], int L_frame_glob, /* input: frame length */ int L_frameTCX_glob, int L_spec, int nb_bits, /*input: bit budget*/ int tcxonly, /*input: only TCX flag*/ float spectrum[], /* i/o: MDCT spectrum */ LPD_state *LPDmem, /*i/o: memories*/ int prm[], /* output: tcx parameters */ Encoder_State *st, CONTEXT_HM_CONFIG *hm_cfg ) { int L_frame; int left_overlap=-1, right_overlap=-1; int tnsSize = 0; /* number of tns parameters put into prm */ int tnsBits = 0; /* number of tns bits in the frame */ int ltpBits = 0; float gainlpc[FDNS_NPTS]; float buf[N_MAX+L_MDCT_OVLP_MAX]; float winMDST[N_MAX+L_MDCT_OVLP_MAX]; float * win; float * powerSpec; powerSpec = win = buf; /* Share memory for windowed TD signal and for the power spectrum */ L_frame = L_frameTCX_glob; /*-----------------------------------------------------------* * Windowing * *-----------------------------------------------------------*/ if (st->tcx_cfg.tcx_last_overlap_mode == TRANSITION_OVERLAP) { WindowSignal( tcx_cfg, tcx_cfg->tcx_offsetFB, tcx_cfg->tcx_last_overlap_mode, tcx_cfg->tcx_curr_overlap_mode, &left_overlap, &right_overlap, st->speech_TCX, &L_frame, win, 1 ); /*-----------------------------------------------------------* * Compute MDCT for xn_buf[]. * *-----------------------------------------------------------*/ TCX_MDCT( win, spectrum, left_overlap, L_frame-(left_overlap+right_overlap)/2, right_overlap ); } else { wtda( st->new_speech_TCX, win, NULL, tcx_cfg->tcx_last_overlap_mode, tcx_cfg->tcx_curr_overlap_mode, L_frame); WindowSignal( tcx_cfg, tcx_cfg->tcx_offsetFB, tcx_cfg->tcx_last_overlap_mode == ALDO_WINDOW ? FULL_OVERLAP : tcx_cfg->tcx_last_overlap_mode, tcx_cfg->tcx_curr_overlap_mode == ALDO_WINDOW ? FULL_OVERLAP : tcx_cfg->tcx_curr_overlap_mode, &left_overlap, &right_overlap, st->speech_TCX, &L_frame, winMDST, 1 ); edct( win, spectrum, L_frame ); v_multc(spectrum, (float)sqrt((float)NORM_MDCT_FACTOR / L_frame), spectrum, L_frame); } /*-----------------------------------------------------------* * Attenuate upper end of NB spectrum, * * to simulate ACELP behavior * *-----------------------------------------------------------*/ if( st->narrowBand ) { attenuateNbSpectrum(L_frame, spectrum); } /*-----------------------------------------------------------* * Compute noise-measure flags for spectrum filling * * and quantization (0: tonal, 1: noise-like). * * Detect low pass if present. * *-----------------------------------------------------------*/ AnalyzePowerSpectrum( st, L_frame*st->L_frame/st->L_frameTCX, L_frame, left_overlap, right_overlap, spectrum, (st->tcx_cfg.tcx_last_overlap_mode == TRANSITION_OVERLAP) ? win : winMDST, powerSpec ); if (tcx_cfg->fIsTNSAllowed) { SetTnsConfig(tcx_cfg, L_frame_glob == st->L_frame, st->last_core == 0); TNSAnalysis(tcx_cfg, L_frame, L_spec, TCX_20, st->last_core == 0, spectrum, st->tnsData, st->fUseTns, &(&st->hIGFEnc)->tns_predictionGain ); } else { st->fUseTns[0] = st->fUseTns[1] = 0; } if(st->igf) { ProcessIGF(&st->hIGFEnc, st, spectrum, powerSpec, 1, st->fUseTns[0], (st->last_core == ACELP_CORE), 0); } ShapeSpectrum( tcx_cfg, A, gainlpc, L_frame_glob, L_spec, spectrum, st->fUseTns[0], st ); if(st->igf) { nb_bits -= st->hIGFEnc.infoTotalBitsPerFrameWritten; } if (tcx_cfg->fIsTNSAllowed) { EncodeTnsData(tcx_cfg->pCurrentTnsConfig, st->tnsData, prm+1+NOISE_FILL_RANGES+LTPSIZE, &tnsSize, &tnsBits); } QuantizeSpectrum( tcx_cfg, A, Aqind, gainlpc, synth, L_frame_glob, L_frameTCX_glob, L_spec, nb_bits-tnsBits-ltpBits, tcxonly, spectrum,st->tnsData, st->fUseTns[0], tnsSize, LPDmem, prm, n, st, hm_cfg ); return; } /*-------------------------------------------------------------------* * coder_tcx_post() * * *-------------------------------------------------------------------*/ void coder_tcx_post( Encoder_State *st, LPD_state *LPDmem, TCX_config *tcx_cfg, float *synth, float *A, const float *Ai, float *wsig ) { float xn_buf[L_FRAME_MAX]; /* TCX output */ mvr2r( synth, xn_buf, st->L_frame ); /*-----------------------------------------------------------* * Memory update * *-----------------------------------------------------------*/ /* Update LPDmem (Txnq,syn,syn_pe,old_exc,wsyn,Ai,Aq) */ tcx_encoder_memory_update( wsig, xn_buf, st->L_frame, Ai, A, tcx_cfg->preemph_fac, LPDmem, st, M, synth ); return; }