2011-07-07 08:21:25 +00:00
|
|
|
/*
|
2012-01-30 09:39:08 +00:00
|
|
|
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
2011-07-07 08:21:25 +00:00
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2013-05-28 08:11:59 +00:00
|
|
|
#include "webrtc/modules/audio_processing/noise_suppression_impl.h"
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2014-02-27 22:23:17 +00:00
|
|
|
#include "webrtc/modules/audio_processing/audio_buffer.h"
|
2017-07-06 19:44:34 +02:00
|
|
|
#include "webrtc/rtc_base/constructormagic.h"
|
2011-07-07 08:21:25 +00:00
|
|
|
#if defined(WEBRTC_NS_FLOAT)
|
2015-11-11 20:16:11 +01:00
|
|
|
#include "webrtc/modules/audio_processing/ns/noise_suppression.h"
|
2015-12-08 13:22:33 -08:00
|
|
|
#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;
|
2011-07-07 08:21:25 +00:00
|
|
|
#elif defined(WEBRTC_NS_FIXED)
|
2015-11-11 20:16:11 +01:00
|
|
|
#include "webrtc/modules/audio_processing/ns/noise_suppression_x.h"
|
2015-12-08 13:22:33 -08:00
|
|
|
#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;
|
2011-07-07 08:21:25 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
namespace webrtc {
|
2015-12-08 13:22:33 -08:00
|
|
|
class NoiseSuppressionImpl::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);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2015-12-08 13:22:33 -08:00
|
|
|
~Suppressor() {
|
|
|
|
|
NS_FREE(state_);
|
|
|
|
|
}
|
|
|
|
|
NsState* state() { return state_; }
|
|
|
|
|
private:
|
|
|
|
|
NsState* state_ = nullptr;
|
|
|
|
|
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Suppressor);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
NoiseSuppressionImpl::NoiseSuppressionImpl(rtc::CriticalSection* crit)
|
|
|
|
|
: crit_(crit) {
|
2015-11-28 12:35:15 -08:00
|
|
|
RTC_DCHECK(crit);
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
|
|
|
|
NoiseSuppressionImpl::~NoiseSuppressionImpl() {}
|
|
|
|
|
|
Convert channel counts to size_t.
IIRC, this was originally requested by ajm during review of the other size_t conversions I did over the past year, and I agreed it made sense, but wanted to do it separately since those changes were already gargantuan.
BUG=chromium:81439
TEST=none
R=henrik.lundin@webrtc.org, henrika@webrtc.org, kjellander@webrtc.org, minyue@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1316523002 .
Cr-Commit-Position: refs/heads/master@{#11229}
2016-01-12 16:26:35 -08:00
|
|
|
void NoiseSuppressionImpl::Initialize(size_t channels, int sample_rate_hz) {
|
2015-12-08 13:22:33 -08:00
|
|
|
rtc::CritScope cs(crit_);
|
2015-12-16 01:18:15 -08:00
|
|
|
channels_ = channels;
|
|
|
|
|
sample_rate_hz_ = sample_rate_hz;
|
2016-02-19 07:04:49 -08:00
|
|
|
std::vector<std::unique_ptr<Suppressor>> new_suppressors;
|
2015-12-16 01:18:15 -08:00
|
|
|
if (enabled_) {
|
|
|
|
|
new_suppressors.resize(channels);
|
Convert channel counts to size_t.
IIRC, this was originally requested by ajm during review of the other size_t conversions I did over the past year, and I agreed it made sense, but wanted to do it separately since those changes were already gargantuan.
BUG=chromium:81439
TEST=none
R=henrik.lundin@webrtc.org, henrika@webrtc.org, kjellander@webrtc.org, minyue@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1316523002 .
Cr-Commit-Position: refs/heads/master@{#11229}
2016-01-12 16:26:35 -08:00
|
|
|
for (size_t i = 0; i < channels; i++) {
|
2015-12-16 01:18:15 -08:00
|
|
|
new_suppressors[i].reset(new Suppressor(sample_rate_hz));
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-12-08 13:22:33 -08:00
|
|
|
suppressors_.swap(new_suppressors);
|
|
|
|
|
set_level(level_);
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 01:18:15 -08:00
|
|
|
void NoiseSuppressionImpl::AnalyzeCaptureAudio(AudioBuffer* audio) {
|
2015-12-08 13:22:33 -08:00
|
|
|
RTC_DCHECK(audio);
|
2014-09-18 09:54:06 +00:00
|
|
|
#if defined(WEBRTC_NS_FLOAT)
|
2015-12-08 13:22:33 -08:00
|
|
|
rtc::CritScope cs(crit_);
|
|
|
|
|
if (!enabled_) {
|
2015-12-16 01:18:15 -08:00
|
|
|
return;
|
2014-09-18 09:54:06 +00:00
|
|
|
}
|
|
|
|
|
|
2016-11-28 15:21:39 -08:00
|
|
|
RTC_DCHECK_GE(160, audio->num_frames_per_band());
|
Convert channel counts to size_t.
IIRC, this was originally requested by ajm during review of the other size_t conversions I did over the past year, and I agreed it made sense, but wanted to do it separately since those changes were already gargantuan.
BUG=chromium:81439
TEST=none
R=henrik.lundin@webrtc.org, henrika@webrtc.org, kjellander@webrtc.org, minyue@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1316523002 .
Cr-Commit-Position: refs/heads/master@{#11229}
2016-01-12 16:26:35 -08:00
|
|
|
RTC_DCHECK_EQ(suppressors_.size(), audio->num_channels());
|
2015-12-08 13:22:33 -08:00
|
|
|
for (size_t i = 0; i < suppressors_.size(); i++) {
|
|
|
|
|
WebRtcNs_Analyze(suppressors_[i]->state(),
|
|
|
|
|
audio->split_bands_const_f(i)[kBand0To8kHz]);
|
2014-09-18 09:54:06 +00:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 01:18:15 -08:00
|
|
|
void NoiseSuppressionImpl::ProcessCaptureAudio(AudioBuffer* audio) {
|
2015-12-08 13:22:33 -08:00
|
|
|
RTC_DCHECK(audio);
|
2015-11-28 12:35:15 -08:00
|
|
|
rtc::CritScope cs(crit_);
|
2015-12-08 13:22:33 -08:00
|
|
|
if (!enabled_) {
|
2015-12-16 01:18:15 -08:00
|
|
|
return;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-11-28 15:21:39 -08:00
|
|
|
RTC_DCHECK_GE(160, audio->num_frames_per_band());
|
Convert channel counts to size_t.
IIRC, this was originally requested by ajm during review of the other size_t conversions I did over the past year, and I agreed it made sense, but wanted to do it separately since those changes were already gargantuan.
BUG=chromium:81439
TEST=none
R=henrik.lundin@webrtc.org, henrika@webrtc.org, kjellander@webrtc.org, minyue@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1316523002 .
Cr-Commit-Position: refs/heads/master@{#11229}
2016-01-12 16:26:35 -08:00
|
|
|
RTC_DCHECK_EQ(suppressors_.size(), audio->num_channels());
|
2015-12-08 13:22:33 -08:00
|
|
|
for (size_t i = 0; i < suppressors_.size(); i++) {
|
2011-07-07 08:21:25 +00:00
|
|
|
#if defined(WEBRTC_NS_FLOAT)
|
2015-12-08 13:22:33 -08:00
|
|
|
WebRtcNs_Process(suppressors_[i]->state(),
|
2014-12-10 19:30:57 +00:00
|
|
|
audio->split_bands_const_f(i),
|
|
|
|
|
audio->num_bands(),
|
|
|
|
|
audio->split_bands_f(i));
|
2011-07-07 08:21:25 +00:00
|
|
|
#elif defined(WEBRTC_NS_FIXED)
|
2015-12-08 13:22:33 -08:00
|
|
|
WebRtcNsx_Process(suppressors_[i]->state(),
|
2014-12-10 19:30:57 +00:00
|
|
|
audio->split_bands_const(i),
|
|
|
|
|
audio->num_bands(),
|
|
|
|
|
audio->split_bands(i));
|
2011-07-07 08:21:25 +00:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int NoiseSuppressionImpl::Enable(bool enable) {
|
2015-11-28 12:35:15 -08:00
|
|
|
rtc::CritScope cs(crit_);
|
2015-12-16 01:18:15 -08:00
|
|
|
if (enabled_ != enable) {
|
|
|
|
|
enabled_ = enable;
|
|
|
|
|
Initialize(channels_, sample_rate_hz_);
|
|
|
|
|
}
|
2015-12-08 13:22:33 -08:00
|
|
|
return AudioProcessing::kNoError;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NoiseSuppressionImpl::is_enabled() const {
|
2015-11-28 12:35:15 -08:00
|
|
|
rtc::CritScope cs(crit_);
|
2015-12-08 13:22:33 -08:00
|
|
|
return enabled_;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int NoiseSuppressionImpl::set_level(Level level) {
|
2015-12-08 13:22:33 -08:00
|
|
|
int policy = 1;
|
|
|
|
|
switch (level) {
|
|
|
|
|
case NoiseSuppression::kLow:
|
|
|
|
|
policy = 0;
|
|
|
|
|
break;
|
|
|
|
|
case NoiseSuppression::kModerate:
|
|
|
|
|
policy = 1;
|
|
|
|
|
break;
|
|
|
|
|
case NoiseSuppression::kHigh:
|
|
|
|
|
policy = 2;
|
|
|
|
|
break;
|
|
|
|
|
case NoiseSuppression::kVeryHigh:
|
|
|
|
|
policy = 3;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
RTC_NOTREACHED();
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2015-12-16 01:18:15 -08:00
|
|
|
rtc::CritScope cs(crit_);
|
2011-07-07 08:21:25 +00:00
|
|
|
level_ = level;
|
2015-12-08 13:22:33 -08:00
|
|
|
for (auto& suppressor : suppressors_) {
|
|
|
|
|
int error = NS_SET_POLICY(suppressor->state(), policy);
|
|
|
|
|
RTC_DCHECK_EQ(0, error);
|
|
|
|
|
}
|
|
|
|
|
return AudioProcessing::kNoError;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NoiseSuppression::Level NoiseSuppressionImpl::level() const {
|
2015-11-28 12:35:15 -08:00
|
|
|
rtc::CritScope cs(crit_);
|
2011-07-07 08:21:25 +00:00
|
|
|
return level_;
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-12 21:00:43 +00:00
|
|
|
float NoiseSuppressionImpl::speech_probability() const {
|
2015-11-28 12:35:15 -08:00
|
|
|
rtc::CritScope cs(crit_);
|
2012-07-12 21:00:43 +00:00
|
|
|
#if defined(WEBRTC_NS_FLOAT)
|
|
|
|
|
float probability_average = 0.0f;
|
2015-12-08 13:22:33 -08:00
|
|
|
for (auto& suppressor : suppressors_) {
|
|
|
|
|
probability_average +=
|
|
|
|
|
WebRtcNs_prior_speech_probability(suppressor->state());
|
2012-07-12 21:00:43 +00:00
|
|
|
}
|
Misc. small cleanups.
* Better param names
* Avoid using negative values for (bogus) placeholder channel counts (mostly in tests). Since channels will be changing to size_t, negative values will be illegal; it's sufficient to use 0 in these cases.
* Use arraysize()
* Use size_t for counting frames, samples, blocks, buffers, and bytes -- most of these are already size_t in most places, this just fixes some stragglers
* reinterpret_cast<int64_t>(void*) is not necessarily safe; use uintptr_t instead
* Remove unnecessary code, e.g. dead code, needlessly long/repetitive code, or function overrides that exactly match the base definition
* Fix indenting
* Use uint32_t for timestamps (matching how it's already a uint32_t in most places)
* Spelling
* RTC_CHECK_EQ(expected, actual)
* Rewrap
* Use .empty()
* Be more pedantic about matching int/int32_t/
* Remove pointless consts on input parameters to functions
* Add missing sanity checks
All this was found in the course of constructing https://codereview.webrtc.org/1316523002/ , and is being landed separately first.
BUG=none
TEST=none
Review URL: https://codereview.webrtc.org/1534193008
Cr-Commit-Position: refs/heads/master@{#11191}
2016-01-08 13:50:27 -08:00
|
|
|
if (!suppressors_.empty()) {
|
2015-12-08 13:22:33 -08:00
|
|
|
probability_average /= suppressors_.size();
|
|
|
|
|
}
|
|
|
|
|
return probability_average;
|
2012-07-12 21:00:43 +00:00
|
|
|
#elif defined(WEBRTC_NS_FIXED)
|
2015-12-08 13:22:33 -08:00
|
|
|
// TODO(peah): Returning error code as a float! Remove this.
|
2012-07-12 21:00:43 +00:00
|
|
|
// Currently not available for the fixed point implementation.
|
2015-11-28 12:35:15 -08:00
|
|
|
return AudioProcessing::kUnsupportedFunctionError;
|
2012-07-12 21:00:43 +00:00
|
|
|
#endif
|
|
|
|
|
}
|
2016-02-09 11:24:32 -08:00
|
|
|
|
|
|
|
|
std::vector<float> NoiseSuppressionImpl::NoiseEstimate() {
|
|
|
|
|
rtc::CritScope cs(crit_);
|
|
|
|
|
std::vector<float> noise_estimate;
|
|
|
|
|
#if defined(WEBRTC_NS_FLOAT)
|
2016-04-01 13:54:36 -07:00
|
|
|
const float kNumChannelsFraction = 1.f / suppressors_.size();
|
2016-02-09 11:24:32 -08:00
|
|
|
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) {
|
2016-04-01 13:54:36 -07:00
|
|
|
noise_estimate[i] += kNumChannelsFraction * noise[i];
|
2016-02-09 11:24:32 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#elif defined(WEBRTC_NS_FIXED)
|
|
|
|
|
noise_estimate.assign(WebRtcNsx_num_freq(), 0.f);
|
|
|
|
|
for (auto& suppressor : suppressors_) {
|
2016-04-01 13:54:36 -07:00
|
|
|
int q_noise;
|
|
|
|
|
const uint32_t* noise = WebRtcNsx_noise_estimate(suppressor->state(),
|
|
|
|
|
&q_noise);
|
|
|
|
|
const float kNormalizationFactor =
|
|
|
|
|
1.f / ((1 << q_noise) * suppressors_.size());
|
2016-02-09 11:24:32 -08:00
|
|
|
for (size_t i = 0; i < noise_estimate.size(); ++i) {
|
2016-04-01 13:54:36 -07:00
|
|
|
noise_estimate[i] += kNormalizationFactor * noise[i];
|
2016-02-09 11:24:32 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return noise_estimate;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-09 16:24:34 +01:00
|
|
|
size_t NoiseSuppressionImpl::num_noise_bins() {
|
|
|
|
|
#if defined(WEBRTC_NS_FLOAT)
|
|
|
|
|
return WebRtcNs_num_freq();
|
|
|
|
|
#elif defined(WEBRTC_NS_FIXED)
|
|
|
|
|
return WebRtcNsx_num_freq();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-07 08:21:25 +00:00
|
|
|
} // namespace webrtc
|