blob: 10e89364475cbe6510c47f26f868bde9059d9f41 [file] [log] [blame]
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +00001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/audio_coding/neteq/audio_vector.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000012
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000013
14#include <algorithm>
kwiberg2d0c3322016-02-14 09:28:33 -080015#include <memory>
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000016
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "rtc_base/checks.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000018
19namespace webrtc {
20
Yves Gerey665174f2018-06-19 15:03:05 +020021AudioVector::AudioVector() : AudioVector(kDefaultInitialSize) {
minyue-webrtc79553cb2016-05-10 19:55:56 +020022 Clear();
Karl Wiberg7f6c4d42015-04-09 15:44:22 +020023}
24
25AudioVector::AudioVector(size_t initial_size)
minyue-webrtc79553cb2016-05-10 19:55:56 +020026 : array_(new int16_t[initial_size + 1]),
27 capacity_(initial_size + 1),
28 begin_index_(0),
29 end_index_(capacity_ - 1) {
30 memset(array_.get(), 0, capacity_ * sizeof(int16_t));
Karl Wiberg7f6c4d42015-04-09 15:44:22 +020031}
32
33AudioVector::~AudioVector() = default;
34
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +000035void AudioVector::Clear() {
minyue-webrtc79553cb2016-05-10 19:55:56 +020036 end_index_ = begin_index_ = 0;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000037}
38
henrik.lundin@webrtc.orgf6ab6f82014-09-04 10:58:43 +000039void AudioVector::CopyTo(AudioVector* copy_to) const {
minyue-webrtc79553cb2016-05-10 19:55:56 +020040 RTC_DCHECK(copy_to);
41 copy_to->Reserve(Size());
42 CopyTo(Size(), 0, copy_to->array_.get());
43 copy_to->begin_index_ = 0;
44 copy_to->end_index_ = Size();
45}
46
Yves Gerey665174f2018-06-19 15:03:05 +020047void AudioVector::CopyTo(size_t length,
48 size_t position,
49 int16_t* copy_to) const {
minyue-webrtc79553cb2016-05-10 19:55:56 +020050 if (length == 0)
51 return;
52 length = std::min(length, Size() - position);
53 const size_t copy_index = (begin_index_ + position) % capacity_;
Yves Gerey665174f2018-06-19 15:03:05 +020054 const size_t first_chunk_length = std::min(length, capacity_ - copy_index);
55 memcpy(copy_to, &array_[copy_index], first_chunk_length * sizeof(int16_t));
minyue-webrtc79553cb2016-05-10 19:55:56 +020056 const size_t remaining_length = length - first_chunk_length;
57 if (remaining_length > 0) {
58 memcpy(&copy_to[first_chunk_length], array_.get(),
59 remaining_length * sizeof(int16_t));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000060 }
61}
62
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +000063void AudioVector::PushFront(const AudioVector& prepend_this) {
minyue-webrtc79553cb2016-05-10 19:55:56 +020064 const size_t length = prepend_this.Size();
65 if (length == 0)
66 return;
67
68 // Although the subsequent calling to PushFront does Reserve in it, it is
69 // always more efficient to do a big Reserve first.
70 Reserve(Size() + length);
71
72 const size_t first_chunk_length =
73 std::min(length, prepend_this.capacity_ - prepend_this.begin_index_);
74 const size_t remaining_length = length - first_chunk_length;
75 if (remaining_length > 0)
76 PushFront(prepend_this.array_.get(), remaining_length);
77 PushFront(&prepend_this.array_[prepend_this.begin_index_],
78 first_chunk_length);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000079}
80
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +000081void AudioVector::PushFront(const int16_t* prepend_this, size_t length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +020082 if (length == 0)
83 return;
84 Reserve(Size() + length);
85 const size_t first_chunk_length = std::min(length, begin_index_);
86 memcpy(&array_[begin_index_ - first_chunk_length],
87 &prepend_this[length - first_chunk_length],
88 first_chunk_length * sizeof(int16_t));
89 const size_t remaining_length = length - first_chunk_length;
90 if (remaining_length > 0) {
91 memcpy(&array_[capacity_ - remaining_length], prepend_this,
92 remaining_length * sizeof(int16_t));
93 }
94 begin_index_ = (begin_index_ + capacity_ - length) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000095}
96
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +000097void AudioVector::PushBack(const AudioVector& append_this) {
minyue-webrtc79553cb2016-05-10 19:55:56 +020098 PushBack(append_this, append_this.Size(), 0);
99}
100
Yves Gerey665174f2018-06-19 15:03:05 +0200101void AudioVector::PushBack(const AudioVector& append_this,
102 size_t length,
103 size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200104 RTC_DCHECK_LE(position, append_this.Size());
105 RTC_DCHECK_LE(length, append_this.Size() - position);
106
107 if (length == 0)
108 return;
109
110 // Although the subsequent calling to PushBack does Reserve in it, it is
111 // always more efficient to do a big Reserve first.
112 Reserve(Size() + length);
113
114 const size_t start_index =
115 (append_this.begin_index_ + position) % append_this.capacity_;
Yves Gerey665174f2018-06-19 15:03:05 +0200116 const size_t first_chunk_length =
117 std::min(length, append_this.capacity_ - start_index);
minyue-webrtc79553cb2016-05-10 19:55:56 +0200118 PushBack(&append_this.array_[start_index], first_chunk_length);
119
120 const size_t remaining_length = length - first_chunk_length;
121 if (remaining_length > 0)
122 PushBack(append_this.array_.get(), remaining_length);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000123}
124
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000125void AudioVector::PushBack(const int16_t* append_this, size_t length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200126 if (length == 0)
127 return;
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000128 Reserve(Size() + length);
minyue-webrtc79553cb2016-05-10 19:55:56 +0200129 const size_t first_chunk_length = std::min(length, capacity_ - end_index_);
130 memcpy(&array_[end_index_], append_this,
131 first_chunk_length * sizeof(int16_t));
132 const size_t remaining_length = length - first_chunk_length;
133 if (remaining_length > 0) {
134 memcpy(array_.get(), &append_this[first_chunk_length],
135 remaining_length * sizeof(int16_t));
136 }
137 end_index_ = (end_index_ + length) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000138}
139
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000140void AudioVector::PopFront(size_t length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200141 if (length == 0)
142 return;
143 length = std::min(length, Size());
144 begin_index_ = (begin_index_ + length) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000145}
146
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000147void AudioVector::PopBack(size_t length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200148 if (length == 0)
149 return;
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000150 // Never remove more than what is in the array.
151 length = std::min(length, Size());
minyue-webrtc79553cb2016-05-10 19:55:56 +0200152 end_index_ = (end_index_ + capacity_ - length) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000153}
154
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000155void AudioVector::Extend(size_t extra_length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200156 if (extra_length == 0)
157 return;
158 InsertZerosByPushBack(extra_length, Size());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000159}
160
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000161void AudioVector::InsertAt(const int16_t* insert_this,
162 size_t length,
163 size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200164 if (length == 0)
165 return;
166 // Cap the insert position at the current array length.
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000167 position = std::min(Size(), position);
minyue-webrtc79553cb2016-05-10 19:55:56 +0200168
169 // When inserting to a position closer to the beginning, it is more efficient
170 // to insert by pushing front than to insert by pushing back, since less data
171 // will be moved, vice versa.
172 if (position <= Size() - position) {
173 InsertByPushFront(insert_this, length, position);
174 } else {
175 InsertByPushBack(insert_this, length, position);
176 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000177}
178
Yves Gerey665174f2018-06-19 15:03:05 +0200179void AudioVector::InsertZerosAt(size_t length, size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200180 if (length == 0)
181 return;
182 // Cap the insert position at the current array length.
183 position = std::min(Size(), position);
184
185 // When inserting to a position closer to the beginning, it is more efficient
186 // to insert by pushing front than to insert by pushing back, since less data
187 // will be moved, vice versa.
188 if (position <= Size() - position) {
189 InsertZerosByPushFront(length, position);
190 } else {
191 InsertZerosByPushBack(length, position);
192 }
193}
194
195void AudioVector::OverwriteAt(const AudioVector& insert_this,
196 size_t length,
197 size_t position) {
198 RTC_DCHECK_LE(length, insert_this.Size());
199 if (length == 0)
200 return;
201
202 // Cap the insert position at the current array length.
203 position = std::min(Size(), position);
204
205 // Although the subsequent calling to OverwriteAt does Reserve in it, it is
206 // always more efficient to do a big Reserve first.
207 size_t new_size = std::max(Size(), position + length);
208 Reserve(new_size);
209
210 const size_t first_chunk_length =
211 std::min(length, insert_this.capacity_ - insert_this.begin_index_);
212 OverwriteAt(&insert_this.array_[insert_this.begin_index_], first_chunk_length,
213 position);
214 const size_t remaining_length = length - first_chunk_length;
215 if (remaining_length > 0) {
216 OverwriteAt(insert_this.array_.get(), remaining_length,
217 position + first_chunk_length);
218 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000219}
220
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000221void AudioVector::OverwriteAt(const int16_t* insert_this,
222 size_t length,
223 size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200224 if (length == 0)
225 return;
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000226 // Cap the insert position at the current array length.
227 position = std::min(Size(), position);
minyue-webrtc79553cb2016-05-10 19:55:56 +0200228
229 size_t new_size = std::max(Size(), position + length);
230 Reserve(new_size);
231
232 const size_t overwrite_index = (begin_index_ + position) % capacity_;
233 const size_t first_chunk_length =
234 std::min(length, capacity_ - overwrite_index);
235 memcpy(&array_[overwrite_index], insert_this,
236 first_chunk_length * sizeof(int16_t));
237 const size_t remaining_length = length - first_chunk_length;
238 if (remaining_length > 0) {
239 memcpy(array_.get(), &insert_this[first_chunk_length],
240 remaining_length * sizeof(int16_t));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000241 }
minyue-webrtc79553cb2016-05-10 19:55:56 +0200242
243 end_index_ = (begin_index_ + new_size) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000244}
245
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000246void AudioVector::CrossFade(const AudioVector& append_this,
247 size_t fade_length) {
Artem Titovd00ce742021-07-28 20:00:17 +0200248 // Fade length cannot be longer than the current vector or `append_this`.
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200249 RTC_DCHECK_LE(fade_length, Size());
250 RTC_DCHECK_LE(fade_length, append_this.Size());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000251 fade_length = std::min(fade_length, Size());
252 fade_length = std::min(fade_length, append_this.Size());
minyue-webrtc79553cb2016-05-10 19:55:56 +0200253 size_t position = Size() - fade_length + begin_index_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000254 // Cross fade the overlapping regions.
Artem Titovd00ce742021-07-28 20:00:17 +0200255 // `alpha` is the mixing factor in Q14.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000256 // TODO(hlundin): Consider skipping +1 in the denominator to produce a
257 // smoother cross-fade, in particular at the end of the fade.
turaj@webrtc.org362a55e2013-09-20 16:25:28 +0000258 int alpha_step = 16384 / (static_cast<int>(fade_length) + 1);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000259 int alpha = 16384;
260 for (size_t i = 0; i < fade_length; ++i) {
261 alpha -= alpha_step;
minyue-webrtc79553cb2016-05-10 19:55:56 +0200262 array_[(position + i) % capacity_] =
263 (alpha * array_[(position + i) % capacity_] +
Yves Gerey665174f2018-06-19 15:03:05 +0200264 (16384 - alpha) * append_this[i] + 8192) >>
265 14;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000266 }
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200267 RTC_DCHECK_GE(alpha, 0); // Verify that the slope was correct.
Artem Titovd00ce742021-07-28 20:00:17 +0200268 // Append what is left of `append_this`.
henrik.lundin@webrtc.org63464a92013-01-30 09:41:56 +0000269 size_t samples_to_push_back = append_this.Size() - fade_length;
270 if (samples_to_push_back > 0)
minyue-webrtc79553cb2016-05-10 19:55:56 +0200271 PushBack(append_this, samples_to_push_back, fade_length);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000272}
273
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200274// Returns the number of elements in this AudioVector.
275size_t AudioVector::Size() const {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200276 return (end_index_ + capacity_ - begin_index_) % capacity_;
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200277}
278
279// Returns true if this AudioVector is empty.
280bool AudioVector::Empty() const {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200281 return begin_index_ == end_index_;
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200282}
283
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000284void AudioVector::Reserve(size_t n) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200285 if (capacity_ > n)
286 return;
287 const size_t length = Size();
288 // Reserve one more sample to remove the ambiguity between empty vector and
Artem Titovd00ce742021-07-28 20:00:17 +0200289 // full vector. Therefore `begin_index_` == `end_index_` indicates empty
290 // vector, and `begin_index_` == (`end_index_` + 1) % capacity indicates
minyue-webrtc79553cb2016-05-10 19:55:56 +0200291 // full vector.
292 std::unique_ptr<int16_t[]> temp_array(new int16_t[n + 1]);
293 CopyTo(length, 0, temp_array.get());
294 array_.swap(temp_array);
295 begin_index_ = 0;
296 end_index_ = length;
297 capacity_ = n + 1;
298}
299
300void AudioVector::InsertByPushBack(const int16_t* insert_this,
301 size_t length,
302 size_t position) {
303 const size_t move_chunk_length = Size() - position;
304 std::unique_ptr<int16_t[]> temp_array(nullptr);
305 if (move_chunk_length > 0) {
306 // TODO(minyue): see if it is possible to avoid copying to a buffer.
307 temp_array.reset(new int16_t[move_chunk_length]);
308 CopyTo(move_chunk_length, position, temp_array.get());
309 PopBack(move_chunk_length);
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000310 }
minyue-webrtc79553cb2016-05-10 19:55:56 +0200311
312 Reserve(Size() + length + move_chunk_length);
313 PushBack(insert_this, length);
314 if (move_chunk_length > 0)
315 PushBack(temp_array.get(), move_chunk_length);
316}
317
318void AudioVector::InsertByPushFront(const int16_t* insert_this,
Yves Gerey665174f2018-06-19 15:03:05 +0200319 size_t length,
320 size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200321 std::unique_ptr<int16_t[]> temp_array(nullptr);
322 if (position > 0) {
323 // TODO(minyue): see if it is possible to avoid copying to a buffer.
324 temp_array.reset(new int16_t[position]);
325 CopyTo(position, 0, temp_array.get());
326 PopFront(position);
327 }
328
329 Reserve(Size() + length + position);
330 PushFront(insert_this, length);
331 if (position > 0)
332 PushFront(temp_array.get(), position);
333}
334
Yves Gerey665174f2018-06-19 15:03:05 +0200335void AudioVector::InsertZerosByPushBack(size_t length, size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200336 const size_t move_chunk_length = Size() - position;
337 std::unique_ptr<int16_t[]> temp_array(nullptr);
338 if (move_chunk_length > 0) {
339 temp_array.reset(new int16_t[move_chunk_length]);
340 CopyTo(move_chunk_length, position, temp_array.get());
341 PopBack(move_chunk_length);
342 }
343
344 Reserve(Size() + length + move_chunk_length);
345
346 const size_t first_zero_chunk_length =
347 std::min(length, capacity_ - end_index_);
348 memset(&array_[end_index_], 0, first_zero_chunk_length * sizeof(int16_t));
349 const size_t remaining_zero_length = length - first_zero_chunk_length;
350 if (remaining_zero_length > 0)
351 memset(array_.get(), 0, remaining_zero_length * sizeof(int16_t));
352 end_index_ = (end_index_ + length) % capacity_;
353
354 if (move_chunk_length > 0)
355 PushBack(temp_array.get(), move_chunk_length);
356}
357
Yves Gerey665174f2018-06-19 15:03:05 +0200358void AudioVector::InsertZerosByPushFront(size_t length, size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200359 std::unique_ptr<int16_t[]> temp_array(nullptr);
360 if (position > 0) {
361 temp_array.reset(new int16_t[position]);
362 CopyTo(position, 0, temp_array.get());
363 PopFront(position);
364 }
365
366 Reserve(Size() + length + position);
367
368 const size_t first_zero_chunk_length = std::min(length, begin_index_);
369 memset(&array_[begin_index_ - first_zero_chunk_length], 0,
370 first_zero_chunk_length * sizeof(int16_t));
371 const size_t remaining_zero_length = length - first_zero_chunk_length;
372 if (remaining_zero_length > 0)
373 memset(&array_[capacity_ - remaining_zero_length], 0,
374 remaining_zero_length * sizeof(int16_t));
375 begin_index_ = (begin_index_ + capacity_ - length) % capacity_;
376
377 if (position > 0)
378 PushFront(temp_array.get(), position);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000379}
380
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000381} // namespace webrtc