blob: 9908ac0456f1974f263a42e33a5124f5a3f9c33a [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// Specifies helper classes for intelligibility enhancement.
13//
14
ekm030249d2015-06-15 13:02:24 -070015#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_INTELLIGIBILITY_INTELLIGIBILITY_UTILS_H_
16#define WEBRTC_MODULES_AUDIO_PROCESSING_INTELLIGIBILITY_INTELLIGIBILITY_UTILS_H_
17
18#include <complex>
19
ekmdb4fecf2015-06-22 17:49:08 -070020#include "webrtc/base/scoped_ptr.h"
ekm030249d2015-06-15 13:02:24 -070021
22namespace webrtc {
23
24namespace intelligibility {
25
ekm35b72fb2015-07-10 14:11:52 -070026// Return |current| changed towards |target|, with the change being at most
27// |limit|.
28float UpdateFactor(float target, float current, float limit);
29
30// std::isfinite for complex numbers.
31bool cplxfinite(std::complex<float> c);
32
33// std::isnormal for complex numbers.
34bool cplxnormal(std::complex<float> c);
35
36// Apply a small fudge to degenerate complex values. The numbers in the array
37// were chosen randomly, so that even a series of all zeroes has some small
38// variability.
39std::complex<float> zerofudge(std::complex<float> c);
40
41// Incremental mean computation. Return the mean of the series with the
42// mean |mean| with added |data|.
43std::complex<float> NewMean(std::complex<float> mean,
44 std::complex<float> data,
45 int count);
46
47// Updates |mean| with added |data|;
48void AddToMean(std::complex<float> data, int count, std::complex<float>* mean);
49
ekm030249d2015-06-15 13:02:24 -070050// Internal helper for computing the variances of a stream of arrays.
51// The result is an array of variances per position: the i-th variance
52// is the variance of the stream of data on the i-th positions in the
53// input arrays.
54// There are four methods of computation:
55// * kStepInfinite computes variances from the beginning onwards
56// * kStepDecaying uses a recursive exponential decay formula with a
57// settable forgetting factor
58// * kStepWindowed computes variances within a moving window
59// * kStepBlocked is similar to kStepWindowed, but history is kept
60// as a rolling window of blocks: multiple input elements are used for
61// one block and the history then consists of the variances of these blocks
62// with the same effect as kStepWindowed, but less storage, so the window
63// can be longer
64class VarianceArray {
65 public:
66 enum StepType {
67 kStepInfinite = 0,
68 kStepDecaying,
69 kStepWindowed,
ekm35b72fb2015-07-10 14:11:52 -070070 kStepBlocked,
71 kStepBlockBasedMovingAverage
ekm030249d2015-06-15 13:02:24 -070072 };
73
74 // Construct an instance for the given input array length (|freqs|) and
75 // computation algorithm (|type|), with the appropriate parameters.
76 // |window_size| is the number of samples for kStepWindowed and
77 // the number of blocks for kStepBlocked. |decay| is the forgetting factor
78 // for kStepDecaying.
79 VarianceArray(int freqs, StepType type, int window_size, float decay);
80
81 // Add a new data point to the series and compute the new variances.
82 // TODO(bercic) |skip_fudge| is a flag for kStepWindowed and kStepDecaying,
83 // whether they should skip adding some small dummy values to the input
84 // to prevent problems with all-zero inputs. Can probably be removed.
85 void Step(const std::complex<float>* data, bool skip_fudge = false) {
86 (this->*step_func_)(data, skip_fudge);
87 }
88 // Reset variances to zero and forget all history.
89 void Clear();
90 // Scale the input data by |scale|. Effectively multiply variances
91 // by |scale^2|.
92 void ApplyScale(float scale);
93
94 // The current set of variances.
ekmdb4fecf2015-06-22 17:49:08 -070095 const float* variance() const { return variance_.get(); }
ekm030249d2015-06-15 13:02:24 -070096
97 // The mean value of the current set of variances.
ekmdb4fecf2015-06-22 17:49:08 -070098 float array_mean() const { return array_mean_; }
ekm030249d2015-06-15 13:02:24 -070099
100 private:
101 void InfiniteStep(const std::complex<float>* data, bool dummy);
102 void DecayStep(const std::complex<float>* data, bool dummy);
103 void WindowedStep(const std::complex<float>* data, bool dummy);
104 void BlockedStep(const std::complex<float>* data, bool dummy);
ekm35b72fb2015-07-10 14:11:52 -0700105 void BlockBasedMovingAverage(const std::complex<float>* data, bool dummy);
ekm030249d2015-06-15 13:02:24 -0700106
ekmdb4fecf2015-06-22 17:49:08 -0700107 // TODO(ekmeyerson): Switch the following running means
108 // and histories from rtc::scoped_ptr to std::vector.
109
ekm030249d2015-06-15 13:02:24 -0700110 // The current average X and X^2.
ekmdb4fecf2015-06-22 17:49:08 -0700111 rtc::scoped_ptr<std::complex<float>[]> running_mean_;
112 rtc::scoped_ptr<std::complex<float>[]> running_mean_sq_;
ekm030249d2015-06-15 13:02:24 -0700113
114 // Average X and X^2 for the current block in kStepBlocked.
ekmdb4fecf2015-06-22 17:49:08 -0700115 rtc::scoped_ptr<std::complex<float>[]> sub_running_mean_;
116 rtc::scoped_ptr<std::complex<float>[]> sub_running_mean_sq_;
ekm030249d2015-06-15 13:02:24 -0700117
118 // Sample history for the rolling window in kStepWindowed and block-wise
119 // histories for kStepBlocked.
ekmdb4fecf2015-06-22 17:49:08 -0700120 rtc::scoped_ptr<rtc::scoped_ptr<std::complex<float>[]>[]> history_;
121 rtc::scoped_ptr<rtc::scoped_ptr<std::complex<float>[]>[]> subhistory_;
122 rtc::scoped_ptr<rtc::scoped_ptr<std::complex<float>[]>[]> subhistory_sq_;
ekm030249d2015-06-15 13:02:24 -0700123
124 // The current set of variances and sums for Welford's algorithm.
ekmdb4fecf2015-06-22 17:49:08 -0700125 rtc::scoped_ptr<float[]> variance_;
126 rtc::scoped_ptr<float[]> conj_sum_;
ekm030249d2015-06-15 13:02:24 -0700127
128 const int freqs_;
129 const int window_size_;
130 const float decay_;
131 int history_cursor_;
132 int count_;
133 float array_mean_;
ekm35b72fb2015-07-10 14:11:52 -0700134 bool buffer_full_;
ekm030249d2015-06-15 13:02:24 -0700135 void (VarianceArray::*step_func_)(const std::complex<float>*, bool);
136};
137
138// Helper class for smoothing gain changes. On each applicatiion step, the
139// currently used gains are changed towards a set of settable target gains,
140// constrained by a limit on the magnitude of the changes.
141class GainApplier {
142 public:
143 GainApplier(int freqs, float change_limit);
144
145 // Copy |in_block| to |out_block|, multiplied by the current set of gains,
146 // and step the current set of gains towards the target set.
147 void Apply(const std::complex<float>* in_block,
148 std::complex<float>* out_block);
149
150 // Return the current target gain set. Modify this array to set the targets.
ekmdb4fecf2015-06-22 17:49:08 -0700151 float* target() const { return target_.get(); }
ekm030249d2015-06-15 13:02:24 -0700152
153 private:
154 const int freqs_;
155 const float change_limit_;
ekmdb4fecf2015-06-22 17:49:08 -0700156 rtc::scoped_ptr<float[]> target_;
157 rtc::scoped_ptr<float[]> current_;
ekm030249d2015-06-15 13:02:24 -0700158};
159
160} // namespace intelligibility
161
162} // namespace webrtc
163
164#endif // WEBRTC_MODULES_AUDIO_PROCESSING_INTELLIGIBILITY_INTELLIGIBILITY_UTILS_H_