📄 lecns.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 _DT_CRITERIA_MAX (30)
#define _NLP_PASS (1)
#define _NLP_CLIP (2)
#define _NLP_CLEAR (3)
#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, ".lece")
#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]);
}
/*--------------------- public functions ---------------------------------*/
/*-------------------------------------------------------------------------*/
void lec_dt_start
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
// return;
/* we start from assuming that this may be an echo path change.
data base reset to:
S32 slAcc; - not modified. we need to keep it continuous.
S16 sERL; - as is;
S16 sMSE; - as is.
MSE will be fast averaging during this period, so we keep
current value.
S16 sShift; - stays the same.
S16 sStabCnt = 0;
we also reset StabCnt, to re-init fast convergence tracking.
S16 sErlAveraged; - as is
S16 sErleAveraged; take a current Erle, and drop it by ....
it affects EstimatedErrorEn settings.
U16 uConverged = 0;
we set uConverged back to 0, to ensure fast adaptation.
*/
pDb->Adf2.sErleAveraged = pSc->sErle;
pDb->Adf2.sStabCnt = 0;
pDb->Adf2.uConverged = 0;
if (pDb->Adf2.sShift != 0)
{
S16 k;
S16 rnd = (1<<(pDb->Adf2.sShift-1));
for (k = 0; k < LEC_FLT2_SZ; k++)
{
pDb->psFlt2[k] = (pDb->psFlt2[k] + rnd) >> pDb->Adf2.sShift;
}
pDb->Adf2.sShift = 0;
}
// +: initialize erle test for echo path change
pDb->sErrOverrideCnt = 0;
}
/*-------------------------------------------------------------------------*/
void lec_dt_end
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
// return;
/* we think that it was a echo path change
if mse2 is good and erle gain is good.
sometimes, mse2 is very good,
but erle gain did not have enough time to climb high.
if DT was short, we do not have enough information to
decide on echo path change, so we'd better
to return to previous adf1.
*/
S16 sErleDlt = pDb->sErrOverrideCnt;
pSc->uFltCpyMode = 2;
if (sErleDlt > LEC_DB(7.5))
{
S16 sMseDlt = pDb->Adf2.sMSE - pDb->Adf1.sMSE;
sErleDlt = (S16)((sErleDlt * (S32)Q15(0.40))>>15);
if ((sErleDlt - sMseDlt) > 0)
{
pSc->uFltCpyMode = 1;
}
}
}
/*-------------------------------------------------------------------------*/
void lec_double_talk_detector
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
U16 uIsDT = pDb->uIsDT;
S16 sDtCriteria;
S16 sExpectedEchoEn;
S16 sClipLevel;
S16 sSuppression = pDb->Adf1.sErleAveraged;
// minus effect of possible misconvergence
// adf2.slacc is always bigger than adf.slacc.
S16 sConvLack = lec_en2log(LEC_SLACC_MAX,0) - // this is a const
lec_en2log(pDb->Adf1.slAcc,0);
// subtraction of entire ConLack is too much...
sSuppression -= sConvLack/2;
if (sSuppression < 0)
sSuppression = 0;
sExpectedEchoEn = pSc->sRxEn - sSuppression;
/* sometimes at the end of the word, vocal tract starts to vibrate
at the basic frequency, and this is a wave form not observed
before, and it is weak, and preceeded by a strong signal,
so it is hard to adapt.
that's why we slowly decay sExpectedEchoEn,
but keep the rising edge fast.
*/
if (pDb->sClipLevel < sExpectedEchoEn)
{
pDb->sClipLevel = sExpectedEchoEn;
}
else
{
lec_avrg(&pDb->sClipLevel, sExpectedEchoEn, Q15(0.2));
}
sClipLevel = pDb->sClipLevel;
/* Noise floor estimations are never fully reliable,
because it fluctates and we can not track it ideally.
we need to provide some degree of robustness, otherwise
dt detector will give too many false alarms.
*/
if (sClipLevel < pDb->VadErr.sEnNoise - LEC_DB(6))
{
sClipLevel = pDb->VadErr.sEnNoise;
}
/* if between -6 and +6, then: interpolate */
else if (sClipLevel < pDb->VadErr.sEnNoise + LEC_DB(6))
{
S16 sDlt = sClipLevel - (pDb->VadErr.sEnNoise - LEC_DB(6));
sClipLevel = pDb->VadErr.sEnNoise + sDlt/2;
}
else; // unmodified
pSc->sClipThreshold = lec_exp (sClipLevel + pDb->Cfg.sClipThr);
/* the criteria (current frame) is composed from erle loss
and the number of samples exceeding clipping threshold.
if any goes wrong, we have to suspect dt.
*/
sDtCriteria = pDb->VadErr.sEn - (sClipLevel + pDb->Cfg.sClipThr/4);
if (sDtCriteria < 0)
sDtCriteria = 0;
sDtCriteria >>= 7;
sDtCriteria += lec_pkt_excess(&pSc->asErr1[0], pSc->sClipThreshold);
sDtCriteria -= 5;
/* at least 3 frames for DT declaration */
if (sDtCriteria > _DT_CRITERIA_MAX/10)
sDtCriteria = _DT_CRITERIA_MAX/10;
pSc->uNlpMode = _NLP_PASS;
/* if current frame is not a pure RX */
if (pDb->sErlOkCnt > 0)
{
if (pDb->uIsTone)
{
// sDtCriteria = 0;
if (pDb->Cfg.uControl & ILEC_CMD_TONE_ECHO_MASK)
{
// leave tone echo...
pSc->uNlpMode = _NLP_PASS;
}
else
{
// remove tone echo
// pDb->sDtCriteria = 0;
// pDb->uIsDT = FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -