📄 lecdtd.cpp
字号:
/*-------------------------------------------------------------------------*
* *
* 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 _DT_CRITERIA_MAX (30)
/*--------------------- public vars ---------------------------------------*/
/*--------------------- local vars ----------------------------------------*/
/*--------------------- local functions -----------------------------------*/
/*-------------------------------------------------------------------------*/
static void _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.uConverged = 0;
// +: initialize erle test for echo path change
pDb->sErrOverrideCnt = 0;
if (pDb->Adf2.sShift != 0)
{
lec_rshift_adf(pDb->asAdf2, pDb->Adf2.sShift);
pDb->Adf2.sShift = 0;
pDb->Adf2.sNegShift = 0;
}
}
/*-------------------------------------------------------------------------*/
static void _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;
}
}
}
/*-------------------------------------------------------------------------*/
static S16 _dtd_expected_echo_en
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
// minus effect of possible misconvergence
// adf2.slacc is always bigger than adf.slacc.
S16 sConvLack = lec_en2log(LEC_SLACC_MAX) - // this is a const
lec_en2log(pDb->Adf1.slAcc);
S16 sSuppression = pDb->Adf1.sErleAveraged;
// subtraction of entire ConLack is too much...
sSuppression -= sConvLack/2;
if (sSuppression < 0)
sSuppression = 0;
return (pSc->sRxEn - sSuppression);
}
/*-------------------------------------------------------------------------*/
static S16 _dtd_clip_level
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc,
S16 sExpectedEchoEn
)
{
S16 sClipLevel;
S16 sDlt;
/* 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.
*/
sDlt = sClipLevel - pDb->VadErr.sEnNoise;
if (sDlt < LEC_DB(6))
{
sClipLevel -= sDlt/2 - LEC_DB(3);
}
if (sDlt < LEC_DB(-6))
{
sClipLevel -= sDlt/2 + LEC_DB(3);
}
pSc->sClipThreshold = lec_exp (sClipLevel + pDb->Cfg.sClipThr);
return sClipLevel;
}
/*-------------------------------------------------------------------------*/
static S16 _dtd_criteria
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc,
S16 sClipLevel
)
{
/* 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.
*/
S16 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;
return sDtCriteria;
}
/*-------------------------------------------------------------------------*/
static void _dtd_set_nlp_mode
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc,
S16 sDtCriteria
)
{
S16 sErl = pDb->Adf1.sERL - LEC_DB(8);
if (sErl < 0)
sErl = 0;
pSc->uNlpMode = LEC_NLP_PASS;
/* if current frame is not a pure RX */
// if (pDb->sErlOkCnt > 0)
if (pSc->sErl > sErl)
{
if (pDb->uTone > 0)
{
if (pDb->Cfg.uControl & ILEC_CMD_TONE_ECHO)
{
// leave tone echo...
pSc->uNlpMode = LEC_NLP_PASS;
}
else
{
// remove tone echo
pSc->uNlpMode = LEC_NLP_CLEAR;
}
}
else if (pSc->uFlags & LEC_FLAG_HIRCV)
{
if (pDb->Cfg.uControl & ILEC_CMD_CLR_HIRCV_DT)
{
pSc->uNlpMode = LEC_NLP_CLEAR;
}
else
{
if (! pDb->uIsDT)
{
pSc->uNlpMode = LEC_NLP_CLEAR;
}
else
{
pSc->uNlpMode = LEC_NLP_CLIP;
}
}
}
else
{
pDb->sDtCriteria += sDtCriteria;
if (pDb->sDtCriteria > ((2*_DT_CRITERIA_MAX)/3))
{
pDb->uIsDT = TRUE;
pSc->uNlpMode = LEC_NLP_PASS;
/* limit from above */
/* hangover after DT is 120ms (20 frames) */
if (pDb->sDtCriteria > _DT_CRITERIA_MAX)
{
pDb->sDtCriteria = _DT_CRITERIA_MAX;
}
}
else /* DtCrit < MAX/2 */
{
if (pDb->sDtCriteria <= 0)
{
pDb->sDtCriteria = 0;
pDb->uIsDT = FALSE;
}
pSc->uNlpMode = LEC_NLP_CLIP;
/* whether Dt or not, we calculate average values for erl and Erle
if dt, they will be discarged in the process of 1-2 flt copy.
if it is echo path change, that's a good start.
*/
if ((pSc->sRxEn - pDb->Adf2.sErleAveraged) > pDb->VadErr.sEnNoise)
{
lec_avrg(&pDb->Adf2.sErleAveraged, pSc->sErle, Q15(0.03));
}
}
}
}
else // rx is not an echo
{
/* if this is a short rx, do not change dt status */
pDb->sDtCriteria -= 1;
if (pDb->sDtCriteria <= 0)
{
pDb->sDtCriteria = 0;
pDb->uIsDT = FALSE;
}
pSc->uNlpMode = LEC_NLP_PASS;
}
if (pDb->Cfg.uControl & ILEC_CMD_NLP_OFF)
{
// pass as is
pSc->uNlpMode = LEC_NLP_PASS;
}
}
/*--------------------- public functions ---------------------------------*/
/*-------------------------------------------------------------------------*/
void lec_double_talk_detector
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
U16 uIsDT = pDb->uIsDT;
S16 sExpectedEchoEn = _dtd_expected_echo_en(pDb, pSc);
S16 sClipLevel = _dtd_clip_level(pDb, pSc, sExpectedEchoEn);
S16 sDtCriteria = _dtd_criteria(pDb, pSc, sClipLevel);
_dtd_set_nlp_mode(pDb, pSc, sDtCriteria);
if (uIsDT != pDb->uIsDT)
{
if (pDb->uIsDT)
{
_dt_start(pDb, pSc);
}
else
{
_dt_end(pDb, pSc);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -