HART  0.2.0
High level Audio Regression and Testing
Loading...
Searching...
No Matches
hart_rms.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cmath> // sqrt()
4
8#include "metrics/hart_metric_query.hpp"
9#include "metrics/hart_metrics_common.hpp" // ChannelSubsets
10#include "hart_slice.hpp"
11#include "hart_units.hpp" // Unit
12#include "hart_utils.hpp" // nan(), ratioToDecibels()
13
14namespace hart
15{
16
17/// @brief Calculates root mean square (RMS) of a signal
18/// @details RMS a metric that expresses the average magnitude, or effective
19/// energy level, of an audio signal over time. It is commonly used to estimate
20/// perceived loudness, and to measure overall signal level.
21///
22/// RMS is calculated this way:
23/// @f[
24/// \mathrm{RMS} = \sqrt{\frac{1}{N} \sum_{n=0}^{N-1} x[n]^2}
25/// @f]
26/// (RMS = sqrt((1 / N) * sum(x[n] ** 2))),
27///
28/// where x[n] is audio sample value from one channel, and N
29/// is number of frames in the provided buffer.
30///
31/// Can be expressed as ratio or decibels, supports `Unit:::native`,
32/// `Unit::linear`, `Unit::dB` units. Value in decibels is
33/// calculated as a ratio, not power.
34///
35/// @tparam SampleType
36/// @param buffer Audio buffer to calculate RMS at
37/// @return Chainable `MetricQuery` object, which calculates RMS as linear ratio
38/// or decibels
39/// @ingroup Metrics
40template <typename SampleType>
41MetricQuery<double> rms (const AudioBuffer<SampleType>& buffer)
42{
43 typename MetricQuery<double>::SingleChannelMetricEvaluator evaluator =
44 [&buffer]
45 (size_t channel, Slice slice, Unit requestedUnit)
46 -> double
47 {
48 hassert (channel < buffer.getNumChannels());
49
50 if (slice.isEmpty())
51 return hart::nan<double>();
52
53 const auto sliceFrameIndices = buffer.getFrameIndices (slice);
54 const size_t sliceStart = sliceFrameIndices.first;
55 const size_t sliceStop = sliceFrameIndices.second;
56 const size_t numFrames = sliceStop - sliceStart;
57 hassert (numFrames != 0);
58 hassert (sliceStart < sliceStop);
59 hassert (sliceStop <= buffer.getNumFrames());
60
61 const SampleType* channelData = buffer[channel];
62 AccurateSum<SampleType> sumSquares;
63
64 for (size_t frame = sliceStart; frame < sliceStop; ++frame)
65 {
66 const SampleType x = channelData[frame];
67 sumSquares += x * x;
68 }
69
70 const double rmsLinear = std::sqrt (sumSquares.template get<double>() / numFrames);
71
72 switch (requestedUnit)
73 {
74 case Unit::native:
75 case Unit::linear: return rmsLinear;
76
77 case Unit::dB: return hart::ratioToDecibels (rmsLinear);
78
79 default: HART_THROW_OR_RETURN (hart::UnitError, "Unsupported unit", hart::nan<double>());
80 }
81 };
82
83 const size_t numChannels = buffer.getNumChannels();
84 return MetricQuery<double> (
85 std::move (evaluator),
86 numChannels,
88 );
89}
90
91} // namespace hart
Implements Kahan algorithm for floating point accumulations.
Manages the metrics calculations.
MetricQuery(SingleChannelMetricEvaluator evaluator, size_t totalNumChannels, std::vector< size_t > &&defaultChannelsToProcess)
Create a metric query object for a metric that operates on one channel at a time.
Thrown when some metric is requested to return a value in an unsupported unit.
#define hassert(condition)
Triggers a HartAssertException if the condition is false
#define HART_THROW_OR_RETURN(ExceptionType, message, returnValue)
Throws an exception if HART_DO_NOT_THROW_EXCEPTIONS is set, prints a message and returns a specified ...
MetricQuery< double > rms(const AudioBuffer< SampleType > &buffer)
Calculates root mean square (RMS) of a signal.
Definition hart_rms.hpp:41
FloatType nan()
Returns a quiet NaN value for the given floating-point type.
static SampleType ratioToDecibels(SampleType valueLinear)
Converts linear value (ratio) to dB.
Unit
Represents a physical unit.
@ dB
Value of something in decibels. Can represent voltage, power, or a domain-specific unit like "LUFS" o...
@ native
Default (native) unit of whatever returns some value.
@ linear
Value of a sample (voltage) in a linear domain.
Helpers to generate common default channel subsets.
static std::vector< size_t > allChannels(size_t numChannels)
Represents a slice of analysis data.
bool isEmpty() const