speech_probability_buffer.cc (3241B)
1 /* 2 * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "modules/audio_processing/agc2/speech_probability_buffer.h" 12 13 #include "rtc_base/checks.h" 14 15 namespace webrtc { 16 namespace { 17 18 constexpr float kActivityThreshold = 0.9f; 19 constexpr int kNumAnalysisFrames = 100; 20 // We use 12 in AGC2 adaptive digital, but with a slightly different logic. 21 constexpr int kTransientWidthThreshold = 7; 22 23 } // namespace 24 25 SpeechProbabilityBuffer::SpeechProbabilityBuffer( 26 float low_probability_threshold) 27 : low_probability_threshold_(low_probability_threshold), 28 probabilities_(kNumAnalysisFrames) { 29 RTC_DCHECK_GE(low_probability_threshold, 0.0f); 30 RTC_DCHECK_LE(low_probability_threshold, 1.0f); 31 RTC_DCHECK(!probabilities_.empty()); 32 } 33 34 void SpeechProbabilityBuffer::Update(float probability) { 35 // Remove the oldest entry if the circular buffer is full. 36 if (buffer_is_full_) { 37 const float oldest_probability = probabilities_[buffer_index_]; 38 sum_probabilities_ -= oldest_probability; 39 } 40 41 // Check for transients. 42 if (probability <= low_probability_threshold_) { 43 // Set a probability lower than the threshold to zero. 44 probability = 0.0f; 45 46 // Check if this has been a transient. 47 if (num_high_probability_observations_ <= kTransientWidthThreshold) { 48 RemoveTransient(); 49 } 50 num_high_probability_observations_ = 0; 51 } else if (num_high_probability_observations_ <= kTransientWidthThreshold) { 52 ++num_high_probability_observations_; 53 } 54 55 // Update the circular buffer and the current sum. 56 probabilities_[buffer_index_] = probability; 57 sum_probabilities_ += probability; 58 59 // Increment the buffer index and check for wrap-around. 60 if (++buffer_index_ >= kNumAnalysisFrames) { 61 buffer_index_ = 0; 62 buffer_is_full_ = true; 63 } 64 } 65 66 void SpeechProbabilityBuffer::RemoveTransient() { 67 // Don't expect to be here if high-activity region is longer than 68 // `kTransientWidthThreshold` or there has not been any transient. 69 RTC_DCHECK_LE(num_high_probability_observations_, kTransientWidthThreshold); 70 71 // Replace previously added probabilities with zero. 72 int index = 73 (buffer_index_ > 0) ? (buffer_index_ - 1) : (kNumAnalysisFrames - 1); 74 75 while (num_high_probability_observations_-- > 0) { 76 sum_probabilities_ -= probabilities_[index]; 77 probabilities_[index] = 0.0f; 78 79 // Update the circular buffer index. 80 index = (index > 0) ? (index - 1) : (kNumAnalysisFrames - 1); 81 } 82 } 83 84 bool SpeechProbabilityBuffer::IsActiveSegment() const { 85 if (!buffer_is_full_) { 86 return false; 87 } 88 if (sum_probabilities_ < kActivityThreshold * kNumAnalysisFrames) { 89 return false; 90 } 91 return true; 92 } 93 94 void SpeechProbabilityBuffer::Reset() { 95 sum_probabilities_ = 0.0f; 96 97 // Empty the circular buffer. 98 buffer_index_ = 0; 99 buffer_is_full_ = false; 100 num_high_probability_observations_ = 0; 101 } 102 103 } // namespace webrtc