blob: 5013ef05d21b2d70d2b028414e0acee199c7c5e2 [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
ekm35b72fb2015-07-10 14:11:52 -070030// Apply a small fudge to degenerate complex values. The numbers in the array
31// were chosen randomly, so that even a series of all zeroes has some small
32// variability.
33std::complex<float> zerofudge(std::complex<float> c);
34
35// Incremental mean computation. Return the mean of the series with the
36// mean |mean| with added |data|.
37std::complex<float> NewMean(std::complex<float> mean,
38 std::complex<float> data,
39 int count);
40
41// Updates |mean| with added |data|;
42void AddToMean(std::complex<float> data, int count, std::complex<float>* mean);
43
ekm030249d2015-06-15 13:02:24 -070044// Internal helper for computing the variances of a stream of arrays.
45// The result is an array of variances per position: the i-th variance
46// is the variance of the stream of data on the i-th positions in the
47// input arrays.
48// There are four methods of computation:
49// * kStepInfinite computes variances from the beginning onwards
50// * kStepDecaying uses a recursive exponential decay formula with a
51// settable forgetting factor
52// * kStepWindowed computes variances within a moving window
53// * kStepBlocked is similar to kStepWindowed, but history is kept
54// as a rolling window of blocks: multiple input elements are used for
55// one block and the history then consists of the variances of these blocks
56// with the same effect as kStepWindowed, but less storage, so the window
57// can be longer
58class VarianceArray {
59 public:
60 enum StepType {
61 kStepInfinite = 0,
62 kStepDecaying,
63 kStepWindowed,
ekm35b72fb2015-07-10 14:11:52 -070064 kStepBlocked,
65 kStepBlockBasedMovingAverage
ekm030249d2015-06-15 13:02:24 -070066 };
67
68 // Construct an instance for the given input array length (|freqs|) and
69 // computation algorithm (|type|), with the appropriate parameters.
70 // |window_size| is the number of samples for kStepWindowed and
71 // the number of blocks for kStepBlocked. |decay| is the forgetting factor
72 // for kStepDecaying.
73 VarianceArray(int freqs, StepType type, int window_size, float decay);
74
75 // Add a new data point to the series and compute the new variances.
76 // TODO(bercic) |skip_fudge| is a flag for kStepWindowed and kStepDecaying,
77 // whether they should skip adding some small dummy values to the input
78 // to prevent problems with all-zero inputs. Can probably be removed.
79 void Step(const std::complex<float>* data, bool skip_fudge = false) {
80 (this->*step_func_)(data, skip_fudge);
81 }
82 // Reset variances to zero and forget all history.
83 void Clear();
84 // Scale the input data by |scale|. Effectively multiply variances
85 // by |scale^2|.
86 void ApplyScale(float scale);
87
88 // The current set of variances.
ekmdb4fecf2015-06-22 17:49:08 -070089 const float* variance() const { return variance_.get(); }
ekm030249d2015-06-15 13:02:24 -070090
91 // The mean value of the current set of variances.
ekmdb4fecf2015-06-22 17:49:08 -070092 float array_mean() const { return array_mean_; }
ekm030249d2015-06-15 13:02:24 -070093
94 private:
95 void InfiniteStep(const std::complex<float>* data, bool dummy);
96 void DecayStep(const std::complex<float>* data, bool dummy);
97 void WindowedStep(const std::complex<float>* data, bool dummy);
98 void BlockedStep(const std::complex<float>* data, bool dummy);
ekm35b72fb2015-07-10 14:11:52 -070099 void BlockBasedMovingAverage(const std::complex<float>* data, bool dummy);
ekm030249d2015-06-15 13:02:24 -0700100
ekmdb4fecf2015-06-22 17:49:08 -0700101 // TODO(ekmeyerson): Switch the following running means
102 // and histories from rtc::scoped_ptr to std::vector.
103
ekm030249d2015-06-15 13:02:24 -0700104 // The current average X and X^2.
ekmdb4fecf2015-06-22 17:49:08 -0700105 rtc::scoped_ptr<std::complex<float>[]> running_mean_;
106 rtc::scoped_ptr<std::complex<float>[]> running_mean_sq_;
ekm030249d2015-06-15 13:02:24 -0700107
108 // Average X and X^2 for the current block in kStepBlocked.
ekmdb4fecf2015-06-22 17:49:08 -0700109 rtc::scoped_ptr<std::complex<float>[]> sub_running_mean_;
110 rtc::scoped_ptr<std::complex<float>[]> sub_running_mean_sq_;
ekm030249d2015-06-15 13:02:24 -0700111
112 // Sample history for the rolling window in kStepWindowed and block-wise
113 // histories for kStepBlocked.
ekmdb4fecf2015-06-22 17:49:08 -0700114 rtc::scoped_ptr<rtc::scoped_ptr<std::complex<float>[]>[]> history_;
115 rtc::scoped_ptr<rtc::scoped_ptr<std::complex<float>[]>[]> subhistory_;
116 rtc::scoped_ptr<rtc::scoped_ptr<std::complex<float>[]>[]> subhistory_sq_;
ekm030249d2015-06-15 13:02:24 -0700117
118 // The current set of variances and sums for Welford's algorithm.
ekmdb4fecf2015-06-22 17:49:08 -0700119 rtc::scoped_ptr<float[]> variance_;
120 rtc::scoped_ptr<float[]> conj_sum_;
ekm030249d2015-06-15 13:02:24 -0700121
122 const int freqs_;
123 const int window_size_;
124 const float decay_;
125 int history_cursor_;
126 int count_;
127 float array_mean_;
ekm35b72fb2015-07-10 14:11:52 -0700128 bool buffer_full_;
ekm030249d2015-06-15 13:02:24 -0700129 void (VarianceArray::*step_func_)(const std::complex<float>*, bool);
130};
131
132// Helper class for smoothing gain changes. On each applicatiion step, the
133// currently used gains are changed towards a set of settable target gains,
134// constrained by a limit on the magnitude of the changes.
135class GainApplier {
136 public:
137 GainApplier(int freqs, float change_limit);
138
139 // Copy |in_block| to |out_block|, multiplied by the current set of gains,
140 // and step the current set of gains towards the target set.
141 void Apply(const std::complex<float>* in_block,
142 std::complex<float>* out_block);
143
144 // Return the current target gain set. Modify this array to set the targets.
ekmdb4fecf2015-06-22 17:49:08 -0700145 float* target() const { return target_.get(); }
ekm030249d2015-06-15 13:02:24 -0700146
147 private:
148 const int freqs_;
149 const float change_limit_;
ekmdb4fecf2015-06-22 17:49:08 -0700150 rtc::scoped_ptr<float[]> target_;
151 rtc::scoped_ptr<float[]> current_;
ekm030249d2015-06-15 13:02:24 -0700152};
153
154} // namespace intelligibility
155
156} // namespace webrtc
157
158#endif // WEBRTC_MODULES_AUDIO_PROCESSING_INTELLIGIBILITY_INTELLIGIBILITY_UTILS_H_