| /* |
| * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "modules/audio_processing/legacy_noise_suppression.h" |
| |
| #include "modules/audio_processing/audio_buffer.h" |
| #include "rtc_base/checks.h" |
| #if defined(WEBRTC_NS_FLOAT) |
| #include "modules/audio_processing/legacy_ns/noise_suppression.h" |
| |
| #define NS_CREATE WebRtcNs_Create |
| #define NS_FREE WebRtcNs_Free |
| #define NS_INIT WebRtcNs_Init |
| #define NS_SET_POLICY WebRtcNs_set_policy |
| typedef NsHandle NsState; |
| #elif defined(WEBRTC_NS_FIXED) |
| #include "modules/audio_processing/legacy_ns/noise_suppression_x.h" |
| |
| #define NS_CREATE WebRtcNsx_Create |
| #define NS_FREE WebRtcNsx_Free |
| #define NS_INIT WebRtcNsx_Init |
| #define NS_SET_POLICY WebRtcNsx_set_policy |
| typedef NsxHandle NsState; |
| #endif |
| |
| namespace webrtc { |
| namespace { |
| int NoiseSuppressionLevelToPolicy(NoiseSuppression::Level level) { |
| switch (level) { |
| case NoiseSuppression::Level::kLow: |
| return 0; |
| case NoiseSuppression::Level::kModerate: |
| return 1; |
| case NoiseSuppression::Level::kHigh: |
| return 2; |
| case NoiseSuppression::Level::kVeryHigh: |
| return 3; |
| default: |
| RTC_NOTREACHED(); |
| } |
| return 1; |
| } |
| } // namespace |
| |
| class NoiseSuppression::Suppressor { |
| public: |
| explicit Suppressor(int sample_rate_hz) { |
| state_ = NS_CREATE(); |
| RTC_CHECK(state_); |
| int error = NS_INIT(state_, sample_rate_hz); |
| RTC_DCHECK_EQ(0, error); |
| } |
| ~Suppressor() { NS_FREE(state_); } |
| |
| Suppressor(Suppressor&) = delete; |
| Suppressor& operator=(Suppressor&) = delete; |
| |
| NsState* state() { return state_; } |
| |
| private: |
| NsState* state_ = nullptr; |
| }; |
| |
| NoiseSuppression::NoiseSuppression(size_t channels, |
| int sample_rate_hz, |
| Level level) { |
| const int policy = NoiseSuppressionLevelToPolicy(level); |
| for (size_t i = 0; i < channels; ++i) { |
| suppressors_.push_back(std::make_unique<Suppressor>(sample_rate_hz)); |
| int error = NS_SET_POLICY(suppressors_[i]->state(), policy); |
| RTC_DCHECK_EQ(0, error); |
| } |
| } |
| |
| NoiseSuppression::~NoiseSuppression() {} |
| |
| void NoiseSuppression::AnalyzeCaptureAudio(AudioBuffer* audio) { |
| RTC_DCHECK(audio); |
| #if defined(WEBRTC_NS_FLOAT) |
| RTC_DCHECK_GE(160, audio->num_frames_per_band()); |
| RTC_DCHECK_EQ(suppressors_.size(), audio->num_channels()); |
| for (size_t i = 0; i < suppressors_.size(); i++) { |
| WebRtcNs_Analyze(suppressors_[i]->state(), |
| audio->split_bands_const(i)[kBand0To8kHz]); |
| } |
| #endif |
| } |
| |
| void NoiseSuppression::ProcessCaptureAudio(AudioBuffer* audio) { |
| RTC_DCHECK(audio); |
| RTC_DCHECK_GE(160, audio->num_frames_per_band()); |
| RTC_DCHECK_EQ(suppressors_.size(), audio->num_channels()); |
| for (size_t i = 0; i < suppressors_.size(); i++) { |
| #if defined(WEBRTC_NS_FLOAT) |
| WebRtcNs_Process(suppressors_[i]->state(), audio->split_bands_const(i), |
| audio->num_bands(), audio->split_bands(i)); |
| #elif defined(WEBRTC_NS_FIXED) |
| int16_t split_band_data[AudioBuffer::kMaxNumBands] |
| [AudioBuffer::kMaxSplitFrameLength]; |
| int16_t* split_bands[AudioBuffer::kMaxNumBands] = { |
| split_band_data[0], split_band_data[1], split_band_data[2]}; |
| audio->ExportSplitChannelData(i, split_bands); |
| |
| WebRtcNsx_Process(suppressors_[i]->state(), split_bands, audio->num_bands(), |
| split_bands); |
| |
| audio->ImportSplitChannelData(i, split_bands); |
| #endif |
| } |
| } |
| |
| float NoiseSuppression::speech_probability() const { |
| #if defined(WEBRTC_NS_FLOAT) |
| float probability_average = 0.0f; |
| for (auto& suppressor : suppressors_) { |
| probability_average += |
| WebRtcNs_prior_speech_probability(suppressor->state()); |
| } |
| if (!suppressors_.empty()) { |
| probability_average /= suppressors_.size(); |
| } |
| return probability_average; |
| #elif defined(WEBRTC_NS_FIXED) |
| // TODO(peah): Returning error code as a float! Remove this. |
| // Currently not available for the fixed point implementation. |
| return AudioProcessing::kUnsupportedFunctionError; |
| #endif |
| } |
| |
| std::vector<float> NoiseSuppression::NoiseEstimate() { |
| std::vector<float> noise_estimate; |
| #if defined(WEBRTC_NS_FLOAT) |
| const float kNumChannelsFraction = 1.f / suppressors_.size(); |
| noise_estimate.assign(WebRtcNs_num_freq(), 0.f); |
| for (auto& suppressor : suppressors_) { |
| const float* noise = WebRtcNs_noise_estimate(suppressor->state()); |
| for (size_t i = 0; i < noise_estimate.size(); ++i) { |
| noise_estimate[i] += kNumChannelsFraction * noise[i]; |
| } |
| } |
| #elif defined(WEBRTC_NS_FIXED) |
| noise_estimate.assign(WebRtcNsx_num_freq(), 0.f); |
| for (auto& suppressor : suppressors_) { |
| int q_noise; |
| const uint32_t* noise = |
| WebRtcNsx_noise_estimate(suppressor->state(), &q_noise); |
| const float kNormalizationFactor = |
| 1.f / ((1 << q_noise) * suppressors_.size()); |
| for (size_t i = 0; i < noise_estimate.size(); ++i) { |
| noise_estimate[i] += kNormalizationFactor * noise[i]; |
| } |
| } |
| #endif |
| return noise_estimate; |
| } |
| |
| size_t NoiseSuppression::num_noise_bins() { |
| #if defined(WEBRTC_NS_FLOAT) |
| return WebRtcNs_num_freq(); |
| #elif defined(WEBRTC_NS_FIXED) |
| return WebRtcNsx_num_freq(); |
| #endif |
| } |
| |
| } // namespace webrtc |