aboutsummaryrefslogtreecommitdiff
path: root/webrtc/modules/audio_coding/codecs/ilbc/xcorr_coef.c
blob: eb7f828f2a146f6439405761428e217d5b3f163d (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
/*
 *  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.
 */

/******************************************************************

 iLBC Speech Coder ANSI-C Source Code

 WebRtcIlbcfix_XcorrCoef.c

******************************************************************/

#include "defines.h"

/*----------------------------------------------------------------*
 * cross correlation which finds the optimal lag for the
 * crossCorr*crossCorr/(energy) criteria
 *---------------------------------------------------------------*/

int WebRtcIlbcfix_XcorrCoef(
    int16_t *target,  /* (i) first array */
    int16_t *regressor, /* (i) second array */
    int16_t subl,  /* (i) dimension arrays */
    int16_t searchLen, /* (i) the search lenght */
    int16_t offset,  /* (i) samples offset between arrays */
    int16_t step   /* (i) +1 or -1 */
                            ){
  int k;
  int16_t maxlag;
  int16_t pos;
  int16_t max;
  int16_t crossCorrScale, Energyscale;
  int16_t crossCorrSqMod, crossCorrSqMod_Max;
  int32_t crossCorr, Energy;
  int16_t crossCorrmod, EnergyMod, EnergyMod_Max;
  int16_t *tp, *rp;
  int16_t *rp_beg, *rp_end;
  int16_t totscale, totscale_max;
  int16_t scalediff;
  int32_t newCrit, maxCrit;
  int shifts;

  /* Initializations, to make sure that the first one is selected */
  crossCorrSqMod_Max=0;
  EnergyMod_Max=WEBRTC_SPL_WORD16_MAX;
  totscale_max=-500;
  maxlag=0;
  pos=0;

  /* Find scale value and start position */
  if (step==1) {
    max=WebRtcSpl_MaxAbsValueW16(regressor, (int16_t)(subl+searchLen-1));
    rp_beg = regressor;
    rp_end = &regressor[subl];
  } else { /* step==-1 */
    max=WebRtcSpl_MaxAbsValueW16(&regressor[-searchLen], (int16_t)(subl+searchLen-1));
    rp_beg = &regressor[-1];
    rp_end = &regressor[subl-1];
  }

  /* Introduce a scale factor on the Energy in int32_t in
     order to make sure that the calculation does not
     overflow */

  if (max>5000) {
    shifts=2;
  } else {
    shifts=0;
  }

  /* Calculate the first energy, then do a +/- to get the other energies */
  Energy=WebRtcSpl_DotProductWithScale(regressor, regressor, subl, shifts);

  for (k=0;k<searchLen;k++) {
    tp = target;
    rp = &regressor[pos];

    crossCorr=WebRtcSpl_DotProductWithScale(tp, rp, subl, shifts);

    if ((Energy>0)&&(crossCorr>0)) {

      /* Put cross correlation and energy on 16 bit word */
      crossCorrScale=(int16_t)WebRtcSpl_NormW32(crossCorr)-16;
      crossCorrmod=(int16_t)WEBRTC_SPL_SHIFT_W32(crossCorr, crossCorrScale);
      Energyscale=(int16_t)WebRtcSpl_NormW32(Energy)-16;
      EnergyMod=(int16_t)WEBRTC_SPL_SHIFT_W32(Energy, Energyscale);

      /* Square cross correlation and store upper int16_t */
      crossCorrSqMod=(int16_t)WEBRTC_SPL_MUL_16_16_RSFT(crossCorrmod, crossCorrmod, 16);

      /* Calculate the total number of (dynamic) right shifts that have
         been performed on (crossCorr*crossCorr)/energy
      */
      totscale=Energyscale-(crossCorrScale<<1);

      /* Calculate the shift difference in order to be able to compare the two
         (crossCorr*crossCorr)/energy in the same domain
      */
      scalediff=totscale-totscale_max;
      scalediff=WEBRTC_SPL_MIN(scalediff,31);
      scalediff=WEBRTC_SPL_MAX(scalediff,-31);

      /* Compute the cross multiplication between the old best criteria
         and the new one to be able to compare them without using a
         division */

      if (scalediff<0) {
        newCrit = ((int32_t)crossCorrSqMod*EnergyMod_Max)>>(-scalediff);
        maxCrit = ((int32_t)crossCorrSqMod_Max*EnergyMod);
      } else {
        newCrit = ((int32_t)crossCorrSqMod*EnergyMod_Max);
        maxCrit = ((int32_t)crossCorrSqMod_Max*EnergyMod)>>scalediff;
      }

      /* Store the new lag value if the new criteria is larger
         than previous largest criteria */

      if (newCrit > maxCrit) {
        crossCorrSqMod_Max = crossCorrSqMod;
        EnergyMod_Max = EnergyMod;
        totscale_max = totscale;
        maxlag = k;
      }
    }
    pos+=step;

    /* Do a +/- to get the next energy */
    Energy += step*(WEBRTC_SPL_RSHIFT_W32(
        ((int32_t)(*rp_end)*(*rp_end)) - ((int32_t)(*rp_beg)*(*rp_beg)),
        shifts));
    rp_beg+=step;
    rp_end+=step;
  }

  return(maxlag+offset);
}