blob: 126a2094e6732b3a856662b5a9590637688647cf [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
11/* Resamples a signal to an arbitrary rate. Used by the AEC to compensate for clock
12 * skew by resampling the farend signal.
13 */
14
bjornv@webrtc.org4b80eb42011-11-29 08:44:01 +000015#include "aec_resampler.h"
16
niklase@google.com470e71d2011-07-07 08:21:25 +000017#include <assert.h>
18#include <stdlib.h>
19#include <string.h>
20#include <math.h>
21
niklase@google.com470e71d2011-07-07 08:21:25 +000022#include "aec_core.h"
23
niklase@google.com470e71d2011-07-07 08:21:25 +000024enum { kEstimateLengthFrames = 400 };
25
26typedef struct {
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +000027 short buffer[kResamplerBufferSize];
niklase@google.com470e71d2011-07-07 08:21:25 +000028 float position;
29
30 int deviceSampleRateHz;
31 int skewData[kEstimateLengthFrames];
32 int skewDataIndex;
33 float skewEstimate;
34} resampler_t;
35
36static int EstimateSkew(const int* rawSkew,
37 int size,
38 int absLimit,
39 float *skewEst);
40
41int WebRtcAec_CreateResampler(void **resampInst)
42{
43 resampler_t *obj = malloc(sizeof(resampler_t));
44 *resampInst = obj;
45 if (obj == NULL) {
46 return -1;
47 }
48
49 return 0;
50}
51
52int WebRtcAec_InitResampler(void *resampInst, int deviceSampleRateHz)
53{
54 resampler_t *obj = (resampler_t*) resampInst;
55 memset(obj->buffer, 0, sizeof(obj->buffer));
56 obj->position = 0.0;
57
58 obj->deviceSampleRateHz = deviceSampleRateHz;
59 memset(obj->skewData, 0, sizeof(obj->skewData));
60 obj->skewDataIndex = 0;
61 obj->skewEstimate = 0.0;
62
63 return 0;
64}
65
66int WebRtcAec_FreeResampler(void *resampInst)
67{
68 resampler_t *obj = (resampler_t*) resampInst;
69 free(obj);
70
71 return 0;
72}
73
bjornv@webrtc.org281b7982012-05-30 07:41:57 +000074void WebRtcAec_ResampleLinear(void *resampInst,
75 const short *inspeech,
76 int size,
77 float skew,
78 short *outspeech,
79 int *size_out)
niklase@google.com470e71d2011-07-07 08:21:25 +000080{
81 resampler_t *obj = (resampler_t*) resampInst;
82
83 short *y;
84 float be, tnew, interp;
bjornv@webrtc.org281b7982012-05-30 07:41:57 +000085 int tn, mm;
niklase@google.com470e71d2011-07-07 08:21:25 +000086
bjornv@webrtc.org281b7982012-05-30 07:41:57 +000087 assert(!(size < 0 || size > 2 * FRAME_LEN));
88 assert(resampInst != NULL);
89 assert(inspeech != NULL);
90 assert(outspeech != NULL);
91 assert(size_out != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +000092
93 // Add new frame data in lookahead
94 memcpy(&obj->buffer[FRAME_LEN + kResamplingDelay],
95 inspeech,
96 size * sizeof(short));
97
98 // Sample rate ratio
99 be = 1 + skew;
100
101 // Loop over input frame
102 mm = 0;
103 y = &obj->buffer[FRAME_LEN]; // Point at current frame
104
105 tnew = be * mm + obj->position;
106 tn = (int) tnew;
107
108 while (tn < size) {
109
110 // Interpolation
111 interp = y[tn] + (tnew - tn) * (y[tn+1] - y[tn]);
112
113 if (interp > 32767) {
114 interp = 32767;
115 }
116 else if (interp < -32768) {
117 interp = -32768;
118 }
119
120 outspeech[mm] = (short) interp;
121 mm++;
122
123 tnew = be * mm + obj->position;
124 tn = (int) tnew;
125 }
126
bjornv@webrtc.org281b7982012-05-30 07:41:57 +0000127 *size_out = mm;
128 obj->position += (*size_out) * be - size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000129
130 // Shift buffer
131 memmove(obj->buffer,
132 &obj->buffer[size],
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +0000133 (kResamplerBufferSize - size) * sizeof(short));
niklase@google.com470e71d2011-07-07 08:21:25 +0000134}
135
136int WebRtcAec_GetSkew(void *resampInst, int rawSkew, float *skewEst)
137{
138 resampler_t *obj = (resampler_t*)resampInst;
139 int err = 0;
140
141 if (obj->skewDataIndex < kEstimateLengthFrames) {
142 obj->skewData[obj->skewDataIndex] = rawSkew;
143 obj->skewDataIndex++;
144 }
145 else if (obj->skewDataIndex == kEstimateLengthFrames) {
146 err = EstimateSkew(obj->skewData,
147 kEstimateLengthFrames,
148 obj->deviceSampleRateHz,
149 skewEst);
150 obj->skewEstimate = *skewEst;
151 obj->skewDataIndex++;
152 }
153 else {
154 *skewEst = obj->skewEstimate;
155 }
156
157 return err;
158}
159
160int EstimateSkew(const int* rawSkew,
ajm@google.com75e12392011-07-13 16:35:10 +0000161 int size,
162 int deviceSampleRateHz,
niklase@google.com470e71d2011-07-07 08:21:25 +0000163 float *skewEst)
164{
165 const int absLimitOuter = (int)(0.04f * deviceSampleRateHz);
166 const int absLimitInner = (int)(0.0025f * deviceSampleRateHz);
167 int i = 0;
168 int n = 0;
169 float rawAvg = 0;
170 float err = 0;
171 float rawAbsDev = 0;
172 int upperLimit = 0;
173 int lowerLimit = 0;
174 float cumSum = 0;
175 float x = 0;
176 float x2 = 0;
177 float y = 0;
178 float xy = 0;
179 float xAvg = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000180 float denom = 0;
181 float skew = 0;
182
183 *skewEst = 0; // Set in case of error below.
184 for (i = 0; i < size; i++) {
185 if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
186 n++;
187 rawAvg += rawSkew[i];
188 }
189 }
190
191 if (n == 0) {
192 return -1;
193 }
194 assert(n > 0);
195 rawAvg /= n;
196
197 for (i = 0; i < size; i++) {
198 if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
199 err = rawSkew[i] - rawAvg;
200 rawAbsDev += err >= 0 ? err : -err;
201 }
202 }
203 assert(n > 0);
204 rawAbsDev /= n;
205 upperLimit = (int)(rawAvg + 5 * rawAbsDev + 1); // +1 for ceiling.
206 lowerLimit = (int)(rawAvg - 5 * rawAbsDev - 1); // -1 for floor.
207
208 n = 0;
209 for (i = 0; i < size; i++) {
210 if ((rawSkew[i] < absLimitInner && rawSkew[i] > -absLimitInner) ||
211 (rawSkew[i] < upperLimit && rawSkew[i] > lowerLimit)) {
212 n++;
213 cumSum += rawSkew[i];
214 x += n;
215 x2 += n*n;
216 y += cumSum;
217 xy += n * cumSum;
218 }
219 }
220
221 if (n == 0) {
222 return -1;
223 }
224 assert(n > 0);
225 xAvg = x / n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000226 denom = x2 - xAvg*x;
227
228 if (denom != 0) {
229 skew = (xy - xAvg*y) / denom;
230 }
231
232 *skewEst = skew;
233 return 0;
234}