blob: 824b1676d895c0ab20f66c2ec6d1c1ee98a5d453 [file] [log] [blame]
ekm030249d2015-06-15 13:02:24 -07001/*
2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3 *
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
ekmdb4fecf2015-06-22 17:49:08 -070011//
12// Implements helper functions and classes for intelligibility enhancement.
13//
14
ekm030249d2015-06-15 13:02:24 -070015#include "webrtc/modules/audio_processing/intelligibility/intelligibility_utils.h"
16
ekm35b72fb2015-07-10 14:11:52 -070017#include <math.h>
18#include <string.h>
ekm030249d2015-06-15 13:02:24 -070019#include <algorithm>
ekm030249d2015-06-15 13:02:24 -070020
21using std::complex;
ekm35b72fb2015-07-10 14:11:52 -070022using std::min;
ekm030249d2015-06-15 13:02:24 -070023
ekm35b72fb2015-07-10 14:11:52 -070024namespace webrtc {
ekm030249d2015-06-15 13:02:24 -070025
ekm35b72fb2015-07-10 14:11:52 -070026namespace intelligibility {
27
28float UpdateFactor(float target, float current, float limit) {
ekm030249d2015-06-15 13:02:24 -070029 float delta = fabsf(target - current);
30 float sign = copysign(1.0f, target - current);
31 return current + sign * fminf(delta, limit);
32}
33
ekm35b72fb2015-07-10 14:11:52 -070034bool cplxfinite(complex<float> c) {
ekm030249d2015-06-15 13:02:24 -070035 return std::isfinite(c.real()) && std::isfinite(c.imag());
36}
37
ekm35b72fb2015-07-10 14:11:52 -070038bool cplxnormal(complex<float> c) {
ekm030249d2015-06-15 13:02:24 -070039 return std::isnormal(c.real()) && std::isnormal(c.imag());
40}
41
ekm35b72fb2015-07-10 14:11:52 -070042complex<float> zerofudge(complex<float> c) {
ekmdb4fecf2015-06-22 17:49:08 -070043 const static complex<float> fudge[7] = {{0.001f, 0.002f},
44 {0.008f, 0.001f},
45 {0.003f, 0.008f},
46 {0.0006f, 0.0009f},
47 {0.001f, 0.004f},
48 {0.003f, 0.004f},
49 {0.002f, 0.009f}};
ekm030249d2015-06-15 13:02:24 -070050 static int fudge_index = 0;
51 if (cplxfinite(c) && !cplxnormal(c)) {
52 fudge_index = (fudge_index + 1) % 7;
53 return c + fudge[fudge_index];
54 }
55 return c;
56}
57
ekm35b72fb2015-07-10 14:11:52 -070058complex<float> NewMean(complex<float> mean, complex<float> data, int count) {
ekm030249d2015-06-15 13:02:24 -070059 return mean + (data - mean) / static_cast<float>(count);
60}
61
ekm35b72fb2015-07-10 14:11:52 -070062void AddToMean(complex<float> data, int count, complex<float>* mean) {
ekm030249d2015-06-15 13:02:24 -070063 (*mean) = NewMean(*mean, data, count);
64}
65
ekm030249d2015-06-15 13:02:24 -070066
67static const int kWindowBlockSize = 10;
68
ekmdb4fecf2015-06-22 17:49:08 -070069VarianceArray::VarianceArray(int freqs,
70 StepType type,
71 int window_size,
ekm030249d2015-06-15 13:02:24 -070072 float decay)
73 : running_mean_(new complex<float>[freqs]()),
74 running_mean_sq_(new complex<float>[freqs]()),
75 sub_running_mean_(new complex<float>[freqs]()),
76 sub_running_mean_sq_(new complex<float>[freqs]()),
77 variance_(new float[freqs]()),
78 conj_sum_(new float[freqs]()),
79 freqs_(freqs),
80 window_size_(window_size),
81 decay_(decay),
82 history_cursor_(0),
83 count_(0),
ekm35b72fb2015-07-10 14:11:52 -070084 array_mean_(0.0f),
85 buffer_full_(false) {
ekmdb4fecf2015-06-22 17:49:08 -070086 history_.reset(new rtc::scoped_ptr<complex<float>[]>[freqs_]());
ekm030249d2015-06-15 13:02:24 -070087 for (int i = 0; i < freqs_; ++i) {
88 history_[i].reset(new complex<float>[window_size_]());
89 }
ekmdb4fecf2015-06-22 17:49:08 -070090 subhistory_.reset(new rtc::scoped_ptr<complex<float>[]>[freqs_]());
ekm030249d2015-06-15 13:02:24 -070091 for (int i = 0; i < freqs_; ++i) {
92 subhistory_[i].reset(new complex<float>[window_size_]());
93 }
ekmdb4fecf2015-06-22 17:49:08 -070094 subhistory_sq_.reset(new rtc::scoped_ptr<complex<float>[]>[freqs_]());
ekm030249d2015-06-15 13:02:24 -070095 for (int i = 0; i < freqs_; ++i) {
96 subhistory_sq_[i].reset(new complex<float>[window_size_]());
97 }
98 switch (type) {
99 case kStepInfinite:
100 step_func_ = &VarianceArray::InfiniteStep;
101 break;
102 case kStepDecaying:
103 step_func_ = &VarianceArray::DecayStep;
104 break;
105 case kStepWindowed:
106 step_func_ = &VarianceArray::WindowedStep;
107 break;
108 case kStepBlocked:
109 step_func_ = &VarianceArray::BlockedStep;
110 break;
ekm35b72fb2015-07-10 14:11:52 -0700111 case kStepBlockBasedMovingAverage:
112 step_func_ = &VarianceArray::BlockBasedMovingAverage;
113 break;
ekm030249d2015-06-15 13:02:24 -0700114 }
115}
116
117// Compute the variance with Welford's algorithm, adding some fudge to
118// the input in case of all-zeroes.
119void VarianceArray::InfiniteStep(const complex<float>* data, bool skip_fudge) {
120 array_mean_ = 0.0f;
121 ++count_;
122 for (int i = 0; i < freqs_; ++i) {
123 complex<float> sample = data[i];
124 if (!skip_fudge) {
125 sample = zerofudge(sample);
126 }
127 if (count_ == 1) {
128 running_mean_[i] = sample;
129 variance_[i] = 0.0f;
130 } else {
131 float old_sum = conj_sum_[i];
132 complex<float> old_mean = running_mean_[i];
ekmdb4fecf2015-06-22 17:49:08 -0700133 running_mean_[i] =
134 old_mean + (sample - old_mean) / static_cast<float>(count_);
135 conj_sum_[i] =
136 (old_sum + std::conj(sample - old_mean) * (sample - running_mean_[i]))
137 .real();
138 variance_[i] =
139 conj_sum_[i] / (count_ - 1); // + fudge[fudge_index].real();
pkastingb297c5a2015-07-22 15:17:22 -0700140 // if (skip_fudge) {
141 // variance_[i] -= fudge[fudge_index].real();
142 // }
ekm030249d2015-06-15 13:02:24 -0700143 }
144 array_mean_ += (variance_[i] - array_mean_) / (i + 1);
145 }
146}
147
148// Compute the variance from the beginning, with exponential decaying of the
149// series data.
150void VarianceArray::DecayStep(const complex<float>* data, bool /*dummy*/) {
151 array_mean_ = 0.0f;
152 ++count_;
153 for (int i = 0; i < freqs_; ++i) {
154 complex<float> sample = data[i];
155 sample = zerofudge(sample);
156
157 if (count_ == 1) {
158 running_mean_[i] = sample;
159 running_mean_sq_[i] = sample * std::conj(sample);
160 variance_[i] = 0.0f;
161 } else {
162 complex<float> prev = running_mean_[i];
163 complex<float> prev2 = running_mean_sq_[i];
164 running_mean_[i] = decay_ * prev + (1.0f - decay_) * sample;
ekmdb4fecf2015-06-22 17:49:08 -0700165 running_mean_sq_[i] =
166 decay_ * prev2 + (1.0f - decay_) * sample * std::conj(sample);
167 // variance_[i] = decay_ * variance_[i] + (1.0f - decay_) * (
168 // (sample - running_mean_[i]) * std::conj(sample -
169 // running_mean_[i])).real();
170 variance_[i] = (running_mean_sq_[i] -
171 running_mean_[i] * std::conj(running_mean_[i])).real();
ekm030249d2015-06-15 13:02:24 -0700172 }
173
174 array_mean_ += (variance_[i] - array_mean_) / (i + 1);
175 }
176}
177
178// Windowed variance computation. On each step, the variances for the
179// window are recomputed from scratch, using Welford's algorithm.
180void VarianceArray::WindowedStep(const complex<float>* data, bool /*dummy*/) {
181 int num = min(count_ + 1, window_size_);
182 array_mean_ = 0.0f;
183 for (int i = 0; i < freqs_; ++i) {
184 complex<float> mean;
185 float conj_sum = 0.0f;
186
187 history_[i][history_cursor_] = data[i];
188
189 mean = history_[i][history_cursor_];
190 variance_[i] = 0.0f;
191 for (int j = 1; j < num; ++j) {
ekmdb4fecf2015-06-22 17:49:08 -0700192 complex<float> sample =
193 zerofudge(history_[i][(history_cursor_ + j) % window_size_]);
ekm030249d2015-06-15 13:02:24 -0700194 sample = history_[i][(history_cursor_ + j) % window_size_];
195 float old_sum = conj_sum;
196 complex<float> old_mean = mean;
197
198 mean = old_mean + (sample - old_mean) / static_cast<float>(j + 1);
ekmdb4fecf2015-06-22 17:49:08 -0700199 conj_sum =
200 (old_sum + std::conj(sample - old_mean) * (sample - mean)).real();
ekm030249d2015-06-15 13:02:24 -0700201 variance_[i] = conj_sum / (j);
202 }
203 array_mean_ += (variance_[i] - array_mean_) / (i + 1);
204 }
205 history_cursor_ = (history_cursor_ + 1) % window_size_;
206 ++count_;
207}
208
209// Variance with a window of blocks. Within each block, the variances are
210// recomputed from scratch at every stp, using |Var(X) = E(X^2) - E^2(X)|.
211// Once a block is filled with kWindowBlockSize samples, it is added to the
212// history window and a new block is started. The variances for the window
213// are recomputed from scratch at each of these transitions.
214void VarianceArray::BlockedStep(const complex<float>* data, bool /*dummy*/) {
ekm35b72fb2015-07-10 14:11:52 -0700215 int blocks = min(window_size_, history_cursor_ + 1);
ekm030249d2015-06-15 13:02:24 -0700216 for (int i = 0; i < freqs_; ++i) {
217 AddToMean(data[i], count_ + 1, &sub_running_mean_[i]);
218 AddToMean(data[i] * std::conj(data[i]), count_ + 1,
219 &sub_running_mean_sq_[i]);
220 subhistory_[i][history_cursor_ % window_size_] = sub_running_mean_[i];
221 subhistory_sq_[i][history_cursor_ % window_size_] = sub_running_mean_sq_[i];
222
ekmdb4fecf2015-06-22 17:49:08 -0700223 variance_[i] =
224 (NewMean(running_mean_sq_[i], sub_running_mean_sq_[i], blocks) -
225 NewMean(running_mean_[i], sub_running_mean_[i], blocks) *
226 std::conj(NewMean(running_mean_[i], sub_running_mean_[i], blocks)))
227 .real();
ekm030249d2015-06-15 13:02:24 -0700228 if (count_ == kWindowBlockSize - 1) {
229 sub_running_mean_[i] = complex<float>(0.0f, 0.0f);
230 sub_running_mean_sq_[i] = complex<float>(0.0f, 0.0f);
231 running_mean_[i] = complex<float>(0.0f, 0.0f);
232 running_mean_sq_[i] = complex<float>(0.0f, 0.0f);
233 for (int j = 0; j < min(window_size_, history_cursor_); ++j) {
ekm35b72fb2015-07-10 14:11:52 -0700234 AddToMean(subhistory_[i][j], j + 1, &running_mean_[i]);
235 AddToMean(subhistory_sq_[i][j], j + 1, &running_mean_sq_[i]);
ekm030249d2015-06-15 13:02:24 -0700236 }
237 ++history_cursor_;
238 }
239 }
240 ++count_;
241 if (count_ == kWindowBlockSize) {
242 count_ = 0;
243 }
244}
245
ekm35b72fb2015-07-10 14:11:52 -0700246// Recomputes variances for each window from scratch based on previous window.
247void VarianceArray::BlockBasedMovingAverage(const std::complex<float>* data,
248 bool /*dummy*/) {
249 // TODO(ekmeyerson) To mitigate potential divergence, add counter so that
250 // after every so often sums are computed scratch by summing over all
251 // elements instead of subtracting oldest and adding newest.
252 for (int i = 0; i < freqs_; ++i) {
253 sub_running_mean_[i] += data[i];
254 sub_running_mean_sq_[i] += data[i] * std::conj(data[i]);
255 }
256 ++count_;
257
258 // TODO(ekmeyerson) Make kWindowBlockSize nonconstant to allow
259 // experimentation with different block size,window size pairs.
260 if (count_ >= kWindowBlockSize) {
261 count_ = 0;
262
263 for (int i = 0; i < freqs_; ++i) {
264 running_mean_[i] -= subhistory_[i][history_cursor_];
265 running_mean_sq_[i] -= subhistory_sq_[i][history_cursor_];
266
267 float scale = 1.f / kWindowBlockSize;
268 subhistory_[i][history_cursor_] = sub_running_mean_[i] * scale;
269 subhistory_sq_[i][history_cursor_] = sub_running_mean_sq_[i] * scale;
270
271 sub_running_mean_[i] = std::complex<float>(0.0f, 0.0f);
272 sub_running_mean_sq_[i] = std::complex<float>(0.0f, 0.0f);
273
274 running_mean_[i] += subhistory_[i][history_cursor_];
275 running_mean_sq_[i] += subhistory_sq_[i][history_cursor_];
276
277 scale = 1.f / (buffer_full_ ? window_size_ : history_cursor_ + 1);
278 variance_[i] = std::real(running_mean_sq_[i] * scale -
279 running_mean_[i] * scale *
280 std::conj(running_mean_[i]) * scale);
281 }
282
283 ++history_cursor_;
284 if (history_cursor_ >= window_size_) {
285 buffer_full_ = true;
286 history_cursor_ = 0;
287 }
288 }
289}
290
ekm030249d2015-06-15 13:02:24 -0700291void VarianceArray::Clear() {
292 memset(running_mean_.get(), 0, sizeof(*running_mean_.get()) * freqs_);
293 memset(running_mean_sq_.get(), 0, sizeof(*running_mean_sq_.get()) * freqs_);
294 memset(variance_.get(), 0, sizeof(*variance_.get()) * freqs_);
295 memset(conj_sum_.get(), 0, sizeof(*conj_sum_.get()) * freqs_);
296 history_cursor_ = 0;
297 count_ = 0;
298 array_mean_ = 0.0f;
299}
300
301void VarianceArray::ApplyScale(float scale) {
302 array_mean_ = 0.0f;
303 for (int i = 0; i < freqs_; ++i) {
304 variance_[i] *= scale * scale;
305 array_mean_ += (variance_[i] - array_mean_) / (i + 1);
306 }
307}
308
309GainApplier::GainApplier(int freqs, float change_limit)
310 : freqs_(freqs),
311 change_limit_(change_limit),
312 target_(new float[freqs]()),
313 current_(new float[freqs]()) {
314 for (int i = 0; i < freqs; ++i) {
315 target_[i] = 1.0f;
316 current_[i] = 1.0f;
317 }
318}
319
320void GainApplier::Apply(const complex<float>* in_block,
321 complex<float>* out_block) {
322 for (int i = 0; i < freqs_; ++i) {
323 float factor = sqrtf(fabsf(current_[i]));
324 if (!std::isnormal(factor)) {
325 factor = 1.0f;
326 }
327 out_block[i] = factor * in_block[i];
328 current_[i] = UpdateFactor(target_[i], current_[i], change_limit_);
329 }
330}
331
332} // namespace intelligibility
333
334} // namespace webrtc