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

📄 lec.c

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


#if !defined _dsp
#include <memory.h>
#include <math.h>
#include <stdlib.h>
#else
#include <string.h> /* memcpy() */
#endif

#include "stddefs.h"
#include "leci.h"

/*--------------------- local defs ----------------------------------------*/


/* the min erl we expect to be at least is 3 dB  */
#define _ERL_OK_CNT             (3)
#define _ERL_MIN                LEC_DB(3)
#define _ERL_MAX                LEC_DB(25)
#define _ERL_DIFF               LEC_DB(0.5)
#define _ERL_STAB_CNT           (5)

#define _MSE_MIN                LEC_DB(-8)

/* for delay upon transition into fe state */
#define _TX_STATE_DELAY         3
#define _TX_COUNTER_MAX         (200 *2)

#define _EN_VLOW                LEC_DB(25)
#define _EN_VHIGH               LEC_DB(-17)

/* only reused constants */
#define _ZC_NOISE_START 		LEC_DB(15)

/* definition of events */
#define _VOICE_OFF              0 /* activity definetely ended */
#define _VOICE_ON               1 /* activity definetely started */
#define _VOICE_MAYBE            2 /* suspicious activity started */

#define abs(x)                  (((x)>0)? (x):(-x))


/*--------------------- public vars ---------------------------------------*/

/*--------------------- local vars ----------------------------------------*/

#if defined (_dsp)
#endif

/*--------------------- local functions -----------------------------------*/
/*-------------------------------------------------------------------------*/
void                        _vad_init
/*-------------------------------------------------------------------------*/
(
LEC_tVad *p,
S16 sEnNoise
)
{
    p->sZcNoise = _ZC_NOISE_START;
	p->sEnNoise = sEnNoise;
    p->sEnNoiseMax = sEnNoise;
}
/*-------------------------------------------------------------------------*/
S16                         _vad_process
/*-------------------------------------------------------------------------*/
(
LEC_tVad *pVad,
S16 *psData
)
{
    S16 sState = pVad->sState;

    pVad->slEnergy = lec_pkt_energy(psData);
    pVad->sEn = lec_en2log(pVad->slEnergy, -1024);
	pVad->sZc = lec_pkt_zc(psData);
    
    lec_vad_logic(pVad);

    return (pVad->sState - sState);
}

/*-------------------------------------------------------------------------*/
static void                     _detect_high_tx
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
    if (pDb->Cfg.uControl & ILEC_CMD_DETECT_HITX_MASK)
    {
//        S16 sTxMax = lec_pkt_peak(pDb->psHst + (LEC_HST_SZ - ILEC_FR_SZ));
        S16 sTxMax = lec_pkt_peak(pSc->psTx);

	    if (sTxMax > pDb->Cfg.sTxMax)
        {
            pDb->sTxMaxCnt = 6;
        }
        else
        {
            pDb->sTxMaxCnt--;
            if (pDb->sTxMaxCnt < 0)
            {
                pDb->sTxMaxCnt = 0;
            }
        }
    }
    else
    {
        pDb->sTxMaxCnt = 0;
    }

    if (pDb->sTxMaxCnt > 0)
        pSc->uFlags |= LEC_FLAG_HITX;
}
/*-------------------------------------------------------------------------*/
static void                     _detect_tone
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
    S16 sState = pDb->VadTx.sState;
    S16 sLastTxEn = lec_en2log(lec_pkt_energy(pSc->psTx), -1024);
    U16 uLow, uHigh, uEven, uEdge, uStateChange;

    _vad_process(&pDb->VadTx, 
                 &pDb->psHst[LEC_HST_SZ-2*ILEC_FR_SZ-10]);

    uLow =  ((sLastTxEn - pDb->asTxEnLog[6]) > _EN_VLOW) &&
	    	    ((sLastTxEn - pDb->asTxEnLog[5]) > _EN_VLOW) &&
		        ((sLastTxEn - pDb->asTxEnLog[4]) > _EN_VLOW);

    uHigh = (pDb->asTxEnLog[1] > _EN_VHIGH-LEC_DB(6)) &&
                (pDb->asTxEnLog[0] > _EN_VHIGH) &&
				(sLastTxEn         > _EN_VHIGH);

    uEven = (abs(sLastTxEn - pDb->asTxEnLog[0]) < LEC_DB(6)) &&
                (abs(sLastTxEn - pDb->asTxEnLog[1]) < LEC_DB(12));

    uEdge = (uLow && uHigh && uEven);

    uStateChange = (pDb->VadTx.sState == LEC_VAD_ST_ACTIVE) &&
                       (sState != LEC_VAD_ST_ACTIVE);

    /* singularity test */
    if (pSc->sJ0Tx < pDb->Cfg.sToneDetectThr)
    {
        if (pSc->asK[2] < Q15(-0.65))
        {
            pSc->uFlags |= LEC_FLAG_SINGULAR;
        }
        else
        {
            if ((pSc->asK[4] < Q15(-0.65)) &&
                (pSc->asK[1] < Q15(0.5)))
            {
                pSc->uFlags |= LEC_FLAG_SINGULAR;
            }
        }
    }

    /* if state change or a sharp edge */
    if (uStateChange || uEdge)
    {
        pDb->uIsTone = (pSc->uFlags & LEC_FLAG_SINGULAR)? TRUE : FALSE;
    }

    /* when to release */
    if (pDb->uIsTone)
    {
        if (pSc->sJ0Tx > pDb->Cfg.sToneReleaseThr)
        {
            pDb->uIsTone = FALSE;
        }

        if (sState != LEC_VAD_ST_ACTIVE)
        {
            pDb->uIsTone = FALSE;
        }
    }
    /* delay energy array */
    {
        S16 i;
        S16 *p1 = &(pDb->asTxEnLog[6]);
        S16 *p2 = p1 - 1;
    	for (i = 6; i > 0; i--)
    	{
            *p1-- = *p2--;
    	}
        *p1 = sLastTxEn;
    }
}
/*-------------------------------------------------------------------------*/
static void                     _analyse_tx
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
	lec_tx_moments(pDb, pSc);

    lec_ts_moments(pDb, pSc);
    lec_normalise_rk(pDb, pSc, -7, (1<<2));
    pSc->sJ0Tx = lec_durbin(pDb, pSc);
