19a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org/*
29a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
39a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *
49a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  Use of this source code is governed by a BSD-style license
59a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  that can be found in the LICENSE file in the root of the source
69a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  tree. An additional intellectual property rights grant can be found
79a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  in the file PATENTS.  All contributing project authors may
89a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
99a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org */
109a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
11e5abc854f3dc47de16067c2a41476c39b7626722henrik.lundin@webrtc.org#include "webrtc/modules/audio_coding/neteq/audio_vector.h"
129a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
139a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org#include <assert.h>
149a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
159a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org#include <algorithm>
169a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
179a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org#include "webrtc/typedefs.h"
189a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
199a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgnamespace webrtc {
209a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
219b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.orgvoid AudioVector::Clear() {
22591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  first_free_ix_ = 0;
239a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
249a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
250e4084a5b020b0364983acde9d4d420db876995ahenrik.lundin@webrtc.orgvoid AudioVector::CopyTo(AudioVector* copy_to) const {
269a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (copy_to) {
27591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org    copy_to->Reserve(Size());
28591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org    assert(copy_to->capacity_ >= Size());
29591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org    memcpy(copy_to->array_.get(), array_.get(), Size() * sizeof(int16_t));
30591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org    copy_to->first_free_ix_ = first_free_ix_;
319a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
329a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
349b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.orgvoid AudioVector::PushFront(const AudioVector& prepend_this) {
35591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  size_t insert_length = prepend_this.Size();
36591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  Reserve(Size() + insert_length);
37591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  memmove(&array_[insert_length], &array_[0], Size() * sizeof(int16_t));
38591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  memcpy(&array_[0], &prepend_this.array_[0], insert_length * sizeof(int16_t));
39591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  first_free_ix_ += insert_length;
409a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
419a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
429b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.orgvoid AudioVector::PushFront(const int16_t* prepend_this, size_t length) {
439a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Same operation as InsertAt beginning.
449a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  InsertAt(prepend_this, length, 0);
459a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
469a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
479b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.orgvoid AudioVector::PushBack(const AudioVector& append_this) {
48591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  PushBack(append_this.array_.get(), append_this.Size());
499a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
519b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.orgvoid AudioVector::PushBack(const int16_t* append_this, size_t length) {
52591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  Reserve(Size() + length);
53591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  memcpy(&array_[first_free_ix_], append_this, length * sizeof(int16_t));
54591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  first_free_ix_ += length;
559a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
569a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
579b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.orgvoid AudioVector::PopFront(size_t length) {
58591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  if (length >= Size()) {
599a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Remove all elements.
60591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org    Clear();
619a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  } else {
62591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org    size_t remaining_samples = Size() - length;
63591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org    memmove(&array_[0], &array_[length], remaining_samples * sizeof(int16_t));
64591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org    first_free_ix_ -= length;
659a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
669a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
679a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
689b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.orgvoid AudioVector::PopBack(size_t length) {
69591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  // Never remove more than what is in the array.
70591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  length = std::min(length, Size());
71591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  first_free_ix_ -= length;
729a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
739a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
749b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.orgvoid AudioVector::Extend(size_t extra_length) {
75591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  Reserve(Size() + extra_length);
76591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  memset(&array_[first_free_ix_], 0, extra_length * sizeof(int16_t));
77591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  first_free_ix_ += extra_length;
789a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
799a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
809b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.orgvoid AudioVector::InsertAt(const int16_t* insert_this,
819b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.org                           size_t length,
829b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.org                           size_t position) {
83591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  Reserve(Size() + length);
849a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Cap the position at the current vector length, to be sure the iterator
859a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // does not extend beyond the end of the vector.
86591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  position = std::min(Size(), position);
87591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  int16_t* insert_position_ptr = &array_[position];
88591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  size_t samples_to_move = Size() - position;
89591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  memmove(insert_position_ptr + length, insert_position_ptr,
90591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org          samples_to_move * sizeof(int16_t));
91591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  memcpy(insert_position_ptr, insert_this, length * sizeof(int16_t));
92591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  first_free_ix_ += length;
939a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
949a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
959b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.orgvoid AudioVector::InsertZerosAt(size_t length,
969b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.org                                size_t position) {
97591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  Reserve(Size() + length);
989a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Cap the position at the current vector length, to be sure the iterator
999a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // does not extend beyond the end of the vector.
100591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  position = std::min(capacity_, position);
101591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  int16_t* insert_position_ptr = &array_[position];
102591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  size_t samples_to_move = Size() - position;
103591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  memmove(insert_position_ptr + length, insert_position_ptr,
104591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org          samples_to_move * sizeof(int16_t));
105591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  memset(insert_position_ptr, 0, length * sizeof(int16_t));
106591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  first_free_ix_ += length;
1079a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1089a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1099b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.orgvoid AudioVector::OverwriteAt(const int16_t* insert_this,
1109b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.org                              size_t length,
1119b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.org                              size_t position) {
112591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  // Cap the insert position at the current array length.
113591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  position = std::min(Size(), position);
114591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  Reserve(position + length);
115591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  memcpy(&array_[position], insert_this, length * sizeof(int16_t));
116591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  if (position + length > Size()) {
117591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org    // Array was expanded.
118591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org    first_free_ix_ += position + length - Size();
1199a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
1209a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1219a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1229b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.orgvoid AudioVector::CrossFade(const AudioVector& append_this,
1239b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.org                            size_t fade_length) {
1249a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Fade length cannot be longer than the current vector or |append_this|.
1259a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  assert(fade_length <= Size());
1269a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  assert(fade_length <= append_this.Size());
1279a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  fade_length = std::min(fade_length, Size());
1289a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  fade_length = std::min(fade_length, append_this.Size());
1299a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  size_t position = Size() - fade_length;
1309a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Cross fade the overlapping regions.
1319a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // |alpha| is the mixing factor in Q14.
1329a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // TODO(hlundin): Consider skipping +1 in the denominator to produce a
1339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // smoother cross-fade, in particular at the end of the fade.
134045e45efeca8776975254550137ec65268aadb54turaj@webrtc.org  int alpha_step = 16384 / (static_cast<int>(fade_length) + 1);
1359a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int alpha = 16384;
1369a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  for (size_t i = 0; i < fade_length; ++i) {
1379a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    alpha -= alpha_step;
138591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org    array_[position + i] = (alpha * array_[position + i] +
1399a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        (16384 - alpha) * append_this[i] + 8192) >> 14;
1409a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
1419a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  assert(alpha >= 0);  // Verify that the slope was correct.
1429a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Append what is left of |append_this|.
1433b70afa638601d6455f5dd4e33b2c954ab3ddb31henrik.lundin@webrtc.org  size_t samples_to_push_back = append_this.Size() - fade_length;
1443b70afa638601d6455f5dd4e33b2c954ab3ddb31henrik.lundin@webrtc.org  if (samples_to_push_back > 0)
1453b70afa638601d6455f5dd4e33b2c954ab3ddb31henrik.lundin@webrtc.org    PushBack(&append_this[fade_length], samples_to_push_back);
1469a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1479a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1489b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.orgconst int16_t& AudioVector::operator[](size_t index) const {
149591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  return array_[index];
1509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1519a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1529b1b52533c0e6accb1b0d3a4c1934856cd4473edhenrik.lundin@webrtc.orgint16_t& AudioVector::operator[](size_t index) {
153591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  return array_[index];
154591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org}
155591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org
156591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.orgvoid AudioVector::Reserve(size_t n) {
157591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  if (capacity_ < n) {
158591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org    scoped_ptr<int16_t[]> temp_array(new int16_t[n]);
159591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org    memcpy(temp_array.get(), array_.get(), Size() * sizeof(int16_t));
160591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org    array_.swap(temp_array);
161591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org    capacity_ = n;
162591be3b50428e3c1ea6c29093d1d97e6b3743273henrik.lundin@webrtc.org  }
1639a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1649a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1659a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}  // namespace webrtc
166