| /* | |
| * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | |
| * | |
| * Use of this source code is governed by a BSD-style license | |
| * that can be found in the LICENSE file in the root of the source | |
| * tree. An additional intellectual property rights grant can be found | |
| * in the file PATENTS. All contributing project authors may | |
| * be found in the AUTHORS file in the root of the source tree. | |
| */ | |
| #include "webrtc/modules/audio_coding/neteq/audio_vector.h" | |
| #include <assert.h> | |
| #include <algorithm> | |
| #include "webrtc/typedefs.h" | |
| namespace webrtc { | |
| AudioVector::AudioVector() | |
| : array_(new int16_t[kDefaultInitialSize]), | |
| first_free_ix_(0), | |
| capacity_(kDefaultInitialSize) { | |
| } | |
| AudioVector::AudioVector(size_t initial_size) | |
| : array_(new int16_t[initial_size]), | |
| first_free_ix_(initial_size), | |
| capacity_(initial_size) { | |
| memset(array_.get(), 0, initial_size * sizeof(int16_t)); | |
| } | |
| AudioVector::~AudioVector() = default; | |
| void AudioVector::Clear() { | |
| first_free_ix_ = 0; | |
| } | |
| void AudioVector::CopyTo(AudioVector* copy_to) const { | |
| if (copy_to) { | |
| copy_to->Reserve(Size()); | |
| assert(copy_to->capacity_ >= Size()); | |
| memcpy(copy_to->array_.get(), array_.get(), Size() * sizeof(int16_t)); | |
| copy_to->first_free_ix_ = first_free_ix_; | |
| } | |
| } | |
| void AudioVector::PushFront(const AudioVector& prepend_this) { | |
| size_t insert_length = prepend_this.Size(); | |
| Reserve(Size() + insert_length); | |
| memmove(&array_[insert_length], &array_[0], Size() * sizeof(int16_t)); | |
| memcpy(&array_[0], &prepend_this.array_[0], insert_length * sizeof(int16_t)); | |
| first_free_ix_ += insert_length; | |
| } | |
| void AudioVector::PushFront(const int16_t* prepend_this, size_t length) { | |
| // Same operation as InsertAt beginning. | |
| InsertAt(prepend_this, length, 0); | |
| } | |
| void AudioVector::PushBack(const AudioVector& append_this) { | |
| PushBack(append_this.array_.get(), append_this.Size()); | |
| } | |
| void AudioVector::PushBack(const int16_t* append_this, size_t length) { | |
| Reserve(Size() + length); | |
| memcpy(&array_[first_free_ix_], append_this, length * sizeof(int16_t)); | |
| first_free_ix_ += length; | |
| } | |
| void AudioVector::PopFront(size_t length) { | |
| if (length >= Size()) { | |
| // Remove all elements. | |
| Clear(); | |
| } else { | |
| size_t remaining_samples = Size() - length; | |
| memmove(&array_[0], &array_[length], remaining_samples * sizeof(int16_t)); | |
| first_free_ix_ -= length; | |
| } | |
| } | |
| void AudioVector::PopBack(size_t length) { | |
| // Never remove more than what is in the array. | |
| length = std::min(length, Size()); | |
| first_free_ix_ -= length; | |
| } | |
| void AudioVector::Extend(size_t extra_length) { | |
| Reserve(Size() + extra_length); | |
| memset(&array_[first_free_ix_], 0, extra_length * sizeof(int16_t)); | |
| first_free_ix_ += extra_length; | |
| } | |
| void AudioVector::InsertAt(const int16_t* insert_this, | |
| size_t length, | |
| size_t position) { | |
| Reserve(Size() + length); | |
| // Cap the position at the current vector length, to be sure the iterator | |
| // does not extend beyond the end of the vector. | |
| position = std::min(Size(), position); | |
| int16_t* insert_position_ptr = &array_[position]; | |
| size_t samples_to_move = Size() - position; | |
| memmove(insert_position_ptr + length, insert_position_ptr, | |
| samples_to_move * sizeof(int16_t)); | |
| memcpy(insert_position_ptr, insert_this, length * sizeof(int16_t)); | |
| first_free_ix_ += length; | |
| } | |
| void AudioVector::InsertZerosAt(size_t length, | |
| size_t position) { | |
| Reserve(Size() + length); | |
| // Cap the position at the current vector length, to be sure the iterator | |
| // does not extend beyond the end of the vector. | |
| position = std::min(capacity_, position); | |
| int16_t* insert_position_ptr = &array_[position]; | |
| size_t samples_to_move = Size() - position; | |
| memmove(insert_position_ptr + length, insert_position_ptr, | |
| samples_to_move * sizeof(int16_t)); | |
| memset(insert_position_ptr, 0, length * sizeof(int16_t)); | |
| first_free_ix_ += length; | |
| } | |
| void AudioVector::OverwriteAt(const int16_t* insert_this, | |
| size_t length, | |
| size_t position) { | |
| // Cap the insert position at the current array length. | |
| position = std::min(Size(), position); | |
| Reserve(position + length); | |
| memcpy(&array_[position], insert_this, length * sizeof(int16_t)); | |
| if (position + length > Size()) { | |
| // Array was expanded. | |
| first_free_ix_ += position + length - Size(); | |
| } | |
| } | |
| void AudioVector::CrossFade(const AudioVector& append_this, | |
| size_t fade_length) { | |
| // Fade length cannot be longer than the current vector or |append_this|. | |
| assert(fade_length <= Size()); | |
| assert(fade_length <= append_this.Size()); | |
| fade_length = std::min(fade_length, Size()); | |
| fade_length = std::min(fade_length, append_this.Size()); | |
| size_t position = Size() - fade_length; | |
| // Cross fade the overlapping regions. | |
| // |alpha| is the mixing factor in Q14. | |
| // TODO(hlundin): Consider skipping +1 in the denominator to produce a | |
| // smoother cross-fade, in particular at the end of the fade. | |
| int alpha_step = 16384 / (static_cast<int>(fade_length) + 1); | |
| int alpha = 16384; | |
| for (size_t i = 0; i < fade_length; ++i) { | |
| alpha -= alpha_step; | |
| array_[position + i] = (alpha * array_[position + i] + | |
| (16384 - alpha) * append_this[i] + 8192) >> 14; | |
| } | |
| assert(alpha >= 0); // Verify that the slope was correct. | |
| // Append what is left of |append_this|. | |
| size_t samples_to_push_back = append_this.Size() - fade_length; | |
| if (samples_to_push_back > 0) | |
| PushBack(&append_this[fade_length], samples_to_push_back); | |
| } | |
| // Returns the number of elements in this AudioVector. | |
| size_t AudioVector::Size() const { | |
| return first_free_ix_; | |
| } | |
| // Returns true if this AudioVector is empty. | |
| bool AudioVector::Empty() const { | |
| return first_free_ix_ == 0; | |
| } | |
| const int16_t& AudioVector::operator[](size_t index) const { | |
| return array_[index]; | |
| } | |
| int16_t& AudioVector::operator[](size_t index) { | |
| return array_[index]; | |
| } | |
| void AudioVector::Reserve(size_t n) { | |
| if (capacity_ < n) { | |
| rtc::scoped_ptr<int16_t[]> temp_array(new int16_t[n]); | |
| memcpy(temp_array.get(), array_.get(), Size() * sizeof(int16_t)); | |
| array_.swap(temp_array); | |
| capacity_ = n; | |
| } | |
| } | |
| } // namespace webrtc |