#if !defined(_dsp)
    {
        extern void lec_JKS(void);
        lec_JKS();
    }
#endif

    _detect_tone(pDb, pSc);
    _detect_high_tx(pDb, pSc);

    lec_gs_moments(pDb, pSc);
    lec_normalise_rk(pDb, pSc, -4, (1<<4));
    pSc->sJ0 = lec_durbin(pDb, pSc);
#if !defined(_dsp)
    {
        extern void lec_JKW(void);
        lec_JKW();
    }
#endif
	lec_gs_filter(pDb, pSc);
}
/*-------------------------------------------------------------------------*/
void                            _test_erl
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
    U16 uErlOk;

    pSc->sRxEn = lec_en2log(lec_pkt_energy(pSc->psRx),-1024);
    pSc->sErl = pDb->VadTx.sEn - pSc->sRxEn;

    /*  this frame ErlOk tells us if the signal can be an echo.
        if ErlOk is false, then it is definetely not an echo.
        although, it may be DT - we do not know yet.
     */
    if (pDb->Adf1.uConverged)
    {
        pSc->sErlEst = (pDb->Adf1.sErlAveraged + pDb->Adf1.sERL)/2;
        uErlOk = ((pSc->sErl - pSc->sErlEst) > LEC_DB(-6));
    }
    else // not converged yet.
    {
        pSc->sErlEst = pDb->Cfg.sErlMin;
        if (pDb->Adf2.sERL > pSc->sErlEst)
        {
            pSc->sErlEst = (pSc->sErlEst + pDb->Adf2.sERL)/2;
        }
        uErlOk = (pSc->sErl > pSc->sErlEst);
    }
    /*  we do not want to adapt on short spikes. there are very big chances
        that it will bring no good at all, so we delay the start of
        adaptation till we know for sure that it is not a transient process.

        we end adaptation as soon as we see active RX. actually, it is
        usually preceeded by a (possibly, very short) DT period 
        as a transition between TX and RX dominances.
     */
    if (uErlOk)
    {
        pDb->sErlOkCnt++;
        if (pDb->sErlOkCnt > _ERL_OK_CNT)
        {
            pDb->sErlOkCnt = _ERL_OK_CNT;
            pSc->uFlags |= LEC_FLAG_ERL_OK;
        }
    }
    else 
    {
#if 0
        if (pDb->sErlOkCnt == _ERL_OK_CNT)
        {
            // transition to rx, test adf2.
        }
        pDb->sErlOkCnt = 0;
#else
        pDb->sErlOkCnt--;
        if (pDb->sErlOkCnt < 0)
            pDb->sErlOkCnt = 0;
#endif
    }
}

/*-------------------------------------------------------------------------*/
static void                     _estimate_expected_error
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
    S16 sSuppression = pDb->Adf2.sErleAveraged;
    // minus effect of possible misconvergence
    // adf2.slacc is always bigger than adf1.slacc.
    S16 sConvLack = lec_en2log(LEC_SLACC_MAX,0) - // this is a const
                    lec_en2log(pDb->Adf2.slAcc,0);

    // subtraction of entire ConLack is too much...
    sSuppression -= sConvLack/4;
    if (sSuppression < 0)
        sSuppression = 0;

    pSc->sExpectedErrorEn = pSc->sRxEn - sSuppression;
}

