📄 gaecnlp.c
字号:
/*-------------------------------------------------------------------------*
* *
* THIS IS AN UNPUBLISHED WORK CONTAINING CONFIDENTIAL AND PROPRIETARY *
* INFORMATION. IF PUBLICATION OCCURS, THE FOLLOWING NOTICE APPLIES: *
* "COPYRIGHT 2002 MIKET DSP SOLUTIONS, ALL RIGHTS RESERVED" *
* *
*-------------------------------------------------------------------------*/
#if !defined(_dsp)
#include <memory.h>
#else
#include <string.h>
#endif
#include "gaeci.h"
/*--------------------- local defs ----------------------------------------*/
#define _TCL_MIN (GAEC_DB(10))
#define _MULT (31821)
#define _INC (13849)
/*--------------------- public vars ---------------------------------------*/
/*--------------------- local vars ----------------------------------------*/
/*--------------------- local functions -----------------------------------*/
/*-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
void gaec_nlp_get_coefs
/*-------------------------------------------------------------------------*/
(
GAEC_tDb *pDb,
GAEC_tSc *pSc
)
{
int band;
S16 sAttDist = 0;
// scale att according to asErlCrit
S16 sEpcCrit = pDb->sEpcCrit;
if (sEpcCrit < 0)
sEpcCrit = 0;
if (sEpcCrit > GAEC_CRIT_MRGN)
sEpcCrit = GAEC_CRIT_MRGN;
// sEpcCrit = 0;
// if we suspect that there are distortions on strong RCV signal, then we add attenuation
// it will be added to each and every band
if (pSc->sErleMax < GAEC_ERLE_MAX)
{
// sAttDist = (pDb->sErleAv - pSc->sErle) << 1;
sAttDist = GAEC_ERLE_MAX - pSc->sErleMax;
if (sAttDist < 0)
sAttDist = 0;
}
// if this is not a double talk but rather a echo path change,
// we shall allow to decrease attenuation in either of the bands,
// moreover, the asErleAv is not valid anymore, we shall decrease it as well
for (band = 0; band < GAEC_BANDS+1; band++)
{
S32 ac0;
S16 sCorr;
S16 sAttMin;
// we should suppress echo below noise
// sExpectedErrEn takes into account previous Tx Att
S16 sAtt = pDb->asExpectedErrEn[band] -
(pDb->asVadErrNse[band] - GAEC_DB(3.0));
S16 sTclA = pDb->asErlAv[band] + pDb->asErleAv[band];
U16 uEchoAboveNoise = (sAtt > 0);
if (pDb->uIsDT) // half erle if epc
{
ac0 = pDb->asErleAv[band] * (S32) sEpcCrit;
sTclA -= (S16)(ac0 >> (GAEC_CRIT_SHFT+1));
}
// if att is too high:
// total coupling loss needn't be higher than target TCL;
if (sAtt > (pDb->Cfg.sTCLst + pDb->sVolume - sTclA))
{
sAtt = pDb->Cfg.sTCLst + pDb->sVolume - sTclA;
}
else; // tcl (erl+erle+att) is lower than the target,
// but that's enough to put the echo under noise floor
// the circuit must be unconditionally stable
if (sAtt < (_TCL_MIN + pDb->sVolume - sTclA))
{
sAtt = _TCL_MIN + pDb->sVolume - sTclA;
}
// here we shall increase overall attenuation if needed
sAtt += sAttDist;
// negative att - nonsense
if (sAtt < 0)
{
sAtt = 0;
}
sAttMin = sAtt - (pDb->Cfg.sTCLst - pDb->Cfg.sTCLdt);
ac0 = (sAtt - sAttMin) * (S32) sEpcCrit;
sAttMin += (S16)(ac0 >> GAEC_CRIT_SHFT);
if (sAttMin < 0)
{
sAttMin = 0;
}
// if expected echo below noise floor
if (!uEchoAboveNoise)
{
S16 sDltCrit = pDb->asVadErrCrit[band] -
pDb->asVadRinCrit[band];
if (sDltCrit < -GAEC_CRIT_MRGN)
sDltCrit = -GAEC_CRIT_MRGN;
if (sDltCrit > GAEC_CRIT_MRGN)
sDltCrit = GAEC_CRIT_MRGN;
// sCorr = sAttMin if Rx is Active and Tx is inactive
// sCorr = -sAttMin if Tx is active and Rx is under noise
ac0 = sAttMin * (S32) sDltCrit;
sCorr = (S16)(ac0 >> GAEC_CRIT_SHFT);
pSc->asAttRin[band] = (sAttMin + sCorr) >> 1;
pSc->asAttErr[band] = (sAttMin - sCorr) >> 1;
}
else // residual echo above noise
{
// now let's account for double talk
S16 sDtCrit = pDb->asDtCrit[band];
if (sDtCrit > GAEC_CRIT_MRGN) // sure DT
{
// if DT is very strong, and near-end signal masks echo,
// then we shall pass SND as is, attenuating RCV instead
S16 sErlCrit = pDb->asErlCrit[band];
if (sErlCrit < 0)
sErlCrit = 0;
if (sErlCrit > GAEC_CRIT_MRGN)
sErlCrit = GAEC_CRIT_MRGN;
ac0 = sAttMin * (S32) sErlCrit;
sCorr = (S16)(ac0 >> GAEC_CRIT_SHFT);
pSc->asAttErr[band] = (sAttMin - sCorr)>>1;
pSc->asAttRin[band] = sAttMin - pSc->asAttErr[band];
}
else if (sDtCrit > 0) // may-be DT
{
// we start to insert a bit of att into RCV,
// and decrease the overall att, because dt masks echo
ac0 = (sAtt - sAttMin) * (S32)sDtCrit;
sAtt = sAtt - (S16)(ac0 >> GAEC_CRIT_SHFT);
// sCorr = sAtt * sCrit / THR;
ac0 = sAttMin * (S32)sDtCrit;
sCorr = (S16)(ac0 >> (GAEC_CRIT_SHFT+1));
pSc->asAttRin[band] = sCorr;
pSc->asAttErr[band] = sAtt - sCorr;
}
else // no DT
{
pSc->asAttRin[band] = 0;
pSc->asAttErr[band] = sAtt;
}
}
// att is already smooth, because it is based on Exp error,
// taking into account the tail len,
// and ErlAv/ErleAv
}
}
/*-------------------------------------------------------------------------*/
void gaec_nlp_corect_coefs
/*-------------------------------------------------------------------------*/
(
GAEC_tDb *pDb,
GAEC_tSc *pSc
)
{
int band;
// is Snd is muted, we need to pass Rcv unattenuated
if ((pDb->uControl & IGAEC_CMD_SND_MUTED) ||
(pSc->uNlpMode == GAEC_NLP_MODE_CLEAR))
{
for (band = 0; band < GAEC_BANDS+1; band++)
{
pSc->asAttErr[band] += pSc->asAttRin[band];
pSc->asAttRin[band] = 0;
}
}
// ... or pass as is
if (pDb->uControl & IGAEC_CMD_NLP_OFF)
{
for (band = 0; band < GAEC_BANDS+1; band++)
{
pSc->asAttErr[band] = 0;
pSc->asAttRin[band] = 0;
}
}
for (band = 0; band < GAEC_BANDS+1; band++)
{
pSc->asAttErr[band] = gaec_utl_exp((S16)-pSc->asAttErr[band]);
}
}
/*-------------------------------------------------------------------------*/
void gaec_nlp_stts_update
/*-------------------------------------------------------------------------*/
(
GAEC_tDb *pDb,
GAEC_tSc *pSc
)
{
int band;
S32 ac0 = 0;
S16 sAtt;
for (band = 1; band < 9; band++)
{
ac0 += pSc->asAttRin[band];
}
sAtt = (S16)(ac0 >> 3);
pDb->Stts.sRcvAtt = _by17(sAtt);
ac0 = 0;
for (band = 1; band < 9; band++)
{
ac0 += pSc->asAttErr[band];
}
sAtt = (S16)(ac0 >> 3);
pDb->Stts.sSndAtt = _by17(sAtt);
}
/*--------------------- public functions ---------------------------------*/
/*-------------------------------------------------------------------------*/
void gaec_nlp
/*-------------------------------------------------------------------------*/
(
GAEC_tDb *pDb,
GAEC_tSc *pSc
)
{
gaec_nlp_get_coefs(pDb, pSc);
gaec_nlp_corect_coefs(pDb, pSc);
gaec_nlp_stts_update(pDb, pSc);
switch(pSc->uNlpMode)
{
case GAEC_NLP_MODE_CLEAR:
memclr(&pSc->aasErr0[0][0], GAEC_BANDS*2*GAEC_ERR_SZ);
gaec_nlp_mix_noise(pDb, pSc, FALSE);
break;
case GAEC_NLP_MODE_MODIFY:
gaec_nlp_att_rx(pDb, pSc);
gaec_nlp_mix_noise(pDb, pSc, TRUE);
break;
case GAEC_NLP_MODE_PASS:
memcpy(&pSc->aasErr0[0][0],
&pDb->aasErrSav[0][0],
GAEC_BANDS*2*GAEC_ERR_SZ);
break;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -