Using ring buffer for AudioVector in NetEq.

AudioVector used NetEq was based on a shift buffer, which has a high complexity, and the complexity is very much dependent on the capacity of the buffer.

This CL changes the shift buffer to a ring buffer.

Reduction in the CPU usages of NetEq is expected.

BUG=608644
R=henrik.lundin@webrtc.org

Review URL: https://codereview.webrtc.org/1948483002 .

Cr-Commit-Position: refs/heads/master@{#12676}
This commit is contained in:
minyue-webrtc 2016-05-10 19:55:56 +02:00
parent 17fa67214c
commit 79553cb66e
12 changed files with 399 additions and 131 deletions

View File

@ -106,7 +106,7 @@ void AudioMultiVector::PushBackFromIndex(const AudioMultiVector& append_this,
assert(num_channels_ == append_this.num_channels_);
if (num_channels_ == append_this.num_channels_) {
for (size_t i = 0; i < num_channels_; ++i) {
channels_[i]->PushBack(&append_this[i][index], length);
channels_[i]->PushBack(append_this[i], length, index);
}
}
}
@ -133,14 +133,14 @@ size_t AudioMultiVector::ReadInterleavedFromIndex(size_t start_index,
int16_t* destination) const {
RTC_DCHECK(destination);
size_t index = 0; // Number of elements written to |destination| so far.
assert(start_index <= Size());
RTC_DCHECK_LE(start_index, Size());
start_index = std::min(start_index, Size());
if (length + start_index > Size()) {
length = Size() - start_index;
}
if (num_channels_ == 1) {
// Special case to avoid the nested for loop below.
memcpy(destination, &(*this)[0][start_index], length * sizeof(int16_t));
(*this)[0].CopyTo(length, start_index, destination);
return length;
}
for (size_t i = 0; i < length; ++i) {
@ -167,7 +167,7 @@ void AudioMultiVector::OverwriteAt(const AudioMultiVector& insert_this,
length = std::min(length, insert_this.Size());
if (num_channels_ == insert_this.num_channels_) {
for (size_t i = 0; i < num_channels_; ++i) {
channels_[i]->OverwriteAt(&insert_this[i][0], length, position);
channels_[i]->OverwriteAt(insert_this[i], length, position);
}
}
}

View File

@ -15,124 +15,236 @@
#include <algorithm>
#include <memory>
#include "webrtc/base/checks.h"
#include "webrtc/typedefs.h"
namespace webrtc {
AudioVector::AudioVector()
: array_(new int16_t[kDefaultInitialSize]),
first_free_ix_(0),
capacity_(kDefaultInitialSize) {
: AudioVector(kDefaultInitialSize) {
Clear();
}
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));
: array_(new int16_t[initial_size + 1]),
capacity_(initial_size + 1),
begin_index_(0),
end_index_(capacity_ - 1) {
memset(array_.get(), 0, capacity_ * sizeof(int16_t));
}
AudioVector::~AudioVector() = default;
void AudioVector::Clear() {
first_free_ix_ = 0;
end_index_ = begin_index_ = 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_;
RTC_DCHECK(copy_to);
copy_to->Reserve(Size());
CopyTo(Size(), 0, copy_to->array_.get());
copy_to->begin_index_ = 0;
copy_to->end_index_ = Size();
}
void AudioVector::CopyTo(
size_t length, size_t position, int16_t* copy_to) const {
if (length == 0)
return;
length = std::min(length, Size() - position);
const size_t copy_index = (begin_index_ + position) % capacity_;
const size_t first_chunk_length =
std::min(length, capacity_ - copy_index);
memcpy(copy_to, &array_[copy_index],
first_chunk_length * sizeof(int16_t));
const size_t remaining_length = length - first_chunk_length;
if (remaining_length > 0) {
memcpy(&copy_to[first_chunk_length], array_.get(),
remaining_length * sizeof(int16_t));
}
}
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;
const size_t length = prepend_this.Size();
if (length == 0)
return;
// Although the subsequent calling to PushFront does Reserve in it, it is
// always more efficient to do a big Reserve first.
Reserve(Size() + length);
const size_t first_chunk_length =
std::min(length, prepend_this.capacity_ - prepend_this.begin_index_);
const size_t remaining_length = length - first_chunk_length;
if (remaining_length > 0)
PushFront(prepend_this.array_.get(), remaining_length);
PushFront(&prepend_this.array_[prepend_this.begin_index_],
first_chunk_length);
}
void AudioVector::PushFront(const int16_t* prepend_this, size_t length) {
// Same operation as InsertAt beginning.
InsertAt(prepend_this, length, 0);
if (length == 0)
return;
Reserve(Size() + length);
const size_t first_chunk_length = std::min(length, begin_index_);
memcpy(&array_[begin_index_ - first_chunk_length],
&prepend_this[length - first_chunk_length],
first_chunk_length * sizeof(int16_t));
const size_t remaining_length = length - first_chunk_length;
if (remaining_length > 0) {
memcpy(&array_[capacity_ - remaining_length], prepend_this,
remaining_length * sizeof(int16_t));
}
begin_index_ = (begin_index_ + capacity_ - length) % capacity_;
}
void AudioVector::PushBack(const AudioVector& append_this) {
PushBack(append_this.array_.get(), append_this.Size());
PushBack(append_this, append_this.Size(), 0);
}
void AudioVector::PushBack(
const AudioVector& append_this, size_t length, size_t position) {
RTC_DCHECK_LE(position, append_this.Size());
RTC_DCHECK_LE(length, append_this.Size() - position);
if (length == 0)
return;
// Although the subsequent calling to PushBack does Reserve in it, it is
// always more efficient to do a big Reserve first.
Reserve(Size() + length);
const size_t start_index =
(append_this.begin_index_ + position) % append_this.capacity_;
const size_t first_chunk_length = std::min(
length, append_this.capacity_ - start_index);
PushBack(&append_this.array_[start_index], first_chunk_length);
const size_t remaining_length = length - first_chunk_length;
if (remaining_length > 0)
PushBack(append_this.array_.get(), remaining_length);
}
void AudioVector::PushBack(const int16_t* append_this, size_t length) {
if (length == 0)
return;
Reserve(Size() + length);
memcpy(&array_[first_free_ix_], append_this, length * sizeof(int16_t));
first_free_ix_ += length;
const size_t first_chunk_length = std::min(length, capacity_ - end_index_);
memcpy(&array_[end_index_], append_this,
first_chunk_length * sizeof(int16_t));
const size_t remaining_length = length - first_chunk_length;
if (remaining_length > 0) {
memcpy(array_.get(), &append_this[first_chunk_length],
remaining_length * sizeof(int16_t));
}
end_index_ = (end_index_ + length) % capacity_;
}
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;
}
if (length == 0)
return;
length = std::min(length, Size());
begin_index_ = (begin_index_ + length) % capacity_;
}
void AudioVector::PopBack(size_t length) {
if (length == 0)
return;
// Never remove more than what is in the array.
length = std::min(length, Size());
first_free_ix_ -= length;
end_index_ = (end_index_ + capacity_ - length) % capacity_;
}
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;
if (extra_length == 0)
return;
InsertZerosByPushBack(extra_length, Size());
}
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.
if (length == 0)
return;
// Cap the insert position at the current array length.
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;
// When inserting to a position closer to the beginning, it is more efficient
// to insert by pushing front than to insert by pushing back, since less data
// will be moved, vice versa.
if (position <= Size() - position) {
InsertByPushFront(insert_this, length, position);
} else {
InsertByPushBack(insert_this, length, position);
}
}
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;
if (length == 0)
return;
// Cap the insert position at the current array length.
position = std::min(Size(), position);
// When inserting to a position closer to the beginning, it is more efficient
// to insert by pushing front than to insert by pushing back, since less data
// will be moved, vice versa.
if (position <= Size() - position) {
InsertZerosByPushFront(length, position);
} else {
InsertZerosByPushBack(length, position);
}
}
void AudioVector::OverwriteAt(const AudioVector& insert_this,
size_t length,
size_t position) {
RTC_DCHECK_LE(length, insert_this.Size());
if (length == 0)
return;
// Cap the insert position at the current array length.
position = std::min(Size(), position);
// Although the subsequent calling to OverwriteAt does Reserve in it, it is
// always more efficient to do a big Reserve first.
size_t new_size = std::max(Size(), position + length);
Reserve(new_size);
const size_t first_chunk_length =
std::min(length, insert_this.capacity_ - insert_this.begin_index_);
OverwriteAt(&insert_this.array_[insert_this.begin_index_], first_chunk_length,
position);
const size_t remaining_length = length - first_chunk_length;
if (remaining_length > 0) {
OverwriteAt(insert_this.array_.get(), remaining_length,
position + first_chunk_length);
}
}
void AudioVector::OverwriteAt(const int16_t* insert_this,
size_t length,
size_t position) {
if (length == 0)
return;
// 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();
size_t new_size = std::max(Size(), position + length);
Reserve(new_size);
const size_t overwrite_index = (begin_index_ + position) % capacity_;
const size_t first_chunk_length =
std::min(length, capacity_ - overwrite_index);
memcpy(&array_[overwrite_index], insert_this,
first_chunk_length * sizeof(int16_t));
const size_t remaining_length = length - first_chunk_length;
if (remaining_length > 0) {
memcpy(array_.get(), &insert_this[first_chunk_length],
remaining_length * sizeof(int16_t));
}
end_index_ = (begin_index_ + new_size) % capacity_;
}
void AudioVector::CrossFade(const AudioVector& append_this,
@ -142,7 +254,7 @@ void AudioVector::CrossFade(const AudioVector& append_this,
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;
size_t position = Size() - fade_length + begin_index_;
// Cross fade the overlapping regions.
// |alpha| is the mixing factor in Q14.
// TODO(hlundin): Consider skipping +1 in the denominator to produce a
@ -151,41 +263,132 @@ void AudioVector::CrossFade(const AudioVector& append_this,
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;
array_[(position + i) % capacity_] =
(alpha * array_[(position + i) % capacity_] +
(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);
PushBack(append_this, samples_to_push_back, fade_length);
}
// Returns the number of elements in this AudioVector.
size_t AudioVector::Size() const {
return first_free_ix_;
return (end_index_ + capacity_ - begin_index_) % capacity_;
}
// Returns true if this AudioVector is empty.
bool AudioVector::Empty() const {
return first_free_ix_ == 0;
return begin_index_ == end_index_;
}
const int16_t& AudioVector::operator[](size_t index) const {
return array_[index];
return array_[(begin_index_ + index) % capacity_];
}
int16_t& AudioVector::operator[](size_t index) {
return array_[index];
return array_[(begin_index_ + index) % capacity_];
}
void AudioVector::Reserve(size_t n) {
if (capacity_ < n) {
std::unique_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;
if (capacity_ > n)
return;
const size_t length = Size();
// Reserve one more sample to remove the ambiguity between empty vector and
// full vector. Therefore |begin_index_| == |end_index_| indicates empty
// vector, and |begin_index_| == (|end_index_| + 1) % capacity indicates
// full vector.
std::unique_ptr<int16_t[]> temp_array(new int16_t[n + 1]);
CopyTo(length, 0, temp_array.get());
array_.swap(temp_array);
begin_index_ = 0;
end_index_ = length;
capacity_ = n + 1;
}
void AudioVector::InsertByPushBack(const int16_t* insert_this,
size_t length,
size_t position) {
const size_t move_chunk_length = Size() - position;
std::unique_ptr<int16_t[]> temp_array(nullptr);
if (move_chunk_length > 0) {
// TODO(minyue): see if it is possible to avoid copying to a buffer.
temp_array.reset(new int16_t[move_chunk_length]);
CopyTo(move_chunk_length, position, temp_array.get());
PopBack(move_chunk_length);
}
Reserve(Size() + length + move_chunk_length);
PushBack(insert_this, length);
if (move_chunk_length > 0)
PushBack(temp_array.get(), move_chunk_length);
}
void AudioVector::InsertByPushFront(const int16_t* insert_this,
size_t length,
size_t position) {
std::unique_ptr<int16_t[]> temp_array(nullptr);
if (position > 0) {
// TODO(minyue): see if it is possible to avoid copying to a buffer.
temp_array.reset(new int16_t[position]);
CopyTo(position, 0, temp_array.get());
PopFront(position);
}
Reserve(Size() + length + position);
PushFront(insert_this, length);
if (position > 0)
PushFront(temp_array.get(), position);
}
void AudioVector::InsertZerosByPushBack(size_t length,
size_t position) {
const size_t move_chunk_length = Size() - position;
std::unique_ptr<int16_t[]> temp_array(nullptr);
if (move_chunk_length > 0) {
temp_array.reset(new int16_t[move_chunk_length]);
CopyTo(move_chunk_length, position, temp_array.get());
PopBack(move_chunk_length);
}
Reserve(Size() + length + move_chunk_length);
const size_t first_zero_chunk_length =
std::min(length, capacity_ - end_index_);
memset(&array_[end_index_], 0, first_zero_chunk_length * sizeof(int16_t));
const size_t remaining_zero_length = length - first_zero_chunk_length;
if (remaining_zero_length > 0)
memset(array_.get(), 0, remaining_zero_length * sizeof(int16_t));
end_index_ = (end_index_ + length) % capacity_;
if (move_chunk_length > 0)
PushBack(temp_array.get(), move_chunk_length);
}
void AudioVector::InsertZerosByPushFront(size_t length,
size_t position) {
std::unique_ptr<int16_t[]> temp_array(nullptr);
if (position > 0) {
temp_array.reset(new int16_t[position]);
CopyTo(position, 0, temp_array.get());
PopFront(position);
}
Reserve(Size() + length + position);
const size_t first_zero_chunk_length = std::min(length, begin_index_);
memset(&array_[begin_index_ - first_zero_chunk_length], 0,
first_zero_chunk_length * sizeof(int16_t));
const size_t remaining_zero_length = length - first_zero_chunk_length;
if (remaining_zero_length > 0)
memset(&array_[capacity_ - remaining_zero_length], 0,
remaining_zero_length * sizeof(int16_t));
begin_index_ = (begin_index_ + capacity_ - length) % capacity_;
if (position > 0)
PushFront(temp_array.get(), position);
}
} // namespace webrtc

View File

@ -37,6 +37,9 @@ class AudioVector {
// |copy_to| will be an exact replica of this object.
virtual void CopyTo(AudioVector* copy_to) const;
// Copies |length| values from |position| in this vector to |copy_to|.
virtual void CopyTo(size_t length, size_t position, int16_t* copy_to) const;
// Prepends the contents of AudioVector |prepend_this| to this object. The
// length of this object is increased with the length of |prepend_this|.
virtual void PushFront(const AudioVector& prepend_this);
@ -48,6 +51,12 @@ class AudioVector {
// Same as PushFront but will append to the end of this object.
virtual void PushBack(const AudioVector& append_this);
// Appends a segment of |append_this| to the end of this object. The segment
// starts from |position| and has |length| samples.
virtual void PushBack(const AudioVector& append_this,
size_t length,
size_t position);
// Same as PushFront but will append to the end of this object.
virtual void PushBack(const int16_t* append_this, size_t length);
@ -71,6 +80,15 @@ class AudioVector {
// Like InsertAt, but inserts |length| zero elements at |position|.
virtual void InsertZerosAt(size_t length, size_t position);
// Overwrites |length| elements of this AudioVector starting from |position|
// with first values in |AudioVector|. The definition of |position|
// is the same as for InsertAt(). If |length| and |position| are selected
// such that the new data extends beyond the end of the current AudioVector,
// the vector is extended to accommodate the new data.
virtual void OverwriteAt(const AudioVector& insert_this,
size_t length,
size_t position);
// Overwrites |length| elements of this AudioVector with values taken from the
// array |insert_this|, starting at |position|. The definition of |position|
// is the same as for InsertAt(). If |length| and |position| are selected
@ -100,11 +118,27 @@ class AudioVector {
void Reserve(size_t n);
void InsertByPushBack(const int16_t* insert_this, size_t length,
size_t position);
void InsertByPushFront(const int16_t* insert_this, size_t length,
size_t position);
void InsertZerosByPushBack(size_t length, size_t position);
void InsertZerosByPushFront(size_t length, size_t position);
std::unique_ptr<int16_t[]> array_;
size_t first_free_ix_; // The first index after the last sample in array_.
// Note that this index may point outside of array_.
size_t capacity_; // Allocated number of samples in the array.
// The index of the first sample in |array_|, except when
// |begin_index_ == end_index_|, which indicates an empty buffer.
size_t begin_index_;
// The index of the sample after the last sample in |array_|.
size_t end_index_;
RTC_DISALLOW_COPY_AND_ASSIGN(AudioVector);
};

View File

@ -82,14 +82,6 @@ TEST_F(AudioVectorTest, PushBackAndCopy) {
EXPECT_TRUE(vec_copy.Empty());
}
// Try to copy to a NULL pointer. Nothing should happen.
TEST_F(AudioVectorTest, CopyToNull) {
AudioVector vec;
AudioVector* vec_copy = NULL;
vec.PushBack(array_, array_length());
vec.CopyTo(vec_copy);
}
// Test the PushBack method with another AudioVector as input argument.
TEST_F(AudioVectorTest, PushBackVector) {
static const size_t kLength = 10;

View File

@ -59,10 +59,7 @@ void BackgroundNoise::Update(const AudioMultiVector& input,
ChannelParameters& parameters = channel_parameters_[channel_ix];
int16_t temp_signal_array[kVecLen + kMaxLpcOrder] = {0};
int16_t* temp_signal = &temp_signal_array[kMaxLpcOrder];
memcpy(temp_signal,
&input[channel_ix][input.Size() - kVecLen],
sizeof(int16_t) * kVecLen);
input[channel_ix].CopyTo(kVecLen, input.Size() - kVecLen, temp_signal);
int32_t sample_energy = CalculateAutoCorrelation(temp_signal, kVecLen,
auto_correlation);

View File

@ -67,10 +67,10 @@ int ComfortNoise::Generate(size_t requested_length,
LOG(LS_ERROR) << "Unknwown payload type";
return kUnknownPayloadType;
}
// The expression &(*output)[0][0] is a pointer to the first element in
// the first channel.
std::unique_ptr<int16_t[]> temp(new int16_t[number_of_samples]);
if (!cng_decoder->Generate(
rtc::ArrayView<int16_t>(&(*output)[0][0], number_of_samples),
rtc::ArrayView<int16_t>(temp.get(), number_of_samples),
new_period)) {
// Error returned.
output->Zeros(requested_length);
@ -78,6 +78,7 @@ int ComfortNoise::Generate(size_t requested_length,
"ComfortNoiseDecoder::Genererate failed to generate comfort noise";
return kInternalError;
}
(*output)[0].OverwriteAt(temp.get(), number_of_samples, 0);
if (first_call_) {
// Set tapering window parameters. Values are in Q15.

View File

@ -80,6 +80,22 @@ int DspHelper::RampSignal(int16_t* signal,
return RampSignal(signal, length, factor, increment, signal);
}
int DspHelper::RampSignal(AudioVector* signal,
size_t start_index,
size_t length,
int factor,
int increment) {
int factor_q20 = (factor << 6) + 32;
// TODO(hlundin): Add 32 to factor_q20 when converting back to Q14?
for (size_t i = start_index; i < start_index + length; ++i) {
(*signal)[i] = (factor * (*signal)[i] + 8192) >> 14;
factor_q20 += increment;
factor_q20 = std::max(factor_q20, 0); // Never go negative.
factor = std::min(factor_q20 >> 6, 16384);
}
return factor;
}
int DspHelper::RampSignal(AudioMultiVector* signal,
size_t start_index,
size_t length,
@ -94,7 +110,7 @@ int DspHelper::RampSignal(AudioMultiVector* signal,
// Loop over the channels, starting at the same |factor| each time.
for (size_t channel = 0; channel < signal->Channels(); ++channel) {
end_factor =
RampSignal(&(*signal)[channel][start_index], length, factor, increment);
RampSignal(&(*signal)[channel], start_index, length, factor, increment);
}
return end_factor;
}

View File

@ -67,6 +67,13 @@ class DspHelper {
// Same as above, but processes |length| samples from |signal|, starting at
// |start_index|.
static int RampSignal(AudioVector* signal,
size_t start_index,
size_t length,
int factor,
int increment);
// Same as above, but for an AudioMultiVector.
static int RampSignal(AudioMultiVector* signal,
size_t start_index,
size_t length,

View File

@ -112,25 +112,33 @@ int Expand::Process(AudioMultiVector* output) {
// Use only expand_vector0.
assert(expansion_vector_position + temp_length <=
parameters.expand_vector0.Size());
memcpy(voiced_vector_storage,
&parameters.expand_vector0[expansion_vector_position],
sizeof(int16_t) * temp_length);
parameters.expand_vector0.CopyTo(temp_length, expansion_vector_position,
voiced_vector_storage);
} else if (current_lag_index_ == 1) {
std::unique_ptr<int16_t[]> temp_0(new int16_t[temp_length]);
parameters.expand_vector0.CopyTo(temp_length, expansion_vector_position,
temp_0.get());
std::unique_ptr<int16_t[]> temp_1(new int16_t[temp_length]);
parameters.expand_vector1.CopyTo(temp_length, expansion_vector_position,
temp_1.get());
// Mix 3/4 of expand_vector0 with 1/4 of expand_vector1.
WebRtcSpl_ScaleAndAddVectorsWithRound(
&parameters.expand_vector0[expansion_vector_position], 3,
&parameters.expand_vector1[expansion_vector_position], 1, 2,
voiced_vector_storage, temp_length);
WebRtcSpl_ScaleAndAddVectorsWithRound(temp_0.get(), 3, temp_1.get(), 1, 2,
voiced_vector_storage, temp_length);
} else if (current_lag_index_ == 2) {
// Mix 1/2 of expand_vector0 with 1/2 of expand_vector1.
assert(expansion_vector_position + temp_length <=
parameters.expand_vector0.Size());
assert(expansion_vector_position + temp_length <=
parameters.expand_vector1.Size());
WebRtcSpl_ScaleAndAddVectorsWithRound(
&parameters.expand_vector0[expansion_vector_position], 1,
&parameters.expand_vector1[expansion_vector_position], 1, 1,
voiced_vector_storage, temp_length);
std::unique_ptr<int16_t[]> temp_0(new int16_t[temp_length]);
parameters.expand_vector0.CopyTo(temp_length, expansion_vector_position,
temp_0.get());
std::unique_ptr<int16_t[]> temp_1(new int16_t[temp_length]);
parameters.expand_vector1.CopyTo(temp_length, expansion_vector_position,
temp_1.get());
WebRtcSpl_ScaleAndAddVectorsWithRound(temp_0.get(), 1, temp_1.get(), 1, 1,
voiced_vector_storage, temp_length);
}
// Get tapering window parameters. Values are in Q15.
@ -299,8 +307,7 @@ int Expand::Process(AudioMultiVector* output) {
} else {
assert(output->Size() == current_lag);
}
memcpy(&(*output)[channel_ix][0], temp_data,
sizeof(temp_data[0]) * current_lag);
(*output)[channel_ix].OverwriteAt(temp_data, current_lag, 0);
}
// Increase call number and cap it.
@ -384,8 +391,11 @@ void Expand::AnalyzeSignal(int16_t* random_vector) {
size_t fs_mult_lpc_analysis_len = fs_mult * kLpcAnalysisLength;
const size_t signal_length = static_cast<size_t>(256 * fs_mult);
const int16_t* audio_history =
&(*sync_buffer_)[0][sync_buffer_->Size() - signal_length];
const size_t audio_history_position = sync_buffer_->Size() - signal_length;
std::unique_ptr<int16_t[]> audio_history(new int16_t[signal_length]);
(*sync_buffer_)[0].CopyTo(signal_length, audio_history_position,
audio_history.get());
// Initialize.
InitializeForAnExpandPeriod();
@ -394,7 +404,7 @@ void Expand::AnalyzeSignal(int16_t* random_vector) {
size_t correlation_length = 51; // TODO(hlundin): Legacy bit-exactness.
// If it is decided to break bit-exactness |correlation_length| should be
// initialized to the return value of Correlation().
Correlation(audio_history, signal_length, correlation_vector);
Correlation(audio_history.get(), signal_length, correlation_vector);
// Find peaks in correlation vector.
DspHelper::PeakDetection(correlation_vector, correlation_length,
@ -551,12 +561,14 @@ void Expand::AnalyzeSignal(int16_t* random_vector) {
parameters.expand_vector1.Extend(
expansion_length - parameters.expand_vector1.Size());
}
WebRtcSpl_AffineTransformVector(&parameters.expand_vector1[0],
std::unique_ptr<int16_t[]> temp_1(new int16_t[expansion_length]);
WebRtcSpl_AffineTransformVector(temp_1.get(),
const_cast<int16_t*>(vector2),
amplitude_ratio,
4096,
13,
expansion_length);
parameters.expand_vector1.OverwriteAt(temp_1.get(), expansion_length, 0);
} else {
// Energy change constraint not fulfilled. Only use last vector.
parameters.expand_vector0.Clear();

View File

@ -93,8 +93,9 @@ class ExpandTest : public ::testing::Test {
ASSERT_TRUE(input_file_.Seek(speech_start_samples));
// Pre-load the sync buffer with speech data.
ASSERT_TRUE(
input_file_.Read(sync_buffer_.Size(), &sync_buffer_.Channel(0)[0]));
std::unique_ptr<int16_t[]> temp(new int16_t[sync_buffer_.Size()]);
ASSERT_TRUE(input_file_.Read(sync_buffer_.Size(), temp.get()));
sync_buffer_.Channel(0).OverwriteAt(temp.get(), sync_buffer_.Size(), 0);
ASSERT_EQ(1u, num_channels_) << "Fix: Must populate all channels.";
}

View File

@ -63,11 +63,16 @@ size_t Merge::Process(int16_t* input, size_t input_length,
size_t best_correlation_index = 0;
size_t output_length = 0;
std::unique_ptr<int16_t[]> input_channel(
new int16_t[input_length_per_channel]);
std::unique_ptr<int16_t[]> expanded_channel(new int16_t[expanded_length]);
for (size_t channel = 0; channel < num_channels_; ++channel) {
int16_t* input_channel = &input_vector[channel][0];
int16_t* expanded_channel = &expanded_[channel][0];
input_vector[channel].CopyTo(
input_length_per_channel, 0, input_channel.get());
expanded_[channel].CopyTo(expanded_length, 0, expanded_channel.get());
int16_t new_mute_factor = SignalScaling(
input_channel, input_length_per_channel, expanded_channel);
input_channel.get(), input_length_per_channel, expanded_channel.get());
// Adjust muting factor (product of "main" muting factor and expand muting
// factor).
@ -85,8 +90,8 @@ size_t Merge::Process(int16_t* input, size_t input_length,
// Downsample, correlate, and find strongest correlation period for the
// master (i.e., first) channel only.
// Downsample to 4kHz sample rate.
Downsample(input_channel, input_length_per_channel, expanded_channel,
expanded_length);
Downsample(input_channel.get(), input_length_per_channel,
expanded_channel.get(), expanded_length);
// Calculate the lag of the strongest correlation period.
best_correlation_index = CorrelateAndPeakSearch(
@ -108,7 +113,7 @@ size_t Merge::Process(int16_t* input, size_t input_length,
// and so on.
int increment = 4194 / fs_mult_;
*external_mute_factor =
static_cast<int16_t>(DspHelper::RampSignal(input_channel,
static_cast<int16_t>(DspHelper::RampSignal(input_channel.get(),
interpolation_length,
*external_mute_factor,
increment));
@ -128,10 +133,10 @@ size_t Merge::Process(int16_t* input, size_t input_length,
int16_t increment =
static_cast<int16_t>(16384 / (interpolation_length + 1)); // In Q14.
int16_t mute_factor = 16384 - increment;
memmove(temp_data_.data(), expanded_channel,
memmove(temp_data_.data(), expanded_channel.get(),
sizeof(int16_t) * best_correlation_index);
DspHelper::CrossFade(&expanded_channel[best_correlation_index],
input_channel, interpolation_length,
input_channel.get(), interpolation_length,
&mute_factor, increment, decoded_output);
output_length = best_correlation_index + input_length_per_channel;
@ -141,8 +146,7 @@ size_t Merge::Process(int16_t* input, size_t input_length,
} else {
assert(output->Size() == output_length);
}
memcpy(&(*output)[channel][0], temp_data_.data(),
sizeof(temp_data_[0]) * output_length);
(*output)[channel].OverwriteAt(temp_data_.data(), output_length, 0);
}
// Copy back the first part of the data to |sync_buffer_| and remove it from

View File

@ -42,7 +42,6 @@ int Normal::Process(const int16_t* input,
return 0;
}
output->PushBackInterleaved(input, length);
int16_t* signal = &(*output)[0][0];
const int fs_mult = fs_hz_ / 8000;
assert(fs_mult > 0);
@ -63,24 +62,26 @@ int Normal::Process(const int16_t* input,
expand_->Process(&expanded);
expand_->Reset();
size_t length_per_channel = length / output->Channels();
std::unique_ptr<int16_t[]> signal(new int16_t[length_per_channel]);
for (size_t channel_ix = 0; channel_ix < output->Channels(); ++channel_ix) {
// Adjust muting factor (main muting factor times expand muting factor).
external_mute_factor_array[channel_ix] = static_cast<int16_t>(
(external_mute_factor_array[channel_ix] *
expand_->MuteFactor(channel_ix)) >> 14);
int16_t* signal = &(*output)[channel_ix][0];
size_t length_per_channel = length / output->Channels();
(*output)[channel_ix].CopyTo(length_per_channel, 0, signal.get());
// Find largest absolute value in new data.
int16_t decoded_max =
WebRtcSpl_MaxAbsValueW16(signal, length_per_channel);
WebRtcSpl_MaxAbsValueW16(signal.get(), length_per_channel);
// Adjust muting factor if needed (to BGN level).
size_t energy_length =
std::min(static_cast<size_t>(fs_mult * 64), length_per_channel);
int scaling = 6 + fs_shift
- WebRtcSpl_NormW32(decoded_max * decoded_max);
scaling = std::max(scaling, 0); // |scaling| should always be >= 0.
int32_t energy = WebRtcSpl_DotProductWithScale(signal, signal,
int32_t energy = WebRtcSpl_DotProductWithScale(signal.get(), signal.get(),
energy_length, scaling);
int32_t scaled_energy_length =
static_cast<int32_t>(energy_length >> scaling);
@ -159,7 +160,7 @@ int Normal::Process(const int16_t* input,
} else {
// If no CNG instance is defined, just copy from the decoded data.
// (This will result in interpolating the decoded with itself.)
memcpy(cng_output, signal, fs_mult * 8 * sizeof(int16_t));
(*output)[0].CopyTo(fs_mult * 8, 0, cng_output);
}
// Interpolate the CNG into the new vector.
// (NB/WB/SWB32/SWB48 8/16/32/48 samples.)
@ -169,8 +170,8 @@ int Normal::Process(const int16_t* input,
for (size_t i = 0; i < static_cast<size_t>(8 * fs_mult); i++) {
// TODO(hlundin): Add 16 instead of 8 for correct rounding. Keeping 8 now
// for legacy bit-exactness.
signal[i] =
(fraction * signal[i] + (32 - fraction) * cng_output[i] + 8) >> 5;
(*output)[0][i] = (fraction * (*output)[0][i] +
(32 - fraction) * cng_output[i] + 8) >> 5;
fraction += increment;
}
} else if (external_mute_factor_array[0] < 16384) {