blob: c66682b016e953fcc115fda445984802584b8ff7 [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"
19#include "typedefs.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000020
21namespace webrtc {
22
Karl Wiberg7f6c4d42015-04-09 15:44:22 +020023AudioVector::AudioVector()
minyue-webrtc79553cb2016-05-10 19:55:56 +020024 : AudioVector(kDefaultInitialSize) {
25 Clear();
Karl Wiberg7f6c4d42015-04-09 15:44:22 +020026}
27
28AudioVector::AudioVector(size_t initial_size)
minyue-webrtc79553cb2016-05-10 19:55:56 +020029 : array_(new int16_t[initial_size + 1]),
30 capacity_(initial_size + 1),
31 begin_index_(0),
32 end_index_(capacity_ - 1) {
33 memset(array_.get(), 0, capacity_ * sizeof(int16_t));
Karl Wiberg7f6c4d42015-04-09 15:44:22 +020034}
35
36AudioVector::~AudioVector() = default;
37
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +000038void AudioVector::Clear() {
minyue-webrtc79553cb2016-05-10 19:55:56 +020039 end_index_ = begin_index_ = 0;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000040}
41
henrik.lundin@webrtc.orgf6ab6f82014-09-04 10:58:43 +000042void AudioVector::CopyTo(AudioVector* copy_to) const {
minyue-webrtc79553cb2016-05-10 19:55:56 +020043 RTC_DCHECK(copy_to);
44 copy_to->Reserve(Size());
45 CopyTo(Size(), 0, copy_to->array_.get());
46 copy_to->begin_index_ = 0;
47 copy_to->end_index_ = Size();
48}
49
50void AudioVector::CopyTo(
51 size_t length, size_t position, int16_t* copy_to) const {
52 if (length == 0)
53 return;
54 length = std::min(length, Size() - position);
55 const size_t copy_index = (begin_index_ + position) % capacity_;
56 const size_t first_chunk_length =
57 std::min(length, capacity_ - copy_index);
58 memcpy(copy_to, &array_[copy_index],
59 first_chunk_length * sizeof(int16_t));
60 const size_t remaining_length = length - first_chunk_length;
61 if (remaining_length > 0) {
62 memcpy(&copy_to[first_chunk_length], array_.get(),
63 remaining_length * sizeof(int16_t));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000064 }
65}
66
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +000067void AudioVector::PushFront(const AudioVector& prepend_this) {
minyue-webrtc79553cb2016-05-10 19:55:56 +020068 const size_t length = prepend_this.Size();
69 if (length == 0)
70 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 Reserve(Size() + length);
75
76 const size_t first_chunk_length =
77 std::min(length, prepend_this.capacity_ - prepend_this.begin_index_);
78 const size_t remaining_length = length - first_chunk_length;
79 if (remaining_length > 0)
80 PushFront(prepend_this.array_.get(), remaining_length);
81 PushFront(&prepend_this.array_[prepend_this.begin_index_],
82 first_chunk_length);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000083}
84
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +000085void AudioVector::PushFront(const int16_t* prepend_this, size_t length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +020086 if (length == 0)
87 return;
88 Reserve(Size() + length);
89 const size_t first_chunk_length = std::min(length, begin_index_);
90 memcpy(&array_[begin_index_ - first_chunk_length],
91 &prepend_this[length - first_chunk_length],
92 first_chunk_length * sizeof(int16_t));
93 const size_t remaining_length = length - first_chunk_length;
94 if (remaining_length > 0) {
95 memcpy(&array_[capacity_ - remaining_length], prepend_this,
96 remaining_length * sizeof(int16_t));
97 }
98 begin_index_ = (begin_index_ + capacity_ - length) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000099}
100
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000101void AudioVector::PushBack(const AudioVector& append_this) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200102 PushBack(append_this, append_this.Size(), 0);
103}
104
105void AudioVector::PushBack(
106 const AudioVector& append_this, size_t length, size_t position) {
107 RTC_DCHECK_LE(position, append_this.Size());
108 RTC_DCHECK_LE(length, append_this.Size() - position);
109
110 if (length == 0)
111 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 Reserve(Size() + length);
116
117 const size_t start_index =
118 (append_this.begin_index_ + position) % append_this.capacity_;
119 const size_t first_chunk_length = std::min(
120 length, append_this.capacity_ - start_index);
121 PushBack(&append_this.array_[start_index], first_chunk_length);
122
123 const size_t remaining_length = length - first_chunk_length;
124 if (remaining_length > 0)
125 PushBack(append_this.array_.get(), remaining_length);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000126}
127
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000128void AudioVector::PushBack(const int16_t* append_this, size_t length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200129 if (length == 0)
130 return;
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000131 Reserve(Size() + length);
minyue-webrtc79553cb2016-05-10 19:55:56 +0200132 const size_t first_chunk_length = std::min(length, capacity_ - end_index_);
133 memcpy(&array_[end_index_], append_this,
134 first_chunk_length * sizeof(int16_t));
135 const size_t remaining_length = length - first_chunk_length;
136 if (remaining_length > 0) {
137 memcpy(array_.get(), &append_this[first_chunk_length],
138 remaining_length * sizeof(int16_t));
139 }
140 end_index_ = (end_index_ + length) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000141}
142
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000143void AudioVector::PopFront(size_t length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200144 if (length == 0)
145 return;
146 length = std::min(length, Size());
147 begin_index_ = (begin_index_ + length) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000148}
149
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000150void AudioVector::PopBack(size_t length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200151 if (length == 0)
152 return;
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000153 // Never remove more than what is in the array.
154 length = std::min(length, Size());
minyue-webrtc79553cb2016-05-10 19:55:56 +0200155 end_index_ = (end_index_ + capacity_ - length) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000156}
157
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000158void AudioVector::Extend(size_t extra_length) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200159 if (extra_length == 0)
160 return;
161 InsertZerosByPushBack(extra_length, Size());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000162}
163
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000164void AudioVector::InsertAt(const int16_t* insert_this,
165 size_t length,
166 size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200167 if (length == 0)
168 return;
169 // Cap the insert position at the current array length.
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000170 position = std::min(Size(), position);
minyue-webrtc79553cb2016-05-10 19:55:56 +0200171
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 if (position <= Size() - position) {
176 InsertByPushFront(insert_this, length, position);
177 } else {
178 InsertByPushBack(insert_this, length, position);
179 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000180}
181
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000182void AudioVector::InsertZerosAt(size_t length,
183 size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200184 if (length == 0)
185 return;
186 // Cap the insert position at the current array length.
187 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 if (position <= Size() - position) {
193 InsertZerosByPushFront(length, position);
194 } else {
195 InsertZerosByPushBack(length, position);
196 }
197}
198
199void AudioVector::OverwriteAt(const AudioVector& insert_this,
200 size_t length,
201 size_t position) {
202 RTC_DCHECK_LE(length, insert_this.Size());
203 if (length == 0)
204 return;
205
206 // Cap the insert position at the current array length.
207 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 size_t new_size = std::max(Size(), position + length);
212 Reserve(new_size);
213
214 const size_t first_chunk_length =
215 std::min(length, insert_this.capacity_ - insert_this.begin_index_);
216 OverwriteAt(&insert_this.array_[insert_this.begin_index_], first_chunk_length,
217 position);
218 const size_t remaining_length = length - first_chunk_length;
219 if (remaining_length > 0) {
220 OverwriteAt(insert_this.array_.get(), remaining_length,
221 position + first_chunk_length);
222 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000223}
224
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000225void AudioVector::OverwriteAt(const int16_t* insert_this,
226 size_t length,
227 size_t position) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200228 if (length == 0)
229 return;
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000230 // Cap the insert position at the current array length.
231 position = std::min(Size(), position);
minyue-webrtc79553cb2016-05-10 19:55:56 +0200232
233 size_t new_size = std::max(Size(), position + length);
234 Reserve(new_size);
235
236 const size_t overwrite_index = (begin_index_ + position) % capacity_;
237 const size_t first_chunk_length =
238 std::min(length, capacity_ - overwrite_index);
239 memcpy(&array_[overwrite_index], insert_this,
240 first_chunk_length * sizeof(int16_t));
241 const size_t remaining_length = length - first_chunk_length;
242 if (remaining_length > 0) {
243 memcpy(array_.get(), &insert_this[first_chunk_length],
244 remaining_length * sizeof(int16_t));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000245 }
minyue-webrtc79553cb2016-05-10 19:55:56 +0200246
247 end_index_ = (begin_index_ + new_size) % capacity_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000248}
249
henrik.lundin@webrtc.org1871dd22013-10-14 20:33:25 +0000250void AudioVector::CrossFade(const AudioVector& append_this,
251 size_t fade_length) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000252 // Fade length cannot be longer than the current vector or |append_this|.
253 assert(fade_length <= Size());
254 assert(fade_length <= append_this.Size());
255 fade_length = std::min(fade_length, Size());
256 fade_length = std::min(fade_length, append_this.Size());
minyue-webrtc79553cb2016-05-10 19:55:56 +0200257 size_t position = Size() - fade_length + begin_index_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000258 // 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.
turaj@webrtc.org362a55e2013-09-20 16:25:28 +0000262 int alpha_step = 16384 / (static_cast<int>(fade_length) + 1);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000263 int alpha = 16384;
264 for (size_t i = 0; i < fade_length; ++i) {
265 alpha -= alpha_step;
minyue-webrtc79553cb2016-05-10 19:55:56 +0200266 array_[(position + i) % capacity_] =
267 (alpha * array_[(position + i) % capacity_] +
268 (16384 - alpha) * append_this[i] + 8192) >> 14;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000269 }
270 assert(alpha >= 0); // Verify that the slope was correct.
271 // Append what is left of |append_this|.
henrik.lundin@webrtc.org63464a92013-01-30 09:41:56 +0000272 size_t samples_to_push_back = append_this.Size() - fade_length;
273 if (samples_to_push_back > 0)
minyue-webrtc79553cb2016-05-10 19:55:56 +0200274 PushBack(append_this, samples_to_push_back, fade_length);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000275}
276
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200277// Returns the number of elements in this AudioVector.
278size_t AudioVector::Size() const {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200279 return (end_index_ + capacity_ - begin_index_) % capacity_;
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200280}
281
282// Returns true if this AudioVector is empty.
283bool AudioVector::Empty() const {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200284 return begin_index_ == end_index_;
Karl Wiberg7f6c4d42015-04-09 15:44:22 +0200285}
286
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000287void AudioVector::Reserve(size_t n) {
minyue-webrtc79553cb2016-05-10 19:55:56 +0200288 if (capacity_ > n)
289 return;
290 const size_t length = Size();
291 // Reserve one more sample to remove the ambiguity between empty vector and
292 // full vector. Therefore |begin_index_| == |end_index_| indicates empty
293 // vector, and |begin_index_| == (|end_index_| + 1) % capacity indicates
294 // full vector.
295 std::unique_ptr<int16_t[]> temp_array(new int16_t[n + 1]);
296 CopyTo(length, 0, temp_array.get());
297 array_.swap(temp_array);
298 begin_index_ = 0;
299 end_index_ = length;
300 capacity_ = n + 1;
301}
302
303void AudioVector::InsertByPushBack(const int16_t* insert_this,
304 size_t length,
305 size_t position) {
306 const size_t move_chunk_length = Size() - position;
307 std::unique_ptr<int16_t[]> temp_array(nullptr);
308 if (move_chunk_length > 0) {
309 // TODO(minyue): see if it is possible to avoid copying to a buffer.
310 temp_array.reset(new int16_t[move_chunk_length]);
311 CopyTo(move_chunk_length, position, temp_array.get());
312 PopBack(move_chunk_length);
henrik.lundin@webrtc.orge8433eb2013-11-12 13:15:02 +0000313 }
minyue-webrtc79553cb2016-05-10 19:55:56 +0200314
315 Reserve(Size() + length + move_chunk_length);
316 PushBack(insert_this, length);
317 if (move_chunk_length > 0)
318 PushBack(temp_array.get(), move_chunk_length);
319}
320
321void AudioVector::InsertByPushFront(const int16_t* insert_this,
322 size_t length,
323 size_t position) {
324 std::unique_ptr<int16_t[]> temp_array(nullptr);
325 if (position > 0) {
326 // TODO(minyue): see if it is possible to avoid copying to a buffer.
327 temp_array.reset(new int16_t[position]);
328 CopyTo(position, 0, temp_array.get());
329 PopFront(position);
330 }
331
332 Reserve(Size() + length + position);
333 PushFront(insert_this, length);
334 if (position > 0)
335 PushFront(temp_array.get(), position);
336}
337
338void AudioVector::InsertZerosByPushBack(size_t length,
339 size_t position) {
340 const size_t move_chunk_length = Size() - position;
341 std::unique_ptr<int16_t[]> temp_array(nullptr);
342 if (move_chunk_length > 0) {
343 temp_array.reset(new int16_t[move_chunk_length]);
344 CopyTo(move_chunk_length, position, temp_array.get());
345 PopBack(move_chunk_length);
346 }
347
348 Reserve(Size() + length + move_chunk_length);
349
350 const size_t first_zero_chunk_length =
351 std::min(length, capacity_ - end_index_);
352 memset(&array_[end_index_], 0, first_zero_chunk_length * sizeof(int16_t));
353 const size_t remaining_zero_length = length - first_zero_chunk_length;
354 if (remaining_zero_length > 0)
355 memset(array_.get(), 0, remaining_zero_length * sizeof(int16_t));
356 end_index_ = (end_index_ + length) % capacity_;
357
358 if (move_chunk_length > 0)
359 PushBack(temp_array.get(), move_chunk_length);
360}
361
362void AudioVector::InsertZerosByPushFront(size_t length,
363 size_t position) {
364 std::unique_ptr<int16_t[]> temp_array(nullptr);
365 if (position > 0) {
366 temp_array.reset(new int16_t[position]);
367 CopyTo(position, 0, temp_array.get());
368 PopFront(position);
369 }
370
371 Reserve(Size() + length + position);
372
373 const size_t first_zero_chunk_length = std::min(length, begin_index_);
374 memset(&array_[begin_index_ - first_zero_chunk_length], 0,
375 first_zero_chunk_length * sizeof(int16_t));
376 const size_t remaining_zero_length = length - first_zero_chunk_length;
377 if (remaining_zero_length > 0)
378 memset(&array_[capacity_ - remaining_zero_length], 0,
379 remaining_zero_length * sizeof(int16_t));
380 begin_index_ = (begin_index_ + capacity_ - length) % capacity_;
381
382 if (position > 0)
383 PushFront(temp_array.get(), position);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000384}
385
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000386} // namespace webrtc