mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00

This is a reland of 87a7b82520
Original change's description:
> Refactoring of the noise suppressor and adding true multichannel support
>
> This CL adds proper multichannel support to the noise suppressor.
> To accomplish that in a safe way, a full refactoring of the noise
> suppressor code has been done.
>
> Due to floating point precision, the changes made are not entirely
> bitexact. They are, however, very close to being bitexact.
>
> As a safety measure, the former noise suppressor code is preserved
> and a kill-switch is added to allow revering to the legacy noise
> suppressor in case issues arise.
>
> Bug: webrtc:10895, b/143344262
> Change-Id: I0b071011b23265ac12e6d4b3956499d122286657
> Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/158407
> Commit-Queue: Per Åhgren <peah@webrtc.org>
> Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#29646}
Bug: webrtc:10895, b/143344262
Change-Id: I236f1e67bb0baa4e30908a4cf7a8a7bb55fbced3
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/158747
Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org>
Commit-Queue: Per Åhgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29663}
172 lines
5.4 KiB
C++
172 lines
5.4 KiB
C++
/*
|
|
* 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
|