/*-------------------------------------------------------------------------*/
void                            _set_update_flt_mode
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
    S32 slEn0;
    S32 slEn1;
    S16 sEn0;
    S16 sEn1;
    S16 k;

    slEn0 = lec_pkt_energy(pDb->psFlt2);

    slEn1 = 0;
    for (k = 0; k < LEC_FRAMES; k++)
    {
        slEn1 += lec_pkt_energy(pDb->psFlt2 + k * ILEC_FR_SZ);
    }
    
    sEn0 = -lec_en2log(slEn0,-1024-350);
    sEn1 = -lec_en2log(slEn1,-1024-350); // this is ERL

    // if MSE is ok, then this sERL is better to use than sErlAveraged
    pSc->sERL = sEn1 + pDb->Adf2.sShift*1024; // <<10;

    pSc->sMSE = sEn1 - sEn0 + LEC_DB(6); // < 0 if OK, and  shall be much < 0

/// ERL stabilization 

    lec_avrg(&pDb->Adf2.sERL,pSc->sERL, Q15(0.1));

    if ((pDb->Adf2.sERL < _ERL_MAX) &&
        (pSc->sERL      < _ERL_MAX) &&
// what if double talk -- then pSc->sErl will be off... ????
        (abs(pSc->sERL - pDb->Adf2.sERL) < _ERL_DIFF))
    {
        pDb->Adf2.sStabCnt++;
        if (pDb->Adf2.sStabCnt > _ERL_STAB_CNT)
        {
            pDb->Adf2.sStabCnt = _ERL_STAB_CNT;
            // we are in ERL stable state
        }
    }
    else /// a change happened
    {
        pDb->Adf2.sStabCnt = 0;
        // we are back to ERL unstable state.
    }

// actions:
    // if ERL is still unstable
    if (pDb->Adf2.sStabCnt < _ERL_STAB_CNT)
    {
        // if erl has not stabilized yet, do not copy in any case
        pSc->uFltCpyMode = 3;
        lec_avrg(&pDb->Adf2.sMSE, pSc->sMSE, Q15(0.25));
        pSc->uMseMode = 0;
    }
    else // erl has stabilized
    {
        pSc->uMseMode = 1; // dbg

        // if not converged yet
        if (pDb->Adf1.sMSE > _MSE_MIN)
        {
            lec_avrg(&pDb->Adf2.sMSE, pSc->sMSE, Q15(0.125));

            // if MSE is somethings more or less real
            if ((pDb->Adf2.sMSE < 0) &&           
                // if flt2 is better than flt 1 in terms of MSE
                (pDb->Adf2.sMSE < pDb->Adf1.sMSE) && 
                // flt 2 is still ok
                (pSc->sMSE < pDb->Adf2.sMSE) && 
                // flt 2 is better than flt 1 in terms of ERLE
                (pDb->sErrOverrideCnt > LEC_DB(10)))
            {
                pSc->uFltCpyMode = 1;
            }
            else // keep adapting
            {
                pSc->uFltCpyMode = 3;
            }
        }
        else // may be converged 
        {
            pSc->uMseMode |= 2;
            if (pDb->uIsDT)
            {
                lec_avrg(&pDb->Adf2.sMSE, pSc->sMSE, Q15(0.25));
                pSc->uFltCpyMode = 3;
                // no copy, keep converging, unless convergence is very good.
                if (pDb->sErrOverrideCnt > LEC_DB(20))
                {
                    S16 sErleDlt = pDb->sErrOverrideCnt;
                    S16 sMseDlt = pDb->Adf2.sMSE - pDb->Adf1.sMSE;
                    sErleDlt = (S16)((Q15(0.40) * (S32)sErleDlt)>>15);

                    if ((sErleDlt - sMseDlt) > 0)
                    {
                        pSc->uFltCpyMode = 1;
                    }
                }
                else if (pDb->sErrOverrideCnt > LEC_DB(10))
                {
                    // flt2 is at least as good as flt1 in terms of MSE
                    if ((pDb->Adf2.sMSE < (pDb->Adf1.sMSE + LEC_DB(0.25))) && 
                    // current flt2 is good
                        (pSc->sMSE < pDb->Adf2.sMSE))
                    {
                        pSc->uFltCpyMode = 1;
                    }
                }
            }
            else // no double talk recognized
            {
                lec_avrg(&pDb->Adf2.sMSE, pSc->sMSE, Q15(0.05));

⌨️ 快捷键说明

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