1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/*
2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *
4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Use of this source code is governed by a BSD-style license
5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  that can be found in the LICENSE file in the root of the source
6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  tree. An additional intellectual property rights grant can be found
7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  in the file PATENTS.  All contributing project authors may
8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */
10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
112f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org/* Resamples a signal to an arbitrary rate. Used by the AEC to compensate for
12127d8ad377534ca58125bf65ffaf843f73ac36a5andrew@webrtc.org * clock skew by resampling the farend signal.
13b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */
14b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
159fb16139d917ba32720e031d3c871987d418668fpbos@webrtc.org#include "webrtc/modules/audio_processing/aec/aec_resampler.h"
16b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
17b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <assert.h>
189fb16139d917ba32720e031d3c871987d418668fpbos@webrtc.org#include <math.h>
19b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <stdlib.h>
20b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <string.h>
21b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
229fb16139d917ba32720e031d3c871987d418668fpbos@webrtc.org#include "webrtc/modules/audio_processing/aec/aec_core.h"
23b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
242f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.orgenum {
252f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  kEstimateLengthFrames = 400
262f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org};
27b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
28b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgtypedef struct {
2938a0cee9789409eebadb54bcf055a29b61767118kwiberg@webrtc.org  float buffer[kResamplerBufferSize];
302f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  float position;
31b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
322f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  int deviceSampleRateHz;
332f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  int skewData[kEstimateLengthFrames];
342f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  int skewDataIndex;
352f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  float skewEstimate;
36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} resampler_t;
37b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
38b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgstatic int EstimateSkew(const int* rawSkew,
39b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        int size,
40b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        int absLimit,
412f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org                        float* skewEst);
422f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org
432f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.orgint WebRtcAec_CreateResampler(void** resampInst) {
442f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  resampler_t* obj = malloc(sizeof(resampler_t));
452f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  *resampInst = obj;
462f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  if (obj == NULL) {
472f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org    return -1;
482f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  }
49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
502f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  return 0;
51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
532f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.orgint WebRtcAec_InitResampler(void* resampInst, int deviceSampleRateHz) {
542f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  resampler_t* obj = (resampler_t*)resampInst;
552f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  memset(obj->buffer, 0, sizeof(obj->buffer));
562f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  obj->position = 0.0;
57b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
582f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  obj->deviceSampleRateHz = deviceSampleRateHz;
592f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  memset(obj->skewData, 0, sizeof(obj->skewData));
602f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  obj->skewDataIndex = 0;
612f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  obj->skewEstimate = 0.0;
62b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
632f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  return 0;
64b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
65b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
662f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.orgint WebRtcAec_FreeResampler(void* resampInst) {
672f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  resampler_t* obj = (resampler_t*)resampInst;
682f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  free(obj);
69b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
702f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  return 0;
71b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
72b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
732f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.orgvoid WebRtcAec_ResampleLinear(void* resampInst,
7438a0cee9789409eebadb54bcf055a29b61767118kwiberg@webrtc.org                              const float* inspeech,
75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                              int size,
76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                              float skew,
7738a0cee9789409eebadb54bcf055a29b61767118kwiberg@webrtc.org                              float* outspeech,
782f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org                              int* size_out) {
792f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  resampler_t* obj = (resampler_t*)resampInst;
80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
8138a0cee9789409eebadb54bcf055a29b61767118kwiberg@webrtc.org  float* y;
8238a0cee9789409eebadb54bcf055a29b61767118kwiberg@webrtc.org  float be, tnew;
832f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  int tn, mm;
84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
852f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  assert(!(size < 0 || size > 2 * FRAME_LEN));
862f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  assert(resampInst != NULL);
872f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  assert(inspeech != NULL);
882f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  assert(outspeech != NULL);
892f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  assert(size_out != NULL);
90b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
912f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  // Add new frame data in lookahead
922f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  memcpy(&obj->buffer[FRAME_LEN + kResamplingDelay],
932f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org         inspeech,
9438a0cee9789409eebadb54bcf055a29b61767118kwiberg@webrtc.org         size * sizeof(inspeech[0]));
95b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
962f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  // Sample rate ratio
972f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  be = 1 + skew;
98b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
992f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  // Loop over input frame
1002f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  mm = 0;
1012f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  y = &obj->buffer[FRAME_LEN];  // Point at current frame
102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1032f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  tnew = be * mm + obj->position;
1042f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  tn = (int)tnew;
105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1062f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  while (tn < size) {
107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1082f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org    // Interpolation
10938a0cee9789409eebadb54bcf055a29b61767118kwiberg@webrtc.org    outspeech[mm] = y[tn] + (tnew - tn) * (y[tn + 1] - y[tn]);
1102f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org    mm++;
111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1122f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org    tnew = be * mm + obj->position;
1132f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org    tn = (int)tnew;
1142f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  }
115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1162f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  *size_out = mm;
1172f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  obj->position += (*size_out) * be - size;
118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1192f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  // Shift buffer
1202f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  memmove(obj->buffer,
1212f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org          &obj->buffer[size],
12238a0cee9789409eebadb54bcf055a29b61767118kwiberg@webrtc.org          (kResamplerBufferSize - size) * sizeof(obj->buffer[0]));
1232f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org}
124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1252f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.orgint WebRtcAec_GetSkew(void* resampInst, int rawSkew, float* skewEst) {
1262f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  resampler_t* obj = (resampler_t*)resampInst;
1272f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  int err = 0;
1282f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org
1292f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  if (obj->skewDataIndex < kEstimateLengthFrames) {
1302f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org    obj->skewData[obj->skewDataIndex] = rawSkew;
1312f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org    obj->skewDataIndex++;
1322f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  } else if (obj->skewDataIndex == kEstimateLengthFrames) {
1332f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org    err = EstimateSkew(
1342f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org        obj->skewData, kEstimateLengthFrames, obj->deviceSampleRateHz, skewEst);
1352f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org    obj->skewEstimate = *skewEst;
1362f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org    obj->skewDataIndex++;
1372f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  } else {
1382f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org    *skewEst = obj->skewEstimate;
1392f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  }
1402f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org
1412f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  return err;
142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EstimateSkew(const int* rawSkew,
145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 int size,
146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 int deviceSampleRateHz,
1472f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org                 float* skewEst) {
1482f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  const int absLimitOuter = (int)(0.04f * deviceSampleRateHz);
1492f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  const int absLimitInner = (int)(0.0025f * deviceSampleRateHz);
1502f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  int i = 0;
1512f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  int n = 0;
1522f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  float rawAvg = 0;
1532f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  float err = 0;
1542f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  float rawAbsDev = 0;
1552f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  int upperLimit = 0;
1562f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  int lowerLimit = 0;
1572f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  float cumSum = 0;
1582f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  float x = 0;
1592f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  float x2 = 0;
1602f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  float y = 0;
1612f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  float xy = 0;
1622f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  float xAvg = 0;
1632f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  float denom = 0;
1642f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  float skew = 0;
1652f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org
1662f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  *skewEst = 0;  // Set in case of error below.
1672f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  for (i = 0; i < size; i++) {
1682f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org    if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
1692f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org      n++;
1702f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org      rawAvg += rawSkew[i];
171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1722f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  }
1732f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org
1742f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  if (n == 0) {
1752f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org    return -1;
1762f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  }
1772f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  assert(n > 0);
1782f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  rawAvg /= n;
1792f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org
1802f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  for (i = 0; i < size; i++) {
1812f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org    if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
1822f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org      err = rawSkew[i] - rawAvg;
1832f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org      rawAbsDev += err >= 0 ? err : -err;
184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1852f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  }
1862f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  assert(n > 0);
1872f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  rawAbsDev /= n;
1882f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  upperLimit = (int)(rawAvg + 5 * rawAbsDev + 1);  // +1 for ceiling.
1892f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  lowerLimit = (int)(rawAvg - 5 * rawAbsDev - 1);  // -1 for floor.
1902f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org
1912f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  n = 0;
1922f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  for (i = 0; i < size; i++) {
1932f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org    if ((rawSkew[i] < absLimitInner && rawSkew[i] > -absLimitInner) ||
1942f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org        (rawSkew[i] < upperLimit && rawSkew[i] > lowerLimit)) {
1952f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org      n++;
1962f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org      cumSum += rawSkew[i];
1972f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org      x += n;
1982f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org      x2 += n * n;
1992f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org      y += cumSum;
2002f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org      xy += n * cumSum;
201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
2022f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  }
203b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2042f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  if (n == 0) {
2052f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org    return -1;
2062f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  }
2072f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  assert(n > 0);
2082f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  xAvg = x / n;
2092f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  denom = x2 - xAvg * x;
210b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2112f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  if (denom != 0) {
2122f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org    skew = (xy - xAvg * y) / denom;
2132f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  }
214b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2152f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  *skewEst = skew;
2162f40af3ae55077b771fe301e19750984348d3eafandrew@webrtc.org  return 0;
217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
218