blob: b3ad48fc436d0e47926e86678ce0f1b12e73aec3 [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
13#include <assert.h>
14
15#include <algorithm>
kwiberg2d0c3322016-02-14 09:28:33 -080016#include <memory>
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000017
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/checks.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000019
20namespace webrtc {
21
Yves Gerey665174f2018-06-19 15:03:05 +020022AudioVector::AudioVector() : AudioVector(kDefaultInitialSize) {
minyue-webrtc79553cb2016-05-10 19:55:56 +020023 Clear();
Karl Wiberg7f6c4d42015-04-09 15:44:22 +020024}
25
26AudioVector::AudioVector(size_t initial_size)
minyue-webrtc79553cb2016-05-10 19:55:56 +020027 : array_(new int16_t[initial_size + 1]),
28 capacity_(initial_size + 1),
29 begin_index_(0),
30 end_index_(capacity_ - 1) {
31 memset(array_.get(), 0, capacity_ * sizeof(int16_t));
Karl Wiberg7f6c4d42015-04-09 15:44:22 +020032}
33
34AudioVector::~AudioVector() = default;
35
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +000036void AudioVector::Clear() {
minyue-webrtc79553cb2016-05-10 19:55:56 +020037 end_index_ = begin_index_ = 0;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000038}
39
henrik.lundin@webrtc.orgf6ab6f82014-09-04 10:58:43 +000040void AudioVector::CopyTo(AudioVector* copy_to) const {
minyue-webrtc79553cb2016-05-10 19:55:56 +020041 RTC_DCHECK(copy_to);
42 copy_to->Reserve(Size());
43 CopyTo(Size(), 0, copy_to->array_.get());
44 copy_to->begin_index_ = 0;
45 copy_to->end_index_ = Size();
46}
47
Yves Gerey665174f2018-06-19 15:03:05 +020048void AudioVector::CopyTo(size_t length,
49 size_t position,
50 int16_t* copy_to) const {
minyue-webrtc79553cb2016-05-10 19:55:56 +020051 if (length == 0)
52 return;
53 length = std::min(length, Size() - position);
54 const size_t copy_index = (begin_index_ + position) % capacity_;
Yves Gerey665174f2018-06-19 15:03:05 +020055 const size_t first_chunk_length = std::min(length, capacity_ - copy_index);
56 memcpy(copy_to, &array_[copy_index], first_chunk_length * sizeof(int16_t));
minyue-webrtc79553cb2016-05-10 19:55:56 +020057 const size_t remaining_length = length - first_chunk_length;
58 if (remaining_length > 0) {
59 memcpy(&copy_to[first_chunk_length], array_.get(),
60 remaining_length * sizeof(int16_t));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000061 }
62}
63
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +000064void AudioVector::PushFront(const AudioVector& prepend_this) {
minyue-webrtc79553cb2016-05-10 19:55:56 +020065 const size_t length = prepend_this.Size();
66 if (length == 0)
67 return;
68
69 // Although the subsequent calling to PushFront does Reserve in it, it is
70 // always more efficient to do a big Reserve first.
71 Reserve(Size() + length);
72
73 const size_t first_chunk_length =
74 std::min(length, prepend_this.capacity_ - prepend_this.begin_index_);
75 const size_t remaining_length = length - first_chunk_length;
76 if (remaining_length > 0)
77 PushFront(prepend_this.array_.get(), remaining_length);
78 PushFront(&prepend_this.array_[prepend_this.begin_index_],
79 first_chunk_length);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000080}
81
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +000082void AudioVector::PushFront(const int16_t* prepend_this, size_t length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +020083 if (length == 0)
84 return;
85 Reserve(Size() + length);
86 const size_t first_chunk_length = std::min(length, begin_index_);
87 memcpy(&array_[begin_index_ - first_chunk_length],
88 &prepend_this[length - first_chunk_length],
89 first_chunk_length * sizeof(int16_t));
90 const size_t remaining_length = length - first_chunk_length;
91 if (remaining_length > 0) {
92 memcpy(&array_[capacity_ - remaining_length], prepend_this,
93 remaining_length * sizeof(int16_t));
94 }
95 begin_index_ = (begin_index_ + capacity_ - length) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000096}
97
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +000098void AudioVector::PushBack(const AudioVector& append_this) {
minyue-webrtc79553cb2016-05-10 19:55:56 +020099 PushBack(append_this, append_this.Size(), 0);
100}
101
Yves Gerey665174f2018-06-19 15:03:05 +0200102void AudioVector::PushBack(const AudioVector& append_this,
103 size_t length,
104 size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200105 RTC_DCHECK_LE(position, append_this.Size());
106 RTC_DCHECK_LE(length, append_this.Size() - position);
107
108 if (length == 0)
109 return;
110
111 // Although the subsequent calling to PushBack does Reserve in it, it is
112 // always more efficient to do a big Reserve first.
113 Reserve(Size() + length);
114
115 const size_t start_index =
116 (append_this.begin_index_ + position) % append_this.capacity_;
Yves Gerey665174f2018-06-19 15:03:05 +0200117 const size_t first_chunk_length =
118 std::min(length, append_this.capacity_ - start_index);
minyue-webrtc79553cb2016-05-10 19:55:56 +0200119 PushBack(&append_this.array_[start_index], first_chunk_length);
120
121 const size_t remaining_length = length - first_chunk_length;
122 if (remaining_length > 0)
123 PushBack(append_this.array_.get(), remaining_length);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000124}
125
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000126void AudioVector::PushBack(const int16_t* append_this, size_t length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200127 if (length == 0)
128 return;
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000129 Reserve(Size() + length);
minyue-webrtc79553cb2016-05-10 19:55:56 +0200130 const size_t first_chunk_length = std::min(length, capacity_ - end_index_);
131 memcpy(&array_[end_index_], append_this,
132 first_chunk_length * sizeof(int16_t));
133 const size_t remaining_length = length - first_chunk_length;
134 if (remaining_length > 0) {
135 memcpy(array_.get(), &append_this[first_chunk_length],
136 remaining_length * sizeof(int16_t));
137 }
138 end_index_ = (end_index_ + length) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000139}
140
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000141void AudioVector::PopFront(size_t length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200142 if (length == 0)
143 return;
144 length = std::min(length, Size());
145 begin_index_ = (begin_index_ + length) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000146}
147
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000148void AudioVector::PopBack(size_t length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200149 if (length == 0)
150 return;
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000151 // Never remove more than what is in the array.
152 length = std::min(length, Size());
minyue-webrtc79553cb2016-05-10 19:55:56 +0200153 end_index_ = (end_index_ + capacity_ - length) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000154}
155
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000156void AudioVector::Extend(size_t extra_length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200157 if (extra_length == 0)
158 return;
159 InsertZerosByPushBack(extra_length, Size());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000160}
161
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000162void AudioVector::InsertAt(const int16_t* insert_this,
163 size_t length,
164 size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200165 if (length == 0)
166 return;
167 // Cap the insert position at the current array length.
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000168 position = std::min(Size(), position);
minyue-webrtc79553cb2016-05-10 19:55:56 +0200169
170 // When inserting to a position closer to the beginning, it is more efficient
171 // to insert by pushing front than to insert by pushing back, since less data
172 // will be moved, vice versa.
173 if (position <= Size() - position) {
174 InsertByPushFront(insert_this, length, position);
175 } else {
176 InsertByPushBack(insert_this, length, position);
177 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000178}
179
Yves Gerey665174f2018-06-19 15:03:05 +0200180void AudioVector::InsertZerosAt(size_t length, size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200181 if (length == 0)
182 return;
183 // Cap the insert position at the current array length.
184 position = std::min(Size(), position);
185
186 // When inserting to a position closer to the beginning, it is more efficient
187 // to insert by pushing front than to insert by pushing back, since less data
188 // will be moved, vice versa.
189 if (position <= Size() - position) {
190 InsertZerosByPushFront(length, position);
191 } else {
192 InsertZerosByPushBack(length, position);
193 }
194}
195
196void AudioVector::OverwriteAt(const AudioVector& insert_this,
197 size_t length,
198 size_t position) {
199 RTC_DCHECK_LE(length, insert_this.Size());
200 if (length == 0)
201 return;
202
203 // Cap the insert position at the current array length.
204 position = std::min(Size(), position);
205
206 // Although the subsequent calling to OverwriteAt does Reserve in it, it is
207 // always more efficient to do a big Reserve first.
208 size_t new_size = std::max(Size(), position + length);
209 Reserve(new_size);
210
211 const size_t first_chunk_length =
212 std::min(length, insert_this.capacity_ - insert_this.begin_index_);
213 OverwriteAt(&insert_this.array_[insert_this.begin_index_], first_chunk_length,
214 position);
215 const size_t remaining_length = length - first_chunk_length;
216 if (remaining_length > 0) {
217 OverwriteAt(insert_this.array_.get(), remaining_length,
218 position + first_chunk_length);
219 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000220}
221
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000222void AudioVector::OverwriteAt(const int16_t* insert_this,
223 size_t length,
224 size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200225 if (length == 0)
226 return;
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000227 // Cap the insert position at the current array length.
228 position = std::min(Size(), position);
minyue-webrtc79553cb2016-05-10 19:55:56 +0200229
230 size_t new_size = std::max(Size(), position + length);
231 Reserve(new_size);
232
233 const size_t overwrite_index = (begin_index_ + position) % capacity_;
234 const size_t first_chunk_length =
235 std::min(length, capacity_ - overwrite_index);
236 memcpy(&array_[overwrite_index], insert_this,
237 first_chunk_length * sizeof(int16_t));
238 const size_t remaining_length = length - first_chunk_length;
239 if (remaining_length > 0) {
240 memcpy(array_.get(), &insert_this[first_chunk_length],
241 remaining_length * sizeof(int16_t));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000242 }
minyue-webrtc79553cb2016-05-10 19:55:56 +0200243
244 end_index_ = (begin_index_ + new_size) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000245}
246
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000247void AudioVector::CrossFade(const AudioVector& append_this,
248 size_t fade_length) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000249 // Fade length cannot be longer than the current vector or |append_this|.
250 assert(fade_length <= Size());
251 assert(fade_length <= append_this.Size());
252 fade_length = std::min(fade_length, Size());
253 fade_length = std::min(fade_length, append_this.Size());
minyue-webrtc79553cb2016-05-10 19:55:56 +0200254 size_t position = Size() - fade_length + begin_index_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000255 // Cross fade the overlapping regions.
256 // |alpha| is the mixing factor in Q14.
257 // TODO(hlundin): Consider skipping +1 in the denominator to produce a
258 // smoother cross-fade, in particular at the end of the fade.
turaj@webrtc.org362a55e2013-09-20 16:25:28 +0000259 int alpha_step = 16384 / (static_cast<int>(fade_length) + 1);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000260 int alpha = 16384;
261 for (size_t i = 0; i < fade_length; ++i) {
262 alpha -= alpha_step;
minyue-webrtc79553cb2016-05-10 19:55:56 +0200263 array_[(position + i) % capacity_] =
264 (alpha * array_[(position + i) % capacity_] +
Yves Gerey665174f2018-06-19 15:03:05 +0200265 (16384 - alpha) * append_this[i] + 8192) >>
266 14;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000267 }
268 assert(alpha >= 0); // Verify that the slope was correct.
269 // Append what is left of |append_this|.
henrik.lundin@webrtc.org63464a92013-01-30 09:41:56 +0000270 size_t samples_to_push_back = append_this.Size() - fade_length;
271 if (samples_to_push_back > 0)
minyue-webrtc79553cb2016-05-10 19:55:56 +0200272 PushBack(append_this, samples_to_push_back, fade_length);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000273}
274
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200275// Returns the number of elements in this AudioVector.
276size_t AudioVector::Size() const {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200277 return (end_index_ + capacity_ - begin_index_) % capacity_;
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200278}
279
280// Returns true if this AudioVector is empty.
281bool AudioVector::Empty() const {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200282 return begin_index_ == end_index_;
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200283}
284
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000285void AudioVector::Reserve(size_t n) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200286 if (capacity_ > n)
287 return;
288 const size_t length = Size();
289 // Reserve one more sample to remove the ambiguity between empty vector and
290 // full vector. Therefore |begin_index_| == |end_index_| indicates empty
291 // vector, and |begin_index_| == (|end_index_| + 1) % capacity indicates
292 // full vector.
293 std::unique_ptr<int16_t[]> temp_array(new int16_t[n + 1]);
294 CopyTo(length, 0, temp_array.get());
295 array_.swap(temp_array);
296 begin_index_ = 0;
297 end_index_ = length;
298 capacity_ = n + 1;
299}
300
301void AudioVector::InsertByPushBack(const int16_t* insert_this,
302 size_t length,
303 size_t position) {
304 const size_t move_chunk_length = Size() - position;
305 std::unique_ptr<int16_t[]> temp_array(nullptr);
306 if (move_chunk_length > 0) {
307 // TODO(minyue): see if it is possible to avoid copying to a buffer.
308 temp_array.reset(new int16_t[move_chunk_length]);
309 CopyTo(move_chunk_length, position, temp_array.get());
310 PopBack(move_chunk_length);
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000311 }
minyue-webrtc79553cb2016-05-10 19:55:56 +0200312
313 Reserve(Size() + length + move_chunk_length);
314 PushBack(insert_this, length);
315 if (move_chunk_length > 0)
316 PushBack(temp_array.get(), move_chunk_length);
317}
318
319void AudioVector::InsertByPushFront(const int16_t* insert_this,
Yves Gerey665174f2018-06-19 15:03:05 +0200320 size_t length,
321 size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200322 std::unique_ptr<int16_t[]> temp_array(nullptr);
323 if (position > 0) {
324 // TODO(minyue): see if it is possible to avoid copying to a buffer.
325 temp_array.reset(new int16_t[position]);
326 CopyTo(position, 0, temp_array.get());
327 PopFront(position);
328 }
329
330 Reserve(Size() + length + position);
331 PushFront(insert_this, length);
332 if (position > 0)
333 PushFront(temp_array.get(), position);
334}
335
Yves Gerey665174f2018-06-19 15:03:05 +0200336void AudioVector::InsertZerosByPushBack(size_t length, size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200337 const size_t move_chunk_length = Size() - position;
338 std::unique_ptr<int16_t[]> temp_array(nullptr);
339 if (move_chunk_length > 0) {
340 temp_array.reset(new int16_t[move_chunk_length]);
341 CopyTo(move_chunk_length, position, temp_array.get());
342 PopBack(move_chunk_length);
343 }
344
345 Reserve(Size() + length + move_chunk_length);
346
347 const size_t first_zero_chunk_length =
348 std::min(length, capacity_ - end_index_);
349 memset(&array_[end_index_], 0, first_zero_chunk_length * sizeof(int16_t));
350 const size_t remaining_zero_length = length - first_zero_chunk_length;
351 if (remaining_zero_length > 0)
352 memset(array_.get(), 0, remaining_zero_length * sizeof(int16_t));
353 end_index_ = (end_index_ + length) % capacity_;
354
355 if (move_chunk_length > 0)
356 PushBack(temp_array.get(), move_chunk_length);
357}
358
Yves Gerey665174f2018-06-19 15:03:05 +0200359void AudioVector::InsertZerosByPushFront(size_t length, size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200360 std::unique_ptr<int16_t[]> temp_array(nullptr);
361 if (position > 0) {
362 temp_array.reset(new int16_t[position]);
363 CopyTo(position, 0, temp_array.get());
364 PopFront(position);
365 }
366
367 Reserve(Size() + length + position);
368
369 const size_t first_zero_chunk_length = std::min(length, begin_index_);
370 memset(&array_[begin_index_ - first_zero_chunk_length], 0,
371 first_zero_chunk_length * sizeof(int16_t));
372 const size_t remaining_zero_length = length - first_zero_chunk_length;
373 if (remaining_zero_length > 0)
374 memset(&array_[capacity_ - remaining_zero_length], 0,
375 remaining_zero_length * sizeof(int16_t));
376 begin_index_ = (begin_index_ + capacity_ - length) % capacity_;
377
378 if (position > 0)
379 PushFront(temp_array.get(), position);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000380}
381
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000382} // namespace webrtc