blob: 441d981e7e4b40523c9c63fdc249525c68ee34c7 [file] [log] [blame]
/*
* Copyright (c) 2012 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 = 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 = 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;
}