⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lecns.c

📁 The line echo canceller (LEC) is designed to provide the maximum attainable transparent voice qualit
💻 C
📖 第 1 页 / 共 2 页
字号:
                pSc->uNlpMode = _NLP_CLEAR;
            }
        }
        else if (pSc->uFlags & LEC_FLAG_HITX)
        {
//            sDtCriteria = 0;
            if (pDb->Cfg.uControl & ILEC_CMD_CLR_HITX_DT_MASK)
            {
                pSc->uNlpMode = _NLP_CLEAR;
            }
            else
            {
                if (! pDb->uIsDT)
                {
                    pSc->uNlpMode = _NLP_CLEAR;
                }
                else
                {
                    pSc->uNlpMode = _NLP_CLIP;
                }
            }
        }
    	else
        {
    	    pDb->sDtCriteria += sDtCriteria;

            if (pDb->sDtCriteria > ((2*_DT_CRITERIA_MAX)/3))
	        {
       	        pDb->uIsDT = TRUE;
                pSc->uNlpMode = _NLP_PASS;

                /* limit from above */
	            /* hangover after DT is 120ms (20 frames) */
        	    if (pDb->sDtCriteria > _DT_CRITERIA_MAX)
	            {
    	    	    pDb->sDtCriteria = _DT_CRITERIA_MAX;
	            }
    	    }
	        else /* DtCrit < MAX/2 */
            {
                if (pDb->sDtCriteria <= 0)
                {
	    	        pDb->sDtCriteria = 0;
		            pDb->uIsDT = FALSE;
                }
                /* whether Dt or not, we calculate average values for erl and Erle
                   if dt, they will be discarged in the process of 1-2 flt copy.
                   if it is echo path change, that's a good start.
                 */
    	        if ((pSc->sRxEn - pDb->Adf2.sErleAveraged) > pDb->VadErr.sEnNoise)
                {
                    if (pDb->uIsDT)
                    {
                        lec_avrg(&pDb->Adf2.sErleAveraged, pSc->sErle, Q15(0.1));
                        lec_avrg(&pDb->Adf2.sErlAveraged, pSc->sErl, Q15(0.1));
                    }
                    else
                    {
                        lec_avrg(&pDb->Adf2.sErleAveraged, pSc->sErle, Q15(0.02));
                        lec_avrg(&pDb->Adf2.sErlAveraged, pSc->sErl, Q15(0.02));
                    }


                    if (pDb->Adf2.sErlAveraged < pDb->Cfg.sErlMin)
                        pDb->Adf2.sErlAveraged = pDb->Cfg.sErlMin;
                }

                pSc->uNlpMode = _NLP_CLIP;
	        }
        }
	}
	else // rx is not an echo
    {
        /* if this is a short rx, do not change dt status */
        pDb->sDtCriteria -= 1;
        if (pDb->sDtCriteria <= 0)
        {
            pDb->sDtCriteria = 0;
		    pDb->uIsDT = FALSE;
        }
        pSc->uNlpMode = _NLP_PASS;
    }

    if (uIsDT ^ pDb->uIsDT)
    {
        if (pDb->uIsDT)
        {
            lec_dt_start(pDb, pSc);
        }
        else
        {
            lec_dt_end(pDb, pSc);
        }
    }

    if (pDb->Cfg.uControl & ILEC_CMD_NLP_OFF_MASK)
    {
        // pass as is
        pSc->uNlpMode = _NLP_PASS;
    }
}
/*-------------------------------------------------------------------------*/
void                     _make_noise
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
    S16 k;
    S16 sDlt;
    S16 sIdx;

	for (k = 0; k < 4; k++)
	{
		pSc->asTmp[k] = pDb->asRand[k];
	}
    lec_pkt_rand(&pSc->asTmp[4], &pDb->sSeed);

	for (k = 0; k < 4; k++)
	{
		pDb->asRand[k] = pSc->asTmp[k+ILEC_FR_SZ];
	}

    sDlt = pDb->sClipLevel + pDb->Cfg.sClipThr - pDb->sRxNoiseLevel;
    if (sDlt < LEC_DB(8))
    {
        if (sDlt > LEC_DB(-8))
        {
            sIdx = (sDlt - LEC_DB(-8))/(LEC_DB(2)+1);
            if (sIdx < 0) sIdx = 0;
            if (sIdx > 8) sIdx = 8;
        // reduced noise level
            pSc->sRxNoiseAtt = lec_exp
                (pDb->sRxNoiseLevel+_NSE_PLS+_asNoiseAdd[sIdx]);
        }
        else // noise will come through
        {
            pSc->sRxNoiseAtt = 0;
        }
    }
    else // we need to remove signal completely, full noise level
    {
        pSc->sRxNoiseAtt = lec_exp(pDb->sRxNoiseLevel+_NSE_PLS);
    }

    lec_make_noise(pSc->psRx, pSc->asTmp, pSc->sRxNoiseAtt);
