blob: ebd052f80026fe8e3d686227792fd5b32427eb4f [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
12 * clock
niklase@google.com470e71d2011-07-07 08:21:25 +000013 * skew by resampling the farend signal.
14 */
15
pbos@webrtc.org7fad4b82013-05-28 08:11:59 +000016#include "webrtc/modules/audio_processing/aec/aec_resampler.h"
bjornv@webrtc.org4b80eb42011-11-29 08:44:01 +000017
niklase@google.com470e71d2011-07-07 08:21:25 +000018#include <assert.h>
pbos@webrtc.org7fad4b82013-05-28 08:11:59 +000019#include <math.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000020#include <stdlib.h>
21#include <string.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000022
pbos@webrtc.org7fad4b82013-05-28 08:11:59 +000023#include "webrtc/modules/audio_processing/aec/aec_core.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000024
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000025enum {
26 kEstimateLengthFrames = 400
27};
niklase@google.com470e71d2011-07-07 08:21:25 +000028
29typedef struct {
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000030 short buffer[kResamplerBufferSize];
31 float position;
niklase@google.com470e71d2011-07-07 08:21:25 +000032
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000033 int deviceSampleRateHz;
34 int skewData[kEstimateLengthFrames];
35 int skewDataIndex;
36 float skewEstimate;
niklase@google.com470e71d2011-07-07 08:21:25 +000037} resampler_t;
38
39static int EstimateSkew(const int* rawSkew,
40 int size,
41 int absLimit,
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000042 float* skewEst);
niklase@google.com470e71d2011-07-07 08:21:25 +000043
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000044int WebRtcAec_CreateResampler(void** resampInst) {
45 resampler_t* obj = malloc(sizeof(resampler_t));
46 *resampInst = obj;
47 if (obj == NULL) {
48 return -1;
49 }
niklase@google.com470e71d2011-07-07 08:21:25 +000050
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000051 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000052}
53
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000054int WebRtcAec_InitResampler(void* resampInst, int deviceSampleRateHz) {
55 resampler_t* obj = (resampler_t*)resampInst;
56 memset(obj->buffer, 0, sizeof(obj->buffer));
57 obj->position = 0.0;
niklase@google.com470e71d2011-07-07 08:21:25 +000058
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000059 obj->deviceSampleRateHz = deviceSampleRateHz;
60 memset(obj->skewData, 0, sizeof(obj->skewData));
61 obj->skewDataIndex = 0;
62 obj->skewEstimate = 0.0;
niklase@google.com470e71d2011-07-07 08:21:25 +000063
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000064 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000065}
66
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000067int WebRtcAec_FreeResampler(void* resampInst) {
68 resampler_t* obj = (resampler_t*)resampInst;
69 free(obj);
niklase@google.com470e71d2011-07-07 08:21:25 +000070
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000071 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000072}
73
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000074void WebRtcAec_ResampleLinear(void* resampInst,
75 const short* inspeech,
bjornv@webrtc.org281b7982012-05-30 07:41:57 +000076 int size,
77 float skew,
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000078 short* outspeech,
79 int* size_out) {
80 resampler_t* obj = (resampler_t*)resampInst;
niklase@google.com470e71d2011-07-07 08:21:25 +000081
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000082 short* y;
83 float be, tnew, interp;
84 int tn, mm;
niklase@google.com470e71d2011-07-07 08:21:25 +000085
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000086 assert(!(size < 0 || size > 2 * FRAME_LEN));
87 assert(resampInst != NULL);
88 assert(inspeech != NULL);
89 assert(outspeech != NULL);
90 assert(size_out != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +000091
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000092 // Add new frame data in lookahead
93 memcpy(&obj->buffer[FRAME_LEN + kResamplingDelay],
94 inspeech,
95 size * sizeof(short));
niklase@google.com470e71d2011-07-07 08:21:25 +000096
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000097 // Sample rate ratio
98 be = 1 + skew;
niklase@google.com470e71d2011-07-07 08:21:25 +000099
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000100 // Loop over input frame
101 mm = 0;
102 y = &obj->buffer[FRAME_LEN]; // Point at current frame
103
104 tnew = be * mm + obj->position;
105 tn = (int)tnew;
106
107 while (tn < size) {
108
109 // Interpolation
110 interp = y[tn] + (tnew - tn) * (y[tn + 1] - y[tn]);
111
112 if (interp > 32767) {
113 interp = 32767;
114 } else if (interp < -32768) {
115 interp = -32768;
116 }
117
118 outspeech[mm] = (short)interp;
119 mm++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000120
121 tnew = be * mm + obj->position;
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000122 tn = (int)tnew;
123 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000124
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000125 *size_out = mm;
126 obj->position += (*size_out) * be - size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000127
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000128 // Shift buffer
129 memmove(obj->buffer,
130 &obj->buffer[size],
131 (kResamplerBufferSize - size) * sizeof(short));
niklase@google.com470e71d2011-07-07 08:21:25 +0000132}
133
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000134int WebRtcAec_GetSkew(void* resampInst, int rawSkew, float* skewEst) {
135 resampler_t* obj = (resampler_t*)resampInst;
136 int err = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000137
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000138 if (obj->skewDataIndex < kEstimateLengthFrames) {
139 obj->skewData[obj->skewDataIndex] = rawSkew;
140 obj->skewDataIndex++;
141 } else if (obj->skewDataIndex == kEstimateLengthFrames) {
142 err = EstimateSkew(
143 obj->skewData, kEstimateLengthFrames, obj->deviceSampleRateHz, skewEst);
144 obj->skewEstimate = *skewEst;
145 obj->skewDataIndex++;
146 } else {
147 *skewEst = obj->skewEstimate;
148 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000149
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000150 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000151}
152
153int EstimateSkew(const int* rawSkew,
ajm@google.com75e12392011-07-13 16:35:10 +0000154 int size,
155 int deviceSampleRateHz,
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000156 float* skewEst) {
157 const int absLimitOuter = (int)(0.04f * deviceSampleRateHz);
158 const int absLimitInner = (int)(0.0025f * deviceSampleRateHz);
159 int i = 0;
160 int n = 0;
161 float rawAvg = 0;
162 float err = 0;
163 float rawAbsDev = 0;
164 int upperLimit = 0;
165 int lowerLimit = 0;
166 float cumSum = 0;
167 float x = 0;
168 float x2 = 0;
169 float y = 0;
170 float xy = 0;
171 float xAvg = 0;
172 float denom = 0;
173 float skew = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000174
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000175 *skewEst = 0; // Set in case of error below.
176 for (i = 0; i < size; i++) {
177 if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
178 n++;
179 rawAvg += rawSkew[i];
niklase@google.com470e71d2011-07-07 08:21:25 +0000180 }
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000181 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000182
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000183 if (n == 0) {
184 return -1;
185 }
186 assert(n > 0);
187 rawAvg /= n;
188
189 for (i = 0; i < size; i++) {
190 if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
191 err = rawSkew[i] - rawAvg;
192 rawAbsDev += err >= 0 ? err : -err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000193 }
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000194 }
195 assert(n > 0);
196 rawAbsDev /= n;
197 upperLimit = (int)(rawAvg + 5 * rawAbsDev + 1); // +1 for ceiling.
198 lowerLimit = (int)(rawAvg - 5 * rawAbsDev - 1); // -1 for floor.
niklase@google.com470e71d2011-07-07 08:21:25 +0000199
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000200 n = 0;
201 for (i = 0; i < size; i++) {
202 if ((rawSkew[i] < absLimitInner && rawSkew[i] > -absLimitInner) ||
203 (rawSkew[i] < upperLimit && rawSkew[i] > lowerLimit)) {
204 n++;
205 cumSum += rawSkew[i];
206 x += n;
207 x2 += n * n;
208 y += cumSum;
209 xy += n * cumSum;
niklase@google.com470e71d2011-07-07 08:21:25 +0000210 }
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000211 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000212
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000213 if (n == 0) {
214 return -1;
215 }
216 assert(n > 0);
217 xAvg = x / n;
218 denom = x2 - xAvg * x;
niklase@google.com470e71d2011-07-07 08:21:25 +0000219
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000220 if (denom != 0) {
221 skew = (xy - xAvg * y) / denom;
222 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000223
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000224 *skewEst = skew;
225 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000226}