Home | History | Annotate | Download | only in ilbc
      1 /*
      2  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
      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 
     13  iLBC Speech Coder ANSI-C Source Code
     14 
     15  WebRtcIlbcfix_EnhancerInterface.c
     16 
     17 ******************************************************************/
     18 
     19 #include <string.h>
     20 
     21 #include "defines.h"
     22 #include "constants.h"
     23 #include "xcorr_coef.h"
     24 #include "enhancer.h"
     25 #include "hp_output.h"
     26 
     27 
     28 
     29 /*----------------------------------------------------------------*
     30  * interface for enhancer
     31  *---------------------------------------------------------------*/
     32 
     33 int WebRtcIlbcfix_EnhancerInterface( /* (o) Estimated lag in end of in[] */
     34     int16_t *out,     /* (o) enhanced signal */
     35     int16_t *in,      /* (i) unenhanced signal */
     36     iLBC_Dec_Inst_t *iLBCdec_inst /* (i) buffers etc */
     37                                         ){
     38   int iblock;
     39   int lag=20, tlag=20;
     40   int inLen=iLBCdec_inst->blockl+120;
     41   int16_t scale, scale1, plc_blockl;
     42   int16_t *enh_buf, *enh_period;
     43   int32_t tmp1, tmp2, max, new_blocks;
     44   int16_t *enh_bufPtr1;
     45   int i, k;
     46   int16_t EnChange;
     47   int16_t SqrtEnChange;
     48   int16_t inc;
     49   int16_t win;
     50   int16_t *tmpW16ptr;
     51   int16_t startPos;
     52   int16_t *plc_pred;
     53   int16_t *target, *regressor;
     54   int16_t max16;
     55   int shifts;
     56   int32_t ener;
     57   int16_t enerSh;
     58   int16_t corrSh;
     59   int16_t ind, sh;
     60   int16_t start, stop;
     61   /* Stack based */
     62   int16_t totsh[3];
     63   int16_t downsampled[(BLOCKL_MAX+120)>>1]; /* length 180 */
     64   int32_t corr32[50];
     65   int32_t corrmax[3];
     66   int16_t corr16[3];
     67   int16_t en16[3];
     68   int16_t lagmax[3];
     69 
     70   plc_pred = downsampled; /* Reuse memory since plc_pred[ENH_BLOCKL] and
     71                               downsampled are non overlapping */
     72   enh_buf=iLBCdec_inst->enh_buf;
     73   enh_period=iLBCdec_inst->enh_period;
     74 
     75   /* Copy in the new data into the enhancer buffer */
     76   memmove(enh_buf, &enh_buf[iLBCdec_inst->blockl],
     77           (ENH_BUFL - iLBCdec_inst->blockl) * sizeof(*enh_buf));
     78 
     79   WEBRTC_SPL_MEMCPY_W16(&enh_buf[ENH_BUFL-iLBCdec_inst->blockl], in,
     80                         iLBCdec_inst->blockl);
     81 
     82   /* Set variables that are dependent on frame size */
     83   if (iLBCdec_inst->mode==30) {
     84     plc_blockl=ENH_BLOCKL;
     85     new_blocks=3;
     86     startPos=320;  /* Start position for enhancement
     87                      (640-new_blocks*ENH_BLOCKL-80) */
     88   } else {
     89     plc_blockl=40;
     90     new_blocks=2;
     91     startPos=440;  /* Start position for enhancement
     92                     (640-new_blocks*ENH_BLOCKL-40) */
     93   }
     94 
     95   /* Update the pitch prediction for each enhancer block, move the old ones */
     96   memmove(enh_period, &enh_period[new_blocks],
     97           (ENH_NBLOCKS_TOT - new_blocks) * sizeof(*enh_period));
     98 
     99   k=WebRtcSpl_DownsampleFast(
    100       enh_buf+ENH_BUFL-inLen,    /* Input samples */
    101       (int16_t)(inLen+ENH_BUFL_FILTEROVERHEAD),
    102       downsampled,
    103       (int16_t)WEBRTC_SPL_RSHIFT_W16(inLen, 1),
    104       (int16_t*)WebRtcIlbcfix_kLpFiltCoefs,  /* Coefficients in Q12 */
    105       FILTERORDER_DS_PLUS1,    /* Length of filter (order-1) */
    106       FACTOR_DS,
    107       DELAY_DS);
    108 
    109   /* Estimate the pitch in the down sampled domain. */
    110   for(iblock = 0; iblock<new_blocks; iblock++){
    111 
    112     /* references */
    113     i=60+WEBRTC_SPL_MUL_16_16(iblock,ENH_BLOCKL_HALF);
    114     target=downsampled+i;
    115     regressor=downsampled+i-10;
    116 
    117     /* scaling */
    118     max16=WebRtcSpl_MaxAbsValueW16(&regressor[-50],
    119                                    (int16_t)(ENH_BLOCKL_HALF+50-1));
    120     shifts = WebRtcSpl_GetSizeInBits(WEBRTC_SPL_MUL_16_16(max16, max16)) - 25;
    121     shifts = WEBRTC_SPL_MAX(0, shifts);
    122 
    123     /* compute cross correlation */
    124     WebRtcSpl_CrossCorrelation(corr32, target, regressor,
    125                                ENH_BLOCKL_HALF, 50, (int16_t)shifts, -1);
    126 
    127     /* Find 3 highest correlations that should be compared for the
    128        highest (corr*corr)/ener */
    129 
    130     for (i=0;i<2;i++) {
    131       lagmax[i] = WebRtcSpl_MaxIndexW32(corr32, 50);
    132       corrmax[i] = corr32[lagmax[i]];
    133       start = lagmax[i] - 2;
    134       stop = lagmax[i] + 2;
    135       start = WEBRTC_SPL_MAX(0,  start);
    136       stop  = WEBRTC_SPL_MIN(49, stop);
    137       for (k=start; k<=stop; k++) {
    138         corr32[k] = 0;
    139       }
    140     }
    141     lagmax[2] = WebRtcSpl_MaxIndexW32(corr32, 50);
    142     corrmax[2] = corr32[lagmax[2]];
    143 
    144     /* Calculate normalized corr^2 and ener */
    145     for (i=0;i<3;i++) {
    146       corrSh = 15-WebRtcSpl_GetSizeInBits(corrmax[i]);
    147       ener = WebRtcSpl_DotProductWithScale(&regressor[-lagmax[i]],
    148                                            &regressor[-lagmax[i]],
    149                                            ENH_BLOCKL_HALF, shifts);
    150       enerSh = 15-WebRtcSpl_GetSizeInBits(ener);
    151       corr16[i] = (int16_t)WEBRTC_SPL_SHIFT_W32(corrmax[i], corrSh);
    152       corr16[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(corr16[i],
    153                                                            corr16[i], 16);
    154       en16[i] = (int16_t)WEBRTC_SPL_SHIFT_W32(ener, enerSh);
    155       totsh[i] = enerSh - WEBRTC_SPL_LSHIFT_W32(corrSh, 1);
    156     }
    157 
    158     /* Compare lagmax[0..3] for the (corr^2)/ener criteria */
    159     ind = 0;
    160     for (i=1; i<3; i++) {
    161       if (totsh[ind] > totsh[i]) {
    162         sh = WEBRTC_SPL_MIN(31, totsh[ind]-totsh[i]);
    163         if ( WEBRTC_SPL_MUL_16_16(corr16[ind], en16[i]) <
    164             WEBRTC_SPL_MUL_16_16_RSFT(corr16[i], en16[ind], sh)) {
    165           ind = i;
    166         }
    167       } else {
    168         sh = WEBRTC_SPL_MIN(31, totsh[i]-totsh[ind]);
    169         if (WEBRTC_SPL_MUL_16_16_RSFT(corr16[ind], en16[i], sh) <
    170             WEBRTC_SPL_MUL_16_16(corr16[i], en16[ind])) {
    171           ind = i;
    172         }
    173       }
    174     }
    175 
    176     lag = lagmax[ind] + 10;
    177 
    178     /* Store the estimated lag in the non-downsampled domain */
    179     enh_period[ENH_NBLOCKS_TOT-new_blocks+iblock] =
    180         (int16_t)WEBRTC_SPL_MUL_16_16(lag, 8);
    181 
    182     /* Store the estimated lag for backward PLC */
    183     if (iLBCdec_inst->prev_enh_pl==1) {
    184       if (!iblock) {
    185         tlag = WEBRTC_SPL_MUL_16_16(lag, 2);
    186       }
    187     } else {
    188       if (iblock==1) {
    189         tlag = WEBRTC_SPL_MUL_16_16(lag, 2);
    190       }
    191     }
    192 
    193     lag = WEBRTC_SPL_MUL_16_16(lag, 2);
    194   }
    195 
    196   if ((iLBCdec_inst->prev_enh_pl==1)||(iLBCdec_inst->prev_enh_pl==2)) {
    197 
    198     /* Calculate the best lag of the new frame
    199        This is used to interpolate backwards and mix with the PLC'd data
    200     */
    201 
    202     /* references */
    203     target=in;
    204     regressor=in+tlag-1;
    205 
    206     /* scaling */
    207     max16=WebRtcSpl_MaxAbsValueW16(regressor, (int16_t)(plc_blockl+3-1));
    208     if (max16>5000)
    209       shifts=2;
    210     else
    211       shifts=0;
    212 
    213     /* compute cross correlation */
    214     WebRtcSpl_CrossCorrelation(corr32, target, regressor,
    215                                plc_blockl, 3, (int16_t)shifts, 1);
    216 
    217     /* find lag */
    218     lag=WebRtcSpl_MaxIndexW32(corr32, 3);
    219     lag+=tlag-1;
    220 
    221     /* Copy the backward PLC to plc_pred */
    222 
    223     if (iLBCdec_inst->prev_enh_pl==1) {
    224       if (lag>plc_blockl) {
    225         WEBRTC_SPL_MEMCPY_W16(plc_pred, &in[lag-plc_blockl], plc_blockl);
    226       } else {
    227         WEBRTC_SPL_MEMCPY_W16(&plc_pred[plc_blockl-lag], in, lag);
    228         WEBRTC_SPL_MEMCPY_W16(
    229             plc_pred, &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl+lag],
    230             (plc_blockl-lag));
    231       }
    232     } else {
    233       int pos;
    234 
    235       pos = plc_blockl;
    236 
    237       while (lag<pos) {
    238         WEBRTC_SPL_MEMCPY_W16(&plc_pred[pos-lag], in, lag);
    239         pos = pos - lag;
    240       }
    241       WEBRTC_SPL_MEMCPY_W16(plc_pred, &in[lag-pos], pos);
    242 
    243     }
    244 
    245     if (iLBCdec_inst->prev_enh_pl==1) {
    246       /* limit energy change
    247          if energy in backward PLC is more than 4 times higher than the forward
    248          PLC, then reduce the energy in the backward PLC vector:
    249          sample 1...len-16 set energy of the to 4 times forward PLC
    250          sample len-15..len interpolate between 4 times fw PLC and bw PLC energy
    251 
    252          Note: Compared to floating point code there is a slight change,
    253          the window is 16 samples long instead of 10 samples to simplify the
    254          calculations
    255       */
    256 
    257       max=WebRtcSpl_MaxAbsValueW16(
    258           &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl], plc_blockl);
    259       max16=WebRtcSpl_MaxAbsValueW16(plc_pred, plc_blockl);
    260       max = WEBRTC_SPL_MAX(max, max16);
    261       scale=22-(int16_t)WebRtcSpl_NormW32(max);
    262       scale=WEBRTC_SPL_MAX(scale,0);
    263 
    264       tmp2 = WebRtcSpl_DotProductWithScale(
    265           &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl],
    266           &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl],
    267           plc_blockl, scale);
    268       tmp1 = WebRtcSpl_DotProductWithScale(plc_pred, plc_pred,
    269                                            plc_blockl, scale);
    270 
    271       /* Check the energy difference */
    272       if ((tmp1>0)&&((tmp1>>2)>tmp2)) {
    273         /* EnChange is now guaranteed to be <0.5
    274            Calculate EnChange=tmp2/tmp1 in Q16
    275         */
    276 
    277         scale1=(int16_t)WebRtcSpl_NormW32(tmp1);
    278         tmp1=WEBRTC_SPL_SHIFT_W32(tmp1, (scale1-16)); /* using 15 bits */
    279 
    280         tmp2=WEBRTC_SPL_SHIFT_W32(tmp2, (scale1));
    281         EnChange = (int16_t)WebRtcSpl_DivW32W16(tmp2,
    282                                                       (int16_t)tmp1);
    283 
    284         /* Calculate the Sqrt of the energy in Q15 ((14+16)/2) */
    285         SqrtEnChange = (int16_t)WebRtcSpl_SqrtFloor(
    286             WEBRTC_SPL_LSHIFT_W32((int32_t)EnChange, 14));
    287 
    288 
    289         /* Multiply first part of vector with 2*SqrtEnChange */
    290         WebRtcSpl_ScaleVector(plc_pred, plc_pred, SqrtEnChange,
    291                               (int16_t)(plc_blockl-16), 14);
    292 
    293         /* Calculate increase parameter for window part (16 last samples) */
    294         /* (1-2*SqrtEnChange)/16 in Q15 */
    295         inc=(2048-WEBRTC_SPL_RSHIFT_W16(SqrtEnChange, 3));
    296 
    297         win=0;
    298         tmpW16ptr=&plc_pred[plc_blockl-16];
    299 
    300         for (i=16;i>0;i--) {
    301           (*tmpW16ptr)=(int16_t)WEBRTC_SPL_MUL_16_16_RSFT(
    302               (*tmpW16ptr), (SqrtEnChange+(win>>1)), 14);
    303           /* multiply by (2.0*SqrtEnChange+win) */
    304 
    305           win += inc;
    306           tmpW16ptr++;
    307         }
    308       }
    309 
    310       /* Make the linear interpolation between the forward PLC'd data
    311          and the backward PLC'd data (from the new frame)
    312       */
    313 
    314       if (plc_blockl==40) {
    315         inc=400; /* 1/41 in Q14 */
    316       } else { /* plc_blockl==80 */
    317         inc=202; /* 1/81 in Q14 */
    318       }
    319       win=0;
    320       enh_bufPtr1=&enh_buf[ENH_BUFL-1-iLBCdec_inst->blockl];
    321       for (i=0; i<plc_blockl; i++) {
    322         win+=inc;
    323         *enh_bufPtr1 =
    324             (int16_t)WEBRTC_SPL_MUL_16_16_RSFT((*enh_bufPtr1), win, 14);
    325         *enh_bufPtr1 += (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(
    326                 (16384-win), plc_pred[plc_blockl-1-i], 14);
    327         enh_bufPtr1--;
    328       }
    329     } else {
    330       int16_t *synt = &downsampled[LPC_FILTERORDER];
    331 
    332       enh_bufPtr1=&enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl];
    333       WEBRTC_SPL_MEMCPY_W16(enh_bufPtr1, plc_pred, plc_blockl);
    334 
    335       /* Clear fileter memory */
    336       WebRtcSpl_MemSetW16(iLBCdec_inst->syntMem, 0, LPC_FILTERORDER);
    337       WebRtcSpl_MemSetW16(iLBCdec_inst->hpimemy, 0, 4);
    338       WebRtcSpl_MemSetW16(iLBCdec_inst->hpimemx, 0, 2);
    339 
    340       /* Initialize filter memory by filtering through 2 lags */
    341       WEBRTC_SPL_MEMCPY_W16(&synt[-LPC_FILTERORDER], iLBCdec_inst->syntMem,
    342                             LPC_FILTERORDER);
    343       WebRtcSpl_FilterARFastQ12(
    344           enh_bufPtr1,
    345           synt,
    346           &iLBCdec_inst->old_syntdenum[
    347                                        (iLBCdec_inst->nsub-1)*(LPC_FILTERORDER+1)],
    348                                        LPC_FILTERORDER+1, (int16_t)lag);
    349 
    350       WEBRTC_SPL_MEMCPY_W16(&synt[-LPC_FILTERORDER], &synt[lag-LPC_FILTERORDER],
    351                             LPC_FILTERORDER);
    352       WebRtcIlbcfix_HpOutput(synt, (int16_t*)WebRtcIlbcfix_kHpOutCoefs,
    353                              iLBCdec_inst->hpimemy, iLBCdec_inst->hpimemx,
    354                              (int16_t)lag);
    355       WebRtcSpl_FilterARFastQ12(
    356           enh_bufPtr1, synt,
    357           &iLBCdec_inst->old_syntdenum[
    358                                        (iLBCdec_inst->nsub-1)*(LPC_FILTERORDER+1)],
    359                                        LPC_FILTERORDER+1, (int16_t)lag);
    360 
    361       WEBRTC_SPL_MEMCPY_W16(iLBCdec_inst->syntMem, &synt[lag-LPC_FILTERORDER],
    362                             LPC_FILTERORDER);
    363       WebRtcIlbcfix_HpOutput(synt, (int16_t*)WebRtcIlbcfix_kHpOutCoefs,
    364                              iLBCdec_inst->hpimemy, iLBCdec_inst->hpimemx,
    365                              (int16_t)lag);
    366     }
    367   }
    368 
    369 
    370   /* Perform enhancement block by block */
    371 
    372   for (iblock = 0; iblock<new_blocks; iblock++) {
    373     WebRtcIlbcfix_Enhancer(out+WEBRTC_SPL_MUL_16_16(iblock, ENH_BLOCKL),
    374                            enh_buf,
    375                            ENH_BUFL,
    376                            (int16_t)(WEBRTC_SPL_MUL_16_16(iblock, ENH_BLOCKL)+startPos),
    377                            enh_period,
    378                            (int16_t*)WebRtcIlbcfix_kEnhPlocs, ENH_NBLOCKS_TOT);
    379   }
    380 
    381   return (lag);
    382 }
    383