| 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_DCHECK_EQ(X_p, &X[0]); | 
|  | 48   spectrum[0] = (*X_p) * (*X_p); | 
|  | 49   ++X_p; | 
|  | 50   RTC_DCHECK_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_DCHECK_EQ(X_p, &X[2 * k]); | 
|  | 55     spectrum[k] = (*X_p) * (*X_p); | 
|  | 56     ++X_p; | 
|  | 57     RTC_DCHECK_EQ(X_p, &X[2 * k + 1]); | 
|  | 58     spectrum[k] += (*X_p) * (*X_p); | 
|  | 59   } | 
|  | 60 } | 
|  | 61 | 
|  | 62 webrtc::SignalClassifier::SignalType ClassifySignal( | 
|  | 63     rtc::ArrayView<const float> signal_spectrum, | 
|  | 64     rtc::ArrayView<const float> noise_spectrum, | 
|  | 65     ApmDataDumper* data_dumper) { | 
|  | 66   int num_stationary_bands = 0; | 
|  | 67   int num_highly_nonstationary_bands = 0; | 
|  | 68 | 
|  | 69   // Detect stationary and highly nonstationary bands. | 
|  | 70   for (size_t k = 1; k < 40; k++) { | 
|  | 71     if (signal_spectrum[k] < 3 * noise_spectrum[k] && | 
|  | 72         signal_spectrum[k] * 3 > noise_spectrum[k]) { | 
|  | 73       ++num_stationary_bands; | 
|  | 74     } else if (signal_spectrum[k] > 9 * noise_spectrum[k]) { | 
|  | 75       ++num_highly_nonstationary_bands; | 
|  | 76     } | 
|  | 77   } | 
|  | 78 | 
|  | 79   data_dumper->DumpRaw("lc_num_stationary_bands", 1, &num_stationary_bands); | 
|  | 80   data_dumper->DumpRaw("lc_num_highly_nonstationary_bands", 1, | 
|  | 81                        &num_highly_nonstationary_bands); | 
|  | 82 | 
|  | 83   // Use the detected number of bands to classify the overall signal | 
|  | 84   // stationarity. | 
|  | 85   if (num_stationary_bands > 15) { | 
|  | 86     return SignalClassifier::SignalType::kStationary; | 
|  | 87   } else if (num_highly_nonstationary_bands > 15) { | 
|  | 88     return SignalClassifier::SignalType::kHighlyNonStationary; | 
|  | 89   } else { | 
|  | 90     return SignalClassifier::SignalType::kNonStationary; | 
|  | 91   } | 
|  | 92 } | 
|  | 93 | 
|  | 94 }  // namespace | 
|  | 95 | 
|  | 96 void SignalClassifier::FrameExtender::ExtendFrame( | 
|  | 97     rtc::ArrayView<const float> x, | 
|  | 98     rtc::ArrayView<float> x_extended) { | 
|  | 99   RTC_DCHECK_EQ(x_old_.size() + x.size(), x_extended.size()); | 
|  | 100   std::copy(x_old_.data(), x_old_.data() + x_old_.size(), x_extended.data()); | 
|  | 101   std::copy(x.data(), x.data() + x.size(), x_extended.data() + x_old_.size()); | 
|  | 102   std::copy(x_extended.data() + x_extended.size() - x_old_.size(), | 
|  | 103             x_extended.data() + x_extended.size(), x_old_.data()); | 
|  | 104 } | 
|  | 105 | 
|  | 106 SignalClassifier::SignalClassifier(ApmDataDumper* data_dumper) | 
|  | 107     : data_dumper_(data_dumper), | 
|  | 108       down_sampler_(data_dumper_), | 
|  | 109       noise_spectrum_estimator_(data_dumper_) { | 
|  | 110   Initialize(AudioProcessing::kSampleRate48kHz); | 
|  | 111 } | 
|  | 112 SignalClassifier::~SignalClassifier() {} | 
|  | 113 | 
|  | 114 void SignalClassifier::Initialize(int sample_rate_hz) { | 
|  | 115   aec_rdft_init(); | 
|  | 116   down_sampler_.Initialize(sample_rate_hz); | 
|  | 117   noise_spectrum_estimator_.Initialize(); | 
|  | 118   frame_extender_.reset(new FrameExtender(80, 128)); | 
|  | 119   sample_rate_hz_ = sample_rate_hz; | 
|  | 120   initialization_frames_left_ = 2; | 
|  | 121   consistent_classification_counter_ = 3; | 
|  | 122   last_signal_type_ = SignalClassifier::SignalType::kNonStationary; | 
|  | 123 } | 
|  | 124 | 
|  | 125 void SignalClassifier::Analyze(const AudioBuffer& audio, | 
|  | 126                                SignalType* signal_type) { | 
|  | 127   RTC_DCHECK_EQ(audio.num_frames(), static_cast<size_t>(sample_rate_hz_ / 100)); | 
|  | 128 | 
|  | 129   // Compute the signal power spectrum. | 
|  | 130   float downsampled_frame[80]; | 
|  | 131   down_sampler_.DownSample(rtc::ArrayView<const float>( | 
|  | 132                                audio.channels_const_f()[0], audio.num_frames()), | 
|  | 133                            downsampled_frame); | 
|  | 134   float extended_frame[128]; | 
|  | 135   frame_extender_->ExtendFrame(downsampled_frame, extended_frame); | 
|  | 136   RemoveDcLevel(extended_frame); | 
|  | 137   float signal_spectrum[65]; | 
|  | 138   PowerSpectrum(extended_frame, signal_spectrum); | 
|  | 139 | 
|  | 140   // Classify the signal based on the estimate of the noise spectrum and the | 
|  | 141   // signal spectrum estimate. | 
|  | 142   *signal_type = ClassifySignal(signal_spectrum, | 
|  | 143                                 noise_spectrum_estimator_.GetNoiseSpectrum(), | 
|  | 144                                 data_dumper_); | 
|  | 145 | 
|  | 146   // Update the noise spectrum based on the signal spectrum. | 
|  | 147   noise_spectrum_estimator_.Update(signal_spectrum, | 
|  | 148                                    initialization_frames_left_ > 0); | 
|  | 149 | 
|  | 150   // Update the number of frames until a reliable signal spectrum is achieved. | 
|  | 151   initialization_frames_left_ = std::max(0, initialization_frames_left_ - 1); | 
|  | 152 | 
|  | 153   if (last_signal_type_ == *signal_type) { | 
|  | 154     consistent_classification_counter_ = | 
|  | 155         std::max(0, consistent_classification_counter_ - 1); | 
|  | 156   } else { | 
|  | 157     last_signal_type_ = *signal_type; | 
|  | 158     consistent_classification_counter_ = 3; | 
|  | 159   } | 
|  | 160 | 
|  | 161   if (consistent_classification_counter_ > 0) { | 
|  | 162     *signal_type = SignalClassifier::SignalType::kNonStationary; | 
|  | 163   } | 
|  | 164 } | 
|  | 165 | 
|  | 166 }  // namespace webrtc | 
| OLD | NEW | 
|---|