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

📄 lecmse.cpp

📁 The line echo canceller (LEC) is designed to provide the maximum attainable transparent voice qualit
💻 CPP
字号:
/*-------------------------------------------------------------------------*
 *                                                                         *
 *   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 _ERL_MAX                LEC_DB(25)
#define _ERL_DIFF               LEC_DB(0.5)

#define _MSE_MIN                LEC_DB(-8)



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

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

#if defined (_dsp)
#endif

/*--------------------- local functions -----------------------------------*/


/*-------------------------------------------------------------------------*/
static void                     _get_mse_erl
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
    S16 *psAdf = pDb->asAdf2;
    S32 slEn0;
    S32 slEn1;
    S16 sEn0;
    S16 sEn1;
    S16 k;

    slEn0 = lec_pkt_energy(psAdf);

    slEn1 = 0;
    for (k = 0; k < LEC_FRAMES; k++)
    {
        psAdf += ILEC_FR_SZ;
        slEn1 += lec_pkt_energy(psAdf);
    }
    
    sEn0 = -lec_en2log(slEn0)+350;
    sEn1 = -lec_en2log(slEn1)+350; // this is ERL

    // if MSE is ok, then this sERL is better to use than sErlAveraged
    // 1024 = 6Db per 1 shift
    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 
    // if some degree of convergence achieved, 
    // i.e. the filter is different from pure 0
    // then do averaging, otherwise - it's too early
    if (pSc->sERL < _ERL_MAX)
    {
        lec_avrg(&pDb->Adf2.sERL,pSc->sERL, Q15(0.03));
    }
}
/*-------------------------------------------------------------------------*/
static void                 _set_update_flt_mode_not_converged
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
    if (
        // flt 2 is better than flt 1 in terms of ERLE
        (pDb->sErrOverrideCnt > LEC_DB(10)) &&
        // if MSE is somethings more or less real
        (pDb->Adf2.sMSE < 0) &&           
        // if flt2 is better than flt 1 in terms of MSE
        (pDb->Adf2.sMSE < pDb->Adf1.sMSE) && 
        // flt 2 is improving
        (pDb->Adf2.sMSE > pSc->sMSE) 
        )
    {
        pSc->uFltCpyMode = 1;
    }
    else // keep adapting
    {
        pSc->uFltCpyMode = 3;
    }
}
/*-------------------------------------------------------------------------*/
static void                 _set_update_flt_mode_converged_dt
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
    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.80) * (S32)sErleDlt)>>16);

        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
            (pDb->Adf2.sMSE > pSc->sMSE))
        {
            pSc->uFltCpyMode = 1;
        }
    }
}
/*-------------------------------------------------------------------------*/
static void                     _set_update_flt_mode_converged
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
    // flt 2 is much better than flt 1 in terms of ERLE
    if (pDb->sErrOverrideCnt > LEC_DB(10))
    {
        pSc->uFltCpyMode = 1;
    }
    // flt 2 is somehow better than flt 1 in terms of ERLE
    else if ((pDb->sErrOverrideCnt > LEC_DB(5)) &&
             // even if MSE1 and MSE 2 are about the same
             (pDb->Adf2.sMSE < (pDb->Adf1.sMSE + LEC_DB(0.5))) && 
             // current MSE is alright
             (pDb->Adf2.sMSE > pSc->sMSE))
    {
        pSc->uFltCpyMode = 1;
    }
    // flt 2 is better than flt 1 in terms of ERLE,
    // continuous update
    else if ((pDb->sErrOverrideCnt > LEC_DB(0.5)) &&
             // and MSE
             (pDb->Adf2.sMSE < pDb->Adf1.sMSE) && 
             // and current MSE is alright
             (pDb->Adf2.sMSE > pSc->sMSE))
    {
        pSc->uFltCpyMode = 1;
    }
    else // no visible improvements
    {
        // keep adapting
        if (pSc->sMSE < (pDb->Adf1.sMSE + LEC_DB(5)))
        {
            pSc->uFltCpyMode = 3;
        }
        else // or reset back to 1: screwed up...
        {
            pSc->uFltCpyMode = 2;
        }
    }
}
/*-------------------------------------------------------------------------*/
static void                 _set_update_flt_mode
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
    S16 sMseCoef = 0;
    _get_mse_erl(pDb, pSc);

    // actions:
    // if ERL is still unstable
    if (abs(pSc->sERL - pDb->Adf2.sERL) > _ERL_DIFF)
    {
        // if erl has not stabilized yet, do not copy in any case
        pSc->uFltCpyMode = 3;
        sMseCoef = Q15(0.25);
    }
    else // erl has stabilized
    {
        // if not converged yet
        if (pDb->Adf1.sMSE > _MSE_MIN)
        {
            sMseCoef = Q15(0.125);
            _set_update_flt_mode_not_converged(pDb, pSc);
        }
        else // may be converged 
        {
            if (pDb->uIsDT)
            {
                sMseCoef = Q15(0.25);
                _set_update_flt_mode_converged_dt(pDb, pSc);
            }
            else // no double talk recognized
            {
                sMseCoef = Q15(0.05);
                _set_update_flt_mode_converged(pDb, pSc);
            } /* if : DT */
        } /* if : converged */
    } /* if: ERL stabilized */
    lec_avrg(&pDb->Adf2.sMSE, pSc->sMSE, sMseCoef);
}

