549 lines
21 KiB
C
549 lines
21 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 is the function to merge a new packet with expanded data after a packet loss.
|
||
|
*/
|
||
|
|
||
|
#include "dsp.h"
|
||
|
|
||
|
#include "signal_processing_library.h"
|
||
|
|
||
|
#include "dsp_helpfunctions.h"
|
||
|
#include "neteq_error_codes.h"
|
||
|
|
||
|
/****************************************************************************
|
||
|
* WebRtcNetEQ_Merge(...)
|
||
|
*
|
||
|
* This function...
|
||
|
*
|
||
|
* Input:
|
||
|
* - inst : NetEQ DSP instance
|
||
|
* - scratchPtr : Pointer to scratch vector.
|
||
|
* - decoded : Pointer to new decoded speech.
|
||
|
* - len : Number of samples in pw16_decoded.
|
||
|
*
|
||
|
*
|
||
|
* Output:
|
||
|
* - inst : Updated user information
|
||
|
* - outData : Pointer to a memory space where the output data
|
||
|
* should be stored
|
||
|
* - pw16_len : Number of samples written to pw16_outData
|
||
|
*
|
||
|
* Return value : 0 - Ok
|
||
|
* <0 - Error
|
||
|
*/
|
||
|
|
||
|
/* Scratch usage:
|
||
|
|
||
|
Type Name size startpos endpos
|
||
|
WebRtc_Word16 pw16_expanded 210*fs/8000 0 209*fs/8000
|
||
|
WebRtc_Word16 pw16_expandedLB 100 210*fs/8000 99+210*fs/8000
|
||
|
WebRtc_Word16 pw16_decodedLB 40 100+210*fs/8000 139+210*fs/8000
|
||
|
WebRtc_Word32 pw32_corr 2*60 140+210*fs/8000 260+210*fs/8000
|
||
|
WebRtc_Word16 pw16_corrVec 68 210*fs/8000 67+210*fs/8000
|
||
|
|
||
|
[gap in scratch vector]
|
||
|
|
||
|
func WebRtcNetEQ_Expand 40+370*fs/8000 126*fs/8000 39+496*fs/8000
|
||
|
|
||
|
Total: 40+496*fs/8000
|
||
|
*/
|
||
|
|
||
|
#define SCRATCH_pw16_expanded 0
|
||
|
#if (defined(NETEQ_48KHZ_WIDEBAND))
|
||
|
#define SCRATCH_pw16_expandedLB 1260
|
||
|
#define SCRATCH_pw16_decodedLB 1360
|
||
|
#define SCRATCH_pw32_corr 1400
|
||
|
#define SCRATCH_pw16_corrVec 1260
|
||
|
#define SCRATCH_NETEQ_EXPAND 756
|
||
|
#elif (defined(NETEQ_32KHZ_WIDEBAND))
|
||
|
#define SCRATCH_pw16_expandedLB 840
|
||
|
#define SCRATCH_pw16_decodedLB 940
|
||
|
#define SCRATCH_pw32_corr 980
|
||
|
#define SCRATCH_pw16_corrVec 840
|
||
|
#define SCRATCH_NETEQ_EXPAND 504
|
||
|
#elif (defined(NETEQ_WIDEBAND))
|
||
|
#define SCRATCH_pw16_expandedLB 420
|
||
|
#define SCRATCH_pw16_decodedLB 520
|
||
|
#define SCRATCH_pw32_corr 560
|
||
|
#define SCRATCH_pw16_corrVec 420
|
||
|
#define SCRATCH_NETEQ_EXPAND 252
|
||
|
#else /* NB */
|
||
|
#define SCRATCH_pw16_expandedLB 210
|
||
|
#define SCRATCH_pw16_decodedLB 310
|
||
|
#define SCRATCH_pw32_corr 350
|
||
|
#define SCRATCH_pw16_corrVec 210
|
||
|
#define SCRATCH_NETEQ_EXPAND 126
|
||
|
#endif
|
||
|
|
||
|
int WebRtcNetEQ_Merge(DSPInst_t *inst,
|
||
|
#ifdef SCRATCH
|
||
|
WebRtc_Word16 *pw16_scratchPtr,
|
||
|
#endif
|
||
|
WebRtc_Word16 *pw16_decoded, int len, WebRtc_Word16 *pw16_outData,
|
||
|
WebRtc_Word16 *pw16_len)
|
||
|
{
|
||
|
|
||
|
WebRtc_Word16 fs_mult;
|
||
|
WebRtc_Word16 fs_shift;
|
||
|
WebRtc_Word32 w32_En_new_frame, w32_En_old_frame;
|
||
|
WebRtc_Word16 w16_expmax, w16_newmax;
|
||
|
WebRtc_Word16 w16_tmp, w16_tmp2;
|
||
|
WebRtc_Word32 w32_tmp;
|
||
|
#ifdef SCRATCH
|
||
|
WebRtc_Word16 *pw16_expanded = pw16_scratchPtr + SCRATCH_pw16_expanded;
|
||
|
WebRtc_Word16 *pw16_expandedLB = pw16_scratchPtr + SCRATCH_pw16_expandedLB;
|
||
|
WebRtc_Word16 *pw16_decodedLB = pw16_scratchPtr + SCRATCH_pw16_decodedLB;
|
||
|
WebRtc_Word32 *pw32_corr = (WebRtc_Word32*) (pw16_scratchPtr + SCRATCH_pw32_corr);
|
||
|
WebRtc_Word16 *pw16_corrVec = pw16_scratchPtr + SCRATCH_pw16_corrVec;
|
||
|
#else
|
||
|
WebRtc_Word16 pw16_expanded[(125+80+5)*FSMULT];
|
||
|
WebRtc_Word16 pw16_expandedLB[100];
|
||
|
WebRtc_Word16 pw16_decodedLB[40];
|
||
|
WebRtc_Word32 pw32_corr[60];
|
||
|
WebRtc_Word16 pw16_corrVec[4+60+4];
|
||
|
#endif
|
||
|
WebRtc_Word16 *pw16_corr = &pw16_corrVec[4];
|
||
|
WebRtc_Word16 w16_stopPos, w16_bestIndex, w16_interpLen;
|
||
|
WebRtc_Word16 w16_bestVal; /* bestVal is dummy */
|
||
|
WebRtc_Word16 w16_startfact, w16_inc;
|
||
|
WebRtc_Word16 w16_expandedLen;
|
||
|
WebRtc_Word16 w16_startPos;
|
||
|
WebRtc_Word16 w16_expLen, w16_newLen = 0;
|
||
|
WebRtc_Word16 *pw16_decodedOut;
|
||
|
WebRtc_Word16 w16_muted;
|
||
|
|
||
|
int w16_decodedLen = len;
|
||
|
|
||
|
#ifdef NETEQ_STEREO
|
||
|
MasterSlaveInfo *msInfo = inst->msInfo;
|
||
|
#endif
|
||
|
|
||
|
fs_mult = WebRtcSpl_DivW32W16ResW16(inst->fs, 8000);
|
||
|
fs_shift = 30 - WebRtcSpl_NormW32(fs_mult); /* Note that this is not "exact" for 48kHz */
|
||
|
|
||
|
/*************************************
|
||
|
* Generate data to merge with
|
||
|
*************************************/
|
||
|
/*
|
||
|
* Check how much data that is left since earlier
|
||
|
* (at least there should be the overlap)...
|
||
|
*/
|
||
|
w16_startPos = inst->endPosition - inst->curPosition;
|
||
|
/* Get one extra expansion to merge and overlap with */
|
||
|
inst->ExpandInst.w16_stopMuting = 1;
|
||
|
inst->ExpandInst.w16_lagsDirection = 1; /* make sure we get the "optimal" lag */
|
||
|
inst->ExpandInst.w16_lagsPosition = -1; /* out of the 3 possible ones */
|
||
|
w16_expandedLen = 0; /* Does not fill any function currently */
|
||
|
|
||
|
if (w16_startPos >= 210 * FSMULT)
|
||
|
{
|
||
|
/*
|
||
|
* The number of samples available in the sync buffer is more than what fits in
|
||
|
* pw16_expanded.Keep the first 210*FSMULT samples, but shift them towards the end of
|
||
|
* the buffer. This is ok, since all of the buffer will be expand data anyway, so as
|
||
|
* long as the beginning is left untouched, we're fine.
|
||
|
*/
|
||
|
|
||
|
w16_tmp = w16_startPos - 210 * FSMULT; /* length difference */
|
||
|
|
||
|
WEBRTC_SPL_MEMMOVE_W16(&inst->speechBuffer[inst->curPosition+w16_tmp] ,
|
||
|
&inst->speechBuffer[inst->curPosition], 210*FSMULT);
|
||
|
|
||
|
inst->curPosition += w16_tmp; /* move start position of sync buffer accordingly */
|
||
|
w16_startPos = 210 * FSMULT; /* this is the truncated length */
|
||
|
}
|
||
|
|
||
|
WebRtcNetEQ_Expand(inst,
|
||
|
#ifdef SCRATCH
|
||
|
pw16_scratchPtr + SCRATCH_NETEQ_EXPAND,
|
||
|
#endif
|
||
|
pw16_expanded, /* let Expand write to beginning of pw16_expanded to avoid overflow */
|
||
|
&w16_newLen, 0);
|
||
|
|
||
|
/*
|
||
|
* Now shift the data in pw16_expanded to where it belongs.
|
||
|
* Truncate all that ends up outside the vector.
|
||
|
*/
|
||
|
|
||
|
WEBRTC_SPL_MEMMOVE_W16(&pw16_expanded[w16_startPos], pw16_expanded,
|
||
|
WEBRTC_SPL_MIN(w16_newLen,
|
||
|
WEBRTC_SPL_MAX(210*FSMULT - w16_startPos, 0) ) );
|
||
|
|
||
|
inst->ExpandInst.w16_stopMuting = 0;
|
||
|
|
||
|
/* Copy what is left since earlier into the expanded vector */
|
||
|
|
||
|
WEBRTC_SPL_MEMCPY_W16(pw16_expanded, &inst->speechBuffer[inst->curPosition], w16_startPos);
|
||
|
|
||
|
/*
|
||
|
* Do "ugly" copy and paste from the expanded in order to generate more data
|
||
|
* to correlate (but not interpolate) with.
|
||
|
*/
|
||
|
w16_expandedLen = (120 + 80 + 2) * fs_mult;
|
||
|
w16_expLen = w16_startPos + w16_newLen;
|
||
|
|
||
|
if (w16_expLen < w16_expandedLen)
|
||
|
{
|
||
|
while ((w16_expLen + w16_newLen) < w16_expandedLen)
|
||
|
{
|
||
|
WEBRTC_SPL_MEMCPY_W16(&pw16_expanded[w16_expLen], &pw16_expanded[w16_startPos],
|
||
|
w16_newLen);
|
||
|
w16_expLen += w16_newLen;
|
||
|
}
|
||
|
|
||
|
/* Copy last part (fraction of a whole expansion) */
|
||
|
|
||
|
WEBRTC_SPL_MEMCPY_W16(&pw16_expanded[w16_expLen], &pw16_expanded[w16_startPos],
|
||
|
(w16_expandedLen-w16_expLen));
|
||
|
}
|
||
|
w16_expLen = w16_expandedLen;
|
||
|
|
||
|
/* Adjust muting factor (main muting factor times expand muting factor) */
|
||
|
inst->w16_muteFactor
|
||
|
= (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT(inst->w16_muteFactor,
|
||
|
inst->ExpandInst.w16_expandMuteFactor, 14);
|
||
|
|
||
|
/* Adjust muting factor if new vector is more or less of the BGN energy */
|
||
|
len = WEBRTC_SPL_MIN(64*fs_mult, w16_decodedLen);
|
||
|
w16_expmax = WebRtcSpl_MaxAbsValueW16(pw16_expanded, (WebRtc_Word16) len);
|
||
|
w16_newmax = WebRtcSpl_MaxAbsValueW16(pw16_decoded, (WebRtc_Word16) len);
|
||
|
|
||
|
/* Calculate energy of old data */
|
||
|
w16_tmp = 6 + fs_shift - WebRtcSpl_NormW32(WEBRTC_SPL_MUL_16_16(w16_expmax, w16_expmax));
|
||
|
w16_tmp = WEBRTC_SPL_MAX(w16_tmp,0);
|
||
|
w32_En_old_frame = WebRtcNetEQ_DotW16W16(pw16_expanded, pw16_expanded, len, w16_tmp);
|
||
|
|
||
|
/* Calculate energy of new data */
|
||
|
w16_tmp2 = 6 + fs_shift - WebRtcSpl_NormW32(WEBRTC_SPL_MUL_16_16(w16_newmax, w16_newmax));
|
||
|
w16_tmp2 = WEBRTC_SPL_MAX(w16_tmp2,0);
|
||
|
w32_En_new_frame = WebRtcNetEQ_DotW16W16(pw16_decoded, pw16_decoded, len, w16_tmp2);
|
||
|
|
||
|
/* Align to same Q-domain */
|
||
|
if (w16_tmp2 > w16_tmp)
|
||
|
{
|
||
|
w32_En_old_frame = WEBRTC_SPL_RSHIFT_W32(w32_En_old_frame, (w16_tmp2-w16_tmp));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
w32_En_new_frame = WEBRTC_SPL_RSHIFT_W32(w32_En_new_frame, (w16_tmp-w16_tmp2));
|
||
|
}
|
||
|
|
||
|
/* Calculate muting factor to use for new frame */
|
||
|
if (w32_En_new_frame > w32_En_old_frame)
|
||
|
{
|
||
|
/* Normalize w32_En_new_frame to 14 bits */
|
||
|
w16_tmp = WebRtcSpl_NormW32(w32_En_new_frame) - 17;
|
||
|
w32_En_new_frame = WEBRTC_SPL_SHIFT_W32(w32_En_new_frame, w16_tmp);
|
||
|
|
||
|
/*
|
||
|
* Put w32_En_old_frame in a domain 14 higher, so that
|
||
|
* w32_En_old_frame/w32_En_new_frame is in Q14
|
||
|
*/
|
||
|
w16_tmp = w16_tmp + 14;
|
||
|
w32_En_old_frame = WEBRTC_SPL_SHIFT_W32(w32_En_old_frame, w16_tmp);
|
||
|
w16_tmp
|
||
|
= WebRtcSpl_DivW32W16ResW16(w32_En_old_frame, (WebRtc_Word16) w32_En_new_frame);
|
||
|
/* Calculate sqrt(w32_En_old_frame/w32_En_new_frame) in Q14 */
|
||
|
w16_muted = (WebRtc_Word16) WebRtcSpl_Sqrt(
|
||
|
WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)w16_tmp,14));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
w16_muted = 16384; /* Set = 1.0 when old frame has higher energy than new */
|
||
|
}
|
||
|
|
||
|
/* Set the raise the continued muting factor w16_muted if w16_muteFactor is lower */
|
||
|
if (w16_muted > inst->w16_muteFactor)
|
||
|
{
|
||
|
inst->w16_muteFactor = WEBRTC_SPL_MIN(w16_muted, 16384);
|
||
|
}
|
||
|
|
||
|
#ifdef NETEQ_STEREO
|
||
|
|
||
|
/* Sanity for msInfo */
|
||
|
if (msInfo == NULL)
|
||
|
{
|
||
|
/* this should not happen here */
|
||
|
return MASTER_SLAVE_ERROR;
|
||
|
}
|
||
|
|
||
|
/* do not downsample and calculate correlations for slave instance(s) */
|
||
|
if ((msInfo->msMode == NETEQ_MASTER) || (msInfo->msMode == NETEQ_MONO))
|
||
|
{
|
||
|
#endif
|
||
|
|
||
|
/*********************************************
|
||
|
* Downsample to 4kHz and find best overlap
|
||
|
*********************************************/
|
||
|
|
||
|
/* Downsample to 4 kHz */
|
||
|
if (inst->fs == 8000)
|
||
|
{
|
||
|
WebRtcSpl_DownsampleFast(&pw16_expanded[2], (WebRtc_Word16) (w16_expandedLen - 2),
|
||
|
pw16_expandedLB, (WebRtc_Word16) (100),
|
||
|
(WebRtc_Word16*) WebRtcNetEQ_kDownsample8kHzTbl, (WebRtc_Word16) 3,
|
||
|
(WebRtc_Word16) 2, (WebRtc_Word16) 0);
|
||
|
if (w16_decodedLen <= 80)
|
||
|
{
|
||
|
/* Not quite long enough, so we have to cheat a bit... */
|
||
|
WebRtcSpl_DownsampleFast(&pw16_decoded[2], (WebRtc_Word16) 80, pw16_decodedLB,
|
||
|
(WebRtc_Word16) (40), (WebRtc_Word16*) WebRtcNetEQ_kDownsample8kHzTbl,
|
||
|
(WebRtc_Word16) 3, (WebRtc_Word16) 2, (WebRtc_Word16) 0);
|
||
|
w16_tmp = ((w16_decodedLen - 2) >> 1);
|
||
|
WebRtcSpl_MemSetW16(&pw16_decodedLB[w16_tmp], 0, (40 - w16_tmp));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
WebRtcSpl_DownsampleFast(&pw16_decoded[2],
|
||
|
(WebRtc_Word16) (w16_decodedLen - 2), pw16_decodedLB,
|
||
|
(WebRtc_Word16) (40), (WebRtc_Word16*) WebRtcNetEQ_kDownsample8kHzTbl,
|
||
|
(WebRtc_Word16) 3, (WebRtc_Word16) 2, (WebRtc_Word16) 0);
|
||
|
}
|
||
|
#ifdef NETEQ_WIDEBAND
|
||
|
}
|
||
|
else if (inst->fs==16000)
|
||
|
{
|
||
|
WebRtcSpl_DownsampleFast(
|
||
|
&pw16_expanded[4], (WebRtc_Word16)(w16_expandedLen-4),
|
||
|
pw16_expandedLB, (WebRtc_Word16)(100),
|
||
|
(WebRtc_Word16*)WebRtcNetEQ_kDownsample16kHzTbl, (WebRtc_Word16)5,
|
||
|
(WebRtc_Word16)4, (WebRtc_Word16)0);
|
||
|
if (w16_decodedLen<=160)
|
||
|
{
|
||
|
/* Not quite long enough, so we have to cheat a bit... */
|
||
|
WebRtcSpl_DownsampleFast(
|
||
|
&pw16_decoded[4], (WebRtc_Word16)160,
|
||
|
pw16_decodedLB, (WebRtc_Word16)(40),
|
||
|
(WebRtc_Word16*)WebRtcNetEQ_kDownsample16kHzTbl, (WebRtc_Word16)5,
|
||
|
(WebRtc_Word16)4, (WebRtc_Word16)0);
|
||
|
w16_tmp = ((w16_decodedLen-4)>>2);
|
||
|
WebRtcSpl_MemSetW16(&pw16_decodedLB[w16_tmp], 0, (40-w16_tmp));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
WebRtcSpl_DownsampleFast(
|
||
|
&pw16_decoded[4], (WebRtc_Word16)(w16_decodedLen-4),
|
||
|
pw16_decodedLB, (WebRtc_Word16)(40),
|
||
|
(WebRtc_Word16*)WebRtcNetEQ_kDownsample16kHzTbl, (WebRtc_Word16)5,
|
||
|
(WebRtc_Word16)4, (WebRtc_Word16)0);
|
||
|
}
|
||
|
#endif
|
||
|
#ifdef NETEQ_32KHZ_WIDEBAND
|
||
|
}
|
||
|
else if (inst->fs==32000)
|
||
|
{
|
||
|
WebRtcSpl_DownsampleFast(
|
||
|
&pw16_expanded[6], (WebRtc_Word16)(w16_expandedLen-6),
|
||
|
pw16_expandedLB, (WebRtc_Word16)(100),
|
||
|
(WebRtc_Word16*)WebRtcNetEQ_kDownsample32kHzTbl, (WebRtc_Word16)7,
|
||
|
(WebRtc_Word16)8, (WebRtc_Word16)0);
|
||
|
if (w16_decodedLen<=320)
|
||
|
{
|
||
|
/* Not quite long enough, so we have to cheat a bit... */
|
||
|
WebRtcSpl_DownsampleFast(
|
||
|
&pw16_decoded[6], (WebRtc_Word16)320,
|
||
|
pw16_decodedLB, (WebRtc_Word16)(40),
|
||
|
(WebRtc_Word16*)WebRtcNetEQ_kDownsample32kHzTbl, (WebRtc_Word16)7,
|
||
|
(WebRtc_Word16)8, (WebRtc_Word16)0);
|
||
|
w16_tmp = ((w16_decodedLen-6)>>3);
|
||
|
WebRtcSpl_MemSetW16(&pw16_decodedLB[w16_tmp], 0, (40-w16_tmp));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
WebRtcSpl_DownsampleFast(
|
||
|
&pw16_decoded[6], (WebRtc_Word16)(w16_decodedLen-6),
|
||
|
pw16_decodedLB, (WebRtc_Word16)(40),
|
||
|
(WebRtc_Word16*)WebRtcNetEQ_kDownsample32kHzTbl, (WebRtc_Word16)7,
|
||
|
(WebRtc_Word16)8, (WebRtc_Word16)0);
|
||
|
}
|
||
|
#endif
|
||
|
#ifdef NETEQ_48KHZ_WIDEBAND
|
||
|
}
|
||
|
else /* if (inst->fs==48000) */
|
||
|
{
|
||
|
WebRtcSpl_DownsampleFast(
|
||
|
&pw16_expanded[6], (WebRtc_Word16)(w16_expandedLen-6),
|
||
|
pw16_expandedLB, (WebRtc_Word16)(100),
|
||
|
(WebRtc_Word16*)WebRtcNetEQ_kDownsample48kHzTbl, (WebRtc_Word16)7,
|
||
|
(WebRtc_Word16)12, (WebRtc_Word16)0);
|
||
|
if (w16_decodedLen<=320)
|
||
|
{
|
||
|
/* Not quite long enough, so we have to cheat a bit... */
|
||
|
WebRtcSpl_DownsampleFast(
|
||
|
&pw16_decoded[6], (WebRtc_Word16)320,
|
||
|
pw16_decodedLB, (WebRtc_Word16)(40),
|
||
|
(WebRtc_Word16*)WebRtcNetEQ_kDownsample48kHzTbl, (WebRtc_Word16)7,
|
||
|
(WebRtc_Word16)12, (WebRtc_Word16)0);
|
||
|
w16_tmp = ((w16_decodedLen-6)>>3);
|
||
|
WebRtcSpl_MemSetW16(&pw16_decodedLB[w16_tmp], 0, (40-w16_tmp));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
WebRtcSpl_DownsampleFast(
|
||
|
&pw16_decoded[6], (WebRtc_Word16)(w16_decodedLen-6),
|
||
|
pw16_decodedLB, (WebRtc_Word16)(40),
|
||
|
(WebRtc_Word16*)WebRtcNetEQ_kDownsample48kHzTbl, (WebRtc_Word16)7,
|
||
|
(WebRtc_Word16)12, (WebRtc_Word16)0);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/* Calculate correlation without any normalization (40 samples) */
|
||
|
w16_tmp = WebRtcSpl_DivW32W16ResW16((WebRtc_Word32) inst->ExpandInst.w16_maxLag,
|
||
|
(WebRtc_Word16) (fs_mult * 2)) + 1;
|
||
|
w16_stopPos = WEBRTC_SPL_MIN(60, w16_tmp);
|
||
|
w32_tmp = WEBRTC_SPL_MUL_16_16(w16_expmax, w16_newmax);
|
||
|
if (w32_tmp > 26843546)
|
||
|
{
|
||
|
w16_tmp = 3;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
w16_tmp = 0;
|
||
|
}
|
||
|
|
||
|
WebRtcNetEQ_CrossCorr(pw32_corr, pw16_decodedLB, pw16_expandedLB, 40,
|
||
|
(WebRtc_Word16) w16_stopPos, w16_tmp, 1);
|
||
|
|
||
|
/* Normalize correlation to 14 bits and put in a WebRtc_Word16 vector */
|
||
|
WebRtcSpl_MemSetW16(pw16_corrVec, 0, (4 + 60 + 4));
|
||
|
w32_tmp = WebRtcSpl_MaxAbsValueW32(pw32_corr, w16_stopPos);
|
||
|
w16_tmp = 17 - WebRtcSpl_NormW32(w32_tmp);
|
||
|
w16_tmp = WEBRTC_SPL_MAX(0, w16_tmp);
|
||
|
|
||
|
WebRtcSpl_VectorBitShiftW32ToW16(pw16_corr, w16_stopPos, pw32_corr, w16_tmp);
|
||
|
|
||
|
/* Calculate allowed starting point for peak finding.
|
||
|
The peak location bestIndex must fulfill two criteria:
|
||
|
(1) w16_bestIndex+w16_decodedLen < inst->timestampsPerCall+inst->ExpandInst.w16_overlap
|
||
|
(2) w16_bestIndex+w16_decodedLen < w16_startPos */
|
||
|
w16_tmp = WEBRTC_SPL_MAX(0, WEBRTC_SPL_MAX(w16_startPos,
|
||
|
inst->timestampsPerCall+inst->ExpandInst.w16_overlap) - w16_decodedLen);
|
||
|
/* Downscale starting index to 4kHz domain */
|
||
|
w16_tmp2 = WebRtcSpl_DivW32W16ResW16((WebRtc_Word32) w16_tmp,
|
||
|
(WebRtc_Word16) (fs_mult << 1));
|
||
|
|
||
|
#ifdef NETEQ_STEREO
|
||
|
} /* end if (msInfo->msMode != NETEQ_SLAVE) */
|
||
|
|
||
|
if ((msInfo->msMode == NETEQ_MASTER) || (msInfo->msMode == NETEQ_MONO))
|
||
|
{
|
||
|
/* This is master or mono instance; find peak */
|
||
|
WebRtcNetEQ_PeakDetection(&pw16_corr[w16_tmp2], w16_stopPos, 1, fs_mult, &w16_bestIndex,
|
||
|
&w16_bestVal);
|
||
|
w16_bestIndex += w16_tmp; /* compensate for modified starting index */
|
||
|
msInfo->bestIndex = w16_bestIndex;
|
||
|
}
|
||
|
else if (msInfo->msMode == NETEQ_SLAVE)
|
||
|
{
|
||
|
/* Get peak location from master instance */
|
||
|
w16_bestIndex = msInfo->bestIndex;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Invalid mode */
|
||
|
return MASTER_SLAVE_ERROR;
|
||
|
}
|
||
|
|
||
|
#else /* NETEQ_STEREO */
|
||
|
|
||
|
/* Find peak */
|
||
|
WebRtcNetEQ_PeakDetection(&pw16_corr[w16_tmp2], w16_stopPos, 1, fs_mult, &w16_bestIndex,
|
||
|
&w16_bestVal);
|
||
|
w16_bestIndex += w16_tmp; /* compensate for modified starting index */
|
||
|
|
||
|
#endif /* NETEQ_STEREO */
|
||
|
|
||
|
/*
|
||
|
* Ensure that underrun does not occur for 10ms case => we have to get at least
|
||
|
* 10ms + overlap . (This should never happen thanks to the above modification of
|
||
|
* peak-finding starting point.)
|
||
|
* */
|
||
|
while ((w16_bestIndex + w16_decodedLen) < (inst->timestampsPerCall
|
||
|
+ inst->ExpandInst.w16_overlap) || w16_bestIndex + w16_decodedLen < w16_startPos)
|
||
|
{
|
||
|
w16_bestIndex += w16_newLen; /* Jump one lag ahead */
|
||
|
}
|
||
|
pw16_decodedOut = pw16_outData + w16_bestIndex;
|
||
|
|
||
|
/* Mute the new decoded data if needed (and unmute it linearly) */
|
||
|
w16_interpLen = WEBRTC_SPL_MIN(60*fs_mult,
|
||
|
w16_expandedLen-w16_bestIndex); /* this is the overlapping part of pw16_expanded */
|
||
|
w16_interpLen = WEBRTC_SPL_MIN(w16_interpLen, w16_decodedLen);
|
||
|
w16_inc = WebRtcSpl_DivW32W16ResW16(4194,
|
||
|
fs_mult); /* in Q20, 0.004 for NB and 0.002 for WB */
|
||
|
if (inst->w16_muteFactor < 16384)
|
||
|
{
|
||
|
WebRtcNetEQ_UnmuteSignal(pw16_decoded, &inst->w16_muteFactor, pw16_decoded, w16_inc,
|
||
|
(WebRtc_Word16) w16_interpLen);
|
||
|
WebRtcNetEQ_UnmuteSignal(&pw16_decoded[w16_interpLen], &inst->w16_muteFactor,
|
||
|
&pw16_decodedOut[w16_interpLen], w16_inc,
|
||
|
(WebRtc_Word16) (w16_decodedLen - w16_interpLen));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* No muting needed */
|
||
|
|
||
|
WEBRTC_SPL_MEMMOVE_W16(&pw16_decodedOut[w16_interpLen], &pw16_decoded[w16_interpLen],
|
||
|
(w16_decodedLen-w16_interpLen));
|
||
|
}
|
||
|
|
||
|
/* Do overlap and interpolate linearly */
|
||
|
w16_inc = WebRtcSpl_DivW32W16ResW16(16384, (WebRtc_Word16) (w16_interpLen + 1)); /* Q14 */
|
||
|
w16_startfact = (16384 - w16_inc);
|
||
|
WEBRTC_SPL_MEMMOVE_W16(pw16_outData, pw16_expanded, w16_bestIndex);
|
||
|
WebRtcNetEQ_MixVoiceUnvoice(pw16_decodedOut, &pw16_expanded[w16_bestIndex], pw16_decoded,
|
||
|
&w16_startfact, w16_inc, w16_interpLen);
|
||
|
|
||
|
inst->w16_mode = MODE_MERGE;
|
||
|
inst->ExpandInst.w16_consecExp = 0; /* Last was not expand any more */
|
||
|
|
||
|
/* New added length (w16_startPos samples were borrowed) */
|
||
|
*pw16_len = w16_bestIndex + w16_decodedLen - w16_startPos;
|
||
|
|
||
|
/* Update VQmon parameter */
|
||
|
inst->w16_concealedTS += (*pw16_len - w16_decodedLen);
|
||
|
inst->w16_concealedTS = WEBRTC_SPL_MAX(0, inst->w16_concealedTS);
|
||
|
|
||
|
/* Update in-call and post-call statistics */
|
||
|
if (inst->ExpandInst.w16_expandMuteFactor == 0)
|
||
|
{
|
||
|
/* expansion generates noise only */
|
||
|
inst->statInst.expandedNoiseSamples += (*pw16_len - w16_decodedLen);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* expansion generates more than only noise */
|
||
|
inst->statInst.expandedVoiceSamples += (*pw16_len - w16_decodedLen);
|
||
|
}
|
||
|
inst->statInst.expandLength += (*pw16_len - w16_decodedLen);
|
||
|
|
||
|
|
||
|
/* Copy back the first part of the data to the speechHistory */
|
||
|
|
||
|
WEBRTC_SPL_MEMCPY_W16(&inst->speechBuffer[inst->curPosition], pw16_outData, w16_startPos);
|
||
|
|
||
|
|
||
|
/* Move data to within outData */
|
||
|
|
||
|
WEBRTC_SPL_MEMMOVE_W16(pw16_outData, &pw16_outData[w16_startPos], (*pw16_len));
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#undef SCRATCH_pw16_expanded
|
||
|
#undef SCRATCH_pw16_expandedLB
|
||
|
#undef SCRATCH_pw16_decodedLB
|
||
|
#undef SCRATCH_pw32_corr
|
||
|
#undef SCRATCH_pw16_corrVec
|
||
|
#undef SCRATCH_NETEQ_EXPAND
|