//    for(k = 0; k < ILEC_FR_SZ; k++) pSc->psRx[k] = 0;

}
/*-------------------------------------------------------------------------*/
void                     lec_non_linear_processor 
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
/*  if a tone is active on TX, then rx shal be cleared,
    because tone suppression may be poor 
    (especially in the beginning of the call)
    and if its leaks, DTMF detector will wake up on echo.

    if a high TX was detected, then rx shall be cleared,
    (whether DT is active or not) because echo is very high.
    
    if rx signal is an echo (erl & erle are both ok), 
    and echo's level is above noise level, then it shall be removed;
    otherwise: pass it through.

    note: NLP may be disabled by cfg. then just copy the error->rx.
 */
{
#if ! defined (_dsp)
    extern S16 _asCnl[];
    lec_pkts_cpy(_asCnl, pSc->asErr1, 1);
#endif

    _make_noise(pDb, pSc);

    switch(pSc->uNlpMode)
    {
    case _NLP_CLEAR:
        {
            /* noise already in Rx */
            break;
        }
    case _NLP_CLIP:
        {
            S16 sClipThr = lec_exp(pDb->sClipLevel + pDb->Cfg.sClipThr);

            _lp_residual_error(pDb, pSc);

#if _LINEAR // transparent mode
            lec_pkts_cpy(pSc->psRx, pSc->asErr1, 1);
#else      
            lec_central_clipping(pSc->psRx, pSc->asErr1, sClipThr);
#endif
            break;
        }
    case _NLP_PASS:
        {
            if (pDb->uIsDT && (pSc->uFlags & LEC_FLAG_ERL_OK)) 
                _lp_residual_error(pDb, pSc);
            /* overwrite noise */
            lec_pkts_cpy(pSc->psRx, pSc->asErr1, 1);
            break;
        }
    default: // error
        {
            S16 k;
            for(k = 0; k < ILEC_FR_SZ; k++) pSc->psRx[k] = 8000;
            break;
        }
    }
}

/*-------------------------------------------------------------------------*/
void                        lec_adapt_slow
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
    S16 section;
    U16 uEn;
    
    /* compute energy and step size */
    S32 slAcc = lec_get_xz_slow(pDb->psHst, pDb->psTxF);
    pSc->slEn = slAcc;
    
    slAcc += pDb->Adf2.slAcc/4;
    uEn = lec_step_size(slAcc, &pSc->sStepSize);
    pSc->uAdaptMode |= uEn<<2;
    
    for (section = 0; section < ILEC_FR_SZ/LEC_SECTION_SZ; section++)
    {
        S16 base = section*LEC_SECTION_SZ;
        S16 sStepSize; /* section step size */
        S16 k;

/* CANCEL ECHO */

    	for (k = 0; k < LEC_SECTION_SZ; k++)
    	{
            pSc->asErr2[base+k] = lec_cancel_shifted(
                pDb->psHst + LEC_FLT2_SZ + base + k,
                pDb->psFlt2, 
                pSc->psRx[base+k],
                pDb->Adf2.sShift
                );
	    }

        pSc->sStepCorr = lec_step_size_corr_slow(pDb, pSc, base);

        sStepSize = (S16)((pSc->sStepSize * (S32) pSc->sStepCorr + (1<<11))>>12);

        switch(uEn) {
        case 1:
        	lec_adapt_slow_high(pDb, pSc, base, sStepSize);
            break;
        case 2:
        	lec_adapt_slow_low(pDb, pSc, base, sStepSize);
            break;
        default:
            break;
        } // end-of-switch
    } /* end of for: sections */

	lec_shift_err2(pDb, pSc);
	
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -