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