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

📄 lecnlp.c

📁 The line echo canceller (LEC) is designed to provide the maximum attainable transparent voice qualit
💻 C
字号:
/*-------------------------------------------------------------------------*
 *                                                                         *
 *   THIS IS AN UNPUBLISHED WORK CONTAINING CONFIDENTIAL AND PROPRIETARY   *
 *   INFORMATION.  IF PUBLICATION OCCURS, THE FOLLOWING NOTICE APPLIES:    *
 *      "COPYRIGHT 2001 MIKET DSP SOLUTIONS, ALL RIGHTS RESERVED"          *
 *                                                                         *
 *-------------------------------------------------------------------------*/


#if ! defined(_dsp)
#include <stdio.h>
#include <conio.h>
#include <math.h>
#endif

#include "leci.h"

/*--------------------- local defs ----------------------------------------*/
#define _LINEAR                 (0)
#define _NSE_PLS                (LEC_DB(11))

/*--------------------- public vars ---------------------------------------*/
/*--------------------- local vars ----------------------------------------*/
#if defined (_dsp)
#pragma DATA_SECTION(_aasLpFilter, ".lecd")
#endif
const S16 _aasLpFilter[][6] = 
{
    {Q15(0.167), Q15(0.167), Q15(0.167), Q15(0.167), Q15(0.167), Q15(0.167)}, // 1.0
    {Q15(0.271), Q15(0.217), Q15(0.174), Q15(0.139), Q15(0.111), Q15(0.089)}, // 0.8
    {Q15(0.420), Q15(0.252), Q15(0.151), Q15(0.091), Q15(0.054), Q15(0.033)}, // 0.6
    {Q15(0.603), Q15(0.241), Q15(0.097), Q15(0.039), Q15(0.015), Q15(0.006)}, // 0.4
    {Q15(0.800), Q15(0.160), Q15(0.032), Q15(0.006), Q15(0.001), Q15(0.000)}, // 0.2
    {32767,      Q15(0.000), Q15(0.000), Q15(0.000), Q15(0.000), Q15(0.000)}, // 0.0
};

#if defined (_dsp)
#pragma DATA_SECTION(_asNoiseAdd, ".lecd")
#endif
const S16 _asNoiseAdd[9] = {
    LEC_DB(-12.0),
    LEC_DB(-7.0),
    LEC_DB(-5.0),
    LEC_DB(-3.0),

    LEC_DB(-2.0),

    LEC_DB(-1.5),
    LEC_DB(-1.0),
    LEC_DB(-0.5),
    LEC_DB(-0.25),
};

/*--------------------- local functions -----------------------------------*/
/*-------------------------------------------------------------------------*/
void                     _lp_residual_error
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
    S16 sIdx;
    
    /* if residual echo is not going to be masked by rx,
       then we'd better filter it out. 
       if Err signal is higher than noise level,
       and erle loss is high, then we should
       increase filtering as erle loss progresses.
     */
#if _LINEAR // transparent mode
    if (pDb->sClipLevel > pDb->VadErr.sEnNoise - LEC_DB(12))
#else
    if (pDb->sClipLevel > pDb->VadErr.sEnNoise + LEC_DB(6))
#endif
    {
        sIdx = pDb->VadErr.sEn - pDb->sClipLevel;
        sIdx >>= 10; // an idx per 6 db erle loss
        if (sIdx < 0) sIdx = 0;
        if (sIdx > 5) sIdx = 5;
    }
    else // no filter
    {
        sIdx = 5;
    }
    
    lec_lp_residual_error(pDb, pSc, &_aasLpFilter[sIdx][0]);
}
/*-------------------------------------------------------------------------*/
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(2)+1);
//            sIdx = (S16)( (sDlt * ((1L<<16)/LEC_DB(2)) )>>16);
            sIdx = _smpy(sDlt, (S16)(0x8000L/LEC_DB(2)));
            sIdx += 4;
            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;

}

/*--------------------- public  functions ---------------------------------*/
/*-------------------------------------------------------------------------*/
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 LEC_NLP_CLEAR:
        {
            /* noise already in Rx */
            break;
        }
    case LEC_NLP_CLIP:
        {
            S16 sClipThreshold = lec_exp (pDb->sClipLevel + pDb->Cfg.sClipThr);
            if (!(pDb->Cfg.uControl & ILEC_CMD_POST_OFF))
            {
                _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, sClipThreshold);
#endif
            break;
        }
    case LEC_NLP_PASS:
        {
            if ((pDb->uIsDT) && 
                (!(pDb->Cfg.uControl & ILEC_CMD_POST_OFF)) &&
                (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->asAdf2, 
                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);
	
}

/*-------------------------------------------------------------------------*/
void                        lec_adapt_fast
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
    S16 base;
    U16 uEn;

    pSc->slEn = lec_get_xz(pDb->psHst + LEC_FLT2_SZ, 
                           pDb->psTxF + LEC_FLT2_SZ);
                           
    for (base = 0; base < ILEC_FR_SZ; base++)
    {
    	S32 slEn;
        S16 SSS; /* corrected step size */

/* CANCEL ECHO */
        pSc->asErr2[base] = lec_cancel(
             pDb->psHst + LEC_FLT2_SZ + base,
             pDb->asAdf2,
             pSc->psRx[base]
             ); 
		        
        if (base != 0)
        {
            pSc->slEn = lec_update_xz(pSc->slEn,
                     				pDb->psHst + LEC_FLT2_SZ + base,
            		                pDb->psTxF + LEC_FLT2_SZ + base 
                                 	);
        }
        
        slEn = pSc->slEn + pDb->Adf2.slAcc;
		uEn = lec_step_size(slEn, &pSc->sStepSize);
        pSc->uAdaptMode |= uEn<<2;

        /* compute energy and step size */
/* ADJUST STEP SIZE */
        pSc->sStepCorr = lec_step_size_corr_fast2(pDb, pSc, base);
        SSS = (S16)((pSc->sStepSize * (S32) pSc->sStepCorr + (1<<11))>>12);

        switch(uEn) {
        case 1:
        	lec_adapt_fast_high(pDb, pSc, base, SSS);
        	break;
        case 2:
        	lec_adapt_fast_low(pDb, pSc, base, SSS);
            break;
        default:
            break;
        }
    } /* end of for: ILEC_FR_SZ */
}  

⌨️ 快捷键说明

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