Line data Source code
1 : /*
2 : * Copyright (c) 2012 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/modules/audio_coding/neteq/audio_vector.h"
12 :
13 : #include <assert.h>
14 :
15 : #include <algorithm>
16 : #include <memory>
17 :
18 : #include "webrtc/base/checks.h"
19 : #include "webrtc/typedefs.h"
20 :
21 : namespace webrtc {
22 :
23 0 : AudioVector::AudioVector()
24 0 : : AudioVector(kDefaultInitialSize) {
25 0 : Clear();
26 0 : }
27 :
28 0 : AudioVector::AudioVector(size_t initial_size)
29 0 : : array_(new int16_t[initial_size + 1]),
30 0 : capacity_(initial_size + 1),
31 : begin_index_(0),
32 0 : end_index_(capacity_ - 1) {
33 0 : memset(array_.get(), 0, capacity_ * sizeof(int16_t));
34 0 : }
35 :
36 : AudioVector::~AudioVector() = default;
37 :
38 0 : void AudioVector::Clear() {
39 0 : end_index_ = begin_index_ = 0;
40 0 : }
41 :
42 0 : void AudioVector::CopyTo(AudioVector* copy_to) const {
43 0 : RTC_DCHECK(copy_to);
44 0 : copy_to->Reserve(Size());
45 0 : CopyTo(Size(), 0, copy_to->array_.get());
46 0 : copy_to->begin_index_ = 0;
47 0 : copy_to->end_index_ = Size();
48 0 : }
49 :
50 0 : void AudioVector::CopyTo(
51 : size_t length, size_t position, int16_t* copy_to) const {
52 0 : if (length == 0)
53 0 : return;
54 0 : length = std::min(length, Size() - position);
55 0 : const size_t copy_index = (begin_index_ + position) % capacity_;
56 : const size_t first_chunk_length =
57 0 : std::min(length, capacity_ - copy_index);
58 0 : memcpy(copy_to, &array_[copy_index],
59 0 : first_chunk_length * sizeof(int16_t));
60 0 : const size_t remaining_length = length - first_chunk_length;
61 0 : if (remaining_length > 0) {
62 0 : memcpy(©_to[first_chunk_length], array_.get(),
63 0 : remaining_length * sizeof(int16_t));
64 : }
65 : }
66 :
67 0 : void AudioVector::PushFront(const AudioVector& prepend_this) {
68 0 : const size_t length = prepend_this.Size();
69 0 : if (length == 0)
70 0 : return;
71 :
72 : // Although the subsequent calling to PushFront does Reserve in it, it is
73 : // always more efficient to do a big Reserve first.
74 0 : Reserve(Size() + length);
75 :
76 : const size_t first_chunk_length =
77 0 : std::min(length, prepend_this.capacity_ - prepend_this.begin_index_);
78 0 : const size_t remaining_length = length - first_chunk_length;
79 0 : if (remaining_length > 0)
80 0 : PushFront(prepend_this.array_.get(), remaining_length);
81 0 : PushFront(&prepend_this.array_[prepend_this.begin_index_],
82 0 : first_chunk_length);
83 : }
84 :
85 0 : void AudioVector::PushFront(const int16_t* prepend_this, size_t length) {
86 0 : if (length == 0)
87 0 : return;
88 0 : Reserve(Size() + length);
89 0 : const size_t first_chunk_length = std::min(length, begin_index_);
90 0 : memcpy(&array_[begin_index_ - first_chunk_length],
91 0 : &prepend_this[length - first_chunk_length],
92 0 : first_chunk_length * sizeof(int16_t));
93 0 : const size_t remaining_length = length - first_chunk_length;
94 0 : if (remaining_length > 0) {
95 0 : memcpy(&array_[capacity_ - remaining_length], prepend_this,
96 0 : remaining_length * sizeof(int16_t));
97 : }
98 0 : begin_index_ = (begin_index_ + capacity_ - length) % capacity_;
99 : }
100 :
101 0 : void AudioVector::PushBack(const AudioVector& append_this) {
102 0 : PushBack(append_this, append_this.Size(), 0);
103 0 : }
104 :
105 0 : void AudioVector::PushBack(
106 : const AudioVector& append_this, size_t length, size_t position) {
107 0 : RTC_DCHECK_LE(position, append_this.Size());
108 0 : RTC_DCHECK_LE(length, append_this.Size() - position);
109 :
110 0 : if (length == 0)
111 0 : return;
112 :
113 : // Although the subsequent calling to PushBack does Reserve in it, it is
114 : // always more efficient to do a big Reserve first.
115 0 : Reserve(Size() + length);
116 :
117 : const size_t start_index =
118 0 : (append_this.begin_index_ + position) % append_this.capacity_;
119 : const size_t first_chunk_length = std::min(
120 0 : length, append_this.capacity_ - start_index);
121 0 : PushBack(&append_this.array_[start_index], first_chunk_length);
122 :
123 0 : const size_t remaining_length = length - first_chunk_length;
124 0 : if (remaining_length > 0)
125 0 : PushBack(append_this.array_.get(), remaining_length);
126 : }
127 :
128 0 : void AudioVector::PushBack(const int16_t* append_this, size_t length) {
129 0 : if (length == 0)
130 0 : return;
131 0 : Reserve(Size() + length);
132 0 : const size_t first_chunk_length = std::min(length, capacity_ - end_index_);
133 0 : memcpy(&array_[end_index_], append_this,
134 0 : first_chunk_length * sizeof(int16_t));
135 0 : const size_t remaining_length = length - first_chunk_length;
136 0 : if (remaining_length > 0) {
137 0 : memcpy(array_.get(), &append_this[first_chunk_length],
138 0 : remaining_length * sizeof(int16_t));
139 : }
140 0 : end_index_ = (end_index_ + length) % capacity_;
141 : }
142 :
143 0 : void AudioVector::PopFront(size_t length) {
144 0 : if (length == 0)
145 0 : return;
146 0 : length = std::min(length, Size());
147 0 : begin_index_ = (begin_index_ + length) % capacity_;
148 : }
149 :
150 0 : void AudioVector::PopBack(size_t length) {
151 0 : if (length == 0)
152 0 : return;
153 : // Never remove more than what is in the array.
154 0 : length = std::min(length, Size());
155 0 : end_index_ = (end_index_ + capacity_ - length) % capacity_;
156 : }
157 :
158 0 : void AudioVector::Extend(size_t extra_length) {
159 0 : if (extra_length == 0)
160 0 : return;
161 0 : InsertZerosByPushBack(extra_length, Size());
162 : }
163 :
164 0 : void AudioVector::InsertAt(const int16_t* insert_this,
165 : size_t length,
166 : size_t position) {
167 0 : if (length == 0)
168 0 : return;
169 : // Cap the insert position at the current array length.
170 0 : position = std::min(Size(), position);
171 :
172 : // When inserting to a position closer to the beginning, it is more efficient
173 : // to insert by pushing front than to insert by pushing back, since less data
174 : // will be moved, vice versa.
175 0 : if (position <= Size() - position) {
176 0 : InsertByPushFront(insert_this, length, position);
177 : } else {
178 0 : InsertByPushBack(insert_this, length, position);
179 : }
180 : }
181 :
182 0 : void AudioVector::InsertZerosAt(size_t length,
183 : size_t position) {
184 0 : if (length == 0)
185 0 : return;
186 : // Cap the insert position at the current array length.
187 0 : position = std::min(Size(), position);
188 :
189 : // When inserting to a position closer to the beginning, it is more efficient
190 : // to insert by pushing front than to insert by pushing back, since less data
191 : // will be moved, vice versa.
192 0 : if (position <= Size() - position) {
193 0 : InsertZerosByPushFront(length, position);
194 : } else {
195 0 : InsertZerosByPushBack(length, position);
196 : }
197 : }
198 :
199 0 : void AudioVector::OverwriteAt(const AudioVector& insert_this,
200 : size_t length,
201 : size_t position) {
202 0 : RTC_DCHECK_LE(length, insert_this.Size());
203 0 : if (length == 0)
204 0 : return;
205 :
206 : // Cap the insert position at the current array length.
207 0 : position = std::min(Size(), position);
208 :
209 : // Although the subsequent calling to OverwriteAt does Reserve in it, it is
210 : // always more efficient to do a big Reserve first.
211 0 : size_t new_size = std::max(Size(), position + length);
212 0 : Reserve(new_size);
213 :
214 : const size_t first_chunk_length =
215 0 : std::min(length, insert_this.capacity_ - insert_this.begin_index_);
216 0 : OverwriteAt(&insert_this.array_[insert_this.begin_index_], first_chunk_length,
217 0 : position);
218 0 : const size_t remaining_length = length - first_chunk_length;
219 0 : if (remaining_length > 0) {
220 0 : OverwriteAt(insert_this.array_.get(), remaining_length,
221 0 : position + first_chunk_length);
222 : }
223 : }
224 :
225 0 : void AudioVector::OverwriteAt(const int16_t* insert_this,
226 : size_t length,
227 : size_t position) {
228 0 : if (length == 0)
229 0 : return;
230 : // Cap the insert position at the current array length.
231 0 : position = std::min(Size(), position);
232 :
233 0 : size_t new_size = std::max(Size(), position + length);
234 0 : Reserve(new_size);
235 :
236 0 : const size_t overwrite_index = (begin_index_ + position) % capacity_;
237 : const size_t first_chunk_length =
238 0 : std::min(length, capacity_ - overwrite_index);
239 0 : memcpy(&array_[overwrite_index], insert_this,
240 0 : first_chunk_length * sizeof(int16_t));
241 0 : const size_t remaining_length = length - first_chunk_length;
242 0 : if (remaining_length > 0) {
243 0 : memcpy(array_.get(), &insert_this[first_chunk_length],
244 0 : remaining_length * sizeof(int16_t));
245 : }
246 :
247 0 : end_index_ = (begin_index_ + new_size) % capacity_;
248 : }
249 :
250 0 : void AudioVector::CrossFade(const AudioVector& append_this,
251 : size_t fade_length) {
252 : // Fade length cannot be longer than the current vector or |append_this|.
253 0 : assert(fade_length <= Size());
254 0 : assert(fade_length <= append_this.Size());
255 0 : fade_length = std::min(fade_length, Size());
256 0 : fade_length = std::min(fade_length, append_this.Size());
257 0 : size_t position = Size() - fade_length + begin_index_;
258 : // Cross fade the overlapping regions.
259 : // |alpha| is the mixing factor in Q14.
260 : // TODO(hlundin): Consider skipping +1 in the denominator to produce a
261 : // smoother cross-fade, in particular at the end of the fade.
262 0 : int alpha_step = 16384 / (static_cast<int>(fade_length) + 1);
263 0 : int alpha = 16384;
264 0 : for (size_t i = 0; i < fade_length; ++i) {
265 0 : alpha -= alpha_step;
266 0 : array_[(position + i) % capacity_] =
267 0 : (alpha * array_[(position + i) % capacity_] +
268 0 : (16384 - alpha) * append_this[i] + 8192) >> 14;
269 : }
270 0 : assert(alpha >= 0); // Verify that the slope was correct.
271 : // Append what is left of |append_this|.
272 0 : size_t samples_to_push_back = append_this.Size() - fade_length;
273 0 : if (samples_to_push_back > 0)
274 0 : PushBack(append_this, samples_to_push_back, fade_length);
275 0 : }
276 :
277 : // Returns the number of elements in this AudioVector.
278 0 : size_t AudioVector::Size() const {
279 0 : return (end_index_ + capacity_ - begin_index_) % capacity_;
280 : }
281 :
282 : // Returns true if this AudioVector is empty.
283 0 : bool AudioVector::Empty() const {
284 0 : return begin_index_ == end_index_;
285 : }
286 :
287 0 : const int16_t& AudioVector::operator[](size_t index) const {
288 0 : return array_[(begin_index_ + index) % capacity_];
289 : }
290 :
291 0 : int16_t& AudioVector::operator[](size_t index) {
292 0 : return array_[(begin_index_ + index) % capacity_];
293 : }
294 :
295 0 : void AudioVector::Reserve(size_t n) {
296 0 : if (capacity_ > n)
297 0 : return;
298 0 : const size_t length = Size();
299 : // Reserve one more sample to remove the ambiguity between empty vector and
300 : // full vector. Therefore |begin_index_| == |end_index_| indicates empty
301 : // vector, and |begin_index_| == (|end_index_| + 1) % capacity indicates
302 : // full vector.
303 0 : std::unique_ptr<int16_t[]> temp_array(new int16_t[n + 1]);
304 0 : CopyTo(length, 0, temp_array.get());
305 0 : array_.swap(temp_array);
306 0 : begin_index_ = 0;
307 0 : end_index_ = length;
308 0 : capacity_ = n + 1;
309 : }
310 :
311 0 : void AudioVector::InsertByPushBack(const int16_t* insert_this,
312 : size_t length,
313 : size_t position) {
314 0 : const size_t move_chunk_length = Size() - position;
315 0 : std::unique_ptr<int16_t[]> temp_array(nullptr);
316 0 : if (move_chunk_length > 0) {
317 : // TODO(minyue): see if it is possible to avoid copying to a buffer.
318 0 : temp_array.reset(new int16_t[move_chunk_length]);
319 0 : CopyTo(move_chunk_length, position, temp_array.get());
320 0 : PopBack(move_chunk_length);
321 : }
322 :
323 0 : Reserve(Size() + length + move_chunk_length);
324 0 : PushBack(insert_this, length);
325 0 : if (move_chunk_length > 0)
326 0 : PushBack(temp_array.get(), move_chunk_length);
327 0 : }
328 :
329 0 : void AudioVector::InsertByPushFront(const int16_t* insert_this,
330 : size_t length,
331 : size_t position) {
332 0 : std::unique_ptr<int16_t[]> temp_array(nullptr);
333 0 : if (position > 0) {
334 : // TODO(minyue): see if it is possible to avoid copying to a buffer.
335 0 : temp_array.reset(new int16_t[position]);
336 0 : CopyTo(position, 0, temp_array.get());
337 0 : PopFront(position);
338 : }
339 :
340 0 : Reserve(Size() + length + position);
341 0 : PushFront(insert_this, length);
342 0 : if (position > 0)
343 0 : PushFront(temp_array.get(), position);
344 0 : }
345 :
346 0 : void AudioVector::InsertZerosByPushBack(size_t length,
347 : size_t position) {
348 0 : const size_t move_chunk_length = Size() - position;
349 0 : std::unique_ptr<int16_t[]> temp_array(nullptr);
350 0 : if (move_chunk_length > 0) {
351 0 : temp_array.reset(new int16_t[move_chunk_length]);
352 0 : CopyTo(move_chunk_length, position, temp_array.get());
353 0 : PopBack(move_chunk_length);
354 : }
355 :
356 0 : Reserve(Size() + length + move_chunk_length);
357 :
358 : const size_t first_zero_chunk_length =
359 0 : std::min(length, capacity_ - end_index_);
360 0 : memset(&array_[end_index_], 0, first_zero_chunk_length * sizeof(int16_t));
361 0 : const size_t remaining_zero_length = length - first_zero_chunk_length;
362 0 : if (remaining_zero_length > 0)
363 0 : memset(array_.get(), 0, remaining_zero_length * sizeof(int16_t));
364 0 : end_index_ = (end_index_ + length) % capacity_;
365 :
366 0 : if (move_chunk_length > 0)
367 0 : PushBack(temp_array.get(), move_chunk_length);
368 0 : }
369 :
370 0 : void AudioVector::InsertZerosByPushFront(size_t length,
371 : size_t position) {
372 0 : std::unique_ptr<int16_t[]> temp_array(nullptr);
373 0 : if (position > 0) {
374 0 : temp_array.reset(new int16_t[position]);
375 0 : CopyTo(position, 0, temp_array.get());
376 0 : PopFront(position);
377 : }
378 :
379 0 : Reserve(Size() + length + position);
380 :
381 0 : const size_t first_zero_chunk_length = std::min(length, begin_index_);
382 0 : memset(&array_[begin_index_ - first_zero_chunk_length], 0,
383 0 : first_zero_chunk_length * sizeof(int16_t));
384 0 : const size_t remaining_zero_length = length - first_zero_chunk_length;
385 0 : if (remaining_zero_length > 0)
386 0 : memset(&array_[capacity_ - remaining_zero_length], 0,
387 0 : remaining_zero_length * sizeof(int16_t));
388 0 : begin_index_ = (begin_index_ + capacity_ - length) % capacity_;
389 :
390 0 : if (position > 0)
391 0 : PushFront(temp_array.get(), position);
392 0 : }
393 :
394 : } // namespace webrtc
|