blob: 5382665e10d809ce39ac354a582ced6cd3b3cc90 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
bjornv@webrtc.org281b7982012-05-30 07:41:57 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000011/* Resamples a signal to an arbitrary rate. Used by the AEC to compensate for
andrew@webrtc.org89b1e682013-10-18 14:23:29 +000012 * clock skew by resampling the farend signal.
niklase@google.com470e71d2011-07-07 08:21:25 +000013 */
14
pbos@webrtc.org7fad4b82013-05-28 08:11:59 +000015#include "webrtc/modules/audio_processing/aec/aec_resampler.h"
bjornv@webrtc.org4b80eb42011-11-29 08:44:01 +000016
niklase@google.com470e71d2011-07-07 08:21:25 +000017#include <assert.h>
pbos@webrtc.org7fad4b82013-05-28 08:11:59 +000018#include <math.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000019#include <stdlib.h>
20#include <string.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000021
pbos@webrtc.org7fad4b82013-05-28 08:11:59 +000022#include "webrtc/modules/audio_processing/aec/aec_core.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000023
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000024enum {
25 kEstimateLengthFrames = 400
26};
niklase@google.com470e71d2011-07-07 08:21:25 +000027
28typedef struct {
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000029 short buffer[kResamplerBufferSize];
30 float position;
niklase@google.com470e71d2011-07-07 08:21:25 +000031
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000032 int deviceSampleRateHz;
33 int skewData[kEstimateLengthFrames];
34 int skewDataIndex;
35 float skewEstimate;
niklase@google.com470e71d2011-07-07 08:21:25 +000036} resampler_t;
37
38static int EstimateSkew(const int* rawSkew,
39 int size,
40 int absLimit,
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000041 float* skewEst);
niklase@google.com470e71d2011-07-07 08:21:25 +000042
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000043int WebRtcAec_CreateResampler(void** resampInst) {
44 resampler_t* obj = malloc(sizeof(resampler_t));
45 *resampInst = obj;
46 if (obj == NULL) {
47 return -1;
48 }
niklase@google.com470e71d2011-07-07 08:21:25 +000049
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000050 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000051}
52
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000053int WebRtcAec_InitResampler(void* resampInst, int deviceSampleRateHz) {
54 resampler_t* obj = (resampler_t*)resampInst;
55 memset(obj->buffer, 0, sizeof(obj->buffer));
56 obj->position = 0.0;
niklase@google.com470e71d2011-07-07 08:21:25 +000057
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000058 obj->deviceSampleRateHz = deviceSampleRateHz;
59 memset(obj->skewData, 0, sizeof(obj->skewData));
60 obj->skewDataIndex = 0;
61 obj->skewEstimate = 0.0;
niklase@google.com470e71d2011-07-07 08:21:25 +000062
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000063 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000064}
65
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000066int WebRtcAec_FreeResampler(void* resampInst) {
67 resampler_t* obj = (resampler_t*)resampInst;
68 free(obj);
niklase@google.com470e71d2011-07-07 08:21:25 +000069
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000070 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000071}
72
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000073void WebRtcAec_ResampleLinear(void* resampInst,
74 const short* inspeech,
bjornv@webrtc.org281b7982012-05-30 07:41:57 +000075 int size,
76 float skew,
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000077 short* outspeech,
78 int* size_out) {
79 resampler_t* obj = (resampler_t*)resampInst;
niklase@google.com470e71d2011-07-07 08:21:25 +000080
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000081 short* y;
82 float be, tnew, interp;
83 int tn, mm;
niklase@google.com470e71d2011-07-07 08:21:25 +000084
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000085 assert(!(size < 0 || size > 2 * FRAME_LEN));
86 assert(resampInst != NULL);
87 assert(inspeech != NULL);
88 assert(outspeech != NULL);
89 assert(size_out != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +000090
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000091 // Add new frame data in lookahead
92 memcpy(&obj->buffer[FRAME_LEN + kResamplingDelay],
93 inspeech,
94 size * sizeof(short));
niklase@google.com470e71d2011-07-07 08:21:25 +000095
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000096 // Sample rate ratio
97 be = 1 + skew;
niklase@google.com470e71d2011-07-07 08:21:25 +000098
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000099 // Loop over input frame
100 mm = 0;
101 y = &obj->buffer[FRAME_LEN]; // Point at current frame
102
103 tnew = be * mm + obj->position;
104 tn = (int)tnew;
105
106 while (tn < size) {
107
108 // Interpolation
109 interp = y[tn] + (tnew - tn) * (y[tn + 1] - y[tn]);
110
111 if (interp > 32767) {
112 interp = 32767;
113 } else if (interp < -32768) {
114 interp = -32768;
115 }
116
117 outspeech[mm] = (short)interp;
118 mm++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000119
120 tnew = be * mm + obj->position;
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000121 tn = (int)tnew;
122 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000123
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000124 *size_out = mm;
125 obj->position += (*size_out) * be - size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000126
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000127 // Shift buffer
128 memmove(obj->buffer,
129 &obj->buffer[size],
130 (kResamplerBufferSize - size) * sizeof(short));
niklase@google.com470e71d2011-07-07 08:21:25 +0000131}
132
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000133int WebRtcAec_GetSkew(void* resampInst, int rawSkew, float* skewEst) {
134 resampler_t* obj = (resampler_t*)resampInst;
135 int err = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000136
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000137 if (obj->skewDataIndex < kEstimateLengthFrames) {
138 obj->skewData[obj->skewDataIndex] = rawSkew;
139 obj->skewDataIndex++;
140 } else if (obj->skewDataIndex == kEstimateLengthFrames) {
141 err = EstimateSkew(
142 obj->skewData, kEstimateLengthFrames, obj->deviceSampleRateHz, skewEst);
143 obj->skewEstimate = *skewEst;
144 obj->skewDataIndex++;
145 } else {
146 *skewEst = obj->skewEstimate;
147 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000148
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000149 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000150}
151
152int EstimateSkew(const int* rawSkew,
ajm@google.com75e12392011-07-13 16:35:10 +0000153 int size,
154 int deviceSampleRateHz,
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000155 float* skewEst) {
156 const int absLimitOuter = (int)(0.04f * deviceSampleRateHz);
157 const int absLimitInner = (int)(0.0025f * deviceSampleRateHz);
158 int i = 0;
159 int n = 0;
160 float rawAvg = 0;
161 float err = 0;
162 float rawAbsDev = 0;
163 int upperLimit = 0;
164 int lowerLimit = 0;
165 float cumSum = 0;
166 float x = 0;
167 float x2 = 0;
168 float y = 0;
169 float xy = 0;
170 float xAvg = 0;
171 float denom = 0;
172 float skew = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000173
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000174 *skewEst = 0; // Set in case of error below.
175 for (i = 0; i < size; i++) {
176 if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
177 n++;
178 rawAvg += rawSkew[i];
niklase@google.com470e71d2011-07-07 08:21:25 +0000179 }
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000180 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000181
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000182 if (n == 0) {
183 return -1;
184 }
185 assert(n > 0);
186 rawAvg /= n;
187
188 for (i = 0; i < size; i++) {
189 if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
190 err = rawSkew[i] - rawAvg;
191 rawAbsDev += err >= 0 ? err : -err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000192 }
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000193 }
194 assert(n > 0);
195 rawAbsDev /= n;
196 upperLimit = (int)(rawAvg + 5 * rawAbsDev + 1); // +1 for ceiling.
197 lowerLimit = (int)(rawAvg - 5 * rawAbsDev - 1); // -1 for floor.
niklase@google.com470e71d2011-07-07 08:21:25 +0000198
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000199 n = 0;
200 for (i = 0; i < size; i++) {
201 if ((rawSkew[i] < absLimitInner && rawSkew[i] > -absLimitInner) ||
202 (rawSkew[i] < upperLimit && rawSkew[i] > lowerLimit)) {
203 n++;
204 cumSum += rawSkew[i];
205 x += n;
206 x2 += n * n;
207 y += cumSum;
208 xy += n * cumSum;
niklase@google.com470e71d2011-07-07 08:21:25 +0000209 }
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000210 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000211
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000212 if (n == 0) {
213 return -1;
214 }
215 assert(n > 0);
216 xAvg = x / n;
217 denom = x2 - xAvg * x;
niklase@google.com470e71d2011-07-07 08:21:25 +0000218
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000219 if (denom != 0) {
220 skew = (xy - xAvg * y) / denom;
221 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000222
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000223 *skewEst = skew;
224 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000225}