summaryrefslogtreecommitdiff
path: root/chromium/third_party/webrtc/modules/audio_coding/neteq/merge.c
blob: 78da2c7c7db40aaf6b4780c35c731ed3a1b62567 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
/*
 *  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 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
 int16_t  pw16_expanded           210*fs/8000     0               209*fs/8000
 int16_t  pw16_expandedLB         100             210*fs/8000     99+210*fs/8000
 int16_t  pw16_decodedLB          40              100+210*fs/8000 139+210*fs/8000
 int32_t  pw32_corr               2*60            140+210*fs/8000 260+210*fs/8000
 int16_t  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
                      int16_t *pw16_scratchPtr,
#endif
                      int16_t *pw16_decoded, int len, int16_t *pw16_outData,
                      int16_t *pw16_len)
{

    int16_t fs_mult;
    int16_t fs_shift;
    int32_t w32_En_new_frame, w32_En_old_frame;
    int16_t w16_expmax, w16_newmax;
    int16_t w16_tmp, w16_tmp2;
    int32_t w32_tmp;
#ifdef SCRATCH
    int16_t *pw16_expanded = pw16_scratchPtr + SCRATCH_pw16_expanded;
    int16_t *pw16_expandedLB = pw16_scratchPtr + SCRATCH_pw16_expandedLB;
    int16_t *pw16_decodedLB = pw16_scratchPtr + SCRATCH_pw16_decodedLB;
    int32_t *pw32_corr = (int32_t*) (pw16_scratchPtr + SCRATCH_pw32_corr);
    int16_t *pw16_corrVec = pw16_scratchPtr + SCRATCH_pw16_corrVec;
#else
    int16_t pw16_expanded[(125+80+5)*FSMULT];
    int16_t pw16_expandedLB[100];
    int16_t pw16_decodedLB[40];
    int32_t pw32_corr[60];
    int16_t pw16_corrVec[4+60+4];
#endif
    int16_t *pw16_corr = &pw16_corrVec[4];
    int16_t w16_stopPos = 0, w16_bestIndex, w16_interpLen;
    int16_t w16_bestVal; /* bestVal is dummy */
    int16_t w16_startfact, w16_inc;
    int16_t w16_expandedLen;
    int16_t w16_startPos;
    int16_t w16_expLen, w16_newLen = 0;
    int16_t *pw16_decodedOut;
    int16_t 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
        = (int16_t) 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, (int16_t) len);
    w16_newmax = WebRtcSpl_MaxAbsValueW16(pw16_decoded, (int16_t) 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, (int16_t) w32_En_new_frame);
        /* Calculate sqrt(w32_En_old_frame/w32_En_new_frame) in Q14 */
        w16_muted = (int16_t) WebRtcSpl_SqrtFloor(
            WEBRTC_SPL_LSHIFT_W32((int32_t)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], (int16_t) (w16_expandedLen - 2),
                pw16_expandedLB, (int16_t) (100),
                (int16_t*) WebRtcNetEQ_kDownsample8kHzTbl, (int16_t) 3,
                (int16_t) 2, (int16_t) 0);
            if (w16_decodedLen <= 80)
            {
                /* Not quite long enough, so we have to cheat a bit... */
                int16_t temp_len = w16_decodedLen - 2;
                w16_tmp = temp_len / 2;
                WebRtcSpl_DownsampleFast(&pw16_decoded[2], temp_len,
                                         pw16_decodedLB, w16_tmp,
                                         (int16_t*) WebRtcNetEQ_kDownsample8kHzTbl,
                    (int16_t) 3, (int16_t) 2, (int16_t) 0);
                WebRtcSpl_MemSetW16(&pw16_decodedLB[w16_tmp], 0, (40 - w16_tmp));
            }
            else
            {
                WebRtcSpl_DownsampleFast(&pw16_decoded[2],
                    (int16_t) (w16_decodedLen - 2), pw16_decodedLB,
                    (int16_t) (40), (int16_t*) WebRtcNetEQ_kDownsample8kHzTbl,
                    (int16_t) 3, (int16_t) 2, (int16_t) 0);
            }
