blob: bfaddd989e6734a0dc87bbb81108551264ffa02f [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
bjornv@webrtc.org0c6f9312012-01-30 09:39:08 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/audio_processing/noise_suppression_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "modules/audio_processing/audio_buffer.h"
Yves Gerey988cc082018-10-23 12:03:01 +020014#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080015#include "rtc_base/constructor_magic.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000016#if defined(WEBRTC_NS_FLOAT)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "modules/audio_processing/ns/noise_suppression.h"
Yves Gerey988cc082018-10-23 12:03:01 +020018
solenberg5e465c32015-12-08 13:22:33 -080019#define NS_CREATE WebRtcNs_Create
20#define NS_FREE WebRtcNs_Free
21#define NS_INIT WebRtcNs_Init
22#define NS_SET_POLICY WebRtcNs_set_policy
23typedef NsHandle NsState;
niklase@google.com470e71d2011-07-07 08:21:25 +000024#elif defined(WEBRTC_NS_FIXED)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "modules/audio_processing/ns/noise_suppression_x.h"
Yves Gerey988cc082018-10-23 12:03:01 +020026
solenberg5e465c32015-12-08 13:22:33 -080027#define NS_CREATE WebRtcNsx_Create
28#define NS_FREE WebRtcNsx_Free
29#define NS_INIT WebRtcNsx_Init
30#define NS_SET_POLICY WebRtcNsx_set_policy
31typedef NsxHandle NsState;
niklase@google.com470e71d2011-07-07 08:21:25 +000032#endif
33
niklase@google.com470e71d2011-07-07 08:21:25 +000034namespace webrtc {
solenberg5e465c32015-12-08 13:22:33 -080035class NoiseSuppressionImpl::Suppressor {
36 public:
37 explicit Suppressor(int sample_rate_hz) {
38 state_ = NS_CREATE();
39 RTC_CHECK(state_);
40 int error = NS_INIT(state_, sample_rate_hz);
41 RTC_DCHECK_EQ(0, error);
niklase@google.com470e71d2011-07-07 08:21:25 +000042 }
Yves Gerey665174f2018-06-19 15:03:05 +020043 ~Suppressor() { NS_FREE(state_); }
solenberg5e465c32015-12-08 13:22:33 -080044 NsState* state() { return state_; }
Yves Gerey665174f2018-06-19 15:03:05 +020045
solenberg5e465c32015-12-08 13:22:33 -080046 private:
47 NsState* state_ = nullptr;
48 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Suppressor);
49};
niklase@google.com470e71d2011-07-07 08:21:25 +000050
solenberg5e465c32015-12-08 13:22:33 -080051NoiseSuppressionImpl::NoiseSuppressionImpl(rtc::CriticalSection* crit)
52 : crit_(crit) {
peahdf3efa82015-11-28 12:35:15 -080053 RTC_DCHECK(crit);
54}
niklase@google.com470e71d2011-07-07 08:21:25 +000055
56NoiseSuppressionImpl::~NoiseSuppressionImpl() {}
57
Peter Kasting69558702016-01-12 16:26:35 -080058void NoiseSuppressionImpl::Initialize(size_t channels, int sample_rate_hz) {
solenberg5e465c32015-12-08 13:22:33 -080059 rtc::CritScope cs(crit_);
solenberg29e2f932015-12-16 01:18:15 -080060 channels_ = channels;
61 sample_rate_hz_ = sample_rate_hz;
kwiberg88788ad2016-02-19 07:04:49 -080062 std::vector<std::unique_ptr<Suppressor>> new_suppressors;
solenberg29e2f932015-12-16 01:18:15 -080063 if (enabled_) {
64 new_suppressors.resize(channels);
Peter Kasting69558702016-01-12 16:26:35 -080065 for (size_t i = 0; i < channels; i++) {
solenberg29e2f932015-12-16 01:18:15 -080066 new_suppressors[i].reset(new Suppressor(sample_rate_hz));
67 }
68 }
solenberg5e465c32015-12-08 13:22:33 -080069 suppressors_.swap(new_suppressors);
70 set_level(level_);
71}
72
solenberg29e2f932015-12-16 01:18:15 -080073void NoiseSuppressionImpl::AnalyzeCaptureAudio(AudioBuffer* audio) {
solenberg5e465c32015-12-08 13:22:33 -080074 RTC_DCHECK(audio);
aluebs@webrtc.orgfda2c2e2014-09-18 09:54:06 +000075#if defined(WEBRTC_NS_FLOAT)
solenberg5e465c32015-12-08 13:22:33 -080076 rtc::CritScope cs(crit_);
77 if (!enabled_) {
solenberg29e2f932015-12-16 01:18:15 -080078 return;
aluebs@webrtc.orgfda2c2e2014-09-18 09:54:06 +000079 }
aluebs@webrtc.orgfda2c2e2014-09-18 09:54:06 +000080
kwibergaf476c72016-11-28 15:21:39 -080081 RTC_DCHECK_GE(160, audio->num_frames_per_band());
Peter Kasting69558702016-01-12 16:26:35 -080082 RTC_DCHECK_EQ(suppressors_.size(), audio->num_channels());
solenberg5e465c32015-12-08 13:22:33 -080083 for (size_t i = 0; i < suppressors_.size(); i++) {
84 WebRtcNs_Analyze(suppressors_[i]->state(),
85 audio->split_bands_const_f(i)[kBand0To8kHz]);
aluebs@webrtc.orgfda2c2e2014-09-18 09:54:06 +000086 }
87#endif
aluebs@webrtc.orgfda2c2e2014-09-18 09:54:06 +000088}
89
solenberg29e2f932015-12-16 01:18:15 -080090void NoiseSuppressionImpl::ProcessCaptureAudio(AudioBuffer* audio) {
solenberg5e465c32015-12-08 13:22:33 -080091 RTC_DCHECK(audio);
peahdf3efa82015-11-28 12:35:15 -080092 rtc::CritScope cs(crit_);
solenberg5e465c32015-12-08 13:22:33 -080093 if (!enabled_) {
solenberg29e2f932015-12-16 01:18:15 -080094 return;
niklase@google.com470e71d2011-07-07 08:21:25 +000095 }
niklase@google.com470e71d2011-07-07 08:21:25 +000096
kwibergaf476c72016-11-28 15:21:39 -080097 RTC_DCHECK_GE(160, audio->num_frames_per_band());
Peter Kasting69558702016-01-12 16:26:35 -080098 RTC_DCHECK_EQ(suppressors_.size(), audio->num_channels());
solenberg5e465c32015-12-08 13:22:33 -080099 for (size_t i = 0; i < suppressors_.size(); i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000100#if defined(WEBRTC_NS_FLOAT)
Yves Gerey665174f2018-06-19 15:03:05 +0200101 WebRtcNs_Process(suppressors_[i]->state(), audio->split_bands_const_f(i),
102 audio->num_bands(), audio->split_bands_f(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000103#elif defined(WEBRTC_NS_FIXED)
Yves Gerey665174f2018-06-19 15:03:05 +0200104 WebRtcNsx_Process(suppressors_[i]->state(), audio->split_bands_const(i),
105 audio->num_bands(), audio->split_bands(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000106#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000107 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000108}
109
110int NoiseSuppressionImpl::Enable(bool enable) {
peahdf3efa82015-11-28 12:35:15 -0800111 rtc::CritScope cs(crit_);
solenberg29e2f932015-12-16 01:18:15 -0800112 if (enabled_ != enable) {
113 enabled_ = enable;
114 Initialize(channels_, sample_rate_hz_);
115 }
solenberg5e465c32015-12-08 13:22:33 -0800116 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000117}
118
119bool NoiseSuppressionImpl::is_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800120 rtc::CritScope cs(crit_);
solenberg5e465c32015-12-08 13:22:33 -0800121 return enabled_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000122}
123
124int NoiseSuppressionImpl::set_level(Level level) {
solenberg5e465c32015-12-08 13:22:33 -0800125 int policy = 1;
126 switch (level) {
127 case NoiseSuppression::kLow:
128 policy = 0;
129 break;
130 case NoiseSuppression::kModerate:
131 policy = 1;
132 break;
133 case NoiseSuppression::kHigh:
134 policy = 2;
135 break;
136 case NoiseSuppression::kVeryHigh:
137 policy = 3;
138 break;
139 default:
140 RTC_NOTREACHED();
niklase@google.com470e71d2011-07-07 08:21:25 +0000141 }
solenberg29e2f932015-12-16 01:18:15 -0800142 rtc::CritScope cs(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000143 level_ = level;
solenberg5e465c32015-12-08 13:22:33 -0800144 for (auto& suppressor : suppressors_) {
145 int error = NS_SET_POLICY(suppressor->state(), policy);
146 RTC_DCHECK_EQ(0, error);
147 }
148 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000149}
150
151NoiseSuppression::Level NoiseSuppressionImpl::level() const {
peahdf3efa82015-11-28 12:35:15 -0800152 rtc::CritScope cs(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000153 return level_;
154}
155
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000156float NoiseSuppressionImpl::speech_probability() const {
peahdf3efa82015-11-28 12:35:15 -0800157 rtc::CritScope cs(crit_);
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000158#if defined(WEBRTC_NS_FLOAT)
159 float probability_average = 0.0f;
solenberg5e465c32015-12-08 13:22:33 -0800160 for (auto& suppressor : suppressors_) {
161 probability_average +=
162 WebRtcNs_prior_speech_probability(suppressor->state());
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000163 }
pkasting25702cb2016-01-08 13:50:27 -0800164 if (!suppressors_.empty()) {
solenberg5e465c32015-12-08 13:22:33 -0800165 probability_average /= suppressors_.size();
166 }
167 return probability_average;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000168#elif defined(WEBRTC_NS_FIXED)
solenberg5e465c32015-12-08 13:22:33 -0800169 // TODO(peah): Returning error code as a float! Remove this.
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000170 // Currently not available for the fixed point implementation.
peahdf3efa82015-11-28 12:35:15 -0800171 return AudioProcessing::kUnsupportedFunctionError;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000172#endif
173}
Alejandro Luebsfa639f02016-02-09 11:24:32 -0800174
175std::vector<float> NoiseSuppressionImpl::NoiseEstimate() {
176 rtc::CritScope cs(crit_);
177 std::vector<float> noise_estimate;
178#if defined(WEBRTC_NS_FLOAT)
Alejandro Luebs3b149962016-04-01 13:54:36 -0700179 const float kNumChannelsFraction = 1.f / suppressors_.size();
Alejandro Luebsfa639f02016-02-09 11:24:32 -0800180 noise_estimate.assign(WebRtcNs_num_freq(), 0.f);
181 for (auto& suppressor : suppressors_) {
182 const float* noise = WebRtcNs_noise_estimate(suppressor->state());
183 for (size_t i = 0; i < noise_estimate.size(); ++i) {
Alejandro Luebs3b149962016-04-01 13:54:36 -0700184 noise_estimate[i] += kNumChannelsFraction * noise[i];
Alejandro Luebsfa639f02016-02-09 11:24:32 -0800185 }
186 }
187#elif defined(WEBRTC_NS_FIXED)
Alejandro Luebsfa639f02016-02-09 11:24:32 -0800188 noise_estimate.assign(WebRtcNsx_num_freq(), 0.f);
189 for (auto& suppressor : suppressors_) {
Alejandro Luebs3b149962016-04-01 13:54:36 -0700190 int q_noise;
Yves Gerey665174f2018-06-19 15:03:05 +0200191 const uint32_t* noise =
192 WebRtcNsx_noise_estimate(suppressor->state(), &q_noise);
Alejandro Luebs3b149962016-04-01 13:54:36 -0700193 const float kNormalizationFactor =
194 1.f / ((1 << q_noise) * suppressors_.size());
Alejandro Luebsfa639f02016-02-09 11:24:32 -0800195 for (size_t i = 0; i < noise_estimate.size(); ++i) {
Alejandro Luebs3b149962016-04-01 13:54:36 -0700196 noise_estimate[i] += kNormalizationFactor * noise[i];
Alejandro Luebsfa639f02016-02-09 11:24:32 -0800197 }
198 }
199#endif
200 return noise_estimate;
201}
202
Alex Luebs57ae8292016-03-09 16:24:34 +0100203size_t NoiseSuppressionImpl::num_noise_bins() {
204#if defined(WEBRTC_NS_FLOAT)
205 return WebRtcNs_num_freq();
206#elif defined(WEBRTC_NS_FIXED)
207 return WebRtcNsx_num_freq();
208#endif
209}
210
niklase@google.com470e71d2011-07-07 08:21:25 +0000211} // namespace webrtc