OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 24 matching lines...) Expand all Loading... |
35 | 35 |
36 #include "webrtc/modules/audio_processing/three_band_filter_bank.h" | 36 #include "webrtc/modules/audio_processing/three_band_filter_bank.h" |
37 | 37 |
38 #include <cmath> | 38 #include <cmath> |
39 | 39 |
40 #include "webrtc/base/checks.h" | 40 #include "webrtc/base/checks.h" |
41 | 41 |
42 namespace webrtc { | 42 namespace webrtc { |
43 namespace { | 43 namespace { |
44 | 44 |
45 const int kNumBands = 3; | 45 const size_t kNumBands = 3; |
46 const int kSparsity = 4; | 46 const size_t kSparsity = 4; |
47 | 47 |
48 // Factors to take into account when choosing |kNumCoeffs|: | 48 // Factors to take into account when choosing |kNumCoeffs|: |
49 // 1. Higher |kNumCoeffs|, means faster transition, which ensures less | 49 // 1. Higher |kNumCoeffs|, means faster transition, which ensures less |
50 // aliasing. This is especially important when there is non-linear | 50 // aliasing. This is especially important when there is non-linear |
51 // processing between the splitting and merging. | 51 // processing between the splitting and merging. |
52 // 2. The delay that this filter bank introduces is | 52 // 2. The delay that this filter bank introduces is |
53 // |kNumBands| * |kSparsity| * |kNumCoeffs| / 2, so it increases linearly | 53 // |kNumBands| * |kSparsity| * |kNumCoeffs| / 2, so it increases linearly |
54 // with |kNumCoeffs|. | 54 // with |kNumCoeffs|. |
55 // 3. The computation complexity also increases linearly with |kNumCoeffs|. | 55 // 3. The computation complexity also increases linearly with |kNumCoeffs|. |
56 const int kNumCoeffs = 4; | 56 const size_t kNumCoeffs = 4; |
57 | 57 |
58 // The Matlab code to generate these |kLowpassCoeffs| is: | 58 // The Matlab code to generate these |kLowpassCoeffs| is: |
59 // | 59 // |
60 // N = kNumBands * kSparsity * kNumCoeffs - 1; | 60 // N = kNumBands * kSparsity * kNumCoeffs - 1; |
61 // h = fir1(N, 1 / (2 * kNumBands), kaiser(N + 1, 3.5)); | 61 // h = fir1(N, 1 / (2 * kNumBands), kaiser(N + 1, 3.5)); |
62 // reshape(h, kNumBands * kSparsity, kNumCoeffs); | 62 // reshape(h, kNumBands * kSparsity, kNumCoeffs); |
63 // | 63 // |
64 // Because the total bandwidth of the lower and higher band is double the middle | 64 // Because the total bandwidth of the lower and higher band is double the middle |
65 // one (because of the spectrum parity), the low-pass prototype is half the | 65 // one (because of the spectrum parity), the low-pass prototype is half the |
66 // bandwidth of 1 / (2 * |kNumBands|) and is then shifted with cosine modulation | 66 // bandwidth of 1 / (2 * |kNumBands|) and is then shifted with cosine modulation |
(...skipping 11 matching lines...) Expand all Loading... |
78 {+0.00186353f, +0.01387458f, -0.01136076f, -0.00154717f}, | 78 {+0.00186353f, +0.01387458f, -0.01136076f, -0.00154717f}, |
79 {+0.00607594f, +0.04760441f, -0.02587886f, -0.00346946f}, | 79 {+0.00607594f, +0.04760441f, -0.02587886f, -0.00346946f}, |
80 {+0.00983212f, +0.08543175f, -0.02982767f, -0.00383509f}, | 80 {+0.00983212f, +0.08543175f, -0.02982767f, -0.00383509f}, |
81 {+0.01157993f, +0.12154542f, -0.02536082f, -0.00304815f}, | 81 {+0.01157993f, +0.12154542f, -0.02536082f, -0.00304815f}, |
82 {+0.00994113f, +0.14989004f, -0.01585778f, -0.00173287f}, | 82 {+0.00994113f, +0.14989004f, -0.01585778f, -0.00173287f}, |
83 {+0.00425496f, +0.16547118f, -0.00496888f, -0.00047749f}}; | 83 {+0.00425496f, +0.16547118f, -0.00496888f, -0.00047749f}}; |
84 | 84 |
85 // Downsamples |in| into |out|, taking one every |kNumbands| starting from | 85 // Downsamples |in| into |out|, taking one every |kNumbands| starting from |
86 // |offset|. |split_length| is the |out| length. |in| has to be at least | 86 // |offset|. |split_length| is the |out| length. |in| has to be at least |
87 // |kNumBands| * |split_length| long. | 87 // |kNumBands| * |split_length| long. |
88 void Downsample(const float* in, int split_length, int offset, float* out) { | 88 void Downsample(const float* in, |
89 for (int i = 0; i < split_length; ++i) { | 89 size_t split_length, |
| 90 size_t offset, |
| 91 float* out) { |
| 92 for (size_t i = 0; i < split_length; ++i) { |
90 out[i] = in[kNumBands * i + offset]; | 93 out[i] = in[kNumBands * i + offset]; |
91 } | 94 } |
92 } | 95 } |
93 | 96 |
94 // Upsamples |in| into |out|, scaling by |kNumBands| and accumulating it every | 97 // Upsamples |in| into |out|, scaling by |kNumBands| and accumulating it every |
95 // |kNumBands| starting from |offset|. |split_length| is the |in| length. |out| | 98 // |kNumBands| starting from |offset|. |split_length| is the |in| length. |out| |
96 // has to be at least |kNumBands| * |split_length| long. | 99 // has to be at least |kNumBands| * |split_length| long. |
97 void Upsample(const float* in, int split_length, int offset, float* out) { | 100 void Upsample(const float* in, size_t split_length, size_t offset, float* out) { |
98 for (int i = 0; i < split_length; ++i) { | 101 for (size_t i = 0; i < split_length; ++i) { |
99 out[kNumBands * i + offset] += kNumBands * in[i]; | 102 out[kNumBands * i + offset] += kNumBands * in[i]; |
100 } | 103 } |
101 } | 104 } |
102 | 105 |
103 } // namespace | 106 } // namespace |
104 | 107 |
105 // Because the low-pass filter prototype has half bandwidth it is possible to | 108 // Because the low-pass filter prototype has half bandwidth it is possible to |
106 // use a DCT to shift it in both directions at the same time, to the center | 109 // use a DCT to shift it in both directions at the same time, to the center |
107 // frequencies [1 / 12, 3 / 12, 5 / 12]. | 110 // frequencies [1 / 12, 3 / 12, 5 / 12]. |
108 ThreeBandFilterBank::ThreeBandFilterBank(int length) | 111 ThreeBandFilterBank::ThreeBandFilterBank(size_t length) |
109 : in_buffer_(rtc::CheckedDivExact(length, kNumBands)), | 112 : in_buffer_(rtc::CheckedDivExact(length, kNumBands)), |
110 out_buffer_(in_buffer_.size()) { | 113 out_buffer_(in_buffer_.size()) { |
111 for (int i = 0; i < kSparsity; ++i) { | 114 for (size_t i = 0; i < kSparsity; ++i) { |
112 for (int j = 0; j < kNumBands; ++j) { | 115 for (size_t j = 0; j < kNumBands; ++j) { |
113 analysis_filters_.push_back(new SparseFIRFilter( | 116 analysis_filters_.push_back(new SparseFIRFilter( |
114 kLowpassCoeffs[i * kNumBands + j], kNumCoeffs, kSparsity, i)); | 117 kLowpassCoeffs[i * kNumBands + j], kNumCoeffs, kSparsity, i)); |
115 synthesis_filters_.push_back(new SparseFIRFilter( | 118 synthesis_filters_.push_back(new SparseFIRFilter( |
116 kLowpassCoeffs[i * kNumBands + j], kNumCoeffs, kSparsity, i)); | 119 kLowpassCoeffs[i * kNumBands + j], kNumCoeffs, kSparsity, i)); |
117 } | 120 } |
118 } | 121 } |
119 dct_modulation_.resize(kNumBands * kSparsity); | 122 dct_modulation_.resize(kNumBands * kSparsity); |
120 for (size_t i = 0; i < dct_modulation_.size(); ++i) { | 123 for (size_t i = 0; i < dct_modulation_.size(); ++i) { |
121 dct_modulation_[i].resize(kNumBands); | 124 dct_modulation_[i].resize(kNumBands); |
122 for (int j = 0; j < kNumBands; ++j) { | 125 for (size_t j = 0; j < kNumBands; ++j) { |
123 dct_modulation_[i][j] = | 126 dct_modulation_[i][j] = |
124 2.f * cos(2.f * M_PI * i * (2.f * j + 1.f) / dct_modulation_.size()); | 127 2.f * cos(2.f * M_PI * i * (2.f * j + 1.f) / dct_modulation_.size()); |
125 } | 128 } |
126 } | 129 } |
127 } | 130 } |
128 | 131 |
129 // The analysis can be separated in these steps: | 132 // The analysis can be separated in these steps: |
130 // 1. Serial to parallel downsampling by a factor of |kNumBands|. | 133 // 1. Serial to parallel downsampling by a factor of |kNumBands|. |
131 // 2. Filtering of |kSparsity| different delayed signals with polyphase | 134 // 2. Filtering of |kSparsity| different delayed signals with polyphase |
132 // decomposition of the low-pass prototype filter and upsampled by a factor | 135 // decomposition of the low-pass prototype filter and upsampled by a factor |
133 // of |kSparsity|. | 136 // of |kSparsity|. |
134 // 3. Modulating with cosines and accumulating to get the desired band. | 137 // 3. Modulating with cosines and accumulating to get the desired band. |
135 void ThreeBandFilterBank::Analysis(const float* in, | 138 void ThreeBandFilterBank::Analysis(const float* in, |
136 int length, | 139 size_t length, |
137 float* const* out) { | 140 float* const* out) { |
138 CHECK_EQ(static_cast<int>(in_buffer_.size()), | 141 CHECK_EQ(in_buffer_.size(), rtc::CheckedDivExact(length, kNumBands)); |
139 rtc::CheckedDivExact(length, kNumBands)); | 142 for (size_t i = 0; i < kNumBands; ++i) { |
140 for (int i = 0; i < kNumBands; ++i) { | |
141 memset(out[i], 0, in_buffer_.size() * sizeof(*out[i])); | 143 memset(out[i], 0, in_buffer_.size() * sizeof(*out[i])); |
142 } | 144 } |
143 for (int i = 0; i < kNumBands; ++i) { | 145 for (size_t i = 0; i < kNumBands; ++i) { |
144 Downsample(in, in_buffer_.size(), kNumBands - i - 1, &in_buffer_[0]); | 146 Downsample(in, in_buffer_.size(), kNumBands - i - 1, &in_buffer_[0]); |
145 for (int j = 0; j < kSparsity; ++j) { | 147 for (size_t j = 0; j < kSparsity; ++j) { |
146 const int offset = i + j * kNumBands; | 148 const size_t offset = i + j * kNumBands; |
147 analysis_filters_[offset]->Filter(&in_buffer_[0], | 149 analysis_filters_[offset]->Filter(&in_buffer_[0], |
148 in_buffer_.size(), | 150 in_buffer_.size(), |
149 &out_buffer_[0]); | 151 &out_buffer_[0]); |
150 DownModulate(&out_buffer_[0], out_buffer_.size(), offset, out); | 152 DownModulate(&out_buffer_[0], out_buffer_.size(), offset, out); |
151 } | 153 } |
152 } | 154 } |
153 } | 155 } |
154 | 156 |
155 // The synthesis can be separated in these steps: | 157 // The synthesis can be separated in these steps: |
156 // 1. Modulating with cosines. | 158 // 1. Modulating with cosines. |
157 // 2. Filtering each one with a polyphase decomposition of the low-pass | 159 // 2. Filtering each one with a polyphase decomposition of the low-pass |
158 // prototype filter upsampled by a factor of |kSparsity| and accumulating | 160 // prototype filter upsampled by a factor of |kSparsity| and accumulating |
159 // |kSparsity| signals with different delays. | 161 // |kSparsity| signals with different delays. |
160 // 3. Parallel to serial upsampling by a factor of |kNumBands|. | 162 // 3. Parallel to serial upsampling by a factor of |kNumBands|. |
161 void ThreeBandFilterBank::Synthesis(const float* const* in, | 163 void ThreeBandFilterBank::Synthesis(const float* const* in, |
162 int split_length, | 164 size_t split_length, |
163 float* out) { | 165 float* out) { |
164 CHECK_EQ(static_cast<int>(in_buffer_.size()), split_length); | 166 CHECK_EQ(in_buffer_.size(), split_length); |
165 memset(out, 0, kNumBands * in_buffer_.size() * sizeof(*out)); | 167 memset(out, 0, kNumBands * in_buffer_.size() * sizeof(*out)); |
166 for (int i = 0; i < kNumBands; ++i) { | 168 for (size_t i = 0; i < kNumBands; ++i) { |
167 for (int j = 0; j < kSparsity; ++j) { | 169 for (size_t j = 0; j < kSparsity; ++j) { |
168 const int offset = i + j * kNumBands; | 170 const size_t offset = i + j * kNumBands; |
169 UpModulate(in, in_buffer_.size(), offset, &in_buffer_[0]); | 171 UpModulate(in, in_buffer_.size(), offset, &in_buffer_[0]); |
170 synthesis_filters_[offset]->Filter(&in_buffer_[0], | 172 synthesis_filters_[offset]->Filter(&in_buffer_[0], |
171 in_buffer_.size(), | 173 in_buffer_.size(), |
172 &out_buffer_[0]); | 174 &out_buffer_[0]); |
173 Upsample(&out_buffer_[0], out_buffer_.size(), i, out); | 175 Upsample(&out_buffer_[0], out_buffer_.size(), i, out); |
174 } | 176 } |
175 } | 177 } |
176 } | 178 } |
177 | 179 |
178 | 180 |
179 // Modulates |in| by |dct_modulation_| and accumulates it in each of the | 181 // Modulates |in| by |dct_modulation_| and accumulates it in each of the |
180 // |kNumBands| bands of |out|. |offset| is the index in the period of the | 182 // |kNumBands| bands of |out|. |offset| is the index in the period of the |
181 // cosines used for modulation. |split_length| is the length of |in| and each | 183 // cosines used for modulation. |split_length| is the length of |in| and each |
182 // band of |out|. | 184 // band of |out|. |
183 void ThreeBandFilterBank::DownModulate(const float* in, | 185 void ThreeBandFilterBank::DownModulate(const float* in, |
184 int split_length, | 186 size_t split_length, |
185 int offset, | 187 size_t offset, |
186 float* const* out) { | 188 float* const* out) { |
187 for (int i = 0; i < kNumBands; ++i) { | 189 for (size_t i = 0; i < kNumBands; ++i) { |
188 for (int j = 0; j < split_length; ++j) { | 190 for (size_t j = 0; j < split_length; ++j) { |
189 out[i][j] += dct_modulation_[offset][i] * in[j]; | 191 out[i][j] += dct_modulation_[offset][i] * in[j]; |
190 } | 192 } |
191 } | 193 } |
192 } | 194 } |
193 | 195 |
194 // Modulates each of the |kNumBands| bands of |in| by |dct_modulation_| and | 196 // Modulates each of the |kNumBands| bands of |in| by |dct_modulation_| and |
195 // accumulates them in |out|. |out| is cleared before starting to accumulate. | 197 // accumulates them in |out|. |out| is cleared before starting to accumulate. |
196 // |offset| is the index in the period of the cosines used for modulation. | 198 // |offset| is the index in the period of the cosines used for modulation. |
197 // |split_length| is the length of each band of |in| and |out|. | 199 // |split_length| is the length of each band of |in| and |out|. |
198 void ThreeBandFilterBank::UpModulate(const float* const* in, | 200 void ThreeBandFilterBank::UpModulate(const float* const* in, |
199 int split_length, | 201 size_t split_length, |
200 int offset, | 202 size_t offset, |
201 float* out) { | 203 float* out) { |
202 memset(out, 0, split_length * sizeof(*out)); | 204 memset(out, 0, split_length * sizeof(*out)); |
203 for (int i = 0; i < kNumBands; ++i) { | 205 for (size_t i = 0; i < kNumBands; ++i) { |
204 for (int j = 0; j < split_length; ++j) { | 206 for (size_t j = 0; j < split_length; ++j) { |
205 out[j] += dct_modulation_[offset][i] * in[i][j]; | 207 out[j] += dct_modulation_[offset][i] * in[i][j]; |
206 } | 208 } |
207 } | 209 } |
208 } | 210 } |
209 | 211 |
210 } // namespace webrtc | 212 } // namespace webrtc |
OLD | NEW |