#ifdef NETEQ_WIDEBAND
        }
        else if (inst->fs==16000)
        {
            WebRtcSpl_DownsampleFast(
                &pw16_expanded[4], (int16_t)(w16_expandedLen-4),
                pw16_expandedLB, (int16_t)(100),
                (int16_t*)WebRtcNetEQ_kDownsample16kHzTbl, (int16_t)5,
                (int16_t)4, (int16_t)0);
            if (w16_decodedLen<=160)
            {
                /* Not quite long enough, so we have to cheat a bit... */
                int16_t temp_len = w16_decodedLen - 4;
                w16_tmp = temp_len / 4;
                WebRtcSpl_DownsampleFast(
                    &pw16_decoded[4], temp_len,
                    pw16_decodedLB, w16_tmp,
                    (int16_t*)WebRtcNetEQ_kDownsample16kHzTbl, (int16_t)5,
                    (int16_t)4, (int16_t)0);
                WebRtcSpl_MemSetW16(&pw16_decodedLB[w16_tmp], 0, (40-w16_tmp));
            }
            else
            {
                WebRtcSpl_DownsampleFast(
                    &pw16_decoded[4], (int16_t)(w16_decodedLen-4),
                    pw16_decodedLB, (int16_t)(40),
                    (int16_t*)WebRtcNetEQ_kDownsample16kHzTbl, (int16_t)5,
                    (int16_t)4, (int16_t)0);
            }
#endif
#ifdef NETEQ_32KHZ_WIDEBAND
        }
        else if (inst->fs==32000)
        {
            /*
             * TODO(hlundin) Why is the offset into pw16_expanded 6?
             */
            WebRtcSpl_DownsampleFast(
                &pw16_expanded[6], (int16_t)(w16_expandedLen-6),
                pw16_expandedLB, (int16_t)(100),
                (int16_t*)WebRtcNetEQ_kDownsample32kHzTbl, (int16_t)7,
                (int16_t)8, (int16_t)0);
            if (w16_decodedLen<=320)
            {
                /* Not quite long enough, so we have to cheat a bit... */
                int16_t temp_len = w16_decodedLen - 6;
                w16_tmp = temp_len / 8;
                WebRtcSpl_DownsampleFast(
                      &pw16_decoded[6], temp_len,
                      pw16_decodedLB, w16_tmp,
                      (int16_t*)WebRtcNetEQ_kDownsample32kHzTbl, (int16_t)7,
                      (int16_t)8, (int16_t)0);
                WebRtcSpl_MemSetW16(&pw16_decodedLB[w16_tmp], 0, (40-w16_tmp));
            }
            else
            {
                WebRtcSpl_DownsampleFast(
                    &pw16_decoded[6], (int16_t)(w16_decodedLen-6),
                    pw16_decodedLB, (int16_t)(40),
                    (int16_t*)WebRtcNetEQ_kDownsample32kHzTbl, (int16_t)7,
                    (int16_t)8, (int16_t)0);
            }
#endif
#ifdef NETEQ_48KHZ_WIDEBAND
        }
        else /* if (inst->fs==48000) */
        {
            /*
             * TODO(hlundin) Why is the offset into pw16_expanded 6?
             */
            WebRtcSpl_DownsampleFast(
                &pw16_expanded[6], (int16_t)(w16_expandedLen-6),
                pw16_expandedLB, (int16_t)(100),
                (int16_t*)WebRtcNetEQ_kDownsample48kHzTbl, (int16_t)7,
                (int16_t)12, (int16_t)0);
            if (w16_decodedLen<=320)
            {
                /* Not quite long enough, so we have to cheat a bit... */
                /*
                 * TODO(hlundin): Is this correct? Downsampling is a factor 12
                 * but w16_tmp = temp_len / 8.
                 * (Was w16_tmp = ((w16_decodedLen-6)>>3) before re-write.)
                 */
                int16_t temp_len = w16_decodedLen - 6;
                w16_tmp = temp_len / 8;
                WebRtcSpl_DownsampleFast(
                    &pw16_decoded[6], temp_len,
                    pw16_decodedLB, w16_tmp,
                    (int16_t*)WebRtcNetEQ_kDownsample48kHzTbl, (int16_t)7,
                    (int16_t)12, (int16_t)0);
                WebRtcSpl_MemSetW16(&pw16_decodedLB[w16_tmp], 0, (40-w16_tmp));
            }
            else
            {
                WebRtcSpl_DownsampleFast(
                    &pw16_decoded[6], (int16_t)(w16_decodedLen-6),
                    pw16_decodedLB, (int16_t)(40),
                    (int16_t*)WebRtcNetEQ_kDownsample48kHzTbl, (int16_t)7,
                    (int16_t)12, (int16_t)0);
            }
#endif
        }

        /* Calculate correlation without any normalization (40 samples) */
        w16_tmp = WebRtcSpl_DivW32W16ResW16((int32_t) inst->ExpandInst.w16_maxLag,
            (int16_t) (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,
            (int16_t) w16_stopPos, w16_tmp, 1);

        /* Normalize correlation to 14 bits and put in a int16_t 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((int32_t) w16_tmp,
            (int16_t) (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,
            (int16_t) w16_interpLen);
        WebRtcNetEQ_UnmuteSignal(&pw16_decoded[w16_interpLen], &inst->w16_muteFactor,
            &pw16_decodedOut[w16_interpLen], w16_inc,
            (int16_t) (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, (int16_t) (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);
        /* Short-term activity statistics. */
       inst->activity_stats.merge_expand_bgn_samples +=
            (*pw16_len - w16_decodedLen);
    }
    else
    {
        /* expansion generates more than only noise */
        inst->statInst.expandedVoiceSamples += (*pw16_len - w16_decodedLen);
        /* Short-term activity statistics. */
        inst->activity_stats.merge_expand_normal_samples +=
            (*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