blob: fa16481b69515e6eaa6cc36ff6ce82c6db675afa [file] [log] [blame]
/*
* 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