/*-------------------- public functions -----------------------------------*/

/*-------------------------------------------------------------------------*/
void                        lec_convergence_control
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
    pSc->sErle = pSc->sRxEn - pDb->VadErr.sEn;
    if ((pSc->sErle > 0) && (!pDb->uIsDT))
    {
        S32 sl = pSc->sErle * (S32) (pSc->sJ0 - 5500);//4096);
        sl >>= (15+2);
        if (sl < 0) sl = 0;
        pDb->Adf2.slAcc +=  sl;

        if (pDb->Adf2.slAcc >= LEC_SLACC_MAX)
        {
            pDb->Adf2.slAcc = LEC_SLACC_MAX;
            if (pDb->Adf2.uConverged == 1) 
            {
                lec_shift_adf2(pDb, pSc);
            }
            pDb->Adf2.uConverged = 2;
        }
        else if (pDb->Adf2.slAcc > LEC_SLACC_MAX/2)
        {
            pDb->Adf2.uConverged = 1;
        }
        else
        {
            pDb->Adf2.uConverged = 0;
        }
    }
}
/*-------------------------------------------------------------------------*/
void                        lec_compare_adfs
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
    // if any adaptation happened
    if (pSc->uAdaptMode & 0x000c )
    {
        pSc->sErr2En = lec_en2log(lec_pkt_energy(pSc->asErr2));

        pDb->sErrOverrideCnt += (pSc->sErr1En - pSc->sErr2En)>>5;

        if (pSc->sErr2En < pSc->sErr1En)
        {
            pSc->uFlags |= LEC_FLAG_ERROVERIDE;
            /* prevent wrap-around */
            if (pDb->sErrOverrideCnt > LEC_DB(70))
                pDb->sErrOverrideCnt = LEC_DB(70);
            /* if DT, do not make actual copy...
               flt2 can get pretty crazy, doing all kinds of crazy stuff
               we collect ErrOverrideCnt and that's it. 
             */
            if (!pDb->uIsDT)
                lec_pkts_cpy(pSc->asErr1, pSc->asErr2, 1);

        }
        else  /* use error from cancellation */
        {
            /* limit from below, by a small negative value,
               to prevent spurious triggering of 2-1 copy.
             */
            if (pDb->sErrOverrideCnt < LEC_DB(-6))
                pDb->sErrOverrideCnt = LEC_DB(-6);
        }

        _set_update_flt_mode(pDb, pSc);
    }
    else ; // adaptation was off
}
/*-------------------------------------------------------------------------*/
void                        lec_update_flt
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
    switch(pSc->uFltCpyMode)
    {
    case 1: // flt1 (main filter) update
        pDb->Adf1 = pDb->Adf2;
        pDb->sErrOverrideCnt = 0;
	    lec_pkts_cpy(
            pDb->asAdf1, 
            pDb->asAdf2, 
            LEC_FLT2_SZ/ILEC_FR_SZ
            );

        break;
    case 2: // flt2 override - it got corrupted 
        pDb->Adf2 = pDb->Adf1;
        // enforce re-test that ERL is OK, and insert a waiting period.
        pDb->Adf2.sERL = 0;
        pDb->sErrOverrideCnt = 0;
	    lec_pkts_cpy(
            pDb->asAdf2, 
            pDb->asAdf1, 
            LEC_FLT2_SZ/ILEC_FR_SZ
            );
        break;
    case 3:
    default:
        // do not copy, but continue to adapt
        break;
    }
}

⌨️ 快捷键说明

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