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

📄 lectx.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 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 ----------------------------------------*/


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

/* tone state machine defs */
#define _TONE_OFF               (0)
#define _TONE_ON                (1)
#define _TONE_HANGOVER          (2)
#define _TONE_CNT               (6) /* 30 ms tone echo */

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


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

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

#if defined (_dsp)
#endif

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

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

        if (pDb->sTxMaxCnt > 0)
            pSc->uFlags |= LEC_FLAG_HIRCV;
    }
    else
    {
        pDb->sTxMaxCnt = 0;
    }
}
/*-------------------------------------------------------------------------*/
static void                 _detect_tone
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
    S32 slEn = lec_pkt_energy(pSc->psTx);
    S16 sLastTxEn = lec_en2log(slEn);

    U16 uLow =  ((sLastTxEn - pDb->asTxEn[6]) > _EN_THR) &&
	    	    ((sLastTxEn - pDb->asTxEn[5]) > _EN_THR) &&
		        ((sLastTxEn - pDb->asTxEn[4]) > _EN_THR);

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

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

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

    /* 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;
            }
        }
    }

    switch (pDb->uTone)
    {
    case _TONE_OFF:
        {
            if (uEdge && (pSc->uFlags & LEC_FLAG_SINGULAR))
            {
                pDb->uTone = _TONE_ON;
            }
            break;
        }
    case _TONE_ON:
        {
            // if tone ended...
            // if there are phase reversals ??? TBD
            if ((pSc->sJ0Tx > pDb->Cfg.sToneReleaseThr) ||
                (sLastTxEn < _EN_VLOW))
            {
                pDb->uTone = _TONE_HANGOVER;
                pDb->sToneCnt = _TONE_CNT;
            }
            break;
        }
    case _TONE_HANGOVER:
        {
            if ((pSc->sJ0Tx > pDb->Cfg.sToneReleaseThr) ||
                (sLastTxEn < _EN_VLOW))
            {
                pDb->sToneCnt--;
            }
            else
            {
                pDb->sToneCnt++;
            }

            if (pDb->sToneCnt >= _TONE_CNT)
            {
                pDb->uTone = _TONE_ON;
            }
            else if (pDb->sToneCnt <= 0)
            {
                pDb->uTone = _TONE_OFF;
                pDb->sToneCnt = 0;
            }
            else; // intermediate values
        }
    }
    /* if state change or a sharp edge */

    /* delay energy array */
    {
        S16 i;
        S16 *p1 = &(pDb->asTxEn[6]);
        S16 *p2 = p1 - 1;
    	for (i = 0; i < 6; i++)
    	{
            *p1-- = *p2--;
    	}
        *p1 = sLastTxEn;
    }
    pSc->sTxEn = sLastTxEn;
}
/*-------------------------------------------------------------------------*/
void                        lec_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);
}

⌨️ 快捷键说明

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