blob: 04864163208349b7df1fb6bcf469bf2a61397b56 [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"
Mirko Bonadei71207422017-09-15 13:58:09 +020019#include "typedefs.h" // NOLINT(build/include)
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000020
21namespace webrtc {
22
Yves Gerey665174f2018-06-19 15:03:05 +020023AudioVector::AudioVector() : AudioVector(kDefaultInitialSize) {
minyue-webrtc79553cb2016-05-10 19:55:56 +020024 Clear();
Karl Wiberg7f6c4d42015-04-09 15:44:22 +020025}
26
27AudioVector::AudioVector(size_t initial_size)
minyue-webrtc79553cb2016-05-10 19:55:56 +020028 : array_(new int16_t[initial_size + 1]),
29 capacity_(initial_size + 1),
30 begin_index_(0),
31 end_index_(capacity_ - 1) {
32 memset(array_.get(), 0, capacity_ * sizeof(int16_t));
Karl Wiberg7f6c4d42015-04-09 15:44:22 +020033}
34
35AudioVector::~AudioVector() = default;
36
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +000037void AudioVector::Clear() {
minyue-webrtc79553cb2016-05-10 19:55:56 +020038 end_index_ = begin_index_ = 0;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000039}
40
henrik.lundin@webrtc.orgf6ab6f82014-09-04 10:58:43 +000041void AudioVector::CopyTo(AudioVector* copy_to) const {
minyue-webrtc79553cb2016-05-10 19:55:56 +020042 RTC_DCHECK(copy_to);
43 copy_to->Reserve(Size());
44 CopyTo(Size(), 0, copy_to->array_.get());
45 copy_to->begin_index_ = 0;
46 copy_to->end_index_ = Size();
47}
48
Yves Gerey665174f2018-06-19 15:03:05 +020049void AudioVector::CopyTo(size_t length,
50 size_t position,
51 int16_t* copy_to) const {
minyue-webrtc79553cb2016-05-10 19:55:56 +020052 if (length == 0)
53 return;
54 length = std::min(length, Size() - position);
55 const size_t copy_index = (begin_index_ + position) % capacity_;
Yves Gerey665174f2018-06-19 15:03:05 +020056 const size_t first_chunk_length = std::min(length, capacity_ - copy_index);
57 memcpy(copy_to, &array_[copy_index], first_chunk_length * sizeof(int16_t));
minyue-webrtc79553cb2016-05-10 19:55:56 +020058 const size_t remaining_length = length - first_chunk_length;
59 if (remaining_length > 0) {
60 memcpy(&copy_to[first_chunk_length], array_.get(),
61 remaining_length * sizeof(int16_t));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000062 }
63}
64
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +000065void AudioVector::PushFront(const AudioVector& prepend_this) {
minyue-webrtc79553cb2016-05-10 19:55:56 +020066 const size_t length = prepend_this.Size();
67 if (length == 0)
68 return;
69
70 // Although the subsequent calling to PushFront does Reserve in it, it is
71 // always more efficient to do a big Reserve first.
72 Reserve(Size() + length);
73
74 const size_t first_chunk_length =
75 std::min(length, prepend_this.capacity_ - prepend_this.begin_index_);
76 const size_t remaining_length = length - first_chunk_length;
77 if (remaining_length > 0)
78 PushFront(prepend_this.array_.get(), remaining_length);
79 PushFront(&prepend_this.array_[prepend_this.begin_index_],
80 first_chunk_length);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000081}
82
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +000083void AudioVector::PushFront(const int16_t* prepend_this, size_t length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +020084 if (length == 0)
85 return;
86 Reserve(Size() + length);
87 const size_t first_chunk_length = std::min(length, begin_index_);
88 memcpy(&array_[begin_index_ - first_chunk_length],
89 &prepend_this[length - first_chunk_length],
90 first_chunk_length * sizeof(int16_t));
91 const size_t remaining_length = length - first_chunk_length;
92 if (remaining_length > 0) {
93 memcpy(&array_[capacity_ - remaining_length], prepend_this,
94 remaining_length * sizeof(int16_t));
95 }
96 begin_index_ = (begin_index_ + capacity_ - length) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000097}
98
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +000099void AudioVector::PushBack(const AudioVector& append_this) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200100 PushBack(append_this, append_this.Size(), 0);
101}
102
Yves Gerey665174f2018-06-19 15:03:05 +0200103void AudioVector::PushBack(const AudioVector& append_this,
104 size_t length,
105 size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200106 RTC_DCHECK_LE(position, append_this.Size());
107 RTC_DCHECK_LE(length, append_this.Size() - position);
108
109 if (length == 0)
110 return;
111
112 // Although the subsequent calling to PushBack does Reserve in it, it is
113 // always more efficient to do a big Reserve first.
114 Reserve(Size() + length);
115
116 const size_t start_index =
117 (append_this.begin_index_ + position) % append_this.capacity_;
Yves Gerey665174f2018-06-19 15:03:05 +0200118 const size_t first_chunk_length =
119 std::min(length, append_this.capacity_ - start_index);
minyue-webrtc79553cb2016-05-10 19:55:56 +0200120 PushBack(&append_this.array_[start_index], first_chunk_length);
121
122 const size_t remaining_length = length - first_chunk_length;
123 if (remaining_length > 0)
124 PushBack(append_this.array_.get(), remaining_length);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000125}
126
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000127void AudioVector::PushBack(const int16_t* append_this, size_t length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200128 if (length == 0)
129 return;
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000130 Reserve(Size() + length);
minyue-webrtc79553cb2016-05-10 19:55:56 +0200131 const size_t first_chunk_length = std::min(length, capacity_ - end_index_);
132 memcpy(&array_[end_index_], append_this,
133 first_chunk_length * sizeof(int16_t));
134 const size_t remaining_length = length - first_chunk_length;
135 if (remaining_length > 0) {
136 memcpy(array_.get(), &append_this[first_chunk_length],
137 remaining_length * sizeof(int16_t));
138 }
139 end_index_ = (end_index_ + length) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000140}
141
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000142void AudioVector::PopFront(size_t length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200143 if (length == 0)
144 return;
145 length = std::min(length, Size());
146 begin_index_ = (begin_index_ + length) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000147}
148
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000149void AudioVector::PopBack(size_t length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200150 if (length == 0)
151 return;
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000152 // Never remove more than what is in the array.
153 length = std::min(length, Size());
minyue-webrtc79553cb2016-05-10 19:55:56 +0200154 end_index_ = (end_index_ + capacity_ - length) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000155}
156
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000157void AudioVector::Extend(size_t extra_length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200158 if (extra_length == 0)
159 return;
160 InsertZerosByPushBack(extra_length, Size());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000161}
162
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000163void AudioVector::InsertAt(const int16_t* insert_this,
164 size_t length,
165 size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200166 if (length == 0)
167 return;
168 // Cap the insert position at the current array length.
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000169 position = std::min(Size(), position);
minyue-webrtc79553cb2016-05-10 19:55:56 +0200170
171 // When inserting to a position closer to the beginning, it is more efficient
172 // to insert by pushing front than to insert by pushing back, since less data
173 // will be moved, vice versa.
174 if (position <= Size() - position) {
175 InsertByPushFront(insert_this, length, position);
176 } else {
177 InsertByPushBack(insert_this, length, position);
178 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000179}
180
Yves Gerey665174f2018-06-19 15:03:05 +0200181void AudioVector::InsertZerosAt(size_t length, size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200182 if (length == 0)
183 return;
184 // Cap the insert position at the current array length.
185 position = std::min(Size(), position);
186
187 // When inserting to a position closer to the beginning, it is more efficient
188 // to insert by pushing front than to insert by pushing back, since less data
189 // will be moved, vice versa.
190 if (position <= Size() - position) {
191 InsertZerosByPushFront(length, position);
192 } else {
193 InsertZerosByPushBack(length, position);
194 }
195}
196
197void AudioVector::OverwriteAt(const AudioVector& insert_this,
198 size_t length,
199 size_t position) {
200 RTC_DCHECK_LE(length, insert_this.Size());
201 if (length == 0)
202 return;
203
204 // Cap the insert position at the current array length.
205 position = std::min(Size(), position);
206
207 // Although the subsequent calling to OverwriteAt does Reserve in it, it is
208 // always more efficient to do a big Reserve first.
209 size_t new_size = std::max(Size(), position + length);
210 Reserve(new_size);
211
212 const size_t first_chunk_length =
213 std::min(length, insert_this.capacity_ - insert_this.begin_index_);
214 OverwriteAt(&insert_this.array_[insert_this.begin_index_], first_chunk_length,
215 position);
216 const size_t remaining_length = length - first_chunk_length;
217 if (remaining_length > 0) {
218 OverwriteAt(insert_this.array_.get(), remaining_length,
219 position + first_chunk_length);
220 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000221}
222
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000223void AudioVector::OverwriteAt(const int16_t* insert_this,
224 size_t length,
225 size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200226 if (length == 0)
227 return;
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000228 // Cap the insert position at the current array length.
229 position = std::min(Size(), position);
minyue-webrtc79553cb2016-05-10 19:55:56 +0200230
231 size_t new_size = std::max(Size(), position + length);
232 Reserve(new_size);
233
234 const size_t overwrite_index = (begin_index_ + position) % capacity_;
235 const size_t first_chunk_length =
236 std::min(length, capacity_ - overwrite_index);
237 memcpy(&array_[overwrite_index], insert_this,
238 first_chunk_length * sizeof(int16_t));
239 const size_t remaining_length = length - first_chunk_length;
240 if (remaining_length > 0) {
241 memcpy(array_.get(), &insert_this[first_chunk_length],
242 remaining_length * sizeof(int16_t));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000243 }
minyue-webrtc79553cb2016-05-10 19:55:56 +0200244
245 end_index_ = (begin_index_ + new_size) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000246}
247
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000248void AudioVector::CrossFade(const AudioVector& append_this,
249 size_t fade_length) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000250 // Fade length cannot be longer than the current vector or |append_this|.
251 assert(fade_length <= Size());
252 assert(fade_length <= append_this.Size());
253 fade_length = std::min(fade_length, Size());
254 fade_length = std::min(fade_length, append_this.Size());
minyue-webrtc79553cb2016-05-10 19:55:56 +0200255 size_t position = Size() - fade_length + begin_index_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000256 // Cross fade the overlapping regions.
257 // |alpha| is the mixing factor in Q14.
258 // TODO(hlundin): Consider skipping +1 in the denominator to produce a
259 // smoother cross-fade, in particular at the end of the fade.
turaj@webrtc.org362a55e2013-09-20 16:25:28 +0000260 int alpha_step = 16384 / (static_cast<int>(fade_length) + 1);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000261 int alpha = 16384;
262 for (size_t i = 0; i < fade_length; ++i) {
263 alpha -= alpha_step;
minyue-webrtc79553cb2016-05-10 19:55:56 +0200264 array_[(position + i) % capacity_] =
265 (alpha * array_[(position + i) % capacity_] +
Yves Gerey665174f2018-06-19 15:03:05 +0200266 (16384 - alpha) * append_this[i] + 8192) >>
267 14;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000268 }
269 assert(alpha >= 0); // Verify that the slope was correct.
270 // Append what is left of |append_this|.
henrik.lundin@webrtc.org63464a92013-01-30 09:41:56 +0000271 size_t samples_to_push_back = append_this.Size() - fade_length;
272 if (samples_to_push_back > 0)
minyue-webrtc79553cb2016-05-10 19:55:56 +0200273 PushBack(append_this, samples_to_push_back, fade_length);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000274}
275
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200276// Returns the number of elements in this AudioVector.
277size_t AudioVector::Size() const {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200278 return (end_index_ + capacity_ - begin_index_) % capacity_;
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200279}
280
281// Returns true if this AudioVector is empty.
282bool AudioVector::Empty() const {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200283 return begin_index_ == end_index_;
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200284}
285
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000286void AudioVector::Reserve(size_t n) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200287 if (capacity_ > n)
288 return;
289 const size_t length = Size();
290 // Reserve one more sample to remove the ambiguity between empty vector and
291 // full vector. Therefore |begin_index_| == |end_index_| indicates empty
292 // vector, and |begin_index_| == (|end_index_| + 1) % capacity indicates
293 // full vector.
294 std::unique_ptr<int16_t[]> temp_array(new int16_t[n + 1]);
295 CopyTo(length, 0, temp_array.get());
296 array_.swap(temp_array);
297 begin_index_ = 0;
298 end_index_ = length;
299 capacity_ = n + 1;
300}
301
302void AudioVector::InsertByPushBack(const int16_t* insert_this,
303 size_t length,
304 size_t position) {
305 const size_t move_chunk_length = Size() - position;
306 std::unique_ptr<int16_t[]> temp_array(nullptr);
307 if (move_chunk_length > 0) {
308 // TODO(minyue): see if it is possible to avoid copying to a buffer.
309 temp_array.reset(new int16_t[move_chunk_length]);
310 CopyTo(move_chunk_length, position, temp_array.get());
311 PopBack(move_chunk_length);
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000312 }
minyue-webrtc79553cb2016-05-10 19:55:56 +0200313
314 Reserve(Size() + length + move_chunk_length);
315 PushBack(insert_this, length);
316 if (move_chunk_length > 0)
317 PushBack(temp_array.get(), move_chunk_length);
318}
319
320void AudioVector::InsertByPushFront(const int16_t* insert_this,
Yves Gerey665174f2018-06-19 15:03:05 +0200321 size_t length,
322 size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200323 std::unique_ptr<int16_t[]> temp_array(nullptr);
324 if (position > 0) {
325 // TODO(minyue): see if it is possible to avoid copying to a buffer.
326 temp_array.reset(new int16_t[position]);
327 CopyTo(position, 0, temp_array.get());
328 PopFront(position);
329 }
330
331 Reserve(Size() + length + position);
332 PushFront(insert_this, length);
333 if (position > 0)
334 PushFront(temp_array.get(), position);
335}
336
Yves Gerey665174f2018-06-19 15:03:05 +0200337void AudioVector::InsertZerosByPushBack(size_t length, size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200338 const size_t move_chunk_length = Size() - position;
339 std::unique_ptr<int16_t[]> temp_array(nullptr);
340 if (move_chunk_length > 0) {
341 temp_array.reset(new int16_t[move_chunk_length]);
342 CopyTo(move_chunk_length, position, temp_array.get());
343 PopBack(move_chunk_length);
344 }
345
346 Reserve(Size() + length + move_chunk_length);
347
348 const size_t first_zero_chunk_length =
349 std::min(length, capacity_ - end_index_);
350 memset(&array_[end_index_], 0, first_zero_chunk_length * sizeof(int16_t));
351 const size_t remaining_zero_length = length - first_zero_chunk_length;
352 if (remaining_zero_length > 0)
353 memset(array_.get(), 0, remaining_zero_length * sizeof(int16_t));
354 end_index_ = (end_index_ + length) % capacity_;
355
356 if (move_chunk_length > 0)
357 PushBack(temp_array.get(), move_chunk_length);
358}
359
Yves Gerey665174f2018-06-19 15:03:05 +0200360void AudioVector::InsertZerosByPushFront(size_t length, size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200361 std::unique_ptr<int16_t[]> temp_array(nullptr);
362 if (position > 0) {
363 temp_array.reset(new int16_t[position]);
364 CopyTo(position, 0, temp_array.get());
365 PopFront(position);
366 }
367
368 Reserve(Size() + length + position);
369
370 const size_t first_zero_chunk_length = std::min(length, begin_index_);
371 memset(&array_[begin_index_ - first_zero_chunk_length], 0,
372 first_zero_chunk_length * sizeof(int16_t));
373 const size_t remaining_zero_length = length - first_zero_chunk_length;
374 if (remaining_zero_length > 0)
375 memset(&array_[capacity_ - remaining_zero_length], 0,
376 remaining_zero_length * sizeof(int16_t));
377 begin_index_ = (begin_index_ + capacity_ - length) % capacity_;
378
379 if (position > 0)
380 PushFront(temp_array.get(), position);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000381}
382
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000383} // namespace webrtc