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