/* * 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; }