|  | /* | 
|  | *  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_ns/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 |