19a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org/*
29a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
39a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *
49a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  Use of this source code is governed by a BSD-style license
59a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  that can be found in the LICENSE file in the root of the source
69a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  tree. An additional intellectual property rights grant can be found
79a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  in the file PATENTS.  All contributing project authors may
89a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
99a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org */
109a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
11e5abc854f3dc47de16067c2a41476c39b7626722henrik.lundin@webrtc.org#include "webrtc/modules/audio_coding/neteq/expand.h"
129a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
139a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org#include <assert.h>
143f45c2e0ac4cb280f941efa3a3476895795e3dd6pbos@webrtc.org#include <string.h>  // memset
159a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
169a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org#include <algorithm>  // min, max
1760bf21e85cdf9a8dd18376d934bde5e785ebba87turaj@webrtc.org#include <limits>  // numeric_limits<T>
189a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
199a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
20e5abc854f3dc47de16067c2a41476c39b7626722henrik.lundin@webrtc.org#include "webrtc/modules/audio_coding/neteq/background_noise.h"
21e5abc854f3dc47de16067c2a41476c39b7626722henrik.lundin@webrtc.org#include "webrtc/modules/audio_coding/neteq/dsp_helper.h"
22e5abc854f3dc47de16067c2a41476c39b7626722henrik.lundin@webrtc.org#include "webrtc/modules/audio_coding/neteq/random_vector.h"
23e5abc854f3dc47de16067c2a41476c39b7626722henrik.lundin@webrtc.org#include "webrtc/modules/audio_coding/neteq/sync_buffer.h"
249a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
259a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgnamespace webrtc {
269a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
279a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid Expand::Reset() {
289a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  first_expand_ = true;
299a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  consecutive_expands_ = 0;
309a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  max_lag_ = 0;
319a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  for (size_t ix = 0; ix < num_channels_; ++ix) {
329a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    channel_parameters_[ix].expand_vector0.Clear();
339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    channel_parameters_[ix].expand_vector1.Clear();
349a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
359a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
369a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
370e9c399746f45ceaf46f12b11ba93c09cca0c2bbhenrik.lundin@webrtc.orgint Expand::Process(AudioMultiVector* output) {
389a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t random_vector[kMaxSampleRate / 8000 * 120 + 30];
399a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t scaled_random_vector[kMaxSampleRate / 8000 * 125];
409a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  static const int kTempDataSize = 3600;
419a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t temp_data[kTempDataSize];  // TODO(hlundin) Remove this.
429a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t* voiced_vector_storage = temp_data;
439a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t* voiced_vector = &voiced_vector_storage[overlap_length_];
449a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  static const int kNoiseLpcOrder = BackgroundNoise::kMaxLpcOrder;
459a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t unvoiced_array_memory[kNoiseLpcOrder + kMaxSampleRate / 8000 * 125];
469a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t* unvoiced_vector = unvoiced_array_memory + kUnvoicedLpcOrder;
479a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t* noise_vector = unvoiced_array_memory + kNoiseLpcOrder;
489a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
499a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int fs_mult = fs_hz_ / 8000;
509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
519a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (first_expand_) {
529a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Perform initial setup if this is the first expansion since last reset.
539a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    AnalyzeSignal(random_vector);
549a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    first_expand_ = false;
559a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  } else {
569a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // This is not the first expansion, parameters are already estimated.
579a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Extract a noise segment.
589a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int16_t rand_length = max_lag_;
59c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    // This only applies to SWB where length could be larger than 256.
60c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    assert(rand_length <= kMaxSampleRate / 8000 * 120 + 30);
61c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    GenerateRandomVector(2, rand_length, random_vector);
629a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
639a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
649a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
659a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Generate signal.
669a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  UpdateLagIndex();
679a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
689a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Voiced part.
699a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Generate a weighted vector with the current lag.
709a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  size_t expansion_vector_length = max_lag_ + overlap_length_;
719a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  size_t current_lag = expand_lags_[current_lag_index_];
729a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Copy lag+overlap data.
739a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  size_t expansion_vector_position = expansion_vector_length - current_lag -
749a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      overlap_length_;
759a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  size_t temp_length = current_lag + overlap_length_;
769a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  for (size_t channel_ix = 0; channel_ix < num_channels_; ++channel_ix) {
779a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    ChannelParameters& parameters = channel_parameters_[channel_ix];
789a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if (current_lag_index_ == 0) {
799a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Use only expand_vector0.
809a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      assert(expansion_vector_position + temp_length <=
819a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org             parameters.expand_vector0.Size());
829a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      memcpy(voiced_vector_storage,
839a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org             &parameters.expand_vector0[expansion_vector_position],
849a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org             sizeof(int16_t) * temp_length);
859a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    } else if (current_lag_index_ == 1) {
869a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Mix 3/4 of expand_vector0 with 1/4 of expand_vector1.
879a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      WebRtcSpl_ScaleAndAddVectorsWithRound(
889a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org          &parameters.expand_vector0[expansion_vector_position], 3,
899a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org          &parameters.expand_vector1[expansion_vector_position], 1, 2,
90045e45efeca8776975254550137ec65268aadb54turaj@webrtc.org          voiced_vector_storage, static_cast<int>(temp_length));
919a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    } else if (current_lag_index_ == 2) {
929a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Mix 1/2 of expand_vector0 with 1/2 of expand_vector1.
939a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      assert(expansion_vector_position + temp_length <=
949a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org             parameters.expand_vector0.Size());
959a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      assert(expansion_vector_position + temp_length <=
969a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org             parameters.expand_vector1.Size());
979a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      WebRtcSpl_ScaleAndAddVectorsWithRound(
989a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org          &parameters.expand_vector0[expansion_vector_position], 1,
999a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org          &parameters.expand_vector1[expansion_vector_position], 1, 1,
100045e45efeca8776975254550137ec65268aadb54turaj@webrtc.org          voiced_vector_storage, static_cast<int>(temp_length));
1019a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
1029a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1039a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Get tapering window parameters. Values are in Q15.
1049a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int16_t muting_window, muting_window_increment;
1059a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int16_t unmuting_window, unmuting_window_increment;
1069a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if (fs_hz_ == 8000) {
1079a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      muting_window = DspHelper::kMuteFactorStart8kHz;
1089a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      muting_window_increment = DspHelper::kMuteFactorIncrement8kHz;
1099a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      unmuting_window = DspHelper::kUnmuteFactorStart8kHz;
1109a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      unmuting_window_increment = DspHelper::kUnmuteFactorIncrement8kHz;
1119a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    } else if (fs_hz_ == 16000) {
1129a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      muting_window = DspHelper::kMuteFactorStart16kHz;
1139a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      muting_window_increment = DspHelper::kMuteFactorIncrement16kHz;
1149a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      unmuting_window = DspHelper::kUnmuteFactorStart16kHz;
1159a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      unmuting_window_increment = DspHelper::kUnmuteFactorIncrement16kHz;
1169a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    } else if (fs_hz_ == 32000) {
1179a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      muting_window = DspHelper::kMuteFactorStart32kHz;
1189a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      muting_window_increment = DspHelper::kMuteFactorIncrement32kHz;
1199a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      unmuting_window = DspHelper::kUnmuteFactorStart32kHz;
1209a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      unmuting_window_increment = DspHelper::kUnmuteFactorIncrement32kHz;
1219a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    } else {  // fs_ == 48000
1229a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      muting_window = DspHelper::kMuteFactorStart48kHz;
1239a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      muting_window_increment = DspHelper::kMuteFactorIncrement48kHz;
1249a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      unmuting_window = DspHelper::kUnmuteFactorStart48kHz;
1259a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      unmuting_window_increment = DspHelper::kUnmuteFactorIncrement48kHz;
1269a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
1279a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1289a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Smooth the expanded if it has not been muted to a low amplitude and
1299a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // |current_voice_mix_factor| is larger than 0.5.
1309a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if ((parameters.mute_factor > 819) &&
1319a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        (parameters.current_voice_mix_factor > 8192)) {
1329a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      size_t start_ix = sync_buffer_->Size() - overlap_length_;
1339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      for (size_t i = 0; i < overlap_length_; i++) {
1349a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // Do overlap add between new vector and overlap.
1359a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        (*sync_buffer_)[channel_ix][start_ix + i] =
1369a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org            (((*sync_buffer_)[channel_ix][start_ix + i] * muting_window) +
1379a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                (((parameters.mute_factor * voiced_vector_storage[i]) >> 14) *
1389a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                    unmuting_window) + 16384) >> 15;
1399a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        muting_window += muting_window_increment;
1409a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        unmuting_window += unmuting_window_increment;
1419a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      }
1429a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    } else if (parameters.mute_factor == 0) {
1439a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // The expanded signal will consist of only comfort noise if
1449a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // mute_factor = 0. Set the output length to 15 ms for best noise
1459a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // production.
1469a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // TODO(hlundin): This has been disabled since the length of
1479a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // parameters.expand_vector0 and parameters.expand_vector1 no longer
1489a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // match with expand_lags_, causing invalid reads and writes. Is it a good
1499a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // idea to enable this again, and solve the vector size problem?
1509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org//      max_lag_ = fs_mult * 120;
1519a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org//      expand_lags_[0] = fs_mult * 120;
1529a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org//      expand_lags_[1] = fs_mult * 120;
1539a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org//      expand_lags_[2] = fs_mult * 120;
1549a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
1559a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1569a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Unvoiced part.
1579a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Filter |scaled_random_vector| through |ar_filter_|.
1589a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    memcpy(unvoiced_vector - kUnvoicedLpcOrder, parameters.ar_filter_state,
1599a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org           sizeof(int16_t) * kUnvoicedLpcOrder);
1609a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int32_t add_constant = 0;
1619a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if (parameters.ar_gain_scale > 0) {
1629a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      add_constant = 1 << (parameters.ar_gain_scale - 1);
1639a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
1649a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    WebRtcSpl_AffineTransformVector(scaled_random_vector, random_vector,
1659a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                    parameters.ar_gain, add_constant,
166045e45efeca8776975254550137ec65268aadb54turaj@webrtc.org                                    parameters.ar_gain_scale,
167045e45efeca8776975254550137ec65268aadb54turaj@webrtc.org                                    static_cast<int>(current_lag));
1689a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    WebRtcSpl_FilterARFastQ12(scaled_random_vector, unvoiced_vector,
169045e45efeca8776975254550137ec65268aadb54turaj@webrtc.org                              parameters.ar_filter, kUnvoicedLpcOrder + 1,
170045e45efeca8776975254550137ec65268aadb54turaj@webrtc.org                              static_cast<int>(current_lag));
1719a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    memcpy(parameters.ar_filter_state,
1729a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org           &(unvoiced_vector[current_lag - kUnvoicedLpcOrder]),
1739a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org           sizeof(int16_t) * kUnvoicedLpcOrder);
1749a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1759a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Combine voiced and unvoiced contributions.
1769a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1779a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Set a suitable cross-fading slope.
1789a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // For lag =
1799a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    //   <= 31 * fs_mult            => go from 1 to 0 in about 8 ms;
1809a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    //  (>= 31 .. <= 63) * fs_mult  => go from 1 to 0 in about 16 ms;
1819a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    //   >= 64 * fs_mult            => go from 1 to 0 in about 32 ms.
1829a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // temp_shift = getbits(max_lag_) - 5.
1839a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int temp_shift = (31 - WebRtcSpl_NormW32(max_lag_)) - 5;
1849a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int16_t mix_factor_increment = 256 >> temp_shift;
1859a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if (stop_muting_) {
1869a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      mix_factor_increment = 0;
1879a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
1889a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1899a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Create combined signal by shifting in more and more of unvoiced part.
1909a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    temp_shift = 8 - temp_shift;  // = getbits(mix_factor_increment).
1919a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    size_t temp_lenght = (parameters.current_voice_mix_factor -
1929a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        parameters.voice_mix_factor) >> temp_shift;
1939a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    temp_lenght = std::min(temp_lenght, current_lag);
1949a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    DspHelper::CrossFade(voiced_vector, unvoiced_vector, temp_lenght,
1959a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                         &parameters.current_voice_mix_factor,
1969a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                         mix_factor_increment, temp_data);
1979a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1989a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // End of cross-fading period was reached before end of expanded signal
1999a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // path. Mix the rest with a fixed mixing factor.
2009a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if (temp_lenght < current_lag) {
2019a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      if (mix_factor_increment != 0) {
2029a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        parameters.current_voice_mix_factor = parameters.voice_mix_factor;
2039a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      }
2049a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      int temp_scale = 16384 - parameters.current_voice_mix_factor;
2059a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      WebRtcSpl_ScaleAndAddVectorsWithRound(
2069a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org          voiced_vector + temp_lenght, parameters.current_voice_mix_factor,
2079a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org          unvoiced_vector + temp_lenght, temp_scale, 14,
208045e45efeca8776975254550137ec65268aadb54turaj@webrtc.org          temp_data + temp_lenght, static_cast<int>(current_lag - temp_lenght));
2099a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
2109a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
2119a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Select muting slope depending on how many consecutive expands we have
2129a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // done.
2139a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if (consecutive_expands_ == 3) {
2149a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Let the mute factor decrease from 1.0 to 0.95 in 6.25 ms.
2159a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // mute_slope = 0.0010 / fs_mult in Q20.
2169a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      parameters.mute_slope = std::max(parameters.mute_slope,
2179a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                       static_cast<int16_t>(1049 / fs_mult));
2189a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
2199a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if (consecutive_expands_ == 7) {
2209a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Let the mute factor decrease from 1.0 to 0.90 in 6.25 ms.
2219a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // mute_slope = 0.0020 / fs_mult in Q20.
2229a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      parameters.mute_slope = std::max(parameters.mute_slope,
2239a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                       static_cast<int16_t>(2097 / fs_mult));
2249a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
2259a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
2269a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Mute segment according to slope value.
2279a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if ((consecutive_expands_ != 0) || !parameters.onset) {
2289a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Mute to the previous level, then continue with the muting.
2299a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      WebRtcSpl_AffineTransformVector(temp_data, temp_data,
2309a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                      parameters.mute_factor, 8192,
231045e45efeca8776975254550137ec65268aadb54turaj@webrtc.org                                      14, static_cast<int>(current_lag));
2329a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
2339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      if (!stop_muting_) {
2349a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        DspHelper::MuteSignal(temp_data, parameters.mute_slope, current_lag);
2359a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
2369a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // Shift by 6 to go from Q20 to Q14.
2379a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // TODO(hlundin): Adding 8192 before shifting 6 steps seems wrong.
2389a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // Legacy.
239045e45efeca8776975254550137ec65268aadb54turaj@webrtc.org        int16_t gain = static_cast<int16_t>(16384 -
240045e45efeca8776975254550137ec65268aadb54turaj@webrtc.org            (((current_lag * parameters.mute_slope) + 8192) >> 6));
2419a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        gain = ((gain * parameters.mute_factor) + 8192) >> 14;
2429a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
2439a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // Guard against getting stuck with very small (but sometimes audible)
2449a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // gain.
2459a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        if ((consecutive_expands_ > 3) && (gain >= parameters.mute_factor)) {
2469a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org          parameters.mute_factor = 0;
2479a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        } else {
2489a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org          parameters.mute_factor = gain;
2499a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        }
2509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      }
2519a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
2529a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
2539a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Background noise part.
254c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    GenerateBackgroundNoise(random_vector,
255c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                            channel_ix,
256c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                            channel_parameters_[channel_ix].mute_slope,
257c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                            TooManyExpands(),
258c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                            current_lag,
259c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                            unvoiced_array_memory);
2609a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
2619a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Add background noise to the combined voiced-unvoiced signal.
2629a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    for (size_t i = 0; i < current_lag; i++) {
2639a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      temp_data[i] = temp_data[i] + noise_vector[i];
2649a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
2659a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if (channel_ix == 0) {
2669a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      output->AssertSize(current_lag);
2679a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    } else {
2689a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      assert(output->Size() == current_lag);
2699a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
2709a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    memcpy(&(*output)[channel_ix][0], temp_data,
2719a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org           sizeof(temp_data[0]) * current_lag);
2729a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
2739a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
2749a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Increase call number and cap it.
275c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  consecutive_expands_ = consecutive_expands_ >= kMaxConsecutiveExpands ?
276c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org      kMaxConsecutiveExpands : consecutive_expands_ + 1;
2779a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  return 0;
2789a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
2799a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
2809a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid Expand::SetParametersForNormalAfterExpand() {
2819a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  current_lag_index_ = 0;
2829a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  lag_index_direction_ = 0;
2839a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  stop_muting_ = true;  // Do not mute signal any more.
2849a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
2859a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
2869a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid Expand::SetParametersForMergeAfterExpand() {
2879a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  current_lag_index_ = -1; /* out of the 3 possible ones */
2889a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  lag_index_direction_ = 1; /* make sure we get the "optimal" lag */
2899a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  stop_muting_ = true;
2909a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
2919a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
292c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.orgvoid Expand::InitializeForAnExpandPeriod() {
293c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  lag_index_direction_ = 1;
294c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  current_lag_index_ = -1;
295c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  stop_muting_ = false;
296c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  random_vector_->set_seed_increment(1);
297c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  consecutive_expands_ = 0;
298c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  for (size_t ix = 0; ix < num_channels_; ++ix) {
299c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    channel_parameters_[ix].current_voice_mix_factor = 16384;  // 1.0 in Q14.
300c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    channel_parameters_[ix].mute_factor = 16384;  // 1.0 in Q14.
301c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    // Start with 0 gain for background noise.
302c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    background_noise_->SetMuteFactor(ix, 0);
303c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  }
304c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org}
305c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org
306c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.orgbool Expand::TooManyExpands() {
307c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  return consecutive_expands_ >= kMaxConsecutiveExpands;
308c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org}
309c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org
3109a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid Expand::AnalyzeSignal(int16_t* random_vector) {
3119a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int32_t auto_correlation[kUnvoicedLpcOrder + 1];
3129a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t reflection_coeff[kUnvoicedLpcOrder];
3139a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t correlation_vector[kMaxSampleRate / 8000 * 102];
3149a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int best_correlation_index[kNumCorrelationCandidates];
3159a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t best_correlation[kNumCorrelationCandidates];
3169a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t best_distortion_index[kNumCorrelationCandidates];
3179a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t best_distortion[kNumCorrelationCandidates];
3189a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int32_t correlation_vector2[(99 * kMaxSampleRate / 8000) + 1];
3199a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int32_t best_distortion_w32[kNumCorrelationCandidates];
3209a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  static const int kNoiseLpcOrder = BackgroundNoise::kMaxLpcOrder;
3219a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t unvoiced_array_memory[kNoiseLpcOrder + kMaxSampleRate / 8000 * 125];
3229a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t* unvoiced_vector = unvoiced_array_memory + kUnvoicedLpcOrder;
3239a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
3249a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int fs_mult = fs_hz_ / 8000;
3259a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
3269a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Pre-calculate common multiplications with fs_mult.
3279a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int fs_mult_4 = fs_mult * 4;
3289a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int fs_mult_20 = fs_mult * 20;
3299a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int fs_mult_120 = fs_mult * 120;
3309a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int fs_mult_dist_len = fs_mult * kDistortionLength;
3319a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int fs_mult_lpc_analysis_len = fs_mult * kLpcAnalysisLength;
3329a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
3339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  const size_t signal_length = 256 * fs_mult;
3349a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  const int16_t* audio_history =
3359a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      &(*sync_buffer_)[0][sync_buffer_->Size() - signal_length];
3369a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
337c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  // Initialize.
338c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  InitializeForAnExpandPeriod();
3399a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
3409a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Calculate correlation in downsampled domain (4 kHz sample rate).
3419a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t correlation_scale;
342a9a788e12008fdf4ab9923ddcd7a1dbecf17b8e0turaj@webrtc.org  int correlation_length = 51;  // TODO(hlundin): Legacy bit-exactness.
343a9a788e12008fdf4ab9923ddcd7a1dbecf17b8e0turaj@webrtc.org  // If it is decided to break bit-exactness |correlation_length| should be
344a9a788e12008fdf4ab9923ddcd7a1dbecf17b8e0turaj@webrtc.org  // initialized to the return value of Correlation().
345a9a788e12008fdf4ab9923ddcd7a1dbecf17b8e0turaj@webrtc.org  Correlation(audio_history, signal_length, correlation_vector,
346a9a788e12008fdf4ab9923ddcd7a1dbecf17b8e0turaj@webrtc.org              &correlation_scale);
3479a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
3489a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Find peaks in correlation vector.
3499a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  DspHelper::PeakDetection(correlation_vector, correlation_length,
3509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                           kNumCorrelationCandidates, fs_mult,
3519a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                           best_correlation_index, best_correlation);
3529a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
3539a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Adjust peak locations; cross-correlation lags start at 2.5 ms
3549a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // (20 * fs_mult samples).
3559a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  best_correlation_index[0] += fs_mult_20;
3569a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  best_correlation_index[1] += fs_mult_20;
3579a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  best_correlation_index[2] += fs_mult_20;
3589a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
3599a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Calculate distortion around the |kNumCorrelationCandidates| best lags.
3609a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int distortion_scale = 0;
3619a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  for (int i = 0; i < kNumCorrelationCandidates; i++) {
3629a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int16_t min_index = std::max(fs_mult_20,
3639a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                 best_correlation_index[i] - fs_mult_4);
3649a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int16_t max_index = std::min(fs_mult_120 - 1,
3659a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                 best_correlation_index[i] + fs_mult_4);
3669a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    best_distortion_index[i] = DspHelper::MinDistortion(
3679a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        &(audio_history[signal_length - fs_mult_dist_len]), min_index,
3689a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        max_index, fs_mult_dist_len, &best_distortion_w32[i]);
3699a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    distortion_scale = std::max(16 - WebRtcSpl_NormW32(best_distortion_w32[i]),
3709a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                distortion_scale);
3719a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
3729a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Shift the distortion values to fit in 16 bits.
3739a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  WebRtcSpl_VectorBitShiftW32ToW16(best_distortion, kNumCorrelationCandidates,
3749a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                   best_distortion_w32, distortion_scale);
3759a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
3769a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Find the maximizing index |i| of the cost function
3779a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // f[i] = best_correlation[i] / best_distortion[i].
378a9a788e12008fdf4ab9923ddcd7a1dbecf17b8e0turaj@webrtc.org  int32_t best_ratio = std::numeric_limits<int32_t>::min();
3799a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int best_index = -1;
3809a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  for (int i = 0; i < kNumCorrelationCandidates; ++i) {
3819a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int32_t ratio;
3829a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if (best_distortion[i] > 0) {
3839a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      ratio = (best_correlation[i] << 16) / best_distortion[i];
38460bf21e85cdf9a8dd18376d934bde5e785ebba87turaj@webrtc.org    } else if (best_correlation[i] == 0) {
38560bf21e85cdf9a8dd18376d934bde5e785ebba87turaj@webrtc.org      ratio = 0;  // No correlation set result to zero.
3869a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    } else {
38760bf21e85cdf9a8dd18376d934bde5e785ebba87turaj@webrtc.org      ratio = std::numeric_limits<int32_t>::max();  // Denominator is zero.
3889a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
3899a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if (ratio > best_ratio) {
3909a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      best_index = i;
3919a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      best_ratio = ratio;
3929a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
3939a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
3949a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
3959a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int distortion_lag = best_distortion_index[best_index];
3969a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int correlation_lag = best_correlation_index[best_index];
3979a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  max_lag_ = std::max(distortion_lag, correlation_lag);
3989a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
3999a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Calculate the exact best correlation in the range between
4009a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // |correlation_lag| and |distortion_lag|.
4019a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  correlation_length = distortion_lag + 10;
4029a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  correlation_length = std::min(correlation_length, fs_mult_120);
4039a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  correlation_length = std::max(correlation_length, 60 * fs_mult);
4049a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
4059a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int start_index = std::min(distortion_lag, correlation_lag);
4069a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int correlation_lags = WEBRTC_SPL_ABS_W16((distortion_lag-correlation_lag))
4079a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      + 1;
4089a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  assert(correlation_lags <= 99 * fs_mult + 1);  // Cannot be larger.
4099a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
4109a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  for (size_t channel_ix = 0; channel_ix < num_channels_; ++channel_ix) {
4119a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    ChannelParameters& parameters = channel_parameters_[channel_ix];
4129a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Calculate suitable scaling.
4139a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int16_t signal_max = WebRtcSpl_MaxAbsValueW16(
4149a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        &audio_history[signal_length - correlation_length - start_index
4159a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                       - correlation_lags],
4169a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                       correlation_length + start_index + correlation_lags - 1);
4179a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    correlation_scale = ((31 - WebRtcSpl_NormW32(signal_max * signal_max))
4189a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        + (31 - WebRtcSpl_NormW32(correlation_length))) - 31;
4199a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    correlation_scale = std::max(static_cast<int16_t>(0), correlation_scale);
4209a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
4219a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Calculate the correlation, store in |correlation_vector2|.
4229a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    WebRtcSpl_CrossCorrelation(
4239a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        correlation_vector2,
4249a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        &(audio_history[signal_length - correlation_length]),
4259a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        &(audio_history[signal_length - correlation_length - start_index]),
4269a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        correlation_length, correlation_lags, correlation_scale, -1);
4279a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
4289a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Find maximizing index.
4299a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    best_index = WebRtcSpl_MaxIndexW32(correlation_vector2, correlation_lags);
4309a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int32_t max_correlation = correlation_vector2[best_index];
4319a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Compensate index with start offset.
4329a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    best_index = best_index + start_index;
4339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
4349a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Calculate energies.
4359a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int32_t energy1 = WebRtcSpl_DotProductWithScale(
4369a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        &(audio_history[signal_length - correlation_length]),
4379a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        &(audio_history[signal_length - correlation_length]),
4389a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        correlation_length, correlation_scale);
4399a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int32_t energy2 = WebRtcSpl_DotProductWithScale(
4409a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        &(audio_history[signal_length - correlation_length - best_index]),
4419a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        &(audio_history[signal_length - correlation_length - best_index]),
4429a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        correlation_length, correlation_scale);
4439a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
4449a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Calculate the correlation coefficient between the two portions of the
4459a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // signal.
4469a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int16_t corr_coefficient;
4479a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if ((energy1 > 0) && (energy2 > 0)) {
4489a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      int energy1_scale = std::max(16 - WebRtcSpl_NormW32(energy1), 0);
4499a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      int energy2_scale = std::max(16 - WebRtcSpl_NormW32(energy2), 0);
4509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Make sure total scaling is even (to simplify scale factor after sqrt).
4519a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      if ((energy1_scale + energy2_scale) & 1) {
4529a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // If sum is odd, add 1 to make it even.
4539a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        energy1_scale += 1;
4549a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      }
4559a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      int16_t scaled_energy1 = energy1 >> energy1_scale;
4569a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      int16_t scaled_energy2 = energy2 >> energy2_scale;
4579a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      int16_t sqrt_energy_product = WebRtcSpl_SqrtFloor(
4589a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org          scaled_energy1 * scaled_energy2);
4599a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Calculate max_correlation / sqrt(energy1 * energy2) in Q14.
4609a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      int cc_shift = 14 - (energy1_scale + energy2_scale) / 2;
4619a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      max_correlation = WEBRTC_SPL_SHIFT_W32(max_correlation, cc_shift);
4629a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      corr_coefficient = WebRtcSpl_DivW32W16(max_correlation,
4639a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                             sqrt_energy_product);
4649a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      corr_coefficient = std::min(static_cast<int16_t>(16384),
4659a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                  corr_coefficient);  // Cap at 1.0 in Q14.
4669a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    } else {
4679a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      corr_coefficient = 0;
4689a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
4699a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
4709a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Extract the two vectors expand_vector0 and expand_vector1 from
4719a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // |audio_history|.
472045e45efeca8776975254550137ec65268aadb54turaj@webrtc.org    int16_t expansion_length = static_cast<int16_t>(max_lag_ + overlap_length_);
4739a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    const int16_t* vector1 = &(audio_history[signal_length - expansion_length]);
4749a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    const int16_t* vector2 = vector1 - distortion_lag;
4759a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Normalize the second vector to the same energy as the first.
4769a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    energy1 = WebRtcSpl_DotProductWithScale(vector1, vector1, expansion_length,
4779a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                            correlation_scale);
4789a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    energy2 = WebRtcSpl_DotProductWithScale(vector2, vector2, expansion_length,
4799a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                            correlation_scale);
4809a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Confirm that amplitude ratio sqrt(energy1 / energy2) is within 0.5 - 2.0,
4819a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // i.e., energy1 / energy1 is within 0.25 - 4.
4829a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int16_t amplitude_ratio;
4839a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if ((energy1 / 4 < energy2) && (energy1 > energy2 / 4)) {
4849a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Energy constraint fulfilled. Use both vectors and scale them
4859a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // accordingly.
4869a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      int16_t scaled_energy2 = std::max(16 - WebRtcSpl_NormW32(energy2), 0);
4879a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      int16_t scaled_energy1 = scaled_energy2 - 13;
4889a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Calculate scaled_energy1 / scaled_energy2 in Q13.
4899a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      int32_t energy_ratio = WebRtcSpl_DivW32W16(
4909a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org          WEBRTC_SPL_SHIFT_W32(energy1, -scaled_energy1),
4919a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org          WEBRTC_SPL_RSHIFT_W32(energy2, scaled_energy2));
4929a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Calculate sqrt ratio in Q13 (sqrt of en1/en2 in Q26).
4939a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      amplitude_ratio = WebRtcSpl_SqrtFloor(energy_ratio << 13);
4949a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Copy the two vectors and give them the same energy.
4959a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      parameters.expand_vector0.Clear();
4969a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      parameters.expand_vector0.PushBack(vector1, expansion_length);
4979a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      parameters.expand_vector1.Clear();
4989a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      if (parameters.expand_vector1.Size() <
4999a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org          static_cast<size_t>(expansion_length)) {
5009a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        parameters.expand_vector1.Extend(
5019a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org            expansion_length - parameters.expand_vector1.Size());
5029a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      }
5039a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      WebRtcSpl_AffineTransformVector(&parameters.expand_vector1[0],
5049a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                      const_cast<int16_t*>(vector2),
5059a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                      amplitude_ratio,
5069a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                      4096,
5079a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                      13,
5089a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                      expansion_length);
5099a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    } else {
5109a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Energy change constraint not fulfilled. Only use last vector.
5119a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      parameters.expand_vector0.Clear();
5129a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      parameters.expand_vector0.PushBack(vector1, expansion_length);
5139a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Copy from expand_vector0 to expand_vector1.
5140e4084a5b020b0364983acde9d4d420db876995ahenrik.lundin@webrtc.org      parameters.expand_vector0.CopyTo(&parameters.expand_vector1);
5159a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Set the energy_ratio since it is used by muting slope.
5169a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      if ((energy1 / 4 < energy2) || (energy2 == 0)) {
5179a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        amplitude_ratio = 4096;  // 0.5 in Q13.
5189a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      } else {
5199a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        amplitude_ratio = 16384;  // 2.0 in Q13.
5209a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      }
5219a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
5229a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
5239a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Set the 3 lag values.
5249a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int lag_difference = distortion_lag - correlation_lag;
5259a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if (lag_difference == 0) {
5269a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // |distortion_lag| and |correlation_lag| are equal.
5279a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      expand_lags_[0] = distortion_lag;
5289a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      expand_lags_[1] = distortion_lag;
5299a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      expand_lags_[2] = distortion_lag;
5309a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    } else {
5319a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // |distortion_lag| and |correlation_lag| are not equal; use different
5329a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // combinations of the two.
5339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // First lag is |distortion_lag| only.
5349a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      expand_lags_[0] = distortion_lag;
5359a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Second lag is the average of the two.
5369a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      expand_lags_[1] = (distortion_lag + correlation_lag) / 2;
5379a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Third lag is the average again, but rounding towards |correlation_lag|.
5389a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      if (lag_difference > 0) {
5399a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        expand_lags_[2] = (distortion_lag + correlation_lag - 1) / 2;
5409a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      } else {
5419a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        expand_lags_[2] = (distortion_lag + correlation_lag + 1) / 2;
5429a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      }
5439a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
5449a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
5459a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Calculate the LPC and the gain of the filters.
5469a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Calculate scale value needed for auto-correlation.
5479a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    correlation_scale = WebRtcSpl_MaxAbsValueW16(
5489a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        &(audio_history[signal_length - fs_mult_lpc_analysis_len]),
5499a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        fs_mult_lpc_analysis_len);
5509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
5519a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    correlation_scale = std::min(16 - WebRtcSpl_NormW32(correlation_scale), 0);
5529a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    correlation_scale = std::max(correlation_scale * 2 + 7, 0);
5539a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
5549a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Calculate kUnvoicedLpcOrder + 1 lags of the auto-correlation function.
5559a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    size_t temp_index = signal_length - fs_mult_lpc_analysis_len -
5569a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        kUnvoicedLpcOrder;
5579a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Copy signal to temporary vector to be able to pad with leading zeros.
5589a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int16_t* temp_signal = new int16_t[fs_mult_lpc_analysis_len
5599a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                       + kUnvoicedLpcOrder];
5609a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    memset(temp_signal, 0,
5619a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org           sizeof(int16_t) * (fs_mult_lpc_analysis_len + kUnvoicedLpcOrder));
5629a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    memcpy(&temp_signal[kUnvoicedLpcOrder],
5639a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org           &audio_history[temp_index + kUnvoicedLpcOrder],
5649a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org           sizeof(int16_t) * fs_mult_lpc_analysis_len);
5659a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    WebRtcSpl_CrossCorrelation(auto_correlation,
5669a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                               &temp_signal[kUnvoicedLpcOrder],
5679a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                               &temp_signal[kUnvoicedLpcOrder],
5689a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                               fs_mult_lpc_analysis_len, kUnvoicedLpcOrder + 1,
5699a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                               correlation_scale, -1);
5709a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    delete [] temp_signal;
5719a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
5729a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Verify that variance is positive.
5739a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if (auto_correlation[0] > 0) {
5749a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Estimate AR filter parameters using Levinson-Durbin algorithm;
5759a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // kUnvoicedLpcOrder + 1 filter coefficients.
5769a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      int16_t stability = WebRtcSpl_LevinsonDurbin(auto_correlation,
5779a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                                   parameters.ar_filter,
5789a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                                   reflection_coeff,
5799a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                                   kUnvoicedLpcOrder);
5809a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
5819a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Keep filter parameters only if filter is stable.
5829a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      if (stability != 1) {
5839a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // Set first coefficient to 4096 (1.0 in Q12).
5849a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        parameters.ar_filter[0] = 4096;
5859a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // Set remaining |kUnvoicedLpcOrder| coefficients to zero.
5869a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        WebRtcSpl_MemSetW16(parameters.ar_filter + 1, 0, kUnvoicedLpcOrder);
5879a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      }
5889a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
5899a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
5909a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if (channel_ix == 0) {
5919a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Extract a noise segment.
5929a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      int16_t noise_length;
5939a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      if (distortion_lag < 40) {
5949a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        noise_length = 2 * distortion_lag + 30;
5959a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      } else {
5969a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        noise_length = distortion_lag + 30;
5979a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      }
5989a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      if (noise_length <= RandomVector::kRandomTableSize) {
5999a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        memcpy(random_vector, RandomVector::kRandomTable,
6009a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org               sizeof(int16_t) * noise_length);
6019a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      } else {
6029a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // Only applies to SWB where length could be larger than
6039a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // |kRandomTableSize|.
6049a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        memcpy(random_vector, RandomVector::kRandomTable,
6059a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org               sizeof(int16_t) * RandomVector::kRandomTableSize);
6069a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        assert(noise_length <= kMaxSampleRate / 8000 * 120 + 30);
6079a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        random_vector_->IncreaseSeedIncrement(2);
6089a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        random_vector_->Generate(
6099a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org            noise_length - RandomVector::kRandomTableSize,
6109a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org            &random_vector[RandomVector::kRandomTableSize]);
6119a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      }
6129a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
6139a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
6149a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Set up state vector and calculate scale factor for unvoiced filtering.
6159a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    memcpy(parameters.ar_filter_state,
6169a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org           &(audio_history[signal_length - kUnvoicedLpcOrder]),
6179a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org           sizeof(int16_t) * kUnvoicedLpcOrder);
6189a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    memcpy(unvoiced_vector - kUnvoicedLpcOrder,
6199a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org           &(audio_history[signal_length - 128 - kUnvoicedLpcOrder]),
6209a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org           sizeof(int16_t) * kUnvoicedLpcOrder);
6219a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    WebRtcSpl_FilterMAFastQ12(
6229a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        const_cast<int16_t*>(&audio_history[signal_length - 128]),
6239a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        unvoiced_vector, parameters.ar_filter, kUnvoicedLpcOrder + 1, 128);
6249a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int16_t unvoiced_prescale;
6259a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if (WebRtcSpl_MaxAbsValueW16(unvoiced_vector, 128) > 4000) {
6269a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      unvoiced_prescale = 4;
6279a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    } else {
6289a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      unvoiced_prescale = 0;
6299a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
6309a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int32_t unvoiced_energy = WebRtcSpl_DotProductWithScale(unvoiced_vector,
6319a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                                            unvoiced_vector,
6329a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                                            128,
6339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                                            unvoiced_prescale);
6349a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
6359a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Normalize |unvoiced_energy| to 28 or 29 bits to preserve sqrt() accuracy.
6369a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int16_t unvoiced_scale = WebRtcSpl_NormW32(unvoiced_energy) - 3;
6379a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Make sure we do an odd number of shifts since we already have 7 shifts
6389a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // from dividing with 128 earlier. This will make the total scale factor
6399a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // even, which is suitable for the sqrt.
6409a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    unvoiced_scale += ((unvoiced_scale & 0x1) ^ 0x1);
6419a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    unvoiced_energy = WEBRTC_SPL_SHIFT_W32(unvoiced_energy, unvoiced_scale);
6429a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int32_t unvoiced_gain = WebRtcSpl_SqrtFloor(unvoiced_energy);
6439a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    parameters.ar_gain_scale = 13
6449a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        + (unvoiced_scale + 7 - unvoiced_prescale) / 2;
6459a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    parameters.ar_gain = unvoiced_gain;
6469a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
6479a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Calculate voice_mix_factor from corr_coefficient.
6489a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Let x = corr_coefficient. Then, we compute:
6499a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // if (x > 0.48)
6509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    //   voice_mix_factor = (-5179 + 19931x - 16422x^2 + 5776x^3) / 4096;
6519a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // else
6529a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    //   voice_mix_factor = 0;
6539a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if (corr_coefficient > 7875) {
6549a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      int16_t x1, x2, x3;
6559a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      x1 = corr_coefficient;  // |corr_coefficient| is in Q14.
6569a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      x2 = (x1 * x1) >> 14;   // Shift 14 to keep result in Q14.
6579a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      x3 = (x1 * x2) >> 14;
6589a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      static const int kCoefficients[4] = { -5179, 19931, -16422, 5776 };
6599a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      int32_t temp_sum = kCoefficients[0] << 14;
6609a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      temp_sum += kCoefficients[1] * x1;
6619a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      temp_sum += kCoefficients[2] * x2;
6629a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      temp_sum += kCoefficients[3] * x3;
6639a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      parameters.voice_mix_factor = temp_sum / 4096;
6649a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      parameters.voice_mix_factor = std::min(parameters.voice_mix_factor,
6659a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                             static_cast<int16_t>(16384));
6669a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      parameters.voice_mix_factor = std::max(parameters.voice_mix_factor,
6679a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                             static_cast<int16_t>(0));
6689a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    } else {
6699a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      parameters.voice_mix_factor = 0;
6709a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
6719a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
6729a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Calculate muting slope. Reuse value from earlier scaling of
6739a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // |expand_vector0| and |expand_vector1|.
6749a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int16_t slope = amplitude_ratio;
6759a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if (slope > 12288) {
6769a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // slope > 1.5.
6779a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Calculate (1 - (1 / slope)) / distortion_lag =
6789a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // (slope - 1) / (distortion_lag * slope).
6799a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // |slope| is in Q13, so 1 corresponds to 8192. Shift up to Q25 before
6809a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // the division.
6819a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Shift the denominator from Q13 to Q5 before the division. The result of
6829a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // the division will then be in Q20.
6839a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      int16_t temp_ratio = WebRtcSpl_DivW32W16((slope - 8192) << 12,
6849a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                               (distortion_lag * slope) >> 8);
6859a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      if (slope > 14746) {
6869a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // slope > 1.8.
6879a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // Divide by 2, with proper rounding.
6889a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        parameters.mute_slope = (temp_ratio + 1) / 2;
6899a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      } else {
6909a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // Divide by 8, with proper rounding.
6919a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        parameters.mute_slope = (temp_ratio + 4) / 8;
6929a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      }
6939a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      parameters.onset = true;
6949a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    } else {
6959a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Calculate (1 - slope) / distortion_lag.
6969a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Shift |slope| by 7 to Q20 before the division. The result is in Q20.
6979a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      parameters.mute_slope = WebRtcSpl_DivW32W16((8192 - slope) << 7,
6989a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                                   distortion_lag);
6999a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      if (parameters.voice_mix_factor <= 13107) {
7009a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // Make sure the mute factor decreases from 1.0 to 0.9 in no more than
7019a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // 6.25 ms.
7029a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // mute_slope >= 0.005 / fs_mult in Q20.
7039a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        parameters.mute_slope = std::max(static_cast<int16_t>(5243 / fs_mult),
7049a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                         parameters.mute_slope);
7059a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      } else if (slope > 8028) {
7069a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        parameters.mute_slope = 0;
7079a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      }
7089a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      parameters.onset = false;
7099a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
7109a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
7119a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
7129a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
713045e45efeca8776975254550137ec65268aadb54turaj@webrtc.orgint16_t Expand::Correlation(const int16_t* input, size_t input_length,
7149a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                            int16_t* output, int16_t* output_scale) const {
7159a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Set parameters depending on sample rate.
7169a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  const int16_t* filter_coefficients;
7179a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t num_coefficients;
7189a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t downsampling_factor;
7199a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (fs_hz_ == 8000) {
7209a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    num_coefficients = 3;
7219a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    downsampling_factor = 2;
7229a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    filter_coefficients = DspHelper::kDownsample8kHzTbl;
7239a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  } else if (fs_hz_ == 16000) {
7249a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    num_coefficients = 5;
7259a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    downsampling_factor = 4;
7269a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    filter_coefficients = DspHelper::kDownsample16kHzTbl;
7279a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  } else if (fs_hz_ == 32000) {
7289a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    num_coefficients = 7;
7299a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    downsampling_factor = 8;
7309a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    filter_coefficients = DspHelper::kDownsample32kHzTbl;
7319a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  } else {  // fs_hz_ == 48000.
7329a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    num_coefficients = 7;
7339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    downsampling_factor = 12;
7349a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    filter_coefficients = DspHelper::kDownsample48kHzTbl;
7359a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
7369a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
7379a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Correlate from lag 10 to lag 60 in downsampled domain.
7389a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // (Corresponds to 20-120 for narrow-band, 40-240 for wide-band, and so on.)
7399a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  static const int kCorrelationStartLag = 10;
7409a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  static const int kNumCorrelationLags = 54;
7419a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  static const int kCorrelationLength = 60;
7429a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Downsample to 4 kHz sample rate.
7439a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  static const int kDownsampledLength = kCorrelationStartLag
7449a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      + kNumCorrelationLags + kCorrelationLength;
7459a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t downsampled_input[kDownsampledLength];
7469a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  static const int kFilterDelay = 0;
7479a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  WebRtcSpl_DownsampleFast(
7489a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      input + input_length - kDownsampledLength * downsampling_factor,
7499a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      kDownsampledLength * downsampling_factor, downsampled_input,
7509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      kDownsampledLength, filter_coefficients, num_coefficients,
7519a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      downsampling_factor, kFilterDelay);
7529a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
7539a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Normalize |downsampled_input| to using all 16 bits.
7549a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t max_value = WebRtcSpl_MaxAbsValueW16(downsampled_input,
7559a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                               kDownsampledLength);
7569a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t norm_shift = 16 - WebRtcSpl_NormW32(max_value);
7579a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  WebRtcSpl_VectorBitShiftW16(downsampled_input, kDownsampledLength,
7589a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                              downsampled_input, norm_shift);
7599a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
7609a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int32_t correlation[kNumCorrelationLags];
7619a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  static const int kCorrelationShift = 6;
7629a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  WebRtcSpl_CrossCorrelation(
7639a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      correlation,
7649a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      &downsampled_input[kDownsampledLength - kCorrelationLength],
7659a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      &downsampled_input[kDownsampledLength - kCorrelationLength
7669a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org          - kCorrelationStartLag],
7679a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      kCorrelationLength, kNumCorrelationLags, kCorrelationShift, -1);
7689a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
7699a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Normalize and move data from 32-bit to 16-bit vector.
7709a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int32_t max_correlation = WebRtcSpl_MaxAbsValueW32(correlation,
7719a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                                     kNumCorrelationLags);
7729a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t norm_shift2 = std::max(18 - WebRtcSpl_NormW32(max_correlation), 0);
7739a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  WebRtcSpl_VectorBitShiftW32ToW16(output, kNumCorrelationLags, correlation,
7749a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                   norm_shift2);
7759a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Total scale factor (right shifts) of correlation value.
7769a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  *output_scale = 2 * norm_shift + kCorrelationShift + norm_shift2;
7779a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  return kNumCorrelationLags;
7789a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
7799a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
7809a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid Expand::UpdateLagIndex() {
7819a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  current_lag_index_ = current_lag_index_ + lag_index_direction_;
7829a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Change direction if needed.
7839a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (current_lag_index_ <= 0) {
7849a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    lag_index_direction_ = 1;
7859a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
7869a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (current_lag_index_ >= kNumLags - 1) {
7879a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    lag_index_direction_ = -1;
7889a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
7899a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
7909a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
79137fb66d3bde95c19f5c80ece459f5dd632077ff5henrik.lundin@webrtc.orgExpand* ExpandFactory::Create(BackgroundNoise* background_noise,
79237fb66d3bde95c19f5c80ece459f5dd632077ff5henrik.lundin@webrtc.org                              SyncBuffer* sync_buffer,
79337fb66d3bde95c19f5c80ece459f5dd632077ff5henrik.lundin@webrtc.org                              RandomVector* random_vector,
79437fb66d3bde95c19f5c80ece459f5dd632077ff5henrik.lundin@webrtc.org                              int fs,
79537fb66d3bde95c19f5c80ece459f5dd632077ff5henrik.lundin@webrtc.org                              size_t num_channels) const {
79637fb66d3bde95c19f5c80ece459f5dd632077ff5henrik.lundin@webrtc.org  return new Expand(background_noise, sync_buffer, random_vector, fs,
79737fb66d3bde95c19f5c80ece459f5dd632077ff5henrik.lundin@webrtc.org                    num_channels);
79837fb66d3bde95c19f5c80ece459f5dd632077ff5henrik.lundin@webrtc.org}
79937fb66d3bde95c19f5c80ece459f5dd632077ff5henrik.lundin@webrtc.org
800c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org// TODO(turajs): This can be moved to BackgroundNoise class.
801c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.orgvoid Expand::GenerateBackgroundNoise(int16_t* random_vector,
802c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                                     size_t channel,
803c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                                     int16_t mute_slope,
804c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                                     bool too_many_expands,
805c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                                     size_t num_noise_samples,
806c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                                     int16_t* buffer) {
807c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  static const int kNoiseLpcOrder = BackgroundNoise::kMaxLpcOrder;
808c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  int16_t scaled_random_vector[kMaxSampleRate / 8000 * 125];
809d8b9cd100e889aa8b4a7d8b391ebd39a1298913ehenrik.lundin@webrtc.org  assert(static_cast<size_t>(kMaxSampleRate / 8000 * 125) >= num_noise_samples);
810c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  int16_t* noise_samples = &buffer[kNoiseLpcOrder];
811c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  if (background_noise_->initialized()) {
812c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    // Use background noise parameters.
813c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    memcpy(noise_samples - kNoiseLpcOrder,
814c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org           background_noise_->FilterState(channel),
815c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org           sizeof(int16_t) * kNoiseLpcOrder);
816c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org
817c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    int dc_offset = 0;
818c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    if (background_noise_->ScaleShift(channel) > 1) {
819c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org      dc_offset = 1 << (background_noise_->ScaleShift(channel) - 1);
820c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    }
821c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org
822c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    // Scale random vector to correct energy level.
823c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    WebRtcSpl_AffineTransformVector(
824c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org        scaled_random_vector, random_vector,
825c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org        background_noise_->Scale(channel), dc_offset,
826c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org        background_noise_->ScaleShift(channel),
827c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org        static_cast<int>(num_noise_samples));
828c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org
829c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    WebRtcSpl_FilterARFastQ12(scaled_random_vector, noise_samples,
830c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                              background_noise_->Filter(channel),
831c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                              kNoiseLpcOrder + 1,
832c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                              static_cast<int>(num_noise_samples));
833c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org
834c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    background_noise_->SetFilterState(
835c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org        channel,
836c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org        &(noise_samples[num_noise_samples - kNoiseLpcOrder]),
837c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org        kNoiseLpcOrder);
838c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org
839c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    // Unmute the background noise.
840c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    int16_t bgn_mute_factor = background_noise_->MuteFactor(channel);
841d8b9cd100e889aa8b4a7d8b391ebd39a1298913ehenrik.lundin@webrtc.org    NetEq::BackgroundNoiseMode bgn_mode = background_noise_->mode();
842d8b9cd100e889aa8b4a7d8b391ebd39a1298913ehenrik.lundin@webrtc.org    if (bgn_mode == NetEq::kBgnFade && too_many_expands &&
843d8b9cd100e889aa8b4a7d8b391ebd39a1298913ehenrik.lundin@webrtc.org        bgn_mute_factor > 0) {
844c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org      // Fade BGN to zero.
845c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org      // Calculate muting slope, approximately -2^18 / fs_hz.
846c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org      int16_t mute_slope;
847c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org      if (fs_hz_ == 8000) {
848c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org        mute_slope = -32;
849c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org      } else if (fs_hz_ == 16000) {
850c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org        mute_slope = -16;
851c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org      } else if (fs_hz_ == 32000) {
852c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org        mute_slope = -8;
853c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org      } else {
854c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org        mute_slope = -5;
855c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org      }
856c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org      // Use UnmuteSignal function with negative slope.
857c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org      // |bgn_mute_factor| is in Q14. |mute_slope| is in Q20.
858c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org      DspHelper::UnmuteSignal(noise_samples,
859c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                              num_noise_samples,
860c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                              &bgn_mute_factor,
861c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                              mute_slope,
862c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                              noise_samples);
863c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    } else if (bgn_mute_factor < 16384) {
8648c5063edeaee6421489dd1c0d22fd6353019484chenrik.lundin@webrtc.org      // If mode is kBgnOn, or if kBgnFade has started fading,
8658c5063edeaee6421489dd1c0d22fd6353019484chenrik.lundin@webrtc.org      // use regular |mute_slope|.
866d8b9cd100e889aa8b4a7d8b391ebd39a1298913ehenrik.lundin@webrtc.org      if (!stop_muting_ && bgn_mode != NetEq::kBgnOff &&
867d8b9cd100e889aa8b4a7d8b391ebd39a1298913ehenrik.lundin@webrtc.org          !(bgn_mode == NetEq::kBgnFade && too_many_expands)) {
868c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org        DspHelper::UnmuteSignal(noise_samples,
869c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                                static_cast<int>(num_noise_samples),
870c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                                &bgn_mute_factor,
871c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                                mute_slope,
872c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                                noise_samples);
873c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org      } else {
874c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org        // kBgnOn and stop muting, or
875c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org        // kBgnOff (mute factor is always 0), or
876c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org        // kBgnFade has reached 0.
877c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org        WebRtcSpl_AffineTransformVector(noise_samples, noise_samples,
878c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                                        bgn_mute_factor, 8192, 14,
879c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                                        static_cast<int>(num_noise_samples));
880c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org      }
881c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    }
882c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    // Update mute_factor in BackgroundNoise class.
883c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    background_noise_->SetMuteFactor(channel, bgn_mute_factor);
884c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  } else {
885c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    // BGN parameters have not been initialized; use zero noise.
886c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    memset(noise_samples, 0, sizeof(int16_t) * num_noise_samples);
887c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  }
888c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org}
889c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org
890c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.orgvoid Expand::GenerateRandomVector(int seed_increment,
891c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                                  size_t length,
892c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org                                  int16_t* random_vector) {
893c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  // TODO(turajs): According to hlundin The loop should not be needed. Should be
894c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  // just as good to generate all of the vector in one call.
895c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  size_t samples_generated = 0;
896c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  const size_t kMaxRandSamples = RandomVector::kRandomTableSize;
897d8b9cd100e889aa8b4a7d8b391ebd39a1298913ehenrik.lundin@webrtc.org  while (samples_generated < length) {
898c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    size_t rand_length = std::min(length - samples_generated, kMaxRandSamples);
899c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    random_vector_->IncreaseSeedIncrement(seed_increment);
900c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    random_vector_->Generate(rand_length, &random_vector[samples_generated]);
901c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org    samples_generated += rand_length;
902c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org  }
903c1caa69f05663fc729af5a921eb95a73709f7dcdturaj@webrtc.org}
90437fb66d3bde95c19f5c80ece459f5dd632077ff5henrik.lundin@webrtc.org
9059a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}  // namespace webrtc
906