LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/audio_coding/neteq - audio_vector.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 234 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 27 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13