524 lines
15 KiB
C
524 lines
15 KiB
C
/*
|
|
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
/*
|
|
* This file contains some DSP initialization functions and
|
|
* constant table definitions.
|
|
*/
|
|
|
|
#include "dsp.h"
|
|
|
|
#include "signal_processing_library.h"
|
|
|
|
#include "neteq_error_codes.h"
|
|
|
|
/* Filter coefficients used when downsampling from the indicated
|
|
sample rates (8, 16, 32, 48 kHz) to 4 kHz.
|
|
Coefficients are in Q12. */
|
|
|
|
/* {0.3, 0.4, 0.3} */
|
|
const WebRtc_Word16 WebRtcNetEQ_kDownsample8kHzTbl[] = { 1229, 1638, 1229 };
|
|
|
|
#ifdef NETEQ_WIDEBAND
|
|
/* {0.15, 0.2, 0.3, 0.2, 0.15} */
|
|
const WebRtc_Word16 WebRtcNetEQ_kDownsample16kHzTbl[] =
|
|
{ 614, 819, 1229, 819, 614};
|
|
#endif
|
|
|
|
#ifdef NETEQ_32KHZ_WIDEBAND
|
|
/* {0.1425, 0.1251, 0.1525, 0.1628, 0.1525, 0.1251, 0.1425} */
|
|
const WebRtc_Word16 WebRtcNetEQ_kDownsample32kHzTbl[] =
|
|
{ 584, 512, 625, 667, 625, 512, 584};
|
|
#endif
|
|
|
|
#ifdef NETEQ_48KHZ_WIDEBAND
|
|
/* {0.2487, 0.0952, 0.1042, 0.1074, 0.1042, 0.0952, 0.2487} */
|
|
const WebRtc_Word16 WebRtcNetEQ_kDownsample48kHzTbl[] =
|
|
{ 1019, 390, 427, 440, 427, 390, 1019};
|
|
#endif
|
|
|
|
/* Constants used in expand function WebRtcNetEQ_Expand */
|
|
|
|
/* Q12: -1.264421 + 4.8659148*x - 4.0092827*x^2 + 1.4100529*x^3 */
|
|
const WebRtc_Word16 WebRtcNetEQ_kMixFractionFuncTbl[4] = { -5179, 19931, -16422, 5776 };
|
|
|
|
/* Tabulated divisions to save complexity */
|
|
/* 1049/{0, .., 6} */
|
|
const WebRtc_Word16 WebRtcNetEQ_k1049div[7] = { 0, 1049, 524, 349, 262, 209, 174 };
|
|
|
|
/* 2097/{0, .., 6} */
|
|
const WebRtc_Word16 WebRtcNetEQ_k2097div[7] = { 0, 2097, 1048, 699, 524, 419, 349 };
|
|
|
|
/* 5243/{0, .., 6} */
|
|
const WebRtc_Word16 WebRtcNetEQ_k5243div[7] = { 0, 5243, 2621, 1747, 1310, 1048, 873 };
|
|
|
|
#ifdef WEBRTC_NETEQ_40BITACC_TEST
|
|
/*
|
|
* Run NetEQ with simulated 40-bit accumulator to run bit-exact to a DSP
|
|
* implementation where the main (spl and NetEQ) functions have been
|
|
* 40-bit optimized. For testing purposes.
|
|
*/
|
|
|
|
/****************************************************************************
|
|
* WebRtcNetEQ_40BitAccCrossCorr(...)
|
|
*
|
|
* Calculates the Cross correlation between two sequences seq1 and seq2. Seq1
|
|
* is fixed and seq2 slides as the pointer is increased with step
|
|
*
|
|
* Input:
|
|
* - seq1 : First sequence (fixed throughout the correlation)
|
|
* - seq2 : Second sequence (slided step_seq2 for each
|
|
* new correlation)
|
|
* - dimSeq : Number of samples to use in the cross correlation.
|
|
* Should be no larger than 1024 to avoid overflow.
|
|
* - dimCrossCorr : Number of CrossCorrelations to calculate (start
|
|
* position for seq2 is updated for each new one)
|
|
* - rShift : Number of right shifts to use
|
|
* - step_seq2 : How many (positive or negative) steps the seq2
|
|
* pointer should be updated for each new cross
|
|
* correlation value
|
|
*
|
|
* Output:
|
|
* - crossCorr : The cross correlation in Q-rShift
|
|
*/
|
|
|
|
void WebRtcNetEQ_40BitAccCrossCorr(WebRtc_Word32 *crossCorr,
|
|
WebRtc_Word16 *seq1,
|
|
WebRtc_Word16 *seq2,
|
|
WebRtc_Word16 dimSeq,
|
|
WebRtc_Word16 dimCrossCorr,
|
|
WebRtc_Word16 rShift,
|
|
WebRtc_Word16 step_seq2)
|
|
{
|
|
int i, j;
|
|
WebRtc_Word16 *seq1Ptr, *seq2Ptr;
|
|
WebRtc_Word64 acc;
|
|
|
|
for (i = 0; i < dimCrossCorr; i++)
|
|
{
|
|
/* Set the pointer to the static vector, set the pointer to
|
|
the sliding vector and initialize crossCorr */
|
|
seq1Ptr = seq1;
|
|
seq2Ptr = seq2 + (step_seq2 * i);
|
|
acc = 0;
|
|
|
|
/* Perform the cross correlation */
|
|
for (j = 0; j < dimSeq; j++)
|
|
{
|
|
acc += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr));
|
|
seq1Ptr++;
|
|
seq2Ptr++;
|
|
}
|
|
|
|
(*crossCorr) = (WebRtc_Word32) (acc >> rShift);
|
|
crossCorr++;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* WebRtcNetEQ_40BitAccDotW16W16(...)
|
|
*
|
|
* Calculates the dot product between two vectors (WebRtc_Word16)
|
|
*
|
|
* Input:
|
|
* - vector1 : Vector 1
|
|
* - vector2 : Vector 2
|
|
* - len : Number of samples in vector
|
|
* Should be no larger than 1024 to avoid overflow.
|
|
* - scaling : The number of left shifts required to avoid overflow
|
|
* in the dot product
|
|
* Return value : The dot product
|
|
*/
|
|
|
|
WebRtc_Word32 WebRtcNetEQ_40BitAccDotW16W16(WebRtc_Word16 *vector1,
|
|
WebRtc_Word16 *vector2,
|
|
int len,
|
|
int scaling)
|
|
{
|
|
WebRtc_Word32 sum;
|
|
int i;
|
|
WebRtc_Word64 acc;
|
|
|
|
acc = 0;
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
acc += WEBRTC_SPL_MUL_16_16(*vector1++, *vector2++);
|
|
}
|
|
|
|
sum = (WebRtc_Word32) (acc >> scaling);
|
|
|
|
return(sum);
|
|
}
|
|
|
|
#endif /* WEBRTC_NETEQ_40BITACC_TEST */
|
|
|
|
/****************************************************************************
|
|
* WebRtcNetEQ_DSPInit(...)
|
|
*
|
|
* Initializes DSP side of NetEQ.
|
|
*
|
|
* Input:
|
|
* - inst : NetEq DSP instance
|
|
* - fs : Initial sample rate (may change when decoding data)
|
|
*
|
|
* Output:
|
|
* - inst : Updated instance
|
|
*
|
|
* Return value : 0 - ok
|
|
* : non-zero - error
|
|
*/
|
|
|
|
int WebRtcNetEQ_DSPInit(DSPInst_t *inst, WebRtc_UWord16 fs)
|
|
{
|
|
|
|
int res = 0;
|
|
WebRtc_Word16 fs_mult;
|
|
|
|
/* Pointers and values to save before clearing the instance */
|
|
#ifdef NETEQ_CNG_CODEC
|
|
void *savedPtr1 = inst->CNG_Codec_inst;
|
|
#endif
|
|
void *savedPtr2 = inst->pw16_readAddress;
|
|
void *savedPtr3 = inst->pw16_writeAddress;
|
|
void *savedPtr4 = inst->main_inst;
|
|
#ifdef NETEQ_VAD
|
|
void *savedVADptr = inst->VADInst.VADState;
|
|
VADInitFunction savedVADinit = inst->VADInst.initFunction;
|
|
VADSetmodeFunction savedVADsetmode = inst->VADInst.setmodeFunction;
|
|
VADFunction savedVADfunc = inst->VADInst.VADFunction;
|
|
WebRtc_Word16 savedVADEnabled = inst->VADInst.VADEnabled;
|
|
WebRtc_Word16 savedVADMode = inst->VADInst.VADMode;
|
|
#endif /* NETEQ_VAD */
|
|
DSPStats_t saveStats;
|
|
WebRtc_Word16 saveMsPerCall = inst->millisecondsPerCall;
|
|
enum BGNMode saveBgnMode = inst->BGNInst.bgnMode;
|
|
#ifdef NETEQ_STEREO
|
|
MasterSlaveInfo saveMSinfo;
|
|
#endif
|
|
|
|
/* copy contents of statInst to avoid clearing */WEBRTC_SPL_MEMCPY_W16(&saveStats, &(inst->statInst),
|
|
sizeof(DSPStats_t)/sizeof(WebRtc_Word16));
|
|
|
|
#ifdef NETEQ_STEREO
|
|
/* copy contents of msInfo to avoid clearing */WEBRTC_SPL_MEMCPY_W16(&saveMSinfo, &(inst->msInfo),
|
|
sizeof(MasterSlaveInfo)/sizeof(WebRtc_Word16));
|
|
#endif
|
|
|
|
/* check that the sample rate is valid */
|
|
if ((fs != 8000)
|
|
#ifdef NETEQ_WIDEBAND
|
|
&&(fs!=16000)
|
|
#endif
|
|
#ifdef NETEQ_32KHZ_WIDEBAND
|
|
&&(fs!=32000)
|
|
#endif
|
|
#ifdef NETEQ_48KHZ_WIDEBAND
|
|
&&(fs!=48000)
|
|
#endif
|
|
)
|
|
{
|
|
/* invalid rate */
|
|
return (CODEC_DB_UNSUPPORTED_FS);
|
|
}
|
|
|
|
/* calcualte fs/8000 */
|
|
fs_mult = WebRtcSpl_DivW32W16ResW16(fs, 8000);
|
|
|
|
/* Set everything to zero since most variables should be zero at start */
|
|
WebRtcSpl_MemSetW16((WebRtc_Word16 *) inst, 0, sizeof(DSPInst_t) / sizeof(WebRtc_Word16));
|
|
|
|
/* Restore saved pointers */
|
|
#ifdef NETEQ_CNG_CODEC
|
|
inst->CNG_Codec_inst = (CNG_dec_inst *)savedPtr1;
|
|
#endif
|
|
inst->pw16_readAddress = (WebRtc_Word16 *) savedPtr2;
|
|
inst->pw16_writeAddress = (WebRtc_Word16 *) savedPtr3;
|
|
inst->main_inst = savedPtr4;
|
|
#ifdef NETEQ_VAD
|
|
inst->VADInst.VADState = savedVADptr;
|
|
inst->VADInst.initFunction = savedVADinit;
|
|
inst->VADInst.setmodeFunction = savedVADsetmode;
|
|
inst->VADInst.VADFunction = savedVADfunc;
|
|
inst->VADInst.VADEnabled = savedVADEnabled;
|
|
inst->VADInst.VADMode = savedVADMode;
|
|
#endif /* NETEQ_VAD */
|
|
|
|
/* Initialize main part */
|
|
inst->fs = fs;
|
|
inst->millisecondsPerCall = saveMsPerCall;
|
|
inst->timestampsPerCall = inst->millisecondsPerCall * 8 * fs_mult;
|
|
inst->ExpandInst.w16_overlap = 5 * fs_mult;
|
|
inst->endPosition = 565 * fs_mult;
|
|
inst->curPosition = inst->endPosition - inst->ExpandInst.w16_overlap;
|
|
inst->w16_seedInc = 1;
|
|
inst->uw16_seed = 777;
|
|
inst->w16_muteFactor = 16384; /* 1.0 in Q14 */
|
|
inst->w16_frameLen = 3 * inst->timestampsPerCall; /* Dummy initialize to 30ms */
|
|
|
|
inst->w16_speechHistoryLen = 256 * fs_mult;
|
|
inst->pw16_speechHistory = &inst->speechBuffer[inst->endPosition
|
|
- inst->w16_speechHistoryLen];
|
|
inst->ExpandInst.pw16_overlapVec = &(inst->pw16_speechHistory[inst->w16_speechHistoryLen
|
|
- inst->ExpandInst.w16_overlap]);
|
|
|
|
/* Reusage of memory in speechBuffer inside Expand */
|
|
inst->ExpandInst.pw16_expVecs[0] = &inst->speechBuffer[0];
|
|
inst->ExpandInst.pw16_expVecs[1] = &inst->speechBuffer[126 * fs_mult];
|
|
inst->ExpandInst.pw16_arState = &inst->speechBuffer[2 * 126 * fs_mult];
|
|
inst->ExpandInst.pw16_arFilter = &inst->speechBuffer[2 * 126 * fs_mult
|
|
+ UNVOICED_LPC_ORDER];
|
|
/* Ends at 2*126*fs_mult+UNVOICED_LPC_ORDER+(UNVOICED_LPC_ORDER+1) */
|
|
|
|
inst->ExpandInst.w16_expandMuteFactor = 16384; /* 1.0 in Q14 */
|
|
|
|
/* Initialize BGN part */
|
|
inst->BGNInst.pw16_filter[0] = 4096;
|
|
inst->BGNInst.w16_scale = 20000;
|
|
inst->BGNInst.w16_scaleShift = 24;
|
|
inst->BGNInst.w32_energyUpdate = 500000;
|
|
inst->BGNInst.w32_energyUpdateLow = 0;
|
|
inst->BGNInst.w32_energy = 2500;
|
|
inst->BGNInst.w16_initialized = 0;
|
|
inst->BGNInst.bgnMode = saveBgnMode;
|
|
|
|
/* Recreate statistics counters */WEBRTC_SPL_MEMCPY_W16(&(inst->statInst), &saveStats,
|
|
sizeof(DSPStats_t)/sizeof(WebRtc_Word16));
|
|
|
|
#ifdef NETEQ_STEREO
|
|
/* Recreate MSinfo */WEBRTC_SPL_MEMCPY_W16(&(inst->msInfo), &saveMSinfo,
|
|
sizeof(MasterSlaveInfo)/sizeof(WebRtc_Word16));
|
|
#endif
|
|
|
|
#ifdef NETEQ_CNG_CODEC
|
|
if (inst->CNG_Codec_inst!=NULL)
|
|
{
|
|
/* initialize comfort noise generator */
|
|
res |= WebRtcCng_InitDec(inst->CNG_Codec_inst);
|
|
}
|
|
#endif
|
|
|
|
#ifdef NETEQ_VAD
|
|
/* initialize PostDecode VAD instance
|
|
(don't bother checking for NULL instance, this is done inside init function) */
|
|
res |= WebRtcNetEQ_InitVAD(&inst->VADInst, fs);
|
|
#endif /* NETEQ_VAD */
|
|
|
|
return (res);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* WebRtcNetEQ_AddressInit(...)
|
|
*
|
|
* Initializes the shared-memory communication on the DSP side.
|
|
*
|
|
* Input:
|
|
* - inst : NetEQ DSP instance
|
|
* - data2McuAddress : Pointer to memory where DSP writes / MCU reads
|
|
* - data2DspAddress : Pointer to memory where MCU writes / DSP reads
|
|
* - mainInst : NetEQ main instance
|
|
*
|
|
* Output:
|
|
* - inst : Updated instance
|
|
*
|
|
* Return value : 0 - ok
|
|
*/
|
|
|
|
int WebRtcNetEQ_AddressInit(DSPInst_t *inst, const void *data2McuAddress,
|
|
const void *data2DspAddress, const void *mainInst)
|
|
{
|
|
|
|
/* set shared-memory addresses in the DSP instance */
|
|
inst->pw16_readAddress = (WebRtc_Word16 *) data2DspAddress;
|
|
inst->pw16_writeAddress = (WebRtc_Word16 *) data2McuAddress;
|
|
|
|
/* set pointer to main NetEQ instance */
|
|
inst->main_inst = (void *) mainInst;
|
|
|
|
/* set output frame size to 10 ms = 80 samples in narrowband */
|
|
inst->millisecondsPerCall = 10;
|
|
inst->timestampsPerCall = 80;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
* NETEQDSP_clearInCallStats(...)
|
|
*
|
|
* Reset in-call statistics variables on DSP side.
|
|
*
|
|
* Input:
|
|
* - inst : NetEQ DSP instance
|
|
*
|
|
* Output:
|
|
* - inst : Updated instance
|
|
*
|
|
* Return value : 0 - ok
|
|
*/
|
|
|
|
int WebRtcNetEQ_ClearInCallStats(DSPInst_t *inst)
|
|
{
|
|
|
|
/* Reset statistics counters */
|
|
inst->statInst.accelerateLength = 0;
|
|
inst->statInst.expandLength = 0;
|
|
inst->statInst.preemptiveLength = 0;
|
|
|
|
return (0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* WebRtcNetEQ_ClearPostCallStats(...)
|
|
*
|
|
* Reset post-call statistics variables on DSP side.
|
|
*
|
|
* Input:
|
|
* - inst : NetEQ DSP instance
|
|
*
|
|
* Output:
|
|
* - inst : Updated instance
|
|
*
|
|
* Return value : 0 - ok
|
|
*/
|
|
|
|
int WebRtcNetEQ_ClearPostCallStats(DSPInst_t *inst)
|
|
{
|
|
|
|
/* Reset statistics counters */
|
|
inst->statInst.expandedVoiceSamples = 0;
|
|
inst->statInst.expandedNoiseSamples = 0;
|
|
|
|
return (0);
|
|
}
|
|
|
|
#ifdef NETEQ_VAD
|
|
|
|
/****************************************************************************
|
|
* WebRtcNetEQ_InitVAD(...)
|
|
*
|
|
* Initializes post-decode VAD instance.
|
|
*
|
|
* Input:
|
|
* - VADinst : PostDecodeVAD instance
|
|
* - fs : Initial sample rate
|
|
*
|
|
* Output:
|
|
* - VADinst : Updated instance
|
|
*
|
|
* Return value : 0 - Ok
|
|
* -1 - Error
|
|
*/
|
|
|
|
int WebRtcNetEQ_InitVAD(PostDecodeVAD_t *VADInst, WebRtc_UWord16 fs)
|
|
{
|
|
|
|
int res = 0;
|
|
|
|
/* initially, disable the post-decode VAD */
|
|
VADInst->VADEnabled = 0;
|
|
|
|
if (VADInst->VADState != NULL /* if VAD state is provided */
|
|
&& VADInst->initFunction != NULL /* and all function ... */
|
|
&& VADInst->setmodeFunction != NULL /* ... pointers ... */
|
|
&& VADInst->VADFunction != NULL) /* ... are defined */
|
|
{
|
|
res = (int) VADInst->initFunction( VADInst->VADState ); /* call VAD init function */
|
|
res |= WebRtcNetEQ_SetVADModeInternal( VADInst, VADInst->VADMode );
|
|
|
|
if (res!=0)
|
|
{
|
|
/* something is wrong; play it safe and set the VADstate to NULL */
|
|
VADInst->VADState = NULL;
|
|
}
|
|
else if (fs<=16000)
|
|
{
|
|
/* enable VAD if NB or WB (VAD cannot handle SWB) */
|
|
VADInst->VADEnabled = 1;
|
|
}
|
|
}
|
|
|
|
/* reset SID/CNG interval counter */
|
|
VADInst->SIDintervalCounter = 0;
|
|
|
|
/* initialize with active-speaker decision */
|
|
VADInst->VADDecision = 1;
|
|
|
|
return(res);
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
* WebRtcNetEQ_SetVADModeInternal(...)
|
|
*
|
|
* Set the VAD mode in the VAD struct, and communicate it to the VAD instance
|
|
* if it exists.
|
|
*
|
|
* Input:
|
|
* - VADinst : PostDecodeVAD instance
|
|
* - mode : Mode number passed on to the VAD function
|
|
*
|
|
* Output:
|
|
* - VADinst : Updated instance
|
|
*
|
|
* Return value : 0 - Ok
|
|
* -1 - Error
|
|
*/
|
|
|
|
int WebRtcNetEQ_SetVADModeInternal(PostDecodeVAD_t *VADInst,
|
|
WebRtc_Word16 mode)
|
|
{
|
|
|
|
int res = 0;
|
|
|
|
VADInst->VADMode = mode;
|
|
|
|
if (VADInst->VADState != NULL)
|
|
{
|
|
/* call setmode function */
|
|
res = (int) VADInst->setmodeFunction(VADInst->VADState, mode);
|
|
}
|
|
|
|
return(res);
|
|
|
|
}
|
|
|
|
#endif /* NETEQ_VAD */
|
|
|
|
/****************************************************************************
|
|
* WebRtcNetEQ_FlushSpeechBuffer(...)
|
|
*
|
|
* Flush the speech buffer.
|
|
*
|
|
* Input:
|
|
* - inst : NetEq DSP instance
|
|
*
|
|
* Output:
|
|
* - inst : Updated instance
|
|
*
|
|
* Return value : 0 - ok
|
|
* : non-zero - error
|
|
*/
|
|
|
|
int WebRtcNetEQ_FlushSpeechBuffer(DSPInst_t *inst)
|
|
{
|
|
WebRtc_Word16 fs_mult;
|
|
|
|
/* calcualte fs/8000 */
|
|
fs_mult = WebRtcSpl_DivW32W16ResW16(inst->fs, 8000);
|
|
|
|
/* clear buffer */
|
|
WebRtcSpl_MemSetW16(inst->speechBuffer, 0, SPEECH_BUF_SIZE);
|
|
inst->endPosition = 565 * fs_mult;
|
|
inst->curPosition = inst->endPosition - inst->ExpandInst.w16_overlap;
|
|
|
|
return 0;
|
|
}
|
|
|