HART  0.2.0
High level Audio Regression and Testing
Loading...
Searching...
No Matches
hart_sample_peak.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm> // max()
4#include <cmath> // abs()
5
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
13
14namespace hart
15{
16
17/// @brief Calculates Sample Peak of an audio buffer
18/// @details Calculates rectified peak values for each channel. Use a reducer to
19/// get a scalar value (see @ref Reducers). Supports `Unit::linear` (default) and
20/// `Unit::dB` units. Usage example:
21/// @code
22/// HART_EXPECT_FLOAT_EQ (samplePeak (monoBuffer).as (dB).get(), -3_dB, 1e-2) << "Peaks below 3 dB";
23/// HART_EXPECT_LT (samplePeak (monoBuffer).as (linear).get(), 1.0, 1e-3) << "Peaks below unity gain (in linear domain)";
24/// HART_EXPECT_LT (samplePeak (stereoBuffer).as (dB).get (max()), -3_dB) << "Loudest channel peaks below 3 dB";
25/// @endcode
26/// @note It doesn't estimate inter-sample peaks. For true (inter-sample) peaks,
27/// consider using the `truePeak()` metric or `TruePeaksBelow` matcher.
28/// @param audioBuffer Buffer to measure sample peaks in.
29/// @throws hart::IndexError if slice's boundary is out of audio buffer's range
30/// @throws hart::UnitError if unsupported unit is requested
31/// @ingroup Metrics
32template <typename SampleType>
33MetricQuery<double> samplePeak (const AudioBuffer<SampleType>& audioBuffer)
34{
35 typename MetricQuery<double>::SingleChannelMetricEvaluator evaluator =
36 [&audioBuffer]
37 (size_t channel, Slice slice, Unit requestedUnit)
38 -> double
39 {
40 if (slice.isEmpty())
41 return hart::nan<double>();
42
43 const auto sliceFrameIndices = audioBuffer.getFrameIndices (slice);
44 const size_t sliceStart = sliceFrameIndices.first;
45 const size_t sliceStop = sliceFrameIndices.second;
46 hassert (sliceStop > sliceStart);
47 hassert (sliceStop - sliceStart != 0);
48 hassert (sliceStop <= audioBuffer.getNumFrames());
49
50 const SampleType* samples = audioBuffer[channel];
51 SampleType peakLinear = 0.0;
52
53 for (size_t frame = sliceStart; frame < sliceStop; ++frame)
54 peakLinear = std::max (std::abs (samples[frame]), peakLinear);
55
56 switch (requestedUnit)
57 {
58 case Unit::native:
59 case Unit::linear: return static_cast<double> (peakLinear);
60
61 case Unit::dB: return hart::ratioToDecibels (static_cast<double> (peakLinear));
62
63 default: HART_THROW_OR_RETURN (hart::UnitError, "Unsupported unit", hart::nan<double>());
64 }
65 };
66
67 const size_t numChannels = audioBuffer.getNumChannels();
68 return MetricQuery<double> (
69 std::move (evaluator),
70 numChannels,
72 );
73}
74
75} // namespace hart
Container for audio data.
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 > samplePeak(const AudioBuffer< SampleType > &audioBuffer)
Calculates Sample Peak of an audio buffer.
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