audio_vector.cc (14092B)
1 /* 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 11 #include "modules/audio_coding/neteq/audio_vector.h" 12 13 #include <algorithm> 14 #include <cstddef> 15 #include <cstdint> 16 #include <cstring> 17 #include <memory> 18 19 #include "api/audio/audio_view.h" 20 #include "rtc_base/checks.h" 21 22 namespace webrtc { 23 24 AudioVector::AudioVector() : AudioVector(kDefaultInitialSize) { 25 Clear(); 26 } 27 28 AudioVector::AudioVector(size_t initial_size) 29 : 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)); 34 } 35 36 AudioVector::~AudioVector() = default; 37 38 void AudioVector::Clear() { 39 end_index_ = begin_index_ = 0; 40 } 41 42 void AudioVector::CopyTo(AudioVector* copy_to) const { 43 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 50 void AudioVector::CopyTo(size_t length, 51 size_t position, 52 int16_t* copy_to) const { 53 if (length == 0) 54 return; 55 length = std::min(length, Size() - position); 56 const size_t copy_index = (begin_index_ + position) % capacity_; 57 const size_t first_chunk_length = std::min(length, capacity_ - copy_index); 58 memcpy(copy_to, &array_[copy_index], first_chunk_length * sizeof(int16_t)); 59 const size_t remaining_length = length - first_chunk_length; 60 if (remaining_length > 0) { 61 memcpy(©_to[first_chunk_length], array_.get(), 62 remaining_length * sizeof(int16_t)); 63 } 64 } 65 66 bool AudioVector::CopyTo(size_t position, MonoView<int16_t> dst) const { 67 if ((Size() - position) < dst.size()) { 68 return false; 69 } 70 const size_t copy_index = (begin_index_ + position) % capacity_; 71 const size_t first_chunk_length = 72 std::min(dst.size(), capacity_ - copy_index); 73 auto first_chunk = dst.subview(0, first_chunk_length); 74 CopySamples(first_chunk, 75 MonoView<const int16_t>(&array_[copy_index], first_chunk_length)); 76 const size_t remaining_length = dst.size() - first_chunk_length; 77 if (remaining_length > 0) { 78 auto second_chunk = dst.subview(first_chunk_length, remaining_length); 79 CopySamples(second_chunk, MonoView<int16_t>(&array_[0], remaining_length)); 80 } 81 return true; 82 } 83 84 void AudioVector::PushFront(const AudioVector& prepend_this) { 85 const size_t length = prepend_this.Size(); 86 if (length == 0) 87 return; 88 89 // Although the subsequent calling to PushFront does Reserve in it, it is 90 // always more efficient to do a big Reserve first. 91 Reserve(Size() + length); 92 93 const size_t first_chunk_length = 94 std::min(length, prepend_this.capacity_ - prepend_this.begin_index_); 95 const size_t remaining_length = length - first_chunk_length; 96 if (remaining_length > 0) 97 PushFront(prepend_this.array_.get(), remaining_length); 98 PushFront(&prepend_this.array_[prepend_this.begin_index_], 99 first_chunk_length); 100 } 101 102 void AudioVector::PushFront(const int16_t* prepend_this, size_t length) { 103 if (length == 0) 104 return; 105 Reserve(Size() + length); 106 const size_t first_chunk_length = std::min(length, begin_index_); 107 memcpy(&array_[begin_index_ - first_chunk_length], 108 &prepend_this[length - first_chunk_length], 109 first_chunk_length * sizeof(int16_t)); 110 const size_t remaining_length = length - first_chunk_length; 111 if (remaining_length > 0) { 112 memcpy(&array_[capacity_ - remaining_length], prepend_this, 113 remaining_length * sizeof(int16_t)); 114 } 115 begin_index_ = (begin_index_ + capacity_ - length) % capacity_; 116 } 117 118 void AudioVector::PushBack(const AudioVector& append_this) { 119 PushBack(append_this, append_this.Size(), 0); 120 } 121 122 void AudioVector::PushBack(const AudioVector& append_this, 123 size_t length, 124 size_t position) { 125 RTC_DCHECK_LE(position, append_this.Size()); 126 RTC_DCHECK_LE(length, append_this.Size() - position); 127 128 if (length == 0) 129 return; 130 131 // Although the subsequent calling to PushBack does Reserve in it, it is 132 // always more efficient to do a big Reserve first. 133 Reserve(Size() + length); 134 135 const size_t start_index = 136 (append_this.begin_index_ + position) % append_this.capacity_; 137 const size_t first_chunk_length = 138 std::min(length, append_this.capacity_ - start_index); 139 PushBack(&append_this.array_[start_index], first_chunk_length); 140 141 const size_t remaining_length = length - first_chunk_length; 142 if (remaining_length > 0) 143 PushBack(append_this.array_.get(), remaining_length); 144 } 145 146 void AudioVector::PushBack(const int16_t* append_this, size_t length) { 147 if (length == 0) 148 return; 149 Reserve(Size() + length); 150 const size_t first_chunk_length = std::min(length, capacity_ - end_index_); 151 memcpy(&array_[end_index_], append_this, 152 first_chunk_length * sizeof(int16_t)); 153 const size_t remaining_length = length - first_chunk_length; 154 if (remaining_length > 0) { 155 memcpy(array_.get(), &append_this[first_chunk_length], 156 remaining_length * sizeof(int16_t)); 157 } 158 end_index_ = (end_index_ + length) % capacity_; 159 } 160 161 void AudioVector::PopFront(size_t length) { 162 if (length == 0) 163 return; 164 length = std::min(length, Size()); 165 begin_index_ = (begin_index_ + length) % capacity_; 166 } 167 168 void AudioVector::PopBack(size_t length) { 169 if (length == 0) 170 return; 171 // Never remove more than what is in the array. 172 length = std::min(length, Size()); 173 end_index_ = (end_index_ + capacity_ - length) % capacity_; 174 } 175 176 void AudioVector::Extend(size_t extra_length) { 177 if (extra_length == 0) 178 return; 179 InsertZerosByPushBack(extra_length, Size()); 180 } 181 182 void AudioVector::InsertAt(const int16_t* insert_this, 183 size_t length, 184 size_t position) { 185 if (length == 0) 186 return; 187 // Cap the insert position at the current array length. 188 position = std::min(Size(), position); 189 190 // When inserting to a position closer to the beginning, it is more efficient 191 // to insert by pushing front than to insert by pushing back, since less data 192 // will be moved, vice versa. 193 if (position <= Size() - position) { 194 InsertByPushFront(insert_this, length, position); 195 } else { 196 InsertByPushBack(insert_this, length, position); 197 } 198 } 199 200 void AudioVector::InsertZerosAt(size_t length, size_t position) { 201 if (length == 0) 202 return; 203 // Cap the insert position at the current array length. 204 position = std::min(Size(), position); 205 206 // When inserting to a position closer to the beginning, it is more efficient 207 // to insert by pushing front than to insert by pushing back, since less data 208 // will be moved, vice versa. 209 if (position <= Size() - position) { 210 InsertZerosByPushFront(length, position); 211 } else { 212 InsertZerosByPushBack(length, position); 213 } 214 } 215 216 void AudioVector::OverwriteAt(const AudioVector& insert_this, 217 size_t length, 218 size_t position) { 219 RTC_DCHECK_LE(length, insert_this.Size()); 220 if (length == 0) 221 return; 222 223 // Cap the insert position at the current array length. 224 position = std::min(Size(), position); 225 226 // Although the subsequent calling to OverwriteAt does Reserve in it, it is 227 // always more efficient to do a big Reserve first. 228 size_t new_size = std::max(Size(), position + length); 229 Reserve(new_size); 230 231 const size_t first_chunk_length = 232 std::min(length, insert_this.capacity_ - insert_this.begin_index_); 233 OverwriteAt(&insert_this.array_[insert_this.begin_index_], first_chunk_length, 234 position); 235 const size_t remaining_length = length - first_chunk_length; 236 if (remaining_length > 0) { 237 OverwriteAt(insert_this.array_.get(), remaining_length, 238 position + first_chunk_length); 239 } 240 } 241 242 void AudioVector::OverwriteAt(const int16_t* insert_this, 243 size_t length, 244 size_t position) { 245 if (length == 0) 246 return; 247 // Cap the insert position at the current array length. 248 position = std::min(Size(), position); 249 250 size_t new_size = std::max(Size(), position + length); 251 Reserve(new_size); 252 253 const size_t overwrite_index = (begin_index_ + position) % capacity_; 254 const size_t first_chunk_length = 255 std::min(length, capacity_ - overwrite_index); 256 memcpy(&array_[overwrite_index], insert_this, 257 first_chunk_length * sizeof(int16_t)); 258 const size_t remaining_length = length - first_chunk_length; 259 if (remaining_length > 0) { 260 memcpy(array_.get(), &insert_this[first_chunk_length], 261 remaining_length * sizeof(int16_t)); 262 } 263 264 end_index_ = (begin_index_ + new_size) % capacity_; 265 } 266 267 void AudioVector::CrossFade(const AudioVector& append_this, 268 size_t fade_length) { 269 // Fade length cannot be longer than the current vector or `append_this`. 270 RTC_DCHECK_LE(fade_length, Size()); 271 RTC_DCHECK_LE(fade_length, append_this.Size()); 272 fade_length = std::min(fade_length, Size()); 273 fade_length = std::min(fade_length, append_this.Size()); 274 size_t position = Size() - fade_length + begin_index_; 275 // Cross fade the overlapping regions. 276 // `alpha` is the mixing factor in Q14. 277 // TODO(hlundin): Consider skipping +1 in the denominator to produce a 278 // smoother cross-fade, in particular at the end of the fade. 279 int alpha_step = 16384 / (static_cast<int>(fade_length) + 1); 280 int alpha = 16384; 281 for (size_t i = 0; i < fade_length; ++i) { 282 alpha -= alpha_step; 283 array_[(position + i) % capacity_] = 284 (alpha * array_[(position + i) % capacity_] + 285 (16384 - alpha) * append_this[i] + 8192) >> 286 14; 287 } 288 RTC_DCHECK_GE(alpha, 0); // Verify that the slope was correct. 289 // Append what is left of `append_this`. 290 size_t samples_to_push_back = append_this.Size() - fade_length; 291 if (samples_to_push_back > 0) 292 PushBack(append_this, samples_to_push_back, fade_length); 293 } 294 295 // Returns the number of elements in this AudioVector. 296 size_t AudioVector::Size() const { 297 return (end_index_ + capacity_ - begin_index_) % capacity_; 298 } 299 300 // Returns true if this AudioVector is empty. 301 bool AudioVector::Empty() const { 302 return begin_index_ == end_index_; 303 } 304 305 void AudioVector::Reserve(size_t n) { 306 if (capacity_ > n) 307 return; 308 const size_t length = Size(); 309 // Reserve one more sample to remove the ambiguity between empty vector and 310 // full vector. Therefore `begin_index_` == `end_index_` indicates empty 311 // vector, and `begin_index_` == (`end_index_` + 1) % capacity indicates 312 // full vector. 313 std::unique_ptr<int16_t[]> temp_array(new int16_t[n + 1]); 314 CopyTo(length, 0, temp_array.get()); 315 array_.swap(temp_array); 316 begin_index_ = 0; 317 end_index_ = length; 318 capacity_ = n + 1; 319 } 320 321 void AudioVector::InsertByPushBack(const int16_t* insert_this, 322 size_t length, 323 size_t position) { 324 const size_t move_chunk_length = Size() - position; 325 std::unique_ptr<int16_t[]> temp_array(nullptr); 326 if (move_chunk_length > 0) { 327 // TODO(minyue): see if it is possible to avoid copying to a buffer. 328 temp_array.reset(new int16_t[move_chunk_length]); 329 CopyTo(move_chunk_length, position, temp_array.get()); 330 PopBack(move_chunk_length); 331 } 332 333 Reserve(Size() + length + move_chunk_length); 334 PushBack(insert_this, length); 335 if (move_chunk_length > 0) 336 PushBack(temp_array.get(), move_chunk_length); 337 } 338 339 void AudioVector::InsertByPushFront(const int16_t* insert_this, 340 size_t length, 341 size_t position) { 342 std::unique_ptr<int16_t[]> temp_array(nullptr); 343 if (position > 0) { 344 // TODO(minyue): see if it is possible to avoid copying to a buffer. 345 temp_array.reset(new int16_t[position]); 346 CopyTo(position, 0, temp_array.get()); 347 PopFront(position); 348 } 349 350 Reserve(Size() + length + position); 351 PushFront(insert_this, length); 352 if (position > 0) 353 PushFront(temp_array.get(), position); 354 } 355 356 void AudioVector::InsertZerosByPushBack(size_t length, size_t position) { 357 const size_t move_chunk_length = Size() - position; 358 std::unique_ptr<int16_t[]> temp_array(nullptr); 359 if (move_chunk_length > 0) { 360 temp_array.reset(new int16_t[move_chunk_length]); 361 CopyTo(move_chunk_length, position, temp_array.get()); 362 PopBack(move_chunk_length); 363 } 364 365 Reserve(Size() + length + move_chunk_length); 366 367 const size_t first_zero_chunk_length = 368 std::min(length, capacity_ - end_index_); 369 memset(&array_[end_index_], 0, first_zero_chunk_length * sizeof(int16_t)); 370 const size_t remaining_zero_length = length - first_zero_chunk_length; 371 if (remaining_zero_length > 0) 372 memset(array_.get(), 0, remaining_zero_length * sizeof(int16_t)); 373 end_index_ = (end_index_ + length) % capacity_; 374 375 if (move_chunk_length > 0) 376 PushBack(temp_array.get(), move_chunk_length); 377 } 378 379 void AudioVector::InsertZerosByPushFront(size_t length, size_t position) { 380 std::unique_ptr<int16_t[]> temp_array(nullptr); 381 if (position > 0) { 382 temp_array.reset(new int16_t[position]); 383 CopyTo(position, 0, temp_array.get()); 384 PopFront(position); 385 } 386 387 Reserve(Size() + length + position); 388 389 const size_t first_zero_chunk_length = std::min(length, begin_index_); 390 memset(&array_[begin_index_ - first_zero_chunk_length], 0, 391 first_zero_chunk_length * sizeof(int16_t)); 392 const size_t remaining_zero_length = length - first_zero_chunk_length; 393 if (remaining_zero_length > 0) 394 memset(&array_[capacity_ - remaining_zero_length], 0, 395 remaining_zero_length * sizeof(int16_t)); 396 begin_index_ = (begin_index_ + capacity_ - length) % capacity_; 397 398 if (position > 0) 399 PushFront(temp_array.get(), position); 400 } 401 402 } // namespace webrtc