tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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(&copy_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