/*==================================================================================== EVS Codec 3GPP TS26.443 Jun 30, 2015. Version CR 26.443-0006 ====================================================================================*/ #include #include #include #include #include "options.h" #include "cnst.h" #include "prot.h" /*-------------------------------------------------------------------* * tcx_get_windows() * * *-------------------------------------------------------------------*/ static void tcx_get_windows( TCX_config const * tcx_cfg, /* i: TCX configuration */ const short left_mode, /* i: overlap mode of left window half */ const short right_mode, /* i: overlap mode of right window half */ int *left_overlap, /* o: left overlap length */ float const **left_win, /* o: left overlap window */ int *right_overlap, /* o: right overlap length */ float const **right_win, /* o: right overlap window */ int fullband /* i: fullband flag */ ) { if (!fullband) { /* Left part */ if (left_mode == TRANSITION_OVERLAP) { /* ACELP->TCX transition */ *left_overlap = tcx_cfg->tcx_mdct_window_trans_length; *left_win = tcx_cfg->tcx_mdct_window_trans; } else if (left_mode == MIN_OVERLAP) { *left_overlap = tcx_cfg->tcx_mdct_window_min_length; *left_win = tcx_cfg->tcx_mdct_window_minimum; } else if (left_mode == HALF_OVERLAP) { *left_overlap = tcx_cfg->tcx_mdct_window_half_length; *left_win = tcx_cfg->tcx_mdct_window_half; } else if (left_mode == FULL_OVERLAP) { *left_overlap = tcx_cfg->tcx_mdct_window_length; *left_win = tcx_cfg->tcx_aldo_window_1_trunc; } else { assert(!"Not supported overlap"); } /* Right part */ if (right_mode == MIN_OVERLAP) { *right_overlap = tcx_cfg->tcx_mdct_window_min_length; *right_win = tcx_cfg->tcx_mdct_window_minimum; } else if (right_mode == HALF_OVERLAP) { *right_overlap = tcx_cfg->tcx_mdct_window_half_length; *right_win = tcx_cfg->tcx_mdct_window_half; } else if (right_mode == FULL_OVERLAP) { *right_overlap = tcx_cfg->tcx_mdct_window_delay; *right_win = tcx_cfg->tcx_aldo_window_2; } else { assert(!"Not supported overlap"); } } else { /* Left part */ if (left_mode == TRANSITION_OVERLAP) { /* ACELP->TCX transition */ *left_overlap = tcx_cfg->tcx_mdct_window_trans_lengthFB; *left_win = tcx_cfg->tcx_mdct_window_transFB; } else if (left_mode == MIN_OVERLAP) { *left_overlap = tcx_cfg->tcx_mdct_window_min_lengthFB; *left_win = tcx_cfg->tcx_mdct_window_minimumFB; } else if (left_mode == HALF_OVERLAP) { *left_overlap = tcx_cfg->tcx_mdct_window_half_lengthFB; *left_win = tcx_cfg->tcx_mdct_window_halfFB; } else if (left_mode == RECTANGULAR_OVERLAP) { *left_overlap = 0; *left_win = NULL; } else if (left_mode == FULL_OVERLAP) { *left_overlap = tcx_cfg->tcx_mdct_window_lengthFB; *left_win = tcx_cfg->tcx_aldo_window_1_FB_trunc; } else { assert(!"Not supported overlap"); } /* Right part */ if (right_mode == MIN_OVERLAP) { *right_overlap = tcx_cfg->tcx_mdct_window_min_lengthFB; *right_win = tcx_cfg->tcx_mdct_window_minimumFB; } else if (right_mode == HALF_OVERLAP) { *right_overlap = tcx_cfg->tcx_mdct_window_half_lengthFB; *right_win = tcx_cfg->tcx_mdct_window_halfFB; } else if (right_mode == RECTANGULAR_OVERLAP) { *right_overlap = 0; *right_win = NULL; } else if (right_mode == FULL_OVERLAP) { *right_overlap = tcx_cfg->tcx_mdct_window_delayFB; *right_win = tcx_cfg->tcx_aldo_window_2_FB; } else { assert(!"Not supported overlap"); } } return; } /*-------------------------------------------------------------------* * tcx_windowing_analysis() * * *-------------------------------------------------------------------*/ void tcx_windowing_analysis( float const *signal, /* i: signal vector */ int L_frame, /* i: frame length */ int left_overlap, /* i: left overlap length */ float const *left_win, /* i: left overlap window */ int right_overlap, /* i: right overlap length */ float const *right_win, /* i: right overlap window */ float *output /* o: windowed signal vector */ ) { int w; /* Left overlap */ for (w = 0; w < left_overlap; w++) { *output++ = *signal++ * left_win[w]; } /* Non overlapping region */ for (w = 0; w < L_frame-(left_overlap+right_overlap)/2; w++) { *output++ = *signal++; } /* Right overlap */ for (w = 0; w < right_overlap; w++) { *output++ = *signal++ * right_win[right_overlap-1-w]; } return; } /*-------------------------------------------------------------------* * WindowSignal() * * *-------------------------------------------------------------------*/ void WindowSignal( TCX_config const *tcx_cfg, /* input: configuration of TCX */ int offset, /* input: left folding point offset relative to the input signal pointer */ const short left_overlap_mode, /* input: overlap mode of left window half */ const short right_overlap_mode, /* input: overlap mode of right window half */ int * left_overlap_length, /* output: TCX window left overlap length */ int * right_overlap_length, /* output: TCX window right overlap length */ float const in[], /* input: input signal */ int * L_frame, /* input/output: frame length */ float out[], /* output: output windowed signal */ int fullband /* input: fullband flag */ ) { int l, r; float const * left_win; float const * right_win; /*-----------------------------------------------------------* * Init * *-----------------------------------------------------------*/ tcx_get_windows(tcx_cfg, left_overlap_mode, right_overlap_mode, &l, &left_win, &r, &right_win, fullband ); /* Init lengths */ /* if past frame is ACELP */ if (left_overlap_mode == TRANSITION_OVERLAP) { /* Increase frame size for 5ms */ if (!fullband) { *L_frame += tcx_cfg->tcx5Size; offset = -tcx_cfg->tcx_mdct_window_trans_length/2; } else { *L_frame += tcx_cfg->tcx5SizeFB; offset = -tcx_cfg->tcx_mdct_window_trans_lengthFB/2; } } /*-----------------------------------------------------------* * Windowing * *-----------------------------------------------------------*/ tcx_windowing_analysis(in-l/2+offset, *L_frame, l, left_win, r, right_win, out); if (left_overlap_mode == FULL_OVERLAP) { /* fade truncated ALDO window to avoid discontinuities */ if (!fullband) { v_mult(out, tcx_cfg->tcx_mdct_window_minimum, out, tcx_cfg->tcx_mdct_window_min_length); } else { v_mult(out, tcx_cfg->tcx_mdct_window_minimumFB, out, tcx_cfg->tcx_mdct_window_min_lengthFB); } } *left_overlap_length = l; *right_overlap_length = r; return; } /*-------------------------------------------------------------------* * tcx_windowing_synthesis_current_frame() * * *-------------------------------------------------------------------*/ void tcx_windowing_synthesis_current_frame( float *signal, /* i/o: signal vector */ float *window, /* i: TCX window vector */ float *window_half, /* i: TCX window vector for half-overlap window */ float *window_min, /* i: TCX minimum overlap window */ int window_length, /* i: TCX window length */ int window_half_length, /* i: TCX half window length */ int window_min_length, /* i: TCX minimum overlap length */ int left_rect, /* i: left part is rectangular */ int left_mode, /* i: overlap mode of left window half */ float *acelp_zir, /* i: acelp ZIR */ float *old_syn, /* i: old synthesis */ float *syn_overl, /* i: overlap synthesis */ float *A_zir, float *window_trans, int acelp_zir_len, int acelp_mem_len, int last_core_bfi, /* i: last mode */ int last_is_cng, int fullbandScale ) { int i, overlap; float tmp[L_FRAME_MAX/2]; /* Init */ overlap = window_length>>1; /* Past-frame is TCX concealed as CNG and current-frame is TCX */ if ( last_is_cng==1 && left_rect==0 ) { if (!fullbandScale) { set_zero(acelp_zir, acelp_zir_len); syn_filt(A_zir, M,acelp_zir, acelp_zir, acelp_zir_len, signal+overlap+acelp_mem_len-M, 0); } else { lerp(acelp_zir, tmp, acelp_zir_len, acelp_zir_len*FSCALE_DENOM/fullbandScale); acelp_zir = tmp; } for (i = 0; i < acelp_zir_len; i++) { signal[i] *= (float)(i)/(float)(acelp_zir_len); signal[i] += acelp_zir[i]*(float)(acelp_zir_len-i)/(float)(acelp_zir_len); } } else if ( left_rect==1 && last_core_bfi==ACELP_CORE ) /* Rectangular window (past-frame is ACELP) */ { for (i=0; i= 2.0f * 64) { /* apply a simple low-pass to the ZIR, to avoid potentially unmasked HF content */ for(i=2; i=0; i--) { acelp_zir[i] = 0.40f * acelp_zir[i] + 0.35f * acelp_zir[i+1] + 0.25f * acelp_zir[i+2]; } } } for (i = 0; i < acelp_zir_len; i++) { /*remove reconstructed ZIR and add ACELP ZIR*/ signal[i+overlap+acelp_mem_len] -= acelp_zir[i]*(float)(acelp_zir_len-i)/(float)acelp_zir_len; } } else if ( left_rect==1 && last_core_bfi!=0 ) /* Rectangular window (past-frame is TCX) */ { for (i=0; i lpcGains[i]) { tmp = lpcGains[i]; } if (max < lpcGains[i]) { max = lpcGains[i]; } } tmp *= 32.0f; if ((max < tmp) && (tmp > FLT_MIN)) { fac = tmp = (float)pow(max / tmp, 0.0078125f); if (lf_deemph_factors) { /* gradual lowering of lowest 32 bins; DC is lowered by (max/tmp)^1/4 */ for (i = 31; i >= 0; i--) { x[i] *= fac; lf_deemph_factors[i] *= fac; fac *= tmp; } } else { /* gradual lowering of lowest 32 bins; DC is lowered by (max/tmp)^1/4 */ for (i = 31; i >= 0; i--) { x[i] *= fac; fac *= tmp; } } } return; } /*-------------------------------------------------------------------* * AdaptLowFreqDeemph() * * *-------------------------------------------------------------------*/ void AdaptLowFreqDeemph( float x[], short tcx_lpc_shaped_ari, const float lpcGains[], const int lg, float lf_deemph_factors[] ) { int i, i_max_old,i_max; if(!tcx_lpc_shaped_ari) { /* 1. find first magnitude maximum in lower quarter of spectrum */ i_max = -1; for (i = 0; i < lg/4; i++) { if ((x[i] <= -4.0f) || (x[i] >= 4.0f)) { x[i] += (x[i] < 0.0f) ? 2.0f : -2.0f; i_max = i; break; } } /* 2. expand value range of all xi up to i_max: two extra steps */ for (i = 0; i < i_max; i++) { x[i] *= 0.5f; lf_deemph_factors[i] *= 0.5f; } /* 3. find first magnitude maximum in lower quarter of spectrum */ i_max_old = i_max; if (i_max_old > -1) { i_max = -1; for (i = 0; i < lg/4; i++) { if ((x[i] <= -4.0f) || (x[i] >= 4.0f)) { x[i] += (x[i] < 0.0f) ? 2.0f : -2.0f; i_max = i; break; } } } /* 4. expand value range of all xi up to i_max: two extra steps */ for (i = 0; i < i_max; i++) { x[i] *= 0.5f; lf_deemph_factors[i] *= 0.5f; } /* 5. always expand two lines; lines could be at index 0 and 1! */ if (i_max < i_max_old) { i_max = i_max_old; } i = i_max + 1; if (x[i] < 0.0f) { if (x[i] > -4.0f) { lf_deemph_factors[i] *= 0.5f; } x[i] = (x[i] <= -4.0f) ? x[i] + 2.0f : x[i] * 0.5f; } else { if (x[i] < 4.0f) { lf_deemph_factors[i] *= 0.5f; } x[i] = (x[i] >= 4.0f) ? x[i] - 2.0f : x[i] * 0.5f; } i++; if (x[i] < 0.0f) { if (x[i] > -4.0f) { lf_deemph_factors[i] *= 0.5f; } x[i] = (x[i] <= -4.0f) ? x[i] + 2.0f : x[i] * 0.5f; } else { if (x[i] < 4.0f) { lf_deemph_factors[i] *= 0.5f; } x[i] = (x[i] >= 4.0f) ? x[i] - 2.0f : x[i] * 0.5f; } } else { /*if(!tcx_lpc_shaped_ari)*/ PsychAdaptLowFreqDeemph(x, lpcGains, lf_deemph_factors); }/*if(!tcx_lpc_shaped_ari)*/ return; } /*-------------------------------------------------------------------* * tcx_noise_filling() * * *-------------------------------------------------------------------*/ void tcx_noise_filling( float *Q, const int noiseFillSeed, const int iFirstLine, const int lowpassLine, const int nTransWidth, const int L_frame, float tiltCompFactor, float fac_ns, unsigned char *infoTCXNoise ) { int i, m, segmentOffset; int win; /* window coefficient */ Word16 seed; float tilt_factor, nrg, tmp1, tmp2; /* 16-bit random number generator seed for generating filled lines */ seed = (Word16)noiseFillSeed; tilt_factor = (float)pow(max(0.375f, tiltCompFactor), 1.0f/(float)L_frame); fac_ns /= (float)(nTransWidth * nTransWidth); /* find last nonzero line below iFirstLine, use it as start offset */ for (i = iFirstLine; i > (iFirstLine >> 1); i--) { if (Q[i] != 0.0f) { break; } } fac_ns *= (float)pow(tilt_factor, (float)i); nrg = 1e-9f; win = 0; segmentOffset = ++i; for (; i < lowpassLine; i++) { fac_ns *= tilt_factor; if (Q[i] != 0.0f) { if (win > 0) { /* RMS-normalize current noise-filled segment */ tmp1 = (float)sqrt((i - segmentOffset) / nrg); tmp2 = tmp1 * (float)nTransWidth; for (m = segmentOffset; m < i-win; m++) { Q[m] *= tmp2; } for (; win > 0; win--) { Q[m++] *= tmp1 * (float)win; } nrg = 1e-9f; /* start new segment: reset noise segment energy */ } segmentOffset = i + 1; } else { /* line is zero, so fill line and update window and energy */ if (win < nTransWidth) { win++; } tmp1 = (float)own_random(&seed); nrg += tmp1 * tmp1; /* sum up energy of current noise segment */ Q[i] = tmp1 * (float)win * fac_ns; if(infoTCXNoise) { /* set noiseflags for IGF */ infoTCXNoise[i] = 1; } } } if (win > 0) { /* RMS-normalize uppermost noise-filled segment */ tmp1 = (float)sqrt((lowpassLine - segmentOffset) / nrg); tmp2 = tmp1 * (float)nTransWidth; for (m = segmentOffset; m < lowpassLine; m++) { Q[m] *= tmp2; } } return; } /*-------------------------------------------------------------------* * InitTnsConfigs() * * *-------------------------------------------------------------------*/ void InitTnsConfigs( int nSampleRate, int L_frame, STnsConfig tnsConfig[2][2], int igfStopFreq, int bitrate ) { if (bitrate > ACELP_32k) { InitTnsConfiguration(nSampleRate, L_frame/2, &tnsConfig[0][0], igfStopFreq, bitrate); } InitTnsConfiguration(nSampleRate, L_frame, &tnsConfig[1][0], igfStopFreq, bitrate); InitTnsConfiguration(nSampleRate, L_frame +L_frame/4, &tnsConfig[1][1], igfStopFreq, bitrate); return; } /*-------------------------------------------------------------------* * SetTnsConfig() * * *-------------------------------------------------------------------*/ void SetTnsConfig( TCX_config * tcx_cfg, int isTCX20, int isAfterACELP ) { tcx_cfg->pCurrentTnsConfig = &tcx_cfg->tnsConfig[isTCX20][isAfterACELP]; assert(tcx_cfg->pCurrentTnsConfig != NULL); return; }