blob: b2c88536ca2e6ccf04d320b07b721094a7fd2533 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
saza0bad15f2019-10-16 11:46:11 +02002 * Copyright (c) 2019 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
Per Åhgren0cbb58e2019-10-29 22:59:44 +010011#include "modules/audio_processing/legacy_noise_suppression.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"
niklase@google.com470e71d2011-07-07 08:21:25 +000015#if defined(WEBRTC_NS_FLOAT)
Per Åhgren0cbb58e2019-10-29 22:59:44 +010016#include "modules/audio_processing/legacy_ns/noise_suppression.h"
Yves Gerey988cc082018-10-23 12:03:01 +020017
solenberg5e465c32015-12-08 13:22:33 -080018#define NS_CREATE WebRtcNs_Create
19#define NS_FREE WebRtcNs_Free
20#define NS_INIT WebRtcNs_Init
21#define NS_SET_POLICY WebRtcNs_set_policy
22typedef NsHandle NsState;
niklase@google.com470e71d2011-07-07 08:21:25 +000023#elif defined(WEBRTC_NS_FIXED)
Per Åhgren0cbb58e2019-10-29 22:59:44 +010024#include "modules/audio_processing/legacy_ns/noise_suppression_x.h"
Yves Gerey988cc082018-10-23 12:03:01 +020025
solenberg5e465c32015-12-08 13:22:33 -080026#define NS_CREATE WebRtcNsx_Create
27#define NS_FREE WebRtcNsx_Free
28#define NS_INIT WebRtcNsx_Init
29#define NS_SET_POLICY WebRtcNsx_set_policy
30typedef NsxHandle NsState;
niklase@google.com470e71d2011-07-07 08:21:25 +000031#endif
32
niklase@google.com470e71d2011-07-07 08:21:25 +000033namespace webrtc {
saza0bad15f2019-10-16 11:46:11 +020034namespace {
35int NoiseSuppressionLevelToPolicy(NoiseSuppression::Level level) {
36 switch (level) {
37 case NoiseSuppression::Level::kLow:
38 return 0;
39 case NoiseSuppression::Level::kModerate:
40 return 1;
41 case NoiseSuppression::Level::kHigh:
42 return 2;
43 case NoiseSuppression::Level::kVeryHigh:
44 return 3;
45 default:
46 RTC_NOTREACHED();
47 }
48 return 1;
49}
50} // namespace
51
52class NoiseSuppression::Suppressor {
solenberg5e465c32015-12-08 13:22:33 -080053 public:
54 explicit Suppressor(int sample_rate_hz) {
55 state_ = NS_CREATE();
56 RTC_CHECK(state_);
57 int error = NS_INIT(state_, sample_rate_hz);
58 RTC_DCHECK_EQ(0, error);
niklase@google.com470e71d2011-07-07 08:21:25 +000059 }
Yves Gerey665174f2018-06-19 15:03:05 +020060 ~Suppressor() { NS_FREE(state_); }
saza0bad15f2019-10-16 11:46:11 +020061
62 Suppressor(Suppressor&) = delete;
63 Suppressor& operator=(Suppressor&) = delete;
64
solenberg5e465c32015-12-08 13:22:33 -080065 NsState* state() { return state_; }
Yves Gerey665174f2018-06-19 15:03:05 +020066
solenberg5e465c32015-12-08 13:22:33 -080067 private:
68 NsState* state_ = nullptr;
solenberg5e465c32015-12-08 13:22:33 -080069};
niklase@google.com470e71d2011-07-07 08:21:25 +000070
saza0bad15f2019-10-16 11:46:11 +020071NoiseSuppression::NoiseSuppression(size_t channels,
72 int sample_rate_hz,
73 Level level) {
74 const int policy = NoiseSuppressionLevelToPolicy(level);
75 for (size_t i = 0; i < channels; ++i) {
76 suppressors_.push_back(std::make_unique<Suppressor>(sample_rate_hz));
77 int error = NS_SET_POLICY(suppressors_[i]->state(), policy);
78 RTC_DCHECK_EQ(0, error);
solenberg29e2f932015-12-16 01:18:15 -080079 }
solenberg5e465c32015-12-08 13:22:33 -080080}
81
saza0bad15f2019-10-16 11:46:11 +020082NoiseSuppression::~NoiseSuppression() {}
83
84void NoiseSuppression::AnalyzeCaptureAudio(AudioBuffer* audio) {
solenberg5e465c32015-12-08 13:22:33 -080085 RTC_DCHECK(audio);
aluebs@webrtc.orgfda2c2e2014-09-18 09:54:06 +000086#if defined(WEBRTC_NS_FLOAT)
kwibergaf476c72016-11-28 15:21:39 -080087 RTC_DCHECK_GE(160, audio->num_frames_per_band());
Peter Kasting69558702016-01-12 16:26:35 -080088 RTC_DCHECK_EQ(suppressors_.size(), audio->num_channels());
solenberg5e465c32015-12-08 13:22:33 -080089 for (size_t i = 0; i < suppressors_.size(); i++) {
90 WebRtcNs_Analyze(suppressors_[i]->state(),
Per Åhgrend47941e2019-08-22 11:51:13 +020091 audio->split_bands_const(i)[kBand0To8kHz]);
aluebs@webrtc.orgfda2c2e2014-09-18 09:54:06 +000092 }
93#endif
aluebs@webrtc.orgfda2c2e2014-09-18 09:54:06 +000094}
95
saza0bad15f2019-10-16 11:46:11 +020096void NoiseSuppression::ProcessCaptureAudio(AudioBuffer* audio) {
solenberg5e465c32015-12-08 13:22:33 -080097 RTC_DCHECK(audio);
kwibergaf476c72016-11-28 15:21:39 -080098 RTC_DCHECK_GE(160, audio->num_frames_per_band());
Peter Kasting69558702016-01-12 16:26:35 -080099 RTC_DCHECK_EQ(suppressors_.size(), audio->num_channels());
solenberg5e465c32015-12-08 13:22:33 -0800100 for (size_t i = 0; i < suppressors_.size(); i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000101#if defined(WEBRTC_NS_FLOAT)
Per Åhgrend47941e2019-08-22 11:51:13 +0200102 WebRtcNs_Process(suppressors_[i]->state(), audio->split_bands_const(i),
103 audio->num_bands(), audio->split_bands(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000104#elif defined(WEBRTC_NS_FIXED)
Per Åhgren928146f2019-08-20 09:19:21 +0200105 int16_t split_band_data[AudioBuffer::kMaxNumBands]
106 [AudioBuffer::kMaxSplitFrameLength];
107 int16_t* split_bands[AudioBuffer::kMaxNumBands] = {
108 split_band_data[0], split_band_data[1], split_band_data[2]};
Per Åhgrend47941e2019-08-22 11:51:13 +0200109 audio->ExportSplitChannelData(i, split_bands);
Per Åhgren928146f2019-08-20 09:19:21 +0200110
111 WebRtcNsx_Process(suppressors_[i]->state(), split_bands, audio->num_bands(),
112 split_bands);
113
Per Åhgrend47941e2019-08-22 11:51:13 +0200114 audio->ImportSplitChannelData(i, split_bands);
niklase@google.com470e71d2011-07-07 08:21:25 +0000115#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000116 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000117}
118
saza0bad15f2019-10-16 11:46:11 +0200119float NoiseSuppression::speech_probability() const {
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000120#if defined(WEBRTC_NS_FLOAT)
121 float probability_average = 0.0f;
solenberg5e465c32015-12-08 13:22:33 -0800122 for (auto& suppressor : suppressors_) {
123 probability_average +=
124 WebRtcNs_prior_speech_probability(suppressor->state());
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000125 }
pkasting25702cb2016-01-08 13:50:27 -0800126 if (!suppressors_.empty()) {
solenberg5e465c32015-12-08 13:22:33 -0800127 probability_average /= suppressors_.size();
128 }
129 return probability_average;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000130#elif defined(WEBRTC_NS_FIXED)
solenberg5e465c32015-12-08 13:22:33 -0800131 // TODO(peah): Returning error code as a float! Remove this.
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000132 // Currently not available for the fixed point implementation.
peahdf3efa82015-11-28 12:35:15 -0800133 return AudioProcessing::kUnsupportedFunctionError;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000134#endif
135}
Alejandro Luebsfa639f02016-02-09 11:24:32 -0800136
saza0bad15f2019-10-16 11:46:11 +0200137std::vector<float> NoiseSuppression::NoiseEstimate() {
Alejandro Luebsfa639f02016-02-09 11:24:32 -0800138 std::vector<float> noise_estimate;
139#if defined(WEBRTC_NS_FLOAT)
Alejandro Luebs3b149962016-04-01 13:54:36 -0700140 const float kNumChannelsFraction = 1.f / suppressors_.size();
Alejandro Luebsfa639f02016-02-09 11:24:32 -0800141 noise_estimate.assign(WebRtcNs_num_freq(), 0.f);
142 for (auto& suppressor : suppressors_) {
143 const float* noise = WebRtcNs_noise_estimate(suppressor->state());
144 for (size_t i = 0; i < noise_estimate.size(); ++i) {
Alejandro Luebs3b149962016-04-01 13:54:36 -0700145 noise_estimate[i] += kNumChannelsFraction * noise[i];
Alejandro Luebsfa639f02016-02-09 11:24:32 -0800146 }
147 }
148#elif defined(WEBRTC_NS_FIXED)
Alejandro Luebsfa639f02016-02-09 11:24:32 -0800149 noise_estimate.assign(WebRtcNsx_num_freq(), 0.f);
150 for (auto& suppressor : suppressors_) {
Alejandro Luebs3b149962016-04-01 13:54:36 -0700151 int q_noise;
Yves Gerey665174f2018-06-19 15:03:05 +0200152 const uint32_t* noise =
153 WebRtcNsx_noise_estimate(suppressor->state(), &q_noise);
Alejandro Luebs3b149962016-04-01 13:54:36 -0700154 const float kNormalizationFactor =
155 1.f / ((1 << q_noise) * suppressors_.size());
Alejandro Luebsfa639f02016-02-09 11:24:32 -0800156 for (size_t i = 0; i < noise_estimate.size(); ++i) {
Alejandro Luebs3b149962016-04-01 13:54:36 -0700157 noise_estimate[i] += kNormalizationFactor * noise[i];
Alejandro Luebsfa639f02016-02-09 11:24:32 -0800158 }
159 }
160#endif
161 return noise_estimate;
162}
163
saza0bad15f2019-10-16 11:46:11 +0200164size_t NoiseSuppression::num_noise_bins() {
Alex Luebs57ae8292016-03-09 16:24:34 +0100165#if defined(WEBRTC_NS_FLOAT)
166 return WebRtcNs_num_freq();
167#elif defined(WEBRTC_NS_FIXED)
168 return WebRtcNsx_num_freq();
169#endif
170}
171
niklase@google.com470e71d2011-07-07 08:21:25 +0000172} // namespace webrtc