Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | |
| 3 * | |
| 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 | |
| 11 #include "webrtc/modules/audio_processing/level_controller/signal_classifier.h" | |
| 12 | |
| 13 #include <algorithm> | |
| 14 #include <numeric> | |
| 15 #include <vector> | |
| 16 | |
| 17 #include "webrtc/base/array_view.h" | |
| 18 #include "webrtc/base/constructormagic.h" | |
| 19 #include "webrtc/modules/audio_processing/aec/aec_rdft.h" | |
| 20 #include "webrtc/modules/audio_processing/audio_buffer.h" | |
| 21 #include "webrtc/modules/audio_processing/level_controller/down_sampler.h" | |
| 22 #include "webrtc/modules/audio_processing/level_controller/noise_spectrum_estima tor.h" | |
| 23 #include "webrtc/modules/audio_processing/logging/apm_data_dumper.h" | |
| 24 | |
| 25 namespace webrtc { | |
| 26 namespace { | |
| 27 | |
| 28 void RemoveDcLevel(rtc::ArrayView<float> x) { | |
| 29 RTC_DCHECK_LT(0u, x.size()); | |
| 30 float mean = std::accumulate(x.data(), x.data() + x.size(), 0.f); | |
| 31 mean /= x.size(); | |
| 32 | |
| 33 for (float& v : x) { | |
| 34 v -= mean; | |
| 35 } | |
| 36 } | |
| 37 | |
| 38 void PowerSpectrum(rtc::ArrayView<const float> x, | |
| 39 rtc::ArrayView<float> spectrum) { | |
| 40 RTC_DCHECK_EQ(65u, spectrum.size()); | |
| 41 RTC_DCHECK_EQ(128u, x.size()); | |
| 42 float X[128]; | |
| 43 std::copy(x.data(), x.data() + x.size(), X); | |
| 44 aec_rdft_forward_128(X); | |
| 45 | |
| 46 float* X_p = X; | |
| 47 RTC_CHECK_EQ(X_p, &X[0]); | |
|
hlundin-webrtc
2016/06/27 11:21:17
Use DCHECK here and in the places below.
peah-webrtc
2016/06/27 22:51:50
Done.
| |
| 48 spectrum[0] = (*X_p) * (*X_p); | |
| 49 ++X_p; | |
| 50 RTC_CHECK_EQ(X_p, &X[1]); | |
| 51 spectrum[64] = (*X_p) * (*X_p); | |
| 52 for (int k = 1; k < 64; ++k) { | |
| 53 ++X_p; | |
| 54 RTC_CHECK_EQ(X_p, &X[2 * k]); | |
| 55 spectrum[k] += (*X_p) * (*X_p); | |
|
hlundin-webrtc
2016/06/27 11:21:17
You are adding to an undefined value here. Use = i
peah-webrtc
2016/06/27 22:51:50
Great find!!!!!
Done.
| |
| 56 ++X_p; | |
| 57 RTC_CHECK_EQ(X_p, &X[2 * k + 1]); | |
| 58 spectrum[k] += (*X_p) * (*X_p); | |
| 59 } | |
| 60 } | |
| 61 | |
| 62 void ClassifySignal(rtc::ArrayView<const float> signal_spectrum, | |
| 63 rtc::ArrayView<const float> noise_spectrum, | |
| 64 ApmDataDumper* data_dumper, | |
| 65 SignalClassifier::SignalType* signal_type) { | |
|
hlundin-webrtc
2016/06/27 11:21:17
Return the signal type instead of having it as an
peah-webrtc
2016/06/27 22:51:50
Done.
| |
| 66 int num_stationary_bands = 0; | |
| 67 int num_highly_nonstationary_bands = 0; | |
| 68 | |
| 69 // Detect stationary and highly nonstationary bands. | |
| 70 for (int k = 1; k < 40; k++) { | |
|
hlundin-webrtc
2016/06/27 11:21:17
size_t
peah-webrtc
2016/06/27 22:51:50
Done.
| |
| 71 if (signal_spectrum[k] < 3 * noise_spectrum[k]) { | |
| 72 ++num_stationary_bands; | |
| 73 } else if (signal_spectrum[k] > 9 * noise_spectrum[k]) { | |
| 74 ++num_highly_nonstationary_bands; | |
| 75 } | |
| 76 } | |
| 77 | |
| 78 // Use the detected number of bands to classify the overall signal | |
| 79 // stationarity. | |
| 80 if (num_stationary_bands > 20) { | |
| 81 *signal_type = SignalClassifier::SignalType::kStationary; | |
| 82 } else if (num_highly_nonstationary_bands > 15) { | |
| 83 *signal_type = SignalClassifier::SignalType::kHighlyNonStationary; | |
| 84 } else { | |
| 85 *signal_type = SignalClassifier::SignalType::kNonStationary; | |
| 86 } | |
| 87 | |
| 88 data_dumper->DumpRaw("lc_num_stationary_bands", 1, &num_stationary_bands); | |
| 89 data_dumper->DumpRaw("lc_num_highly_nonstationary_bands", 1, | |
| 90 &num_highly_nonstationary_bands); | |
| 91 } | |
| 92 | |
| 93 } // namespace | |
| 94 | |
| 95 class FrameExtender { | |
|
hlundin-webrtc
2016/06/27 11:21:17
Why is this outside of the unnamed namespace?
peah-webrtc
2016/06/27 22:51:50
I think it needs to be outside of that for the rea
hlundin-webrtc
2016/06/28 11:29:01
Oh, I see. Then I think I would prefer to have it
peah-webrtc
2016/06/28 22:19:37
Done.
| |
| 96 public: | |
| 97 FrameExtender(size_t frame_size, size_t extended_frame_size) | |
| 98 : x_old_(extended_frame_size - frame_size, 0.f) {} | |
| 99 | |
| 100 void ExtendFrame(rtc::ArrayView<const float> x, | |
| 101 rtc::ArrayView<float> x_extended) { | |
| 102 RTC_DCHECK_EQ(x_old_.size() + x.size(), x_extended.size()); | |
| 103 std::copy(x_old_.data(), x_old_.data() + x_old_.size(), x_extended.data()); | |
| 104 std::copy(x.data(), x.data() + x.size(), x_extended.data() + x_old_.size()); | |
| 105 std::copy(x_extended.data() + x_extended.size() - x_old_.size(), | |
| 106 x_extended.data() + x_extended.size(), x_old_.data()); | |
| 107 } | |
| 108 | |
| 109 private: | |
| 110 std::vector<float> x_old_; | |
| 111 | |
| 112 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(FrameExtender); | |
| 113 }; | |
| 114 | |
| 115 SignalClassifier::SignalClassifier(ApmDataDumper* data_dumper) | |
| 116 : data_dumper_(data_dumper) { | |
| 117 Initialize(AudioProcessing::kSampleRate48kHz); | |
| 118 } | |
| 119 SignalClassifier::~SignalClassifier() {} | |
| 120 | |
| 121 void SignalClassifier::Initialize(int sample_rate_hz) { | |
| 122 aec_rdft_init(); | |
| 123 down_sampler_.reset(new DownSampler(data_dumper_, sample_rate_hz)); | |
| 124 frame_extender_.reset(new FrameExtender(80, 128)); | |
| 125 noise_spectrum_estimator_.reset(new NoiseSpectrumEstimator(data_dumper_)); | |
| 126 sample_rate_hz_ = sample_rate_hz; | |
| 127 initialization_frames_left_ = 2; | |
| 128 } | |
| 129 | |
| 130 void SignalClassifier::Analyze(const AudioBuffer& audio, | |
| 131 SignalType* signal_type) { | |
| 132 // Compute the signal power spectrum. | |
|
hlundin-webrtc
2016/06/27 11:21:17
You may want to DCHECK some properties of the Audi
peah-webrtc
2016/06/27 22:51:50
That would make sense, but I think AudioBuffer doe
hlundin-webrtc
2016/06/28 11:29:01
Can't you just check that the number of samples in
peah-webrtc
2016/06/28 22:19:37
True!
Good point!
Done.
| |
| 133 float downsampled_frame[80]; | |
| 134 down_sampler_->DownSample( | |
| 135 rtc::ArrayView<const float>(audio.channels_const_f()[0], | |
| 136 audio.num_frames()), | |
| 137 downsampled_frame); | |
| 138 float extended_frame[128]; | |
| 139 frame_extender_->ExtendFrame(downsampled_frame, extended_frame); | |
| 140 RemoveDcLevel(extended_frame); | |
| 141 float signal_spectrum[65]; | |
| 142 PowerSpectrum(extended_frame, signal_spectrum); | |
| 143 | |
| 144 // Classify the signal based on the estimate of the noise spectrum and the | |
| 145 // signal spectrum estimate. | |
| 146 ClassifySignal(signal_spectrum, noise_spectrum_estimator_->GetNoiseSpectrum(), | |
| 147 data_dumper_, signal_type); | |
| 148 | |
| 149 // Update the noise spectrum based on the signal spectrum. | |
| 150 noise_spectrum_estimator_->Update(signal_spectrum, | |
| 151 initialization_frames_left_ > 0); | |
| 152 | |
| 153 // Update the number of frames until a reliable signal spectrum is achieved. | |
| 154 initialization_frames_left_ = std::max(0, initialization_frames_left_ - 1); | |
| 155 } | |
| 156 | |
| 157 } // namespace webrtc | |
| OLD | NEW |