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