/* * 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 #include #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(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 temp_array(new int16_t[n]); memcpy(temp_array.get(), array_.get(), Size() * sizeof(int16_t)); array_.swap(temp_array); capacity_ = n; } } } // namespace webrtc