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
17#include "webrtc/typedefs.h"
18
19namespace webrtc {
20
21void AudioVector::Clear() {
22  first_free_ix_ = 0;
23}
24
25void AudioVector::CopyTo(AudioVector* copy_to) const {
26  if (copy_to) {
27    copy_to->Reserve(Size());
28    assert(copy_to->capacity_ >= Size());
29    memcpy(copy_to->array_.get(), array_.get(), Size() * sizeof(int16_t));
30    copy_to->first_free_ix_ = first_free_ix_;
31  }
32}
33
34void AudioVector::PushFront(const AudioVector& prepend_this) {
35  size_t insert_length = prepend_this.Size();
36  Reserve(Size() + insert_length);
37  memmove(&array_[insert_length], &array_[0], Size() * sizeof(int16_t));
38  memcpy(&array_[0], &prepend_this.array_[0], insert_length * sizeof(int16_t));
39  first_free_ix_ += insert_length;
40}
41
42void AudioVector::PushFront(const int16_t* prepend_this, size_t length) {
43  // Same operation as InsertAt beginning.
44  InsertAt(prepend_this, length, 0);
45}
46
47void AudioVector::PushBack(const AudioVector& append_this) {
48  PushBack(append_this.array_.get(), append_this.Size());
49}
50
51void AudioVector::PushBack(const int16_t* append_this, size_t length) {
52  Reserve(Size() + length);
53  memcpy(&array_[first_free_ix_], append_this, length * sizeof(int16_t));
54  first_free_ix_ += length;
55}
56
57void AudioVector::PopFront(size_t length) {
58  if (length >= Size()) {
59    // Remove all elements.
60    Clear();
61  } else {
62    size_t remaining_samples = Size() - length;
63    memmove(&array_[0], &array_[length], remaining_samples * sizeof(int16_t));
64    first_free_ix_ -= length;
65  }
66}
67
68void AudioVector::PopBack(size_t length) {
69  // Never remove more than what is in the array.
70  length = std::min(length, Size());
71  first_free_ix_ -= length;
72}
73
74void AudioVector::Extend(size_t extra_length) {
75  Reserve(Size() + extra_length);
76  memset(&array_[first_free_ix_], 0, extra_length * sizeof(int16_t));
77  first_free_ix_ += extra_length;
78}
79
80void AudioVector::InsertAt(const int16_t* insert_this,
81                           size_t length,
82                           size_t position) {
83  Reserve(Size() + length);
84  // Cap the position at the current vector length, to be sure the iterator
85  // does not extend beyond the end of the vector.
86  position = std::min(Size(), position);
87  int16_t* insert_position_ptr = &array_[position];
88  size_t samples_to_move = Size() - position;
89  memmove(insert_position_ptr + length, insert_position_ptr,
90          samples_to_move * sizeof(int16_t));
91  memcpy(insert_position_ptr, insert_this, length * sizeof(int16_t));
92  first_free_ix_ += length;
93}
94
95void AudioVector::InsertZerosAt(size_t length,
96                                size_t position) {
97  Reserve(Size() + length);
98  // Cap the position at the current vector length, to be sure the iterator
99  // does not extend beyond the end of the vector.
100  position = std::min(capacity_, position);
101  int16_t* insert_position_ptr = &array_[position];
102  size_t samples_to_move = Size() - position;
103  memmove(insert_position_ptr + length, insert_position_ptr,
104          samples_to_move * sizeof(int16_t));
105  memset(insert_position_ptr, 0, length * sizeof(int16_t));
106  first_free_ix_ += length;
107}
108
109void AudioVector::OverwriteAt(const int16_t* insert_this,
110                              size_t length,
111                              size_t position) {
112  // Cap the insert position at the current array length.
113  position = std::min(Size(), position);
114  Reserve(position + length);
115  memcpy(&array_[position], insert_this, length * sizeof(int16_t));
116  if (position + length > Size()) {
117    // Array was expanded.
118    first_free_ix_ += position + length - Size();
119  }
120}
121
122void AudioVector::CrossFade(const AudioVector& append_this,
123                            size_t fade_length) {
124  // Fade length cannot be longer than the current vector or |append_this|.
125  assert(fade_length <= Size());
126  assert(fade_length <= append_this.Size());
127  fade_length = std::min(fade_length, Size());
128  fade_length = std::min(fade_length, append_this.Size());
129  size_t position = Size() - fade_length;
130  // Cross fade the overlapping regions.
131  // |alpha| is the mixing factor in Q14.
132  // TODO(hlundin): Consider skipping +1 in the denominator to produce a
133  // smoother cross-fade, in particular at the end of the fade.
134  int alpha_step = 16384 / (static_cast<int>(fade_length) + 1);
135  int alpha = 16384;
136  for (size_t i = 0; i < fade_length; ++i) {
137    alpha -= alpha_step;
138    array_[position + i] = (alpha * array_[position + i] +
139        (16384 - alpha) * append_this[i] + 8192) >> 14;
140  }
141  assert(alpha >= 0);  // Verify that the slope was correct.
142  // Append what is left of |append_this|.
143  size_t samples_to_push_back = append_this.Size() - fade_length;
144  if (samples_to_push_back > 0)
145    PushBack(&append_this[fade_length], samples_to_push_back);
146}
147
148const int16_t& AudioVector::operator[](size_t index) const {
149  return array_[index];
150}
151
152int16_t& AudioVector::operator[](size_t index) {
153  return array_[index];
154}
155
156void AudioVector::Reserve(size_t n) {
157  if (capacity_ < n) {
158    scoped_ptr<int16_t[]> temp_array(new int16_t[n]);
159    memcpy(temp_array.get(), array_.get(), Size() * sizeof(int16_t));
160    array_.swap(temp_array);
161    capacity_ = n;
162  }
163}
164
165}  // namespace webrtc
166