niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 1 | /* |
henrik.lundin@webrtc.org | dd478e2 | 2012-01-31 13:12:41 +0000 | [diff] [blame] | 2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
| 11 | /* |
| 12 | * This is the function to merge a new packet with expanded data after a packet loss. |
| 13 | */ |
| 14 | |
| 15 | #include "dsp.h" |
| 16 | |
| 17 | #include "signal_processing_library.h" |
| 18 | |
| 19 | #include "dsp_helpfunctions.h" |
| 20 | #include "neteq_error_codes.h" |
| 21 | |
| 22 | /**************************************************************************** |
| 23 | * WebRtcNetEQ_Merge(...) |
| 24 | * |
| 25 | * This function... |
| 26 | * |
| 27 | * Input: |
| 28 | * - inst : NetEQ DSP instance |
| 29 | * - scratchPtr : Pointer to scratch vector. |
| 30 | * - decoded : Pointer to new decoded speech. |
| 31 | * - len : Number of samples in pw16_decoded. |
| 32 | * |
| 33 | * |
| 34 | * Output: |
| 35 | * - inst : Updated user information |
| 36 | * - outData : Pointer to a memory space where the output data |
| 37 | * should be stored |
| 38 | * - pw16_len : Number of samples written to pw16_outData |
| 39 | * |
| 40 | * Return value : 0 - Ok |
| 41 | * <0 - Error |
| 42 | */ |
| 43 | |
| 44 | /* Scratch usage: |
| 45 | |
| 46 | Type Name size startpos endpos |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 47 | int16_t pw16_expanded 210*fs/8000 0 209*fs/8000 |
| 48 | int16_t pw16_expandedLB 100 210*fs/8000 99+210*fs/8000 |
| 49 | int16_t pw16_decodedLB 40 100+210*fs/8000 139+210*fs/8000 |
| 50 | int32_t pw32_corr 2*60 140+210*fs/8000 260+210*fs/8000 |
| 51 | int16_t pw16_corrVec 68 210*fs/8000 67+210*fs/8000 |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 52 | |
| 53 | [gap in scratch vector] |
| 54 | |
| 55 | func WebRtcNetEQ_Expand 40+370*fs/8000 126*fs/8000 39+496*fs/8000 |
| 56 | |
| 57 | Total: 40+496*fs/8000 |
| 58 | */ |
| 59 | |
| 60 | #define SCRATCH_pw16_expanded 0 |
| 61 | #if (defined(NETEQ_48KHZ_WIDEBAND)) |
| 62 | #define SCRATCH_pw16_expandedLB 1260 |
| 63 | #define SCRATCH_pw16_decodedLB 1360 |
| 64 | #define SCRATCH_pw32_corr 1400 |
| 65 | #define SCRATCH_pw16_corrVec 1260 |
| 66 | #define SCRATCH_NETEQ_EXPAND 756 |
| 67 | #elif (defined(NETEQ_32KHZ_WIDEBAND)) |
| 68 | #define SCRATCH_pw16_expandedLB 840 |
| 69 | #define SCRATCH_pw16_decodedLB 940 |
| 70 | #define SCRATCH_pw32_corr 980 |
| 71 | #define SCRATCH_pw16_corrVec 840 |
| 72 | #define SCRATCH_NETEQ_EXPAND 504 |
| 73 | #elif (defined(NETEQ_WIDEBAND)) |
| 74 | #define SCRATCH_pw16_expandedLB 420 |
| 75 | #define SCRATCH_pw16_decodedLB 520 |
| 76 | #define SCRATCH_pw32_corr 560 |
| 77 | #define SCRATCH_pw16_corrVec 420 |
| 78 | #define SCRATCH_NETEQ_EXPAND 252 |
| 79 | #else /* NB */ |
| 80 | #define SCRATCH_pw16_expandedLB 210 |
| 81 | #define SCRATCH_pw16_decodedLB 310 |
| 82 | #define SCRATCH_pw32_corr 350 |
| 83 | #define SCRATCH_pw16_corrVec 210 |
| 84 | #define SCRATCH_NETEQ_EXPAND 126 |
| 85 | #endif |
| 86 | |
| 87 | int WebRtcNetEQ_Merge(DSPInst_t *inst, |
| 88 | #ifdef SCRATCH |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 89 | int16_t *pw16_scratchPtr, |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 90 | #endif |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 91 | int16_t *pw16_decoded, int len, int16_t *pw16_outData, |
| 92 | int16_t *pw16_len) |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 93 | { |
| 94 | |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 95 | int16_t fs_mult; |
| 96 | int16_t fs_shift; |
| 97 | int32_t w32_En_new_frame, w32_En_old_frame; |
| 98 | int16_t w16_expmax, w16_newmax; |
| 99 | int16_t w16_tmp, w16_tmp2; |
| 100 | int32_t w32_tmp; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 101 | #ifdef SCRATCH |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 102 | int16_t *pw16_expanded = pw16_scratchPtr + SCRATCH_pw16_expanded; |
| 103 | int16_t *pw16_expandedLB = pw16_scratchPtr + SCRATCH_pw16_expandedLB; |
| 104 | int16_t *pw16_decodedLB = pw16_scratchPtr + SCRATCH_pw16_decodedLB; |
| 105 | int32_t *pw32_corr = (int32_t*) (pw16_scratchPtr + SCRATCH_pw32_corr); |
| 106 | int16_t *pw16_corrVec = pw16_scratchPtr + SCRATCH_pw16_corrVec; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 107 | #else |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 108 | int16_t pw16_expanded[(125+80+5)*FSMULT]; |
| 109 | int16_t pw16_expandedLB[100]; |
| 110 | int16_t pw16_decodedLB[40]; |
| 111 | int32_t pw32_corr[60]; |
| 112 | int16_t pw16_corrVec[4+60+4]; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 113 | #endif |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 114 | int16_t *pw16_corr = &pw16_corrVec[4]; |
| 115 | int16_t w16_stopPos = 0, w16_bestIndex, w16_interpLen; |
| 116 | int16_t w16_bestVal; /* bestVal is dummy */ |
| 117 | int16_t w16_startfact, w16_inc; |
| 118 | int16_t w16_expandedLen; |
| 119 | int16_t w16_startPos; |
| 120 | int16_t w16_expLen, w16_newLen = 0; |
| 121 | int16_t *pw16_decodedOut; |
| 122 | int16_t w16_muted; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 123 | |
| 124 | int w16_decodedLen = len; |
| 125 | |
| 126 | #ifdef NETEQ_STEREO |
| 127 | MasterSlaveInfo *msInfo = inst->msInfo; |
| 128 | #endif |
| 129 | |
| 130 | fs_mult = WebRtcSpl_DivW32W16ResW16(inst->fs, 8000); |
| 131 | fs_shift = 30 - WebRtcSpl_NormW32(fs_mult); /* Note that this is not "exact" for 48kHz */ |
| 132 | |
| 133 | /************************************* |
| 134 | * Generate data to merge with |
| 135 | *************************************/ |
| 136 | /* |
| 137 | * Check how much data that is left since earlier |
| 138 | * (at least there should be the overlap)... |
| 139 | */ |
| 140 | w16_startPos = inst->endPosition - inst->curPosition; |
| 141 | /* Get one extra expansion to merge and overlap with */ |
| 142 | inst->ExpandInst.w16_stopMuting = 1; |
| 143 | inst->ExpandInst.w16_lagsDirection = 1; /* make sure we get the "optimal" lag */ |
| 144 | inst->ExpandInst.w16_lagsPosition = -1; /* out of the 3 possible ones */ |
| 145 | w16_expandedLen = 0; /* Does not fill any function currently */ |
| 146 | |
| 147 | if (w16_startPos >= 210 * FSMULT) |
| 148 | { |
| 149 | /* |
| 150 | * The number of samples available in the sync buffer is more than what fits in |
| 151 | * pw16_expanded.Keep the first 210*FSMULT samples, but shift them towards the end of |
| 152 | * the buffer. This is ok, since all of the buffer will be expand data anyway, so as |
| 153 | * long as the beginning is left untouched, we're fine. |
| 154 | */ |
| 155 | |
| 156 | w16_tmp = w16_startPos - 210 * FSMULT; /* length difference */ |
| 157 | |
| 158 | WEBRTC_SPL_MEMMOVE_W16(&inst->speechBuffer[inst->curPosition+w16_tmp] , |
| 159 | &inst->speechBuffer[inst->curPosition], 210*FSMULT); |
| 160 | |
| 161 | inst->curPosition += w16_tmp; /* move start position of sync buffer accordingly */ |
| 162 | w16_startPos = 210 * FSMULT; /* this is the truncated length */ |
| 163 | } |
| 164 | |
| 165 | WebRtcNetEQ_Expand(inst, |
| 166 | #ifdef SCRATCH |
| 167 | pw16_scratchPtr + SCRATCH_NETEQ_EXPAND, |
| 168 | #endif |
| 169 | pw16_expanded, /* let Expand write to beginning of pw16_expanded to avoid overflow */ |
| 170 | &w16_newLen, 0); |
| 171 | |
| 172 | /* |
| 173 | * Now shift the data in pw16_expanded to where it belongs. |
| 174 | * Truncate all that ends up outside the vector. |
| 175 | */ |
| 176 | |
| 177 | WEBRTC_SPL_MEMMOVE_W16(&pw16_expanded[w16_startPos], pw16_expanded, |
| 178 | WEBRTC_SPL_MIN(w16_newLen, |
| 179 | WEBRTC_SPL_MAX(210*FSMULT - w16_startPos, 0) ) ); |
| 180 | |
| 181 | inst->ExpandInst.w16_stopMuting = 0; |
| 182 | |
| 183 | /* Copy what is left since earlier into the expanded vector */ |
| 184 | |
| 185 | WEBRTC_SPL_MEMCPY_W16(pw16_expanded, &inst->speechBuffer[inst->curPosition], w16_startPos); |
| 186 | |
| 187 | /* |
| 188 | * Do "ugly" copy and paste from the expanded in order to generate more data |
| 189 | * to correlate (but not interpolate) with. |
| 190 | */ |
| 191 | w16_expandedLen = (120 + 80 + 2) * fs_mult; |
| 192 | w16_expLen = w16_startPos + w16_newLen; |
| 193 | |
| 194 | if (w16_expLen < w16_expandedLen) |
| 195 | { |
| 196 | while ((w16_expLen + w16_newLen) < w16_expandedLen) |
| 197 | { |
| 198 | WEBRTC_SPL_MEMCPY_W16(&pw16_expanded[w16_expLen], &pw16_expanded[w16_startPos], |
| 199 | w16_newLen); |
| 200 | w16_expLen += w16_newLen; |
| 201 | } |
| 202 | |
| 203 | /* Copy last part (fraction of a whole expansion) */ |
| 204 | |
| 205 | WEBRTC_SPL_MEMCPY_W16(&pw16_expanded[w16_expLen], &pw16_expanded[w16_startPos], |
| 206 | (w16_expandedLen-w16_expLen)); |
| 207 | } |
| 208 | w16_expLen = w16_expandedLen; |
| 209 | |
| 210 | /* Adjust muting factor (main muting factor times expand muting factor) */ |
| 211 | inst->w16_muteFactor |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 212 | = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(inst->w16_muteFactor, |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 213 | inst->ExpandInst.w16_expandMuteFactor, 14); |
| 214 | |
| 215 | /* Adjust muting factor if new vector is more or less of the BGN energy */ |
| 216 | len = WEBRTC_SPL_MIN(64*fs_mult, w16_decodedLen); |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 217 | w16_expmax = WebRtcSpl_MaxAbsValueW16(pw16_expanded, (int16_t) len); |
| 218 | w16_newmax = WebRtcSpl_MaxAbsValueW16(pw16_decoded, (int16_t) len); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 219 | |
| 220 | /* Calculate energy of old data */ |
| 221 | w16_tmp = 6 + fs_shift - WebRtcSpl_NormW32(WEBRTC_SPL_MUL_16_16(w16_expmax, w16_expmax)); |
| 222 | w16_tmp = WEBRTC_SPL_MAX(w16_tmp,0); |
| 223 | w32_En_old_frame = WebRtcNetEQ_DotW16W16(pw16_expanded, pw16_expanded, len, w16_tmp); |
| 224 | |
| 225 | /* Calculate energy of new data */ |
| 226 | w16_tmp2 = 6 + fs_shift - WebRtcSpl_NormW32(WEBRTC_SPL_MUL_16_16(w16_newmax, w16_newmax)); |
| 227 | w16_tmp2 = WEBRTC_SPL_MAX(w16_tmp2,0); |
| 228 | w32_En_new_frame = WebRtcNetEQ_DotW16W16(pw16_decoded, pw16_decoded, len, w16_tmp2); |
| 229 | |
| 230 | /* Align to same Q-domain */ |
| 231 | if (w16_tmp2 > w16_tmp) |
| 232 | { |
| 233 | w32_En_old_frame = WEBRTC_SPL_RSHIFT_W32(w32_En_old_frame, (w16_tmp2-w16_tmp)); |
| 234 | } |
| 235 | else |
| 236 | { |
| 237 | w32_En_new_frame = WEBRTC_SPL_RSHIFT_W32(w32_En_new_frame, (w16_tmp-w16_tmp2)); |
| 238 | } |
| 239 | |
| 240 | /* Calculate muting factor to use for new frame */ |
| 241 | if (w32_En_new_frame > w32_En_old_frame) |
| 242 | { |
| 243 | /* Normalize w32_En_new_frame to 14 bits */ |
| 244 | w16_tmp = WebRtcSpl_NormW32(w32_En_new_frame) - 17; |
| 245 | w32_En_new_frame = WEBRTC_SPL_SHIFT_W32(w32_En_new_frame, w16_tmp); |
| 246 | |
| 247 | /* |
| 248 | * Put w32_En_old_frame in a domain 14 higher, so that |
| 249 | * w32_En_old_frame/w32_En_new_frame is in Q14 |
| 250 | */ |
| 251 | w16_tmp = w16_tmp + 14; |
| 252 | w32_En_old_frame = WEBRTC_SPL_SHIFT_W32(w32_En_old_frame, w16_tmp); |
| 253 | w16_tmp |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 254 | = WebRtcSpl_DivW32W16ResW16(w32_En_old_frame, (int16_t) w32_En_new_frame); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 255 | /* Calculate sqrt(w32_En_old_frame/w32_En_new_frame) in Q14 */ |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 256 | w16_muted = (int16_t) WebRtcSpl_SqrtFloor( |
| 257 | WEBRTC_SPL_LSHIFT_W32((int32_t)w16_tmp,14)); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 258 | } |
| 259 | else |
| 260 | { |
| 261 | w16_muted = 16384; /* Set = 1.0 when old frame has higher energy than new */ |
| 262 | } |
| 263 | |
| 264 | /* Set the raise the continued muting factor w16_muted if w16_muteFactor is lower */ |
| 265 | if (w16_muted > inst->w16_muteFactor) |
| 266 | { |
| 267 | inst->w16_muteFactor = WEBRTC_SPL_MIN(w16_muted, 16384); |
| 268 | } |
| 269 | |
| 270 | #ifdef NETEQ_STEREO |
| 271 | |
| 272 | /* Sanity for msInfo */ |
| 273 | if (msInfo == NULL) |
| 274 | { |
| 275 | /* this should not happen here */ |
| 276 | return MASTER_SLAVE_ERROR; |
| 277 | } |
| 278 | |
| 279 | /* do not downsample and calculate correlations for slave instance(s) */ |
| 280 | if ((msInfo->msMode == NETEQ_MASTER) || (msInfo->msMode == NETEQ_MONO)) |
| 281 | { |
| 282 | #endif |
| 283 | |
| 284 | /********************************************* |
| 285 | * Downsample to 4kHz and find best overlap |
| 286 | *********************************************/ |
| 287 | |
| 288 | /* Downsample to 4 kHz */ |
| 289 | if (inst->fs == 8000) |
| 290 | { |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 291 | WebRtcSpl_DownsampleFast(&pw16_expanded[2], (int16_t) (w16_expandedLen - 2), |
| 292 | pw16_expandedLB, (int16_t) (100), |
| 293 | (int16_t*) WebRtcNetEQ_kDownsample8kHzTbl, (int16_t) 3, |
| 294 | (int16_t) 2, (int16_t) 0); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 295 | if (w16_decodedLen <= 80) |
| 296 | { |
| 297 | /* Not quite long enough, so we have to cheat a bit... */ |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 298 | int16_t temp_len = w16_decodedLen - 2; |
henrik.lundin@webrtc.org | 789da89 | 2011-11-25 12:35:31 +0000 | [diff] [blame] | 299 | w16_tmp = temp_len / 2; |
| 300 | WebRtcSpl_DownsampleFast(&pw16_decoded[2], temp_len, |
| 301 | pw16_decodedLB, w16_tmp, |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 302 | (int16_t*) WebRtcNetEQ_kDownsample8kHzTbl, |
| 303 | (int16_t) 3, (int16_t) 2, (int16_t) 0); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 304 | WebRtcSpl_MemSetW16(&pw16_decodedLB[w16_tmp], 0, (40 - w16_tmp)); |
| 305 | } |
| 306 | else |
| 307 | { |
| 308 | WebRtcSpl_DownsampleFast(&pw16_decoded[2], |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 309 | (int16_t) (w16_decodedLen - 2), pw16_decodedLB, |
| 310 | (int16_t) (40), (int16_t*) WebRtcNetEQ_kDownsample8kHzTbl, |
| 311 | (int16_t) 3, (int16_t) 2, (int16_t) 0); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 312 | } |
| 313 | #ifdef NETEQ_WIDEBAND |
| 314 | } |
| 315 | else if (inst->fs==16000) |
| 316 | { |
| 317 | WebRtcSpl_DownsampleFast( |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 318 | &pw16_expanded[4], (int16_t)(w16_expandedLen-4), |
| 319 | pw16_expandedLB, (int16_t)(100), |
| 320 | (int16_t*)WebRtcNetEQ_kDownsample16kHzTbl, (int16_t)5, |
| 321 | (int16_t)4, (int16_t)0); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 322 | if (w16_decodedLen<=160) |
| 323 | { |
| 324 | /* Not quite long enough, so we have to cheat a bit... */ |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 325 | int16_t temp_len = w16_decodedLen - 4; |
henrik.lundin@webrtc.org | 789da89 | 2011-11-25 12:35:31 +0000 | [diff] [blame] | 326 | w16_tmp = temp_len / 4; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 327 | WebRtcSpl_DownsampleFast( |
henrik.lundin@webrtc.org | 789da89 | 2011-11-25 12:35:31 +0000 | [diff] [blame] | 328 | &pw16_decoded[4], temp_len, |
| 329 | pw16_decodedLB, w16_tmp, |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 330 | (int16_t*)WebRtcNetEQ_kDownsample16kHzTbl, (int16_t)5, |
| 331 | (int16_t)4, (int16_t)0); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 332 | WebRtcSpl_MemSetW16(&pw16_decodedLB[w16_tmp], 0, (40-w16_tmp)); |
| 333 | } |
| 334 | else |
| 335 | { |
| 336 | WebRtcSpl_DownsampleFast( |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 337 | &pw16_decoded[4], (int16_t)(w16_decodedLen-4), |
| 338 | pw16_decodedLB, (int16_t)(40), |
| 339 | (int16_t*)WebRtcNetEQ_kDownsample16kHzTbl, (int16_t)5, |
| 340 | (int16_t)4, (int16_t)0); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 341 | } |
| 342 | #endif |
| 343 | #ifdef NETEQ_32KHZ_WIDEBAND |
| 344 | } |
| 345 | else if (inst->fs==32000) |
| 346 | { |
henrik.lundin@webrtc.org | 789da89 | 2011-11-25 12:35:31 +0000 | [diff] [blame] | 347 | /* |
| 348 | * TODO(hlundin) Why is the offset into pw16_expanded 6? |
| 349 | */ |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 350 | WebRtcSpl_DownsampleFast( |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 351 | &pw16_expanded[6], (int16_t)(w16_expandedLen-6), |
| 352 | pw16_expandedLB, (int16_t)(100), |
| 353 | (int16_t*)WebRtcNetEQ_kDownsample32kHzTbl, (int16_t)7, |
| 354 | (int16_t)8, (int16_t)0); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 355 | if (w16_decodedLen<=320) |
| 356 | { |
| 357 | /* Not quite long enough, so we have to cheat a bit... */ |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 358 | int16_t temp_len = w16_decodedLen - 6; |
henrik.lundin@webrtc.org | 789da89 | 2011-11-25 12:35:31 +0000 | [diff] [blame] | 359 | w16_tmp = temp_len / 8; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 360 | WebRtcSpl_DownsampleFast( |
henrik.lundin@webrtc.org | 789da89 | 2011-11-25 12:35:31 +0000 | [diff] [blame] | 361 | &pw16_decoded[6], temp_len, |
| 362 | pw16_decodedLB, w16_tmp, |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 363 | (int16_t*)WebRtcNetEQ_kDownsample32kHzTbl, (int16_t)7, |
| 364 | (int16_t)8, (int16_t)0); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 365 | WebRtcSpl_MemSetW16(&pw16_decodedLB[w16_tmp], 0, (40-w16_tmp)); |
| 366 | } |
| 367 | else |
| 368 | { |
| 369 | WebRtcSpl_DownsampleFast( |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 370 | &pw16_decoded[6], (int16_t)(w16_decodedLen-6), |
| 371 | pw16_decodedLB, (int16_t)(40), |
| 372 | (int16_t*)WebRtcNetEQ_kDownsample32kHzTbl, (int16_t)7, |
| 373 | (int16_t)8, (int16_t)0); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 374 | } |
| 375 | #endif |
| 376 | #ifdef NETEQ_48KHZ_WIDEBAND |
| 377 | } |
| 378 | else /* if (inst->fs==48000) */ |
| 379 | { |
henrik.lundin@webrtc.org | 789da89 | 2011-11-25 12:35:31 +0000 | [diff] [blame] | 380 | /* |
| 381 | * TODO(hlundin) Why is the offset into pw16_expanded 6? |
| 382 | */ |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 383 | WebRtcSpl_DownsampleFast( |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 384 | &pw16_expanded[6], (int16_t)(w16_expandedLen-6), |
| 385 | pw16_expandedLB, (int16_t)(100), |
| 386 | (int16_t*)WebRtcNetEQ_kDownsample48kHzTbl, (int16_t)7, |
| 387 | (int16_t)12, (int16_t)0); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 388 | if (w16_decodedLen<=320) |
| 389 | { |
| 390 | /* Not quite long enough, so we have to cheat a bit... */ |
henrik.lundin@webrtc.org | 789da89 | 2011-11-25 12:35:31 +0000 | [diff] [blame] | 391 | /* |
| 392 | * TODO(hlundin): Is this correct? Downsampling is a factor 12 |
| 393 | * but w16_tmp = temp_len / 8. |
| 394 | * (Was w16_tmp = ((w16_decodedLen-6)>>3) before re-write.) |
| 395 | */ |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 396 | int16_t temp_len = w16_decodedLen - 6; |
henrik.lundin@webrtc.org | 789da89 | 2011-11-25 12:35:31 +0000 | [diff] [blame] | 397 | w16_tmp = temp_len / 8; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 398 | WebRtcSpl_DownsampleFast( |
henrik.lundin@webrtc.org | 789da89 | 2011-11-25 12:35:31 +0000 | [diff] [blame] | 399 | &pw16_decoded[6], temp_len, |
| 400 | pw16_decodedLB, w16_tmp, |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 401 | (int16_t*)WebRtcNetEQ_kDownsample48kHzTbl, (int16_t)7, |
| 402 | (int16_t)12, (int16_t)0); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 403 | WebRtcSpl_MemSetW16(&pw16_decodedLB[w16_tmp], 0, (40-w16_tmp)); |
| 404 | } |
| 405 | else |
| 406 | { |
| 407 | WebRtcSpl_DownsampleFast( |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 408 | &pw16_decoded[6], (int16_t)(w16_decodedLen-6), |
| 409 | pw16_decodedLB, (int16_t)(40), |
| 410 | (int16_t*)WebRtcNetEQ_kDownsample48kHzTbl, (int16_t)7, |
| 411 | (int16_t)12, (int16_t)0); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 412 | } |
| 413 | #endif |
| 414 | } |
| 415 | |
| 416 | /* Calculate correlation without any normalization (40 samples) */ |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 417 | w16_tmp = WebRtcSpl_DivW32W16ResW16((int32_t) inst->ExpandInst.w16_maxLag, |
| 418 | (int16_t) (fs_mult * 2)) + 1; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 419 | w16_stopPos = WEBRTC_SPL_MIN(60, w16_tmp); |
| 420 | w32_tmp = WEBRTC_SPL_MUL_16_16(w16_expmax, w16_newmax); |
| 421 | if (w32_tmp > 26843546) |
| 422 | { |
| 423 | w16_tmp = 3; |
| 424 | } |
| 425 | else |
| 426 | { |
| 427 | w16_tmp = 0; |
| 428 | } |
| 429 | |
| 430 | WebRtcNetEQ_CrossCorr(pw32_corr, pw16_decodedLB, pw16_expandedLB, 40, |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 431 | (int16_t) w16_stopPos, w16_tmp, 1); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 432 | |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 433 | /* Normalize correlation to 14 bits and put in a int16_t vector */ |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 434 | WebRtcSpl_MemSetW16(pw16_corrVec, 0, (4 + 60 + 4)); |
| 435 | w32_tmp = WebRtcSpl_MaxAbsValueW32(pw32_corr, w16_stopPos); |
| 436 | w16_tmp = 17 - WebRtcSpl_NormW32(w32_tmp); |
| 437 | w16_tmp = WEBRTC_SPL_MAX(0, w16_tmp); |
| 438 | |
| 439 | WebRtcSpl_VectorBitShiftW32ToW16(pw16_corr, w16_stopPos, pw32_corr, w16_tmp); |
| 440 | |
| 441 | /* Calculate allowed starting point for peak finding. |
| 442 | The peak location bestIndex must fulfill two criteria: |
| 443 | (1) w16_bestIndex+w16_decodedLen < inst->timestampsPerCall+inst->ExpandInst.w16_overlap |
| 444 | (2) w16_bestIndex+w16_decodedLen < w16_startPos */ |
| 445 | w16_tmp = WEBRTC_SPL_MAX(0, WEBRTC_SPL_MAX(w16_startPos, |
| 446 | inst->timestampsPerCall+inst->ExpandInst.w16_overlap) - w16_decodedLen); |
| 447 | /* Downscale starting index to 4kHz domain */ |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 448 | w16_tmp2 = WebRtcSpl_DivW32W16ResW16((int32_t) w16_tmp, |
| 449 | (int16_t) (fs_mult << 1)); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 450 | |
| 451 | #ifdef NETEQ_STEREO |
| 452 | } /* end if (msInfo->msMode != NETEQ_SLAVE) */ |
| 453 | |
| 454 | if ((msInfo->msMode == NETEQ_MASTER) || (msInfo->msMode == NETEQ_MONO)) |
| 455 | { |
| 456 | /* This is master or mono instance; find peak */ |
| 457 | WebRtcNetEQ_PeakDetection(&pw16_corr[w16_tmp2], w16_stopPos, 1, fs_mult, &w16_bestIndex, |
| 458 | &w16_bestVal); |
| 459 | w16_bestIndex += w16_tmp; /* compensate for modified starting index */ |
| 460 | msInfo->bestIndex = w16_bestIndex; |
| 461 | } |
| 462 | else if (msInfo->msMode == NETEQ_SLAVE) |
| 463 | { |
| 464 | /* Get peak location from master instance */ |
| 465 | w16_bestIndex = msInfo->bestIndex; |
| 466 | } |
| 467 | else |
| 468 | { |
| 469 | /* Invalid mode */ |
| 470 | return MASTER_SLAVE_ERROR; |
| 471 | } |
| 472 | |
| 473 | #else /* NETEQ_STEREO */ |
| 474 | |
| 475 | /* Find peak */ |
| 476 | WebRtcNetEQ_PeakDetection(&pw16_corr[w16_tmp2], w16_stopPos, 1, fs_mult, &w16_bestIndex, |
| 477 | &w16_bestVal); |
| 478 | w16_bestIndex += w16_tmp; /* compensate for modified starting index */ |
| 479 | |
| 480 | #endif /* NETEQ_STEREO */ |
| 481 | |
| 482 | /* |
| 483 | * Ensure that underrun does not occur for 10ms case => we have to get at least |
| 484 | * 10ms + overlap . (This should never happen thanks to the above modification of |
| 485 | * peak-finding starting point.) |
| 486 | * */ |
| 487 | while ((w16_bestIndex + w16_decodedLen) < (inst->timestampsPerCall |
| 488 | + inst->ExpandInst.w16_overlap) || w16_bestIndex + w16_decodedLen < w16_startPos) |
| 489 | { |
| 490 | w16_bestIndex += w16_newLen; /* Jump one lag ahead */ |
| 491 | } |
| 492 | pw16_decodedOut = pw16_outData + w16_bestIndex; |
| 493 | |
| 494 | /* Mute the new decoded data if needed (and unmute it linearly) */ |
| 495 | w16_interpLen = WEBRTC_SPL_MIN(60*fs_mult, |
| 496 | w16_expandedLen-w16_bestIndex); /* this is the overlapping part of pw16_expanded */ |
| 497 | w16_interpLen = WEBRTC_SPL_MIN(w16_interpLen, w16_decodedLen); |
| 498 | w16_inc = WebRtcSpl_DivW32W16ResW16(4194, |
| 499 | fs_mult); /* in Q20, 0.004 for NB and 0.002 for WB */ |
| 500 | if (inst->w16_muteFactor < 16384) |
| 501 | { |
| 502 | WebRtcNetEQ_UnmuteSignal(pw16_decoded, &inst->w16_muteFactor, pw16_decoded, w16_inc, |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 503 | (int16_t) w16_interpLen); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 504 | WebRtcNetEQ_UnmuteSignal(&pw16_decoded[w16_interpLen], &inst->w16_muteFactor, |
| 505 | &pw16_decodedOut[w16_interpLen], w16_inc, |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 506 | (int16_t) (w16_decodedLen - w16_interpLen)); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 507 | } |
| 508 | else |
| 509 | { |
| 510 | /* No muting needed */ |
| 511 | |
| 512 | WEBRTC_SPL_MEMMOVE_W16(&pw16_decodedOut[w16_interpLen], &pw16_decoded[w16_interpLen], |
| 513 | (w16_decodedLen-w16_interpLen)); |
| 514 | } |
| 515 | |
| 516 | /* Do overlap and interpolate linearly */ |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 517 | w16_inc = WebRtcSpl_DivW32W16ResW16(16384, (int16_t) (w16_interpLen + 1)); /* Q14 */ |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 518 | w16_startfact = (16384 - w16_inc); |
| 519 | WEBRTC_SPL_MEMMOVE_W16(pw16_outData, pw16_expanded, w16_bestIndex); |
| 520 | WebRtcNetEQ_MixVoiceUnvoice(pw16_decodedOut, &pw16_expanded[w16_bestIndex], pw16_decoded, |
| 521 | &w16_startfact, w16_inc, w16_interpLen); |
| 522 | |
| 523 | inst->w16_mode = MODE_MERGE; |
| 524 | inst->ExpandInst.w16_consecExp = 0; /* Last was not expand any more */ |
| 525 | |
| 526 | /* New added length (w16_startPos samples were borrowed) */ |
| 527 | *pw16_len = w16_bestIndex + w16_decodedLen - w16_startPos; |
| 528 | |
| 529 | /* Update VQmon parameter */ |
| 530 | inst->w16_concealedTS += (*pw16_len - w16_decodedLen); |
| 531 | inst->w16_concealedTS = WEBRTC_SPL_MAX(0, inst->w16_concealedTS); |
| 532 | |
| 533 | /* Update in-call and post-call statistics */ |
| 534 | if (inst->ExpandInst.w16_expandMuteFactor == 0) |
| 535 | { |
| 536 | /* expansion generates noise only */ |
| 537 | inst->statInst.expandedNoiseSamples += (*pw16_len - w16_decodedLen); |
turaj@webrtc.org | 92d1f07 | 2013-04-15 16:52:04 +0000 | [diff] [blame^] | 538 | /* Short-term activity statistics. */ |
| 539 | inst->activity_stats.merge_expand_bgn_samples += |
| 540 | (*pw16_len - w16_decodedLen); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 541 | } |
| 542 | else |
| 543 | { |
| 544 | /* expansion generates more than only noise */ |
| 545 | inst->statInst.expandedVoiceSamples += (*pw16_len - w16_decodedLen); |
turaj@webrtc.org | 92d1f07 | 2013-04-15 16:52:04 +0000 | [diff] [blame^] | 546 | /* Short-term activity statistics. */ |
| 547 | inst->activity_stats.merge_expand_normal_samples += |
| 548 | (*pw16_len - w16_decodedLen); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 549 | } |
| 550 | inst->statInst.expandLength += (*pw16_len - w16_decodedLen); |
| 551 | |
| 552 | |
| 553 | /* Copy back the first part of the data to the speechHistory */ |
| 554 | |
| 555 | WEBRTC_SPL_MEMCPY_W16(&inst->speechBuffer[inst->curPosition], pw16_outData, w16_startPos); |
| 556 | |
| 557 | |
| 558 | /* Move data to within outData */ |
| 559 | |
| 560 | WEBRTC_SPL_MEMMOVE_W16(pw16_outData, &pw16_outData[w16_startPos], (*pw16_len)); |
| 561 | |
| 562 | return 0; |
| 563 | } |
| 564 | |
| 565 | #undef SCRATCH_pw16_expanded |
| 566 | #undef SCRATCH_pw16_expandedLB |
| 567 | #undef SCRATCH_pw16_decodedLB |
| 568 | #undef SCRATCH_pw32_corr |
| 569 | #undef SCRATCH_pw16_corrVec |
| 570 | #undef SCRATCH_NETEQ_EXPAND |