Line data Source code
1 : /*
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 :
11 : #include "webrtc/common_audio/blocker.h"
12 :
13 : #include <string.h>
14 :
15 : #include "webrtc/base/checks.h"
16 :
17 : namespace {
18 :
19 : // Adds |a| and |b| frame by frame into |result| (basically matrix addition).
20 0 : void AddFrames(const float* const* a,
21 : size_t a_start_index,
22 : const float* const* b,
23 : int b_start_index,
24 : size_t num_frames,
25 : size_t num_channels,
26 : float* const* result,
27 : size_t result_start_index) {
28 0 : for (size_t i = 0; i < num_channels; ++i) {
29 0 : for (size_t j = 0; j < num_frames; ++j) {
30 0 : result[i][j + result_start_index] =
31 0 : a[i][j + a_start_index] + b[i][j + b_start_index];
32 : }
33 : }
34 0 : }
35 :
36 : // Copies |src| into |dst| channel by channel.
37 0 : void CopyFrames(const float* const* src,
38 : size_t src_start_index,
39 : size_t num_frames,
40 : size_t num_channels,
41 : float* const* dst,
42 : size_t dst_start_index) {
43 0 : for (size_t i = 0; i < num_channels; ++i) {
44 0 : memcpy(&dst[i][dst_start_index],
45 0 : &src[i][src_start_index],
46 0 : num_frames * sizeof(dst[i][dst_start_index]));
47 : }
48 0 : }
49 :
50 : // Moves |src| into |dst| channel by channel.
51 0 : void MoveFrames(const float* const* src,
52 : size_t src_start_index,
53 : size_t num_frames,
54 : size_t num_channels,
55 : float* const* dst,
56 : size_t dst_start_index) {
57 0 : for (size_t i = 0; i < num_channels; ++i) {
58 0 : memmove(&dst[i][dst_start_index],
59 0 : &src[i][src_start_index],
60 0 : num_frames * sizeof(dst[i][dst_start_index]));
61 : }
62 0 : }
63 :
64 0 : void ZeroOut(float* const* buffer,
65 : size_t starting_idx,
66 : size_t num_frames,
67 : size_t num_channels) {
68 0 : for (size_t i = 0; i < num_channels; ++i) {
69 0 : memset(&buffer[i][starting_idx], 0,
70 0 : num_frames * sizeof(buffer[i][starting_idx]));
71 : }
72 0 : }
73 :
74 : // Pointwise multiplies each channel of |frames| with |window|. Results are
75 : // stored in |frames|.
76 0 : void ApplyWindow(const float* window,
77 : size_t num_frames,
78 : size_t num_channels,
79 : float* const* frames) {
80 0 : for (size_t i = 0; i < num_channels; ++i) {
81 0 : for (size_t j = 0; j < num_frames; ++j) {
82 0 : frames[i][j] = frames[i][j] * window[j];
83 : }
84 : }
85 0 : }
86 :
87 0 : size_t gcd(size_t a, size_t b) {
88 : size_t tmp;
89 0 : while (b) {
90 0 : tmp = a;
91 0 : a = b;
92 0 : b = tmp % b;
93 : }
94 0 : return a;
95 : }
96 :
97 : } // namespace
98 :
99 : namespace webrtc {
100 :
101 0 : Blocker::Blocker(size_t chunk_size,
102 : size_t block_size,
103 : size_t num_input_channels,
104 : size_t num_output_channels,
105 : const float* window,
106 : size_t shift_amount,
107 0 : BlockerCallback* callback)
108 : : chunk_size_(chunk_size),
109 : block_size_(block_size),
110 : num_input_channels_(num_input_channels),
111 : num_output_channels_(num_output_channels),
112 0 : initial_delay_(block_size_ - gcd(chunk_size, shift_amount)),
113 : frame_offset_(0),
114 0 : input_buffer_(num_input_channels_, chunk_size_ + initial_delay_),
115 0 : output_buffer_(chunk_size_ + initial_delay_, num_output_channels_),
116 0 : input_block_(block_size_, num_input_channels_),
117 0 : output_block_(block_size_, num_output_channels_),
118 0 : window_(new float[block_size_]),
119 : shift_amount_(shift_amount),
120 0 : callback_(callback) {
121 0 : RTC_CHECK_LE(num_output_channels_, num_input_channels_);
122 0 : RTC_CHECK_LE(shift_amount_, block_size_);
123 :
124 0 : memcpy(window_.get(), window, block_size_ * sizeof(*window_.get()));
125 0 : input_buffer_.MoveReadPositionBackward(initial_delay_);
126 0 : }
127 :
128 : Blocker::~Blocker() = default;
129 :
130 : // When block_size < chunk_size the input and output buffers look like this:
131 : //
132 : // delay* chunk_size chunk_size + delay*
133 : // buffer: <-------------|---------------------|---------------|>
134 : // _a_ _b_ _c_
135 : //
136 : // On each call to ProcessChunk():
137 : // 1. New input gets read into sections _b_ and _c_ of the input buffer.
138 : // 2. We block starting from frame_offset.
139 : // 3. We block until we reach a block |bl| that doesn't contain any frames
140 : // from sections _a_ or _b_ of the input buffer.
141 : // 4. We window the current block, fire the callback for processing, window
142 : // again, and overlap/add to the output buffer.
143 : // 5. We copy sections _a_ and _b_ of the output buffer into output.
144 : // 6. For both the input and the output buffers, we copy section _c_ into
145 : // section _a_.
146 : // 7. We set the new frame_offset to be the difference between the first frame
147 : // of |bl| and the border between sections _b_ and _c_.
148 : //
149 : // When block_size > chunk_size the input and output buffers look like this:
150 : //
151 : // chunk_size delay* chunk_size + delay*
152 : // buffer: <-------------|---------------------|---------------|>
153 : // _a_ _b_ _c_
154 : //
155 : // On each call to ProcessChunk():
156 : // The procedure is the same as above, except for:
157 : // 1. New input gets read into section _c_ of the input buffer.
158 : // 3. We block until we reach a block |bl| that doesn't contain any frames
159 : // from section _a_ of the input buffer.
160 : // 5. We copy section _a_ of the output buffer into output.
161 : // 6. For both the input and the output buffers, we copy sections _b_ and _c_
162 : // into section _a_ and _b_.
163 : // 7. We set the new frame_offset to be the difference between the first frame
164 : // of |bl| and the border between sections _a_ and _b_.
165 : //
166 : // * delay here refers to inintial_delay_
167 : //
168 : // TODO(claguna): Look at using ring buffers to eliminate some copies.
169 0 : void Blocker::ProcessChunk(const float* const* input,
170 : size_t chunk_size,
171 : size_t num_input_channels,
172 : size_t num_output_channels,
173 : float* const* output) {
174 0 : RTC_CHECK_EQ(chunk_size, chunk_size_);
175 0 : RTC_CHECK_EQ(num_input_channels, num_input_channels_);
176 0 : RTC_CHECK_EQ(num_output_channels, num_output_channels_);
177 :
178 0 : input_buffer_.Write(input, num_input_channels, chunk_size_);
179 0 : size_t first_frame_in_block = frame_offset_;
180 :
181 : // Loop through blocks.
182 0 : while (first_frame_in_block < chunk_size_) {
183 0 : input_buffer_.Read(input_block_.channels(), num_input_channels,
184 0 : block_size_);
185 0 : input_buffer_.MoveReadPositionBackward(block_size_ - shift_amount_);
186 :
187 0 : ApplyWindow(window_.get(),
188 0 : block_size_,
189 0 : num_input_channels_,
190 0 : input_block_.channels());
191 0 : callback_->ProcessBlock(input_block_.channels(),
192 0 : block_size_,
193 0 : num_input_channels_,
194 0 : num_output_channels_,
195 0 : output_block_.channels());
196 0 : ApplyWindow(window_.get(),
197 0 : block_size_,
198 0 : num_output_channels_,
199 0 : output_block_.channels());
200 :
201 0 : AddFrames(output_buffer_.channels(),
202 : first_frame_in_block,
203 0 : output_block_.channels(),
204 : 0,
205 0 : block_size_,
206 0 : num_output_channels_,
207 : output_buffer_.channels(),
208 0 : first_frame_in_block);
209 :
210 0 : first_frame_in_block += shift_amount_;
211 : }
212 :
213 : // Copy output buffer to output
214 0 : CopyFrames(output_buffer_.channels(),
215 : 0,
216 0 : chunk_size_,
217 0 : num_output_channels_,
218 : output,
219 0 : 0);
220 :
221 : // Copy output buffer [chunk_size_, chunk_size_ + initial_delay]
222 : // to output buffer [0, initial_delay], zero the rest.
223 0 : MoveFrames(output_buffer_.channels(),
224 : chunk_size,
225 0 : initial_delay_,
226 0 : num_output_channels_,
227 : output_buffer_.channels(),
228 0 : 0);
229 0 : ZeroOut(output_buffer_.channels(),
230 0 : initial_delay_,
231 0 : chunk_size_,
232 0 : num_output_channels_);
233 :
234 : // Calculate new starting frames.
235 0 : frame_offset_ = first_frame_in_block - chunk_size_;
236 0 : }
237 :
238 : } // namespace webrtc
|