Index: webrtc/modules/audio_processing/rms_level.cc |
diff --git a/webrtc/modules/audio_processing/rms_level.cc b/webrtc/modules/audio_processing/rms_level.cc |
index 957a7b5839b9d607f5120567d2b67939333cdc2e..f77357a0006d9d8fcaa5ba5c277f3220330ba73f 100644 |
--- a/webrtc/modules/audio_processing/rms_level.cc |
+++ b/webrtc/modules/audio_processing/rms_level.cc |
@@ -11,52 +11,98 @@ |
#include "webrtc/modules/audio_processing/rms_level.h" |
#include <math.h> |
+#include <algorithm> |
+#include <numeric> |
#include "webrtc/base/checks.h" |
namespace webrtc { |
+namespace { |
+static constexpr float kMaxSquaredLevel = 32768 * 32768; |
+static constexpr int kMinLevelDb = 127; |
+// kMinLevel is the level corresponding to kMinLevelDb, that is 10^(-127/10). |
+static constexpr float kMinLevel = 1.995262314968883e-13f; |
-static const float kMaxSquaredLevel = 32768 * 32768; |
+// Calculates the normalized RMS value from a mean square value. The input |
+// should be the sum of squared samples divided by the number of samples. The |
+// value will be normalized to full range before computing the RMS, wich is |
+// returned as a negated dBfs. That is, 0 is full amplitude while 127 is very |
+// faint. |
+int ComputeRms(float mean_square) { |
+ if (mean_square <= kMinLevel * kMaxSquaredLevel) { |
+ // Very faint; simply return the minimum value. |
+ return kMinLevelDb; |
+ } |
+ // Normalize by the max level. |
+ const float mean_square_norm = mean_square / kMaxSquaredLevel; |
+ RTC_DCHECK_GT(mean_square_norm, kMinLevel); |
+ // 20log_10(x^0.5) = 10log_10(x) |
+ const float rms = 10.f * log10(mean_square_norm); |
+ RTC_DCHECK_LE(rms, 0.f); |
+ RTC_DCHECK_GT(rms, -kMinLevelDb); |
+ // Return the negated value. |
+ return static_cast<int>(-rms + 0.5f); |
+} |
+} // namespace |
-RMSLevel::RMSLevel() |
- : sum_square_(0), |
- sample_count_(0) {} |
+RmsLevel::RmsLevel() { |
+ Reset(); |
+} |
-RMSLevel::~RMSLevel() {} |
+RmsLevel::~RmsLevel() = default; |
-void RMSLevel::Reset() { |
- sum_square_ = 0; |
+void RmsLevel::Reset() { |
+ sum_square_ = 0.f; |
sample_count_ = 0; |
+ max_sum_square_ = 0.f; |
+ block_size_ = rtc::Optional<size_t>(); |
} |
-void RMSLevel::Process(const int16_t* data, size_t length) { |
- for (size_t i = 0; i < length; ++i) { |
- sum_square_ += data[i] * data[i]; |
+void RmsLevel::Analyze(rtc::ArrayView<const int16_t> data) { |
+ if (data.empty()) { |
+ return; |
} |
- sample_count_ += length; |
+ |
+ CheckBlockSize(data.size()); |
+ |
+ const float sum_square = |
+ std::accumulate(data.begin(), data.end(), 0.f, |
+ [](float a, int16_t b) { return a + b * b; }); |
+ RTC_DCHECK_GE(sum_square, 0.f); |
+ sum_square_ += sum_square; |
+ sample_count_ += data.size(); |
+ |
+ max_sum_square_ = std::max(max_sum_square_, sum_square); |
} |
-void RMSLevel::ProcessMuted(size_t length) { |
+void RmsLevel::AnalyzeMuted(size_t length) { |
+ CheckBlockSize(length); |
sample_count_ += length; |
} |
-int RMSLevel::RMS() { |
- if (sample_count_ == 0 || sum_square_ == 0) { |
- Reset(); |
- return kMinLevel; |
- } |
- |
- // Normalize by the max level. |
- float rms = sum_square_ / (sample_count_ * kMaxSquaredLevel); |
- // 20log_10(x^0.5) = 10log_10(x) |
- rms = 10 * log10(rms); |
- RTC_DCHECK_LE(rms, 0); |
- if (rms < -kMinLevel) |
- rms = -kMinLevel; |
+int RmsLevel::Average() { |
+ int rms = (sample_count_ == 0) ? kMinLevelDb |
+ : ComputeRms(sum_square_ / sample_count_); |
+ Reset(); |
+ return rms; |
+} |
- rms = -rms; |
+RmsLevel::Levels RmsLevel::AverageAndPeak() { |
+ // Note that block_size_ should by design always be non-empty when |
+ // sample_count_ != 0. Also, the * operator of rtc::Optional enforces this |
+ // with a DCHECK. |
+ Levels levels = (sample_count_ == 0) |
+ ? Levels{kMinLevelDb, kMinLevelDb} |
+ : Levels{ComputeRms(sum_square_ / sample_count_), |
+ ComputeRms(max_sum_square_ / *block_size_)}; |
Reset(); |
- return static_cast<int>(rms + 0.5); |
+ return levels; |
} |
+void RmsLevel::CheckBlockSize(size_t block_size) { |
+ if (block_size_ != rtc::Optional<size_t>(block_size)) { |
+ Reset(); |
+ block_size_ = rtc::Optional<size_t>(block_size); |
+ } |
+} |
} // namespace webrtc |