HART  0.2.0
High level Audio Regression and Testing
Loading...
Searching...
No Matches
hart_peaksat.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm> // max()
4#include <cmath> // abs()
5#include <iomanip>
6#include <sstream>
7
8#include "matchers/hart_matcher.hpp"
10#include "hart_utils.hpp" // decibelsToRatio(), ratioToDecibels()
11
12namespace hart
13{
14
15/// @brief Checks whether the audio peaks at specific level
16/// @details This matcher will calculate peak value of a full audio signal (not a per-block peaks)
17/// and compare against a value provided during instantiation with a provided tolerance.
18/// It checks where all selected channels peak collectively, not for each individual channel.
19/// To do more strict per channel checks, use multiple matchers with @ref atChannel(), so that
20/// each matcher only targets one specific channel.
21/// @attention It checks the sample peaks, not the inter-sample peaks (a popular metric in audio
22/// mastering community). For inter-sample peak checking, see `TruePeaksBelow` and `truePeak()`.
23/// For more versatile expressions, check the `samplePeak()` metric.
24/// @ingroup Matchers
25template<typename SampleType>
26class PeaksAt:
27 public Matcher<SampleType, PeaksAt<SampleType>>
28{
29public:
30 /// @brief Creates a matcher for a specific peak level
31 /// @param targetDb Expected sample peak value in decibels
32 /// @param toleranceLinear Absolute tolerance for comparing frames, in linear domain (not decibels)
33 PeaksAt (double targetDb, double toleranceLinear = 1e-3):
34 m_targetDb ((SampleType) targetDb),
35 m_targetLinear ((SampleType) decibelsToRatio (targetDb)),
36 m_toleranceLinear ((SampleType) toleranceLinear)
37 {
38 }
39
40 void prepare (double /*sampleRateHz*/, size_t /* numInputChannels */, size_t /* numOutputChannels */, size_t /* maxBlockSizeFrames */) override {}
41
42 bool match (AnalysisContext<SampleType> context) override
43 {
44 const AudioBuffer<SampleType>& observedOutputAudio = context.outputAudio();
45 SampleType observedPeakLinear = 0;
46 size_t frameOfObservedPeakLinear = 0;
47 size_t channelOfObservedPeakLinear = 0;
48
49 for (size_t channel = 0; channel < observedOutputAudio.getNumChannels(); ++channel)
50 {
51 if (! this->appliesToChannel (channel))
52 continue;
53
54 for (size_t frame = 0; frame < observedOutputAudio.getNumFrames(); ++frame)
55 {
56 const SampleType currentPeakLinear = std::abs (observedOutputAudio[channel][frame]);
57
58 if (currentPeakLinear > observedPeakLinear)
59 {
60 observedPeakLinear = currentPeakLinear;
61 frameOfObservedPeakLinear = frame;
62 channelOfObservedPeakLinear = channel;
63 }
64 }
65 }
66
67 if (std::abs (observedPeakLinear - m_targetLinear) > m_toleranceLinear)
68 {
69 m_failedFrame = frameOfObservedPeakLinear;
70 m_failedChannel = (int) channelOfObservedPeakLinear;
71 m_observedPeakDb = ratioToDecibels (observedPeakLinear);
72 return false;
73 }
74
75 return true;
76 }
77
78 bool canOperatePerBlock() const override
79 {
80 return false;
81 }
82
84 {
85 std::stringstream stream;
86 stream << dbPrecision << "Observed audio peaks at " << m_observedPeakDb << " dB";
87
89 details.frame = m_failedFrame;
90 details.channel = m_failedChannel;
91 details.description = stream.str();
92 return details;
93 }
94
95 void represent (std::ostream& stream) const override
96 {
97 stream << "PeaksAt ("
98 << dbPrecision << m_targetDb << "_dB, "
99 << linPrecision << m_toleranceLinear << ')';
100 }
101
102private:
103 const SampleType m_targetDb;
104 const SampleType m_targetLinear;
105 const SampleType m_toleranceLinear;
106
107 size_t m_failedFrame = 0;
108 size_t m_failedChannel = 0;
109 SampleType m_observedPeakDb = (SampleType) 0;
110};
111
113
114} // namespace hart
Contains audio-related artefacts useful for analysis by matchers.
Container for audio data.
Base for audio matchers.
Checks whether the audio peaks at specific level.
void represent(std::ostream &stream) const override
Makes a text representation of this Matcher for test failure outputs.
void prepare(double, size_t, size_t, size_t) override
Prepare for processing It is guaranteed that all subsequent process() calls will be in line with the ...
bool match(AnalysisContext< SampleType > context) override
Tells the host if the piece of audio satisfies Matcher's condition or not.
PeaksAt(double targetDb, double toleranceLinear=1e-3)
Creates a matcher for a specific peak level.
bool canOperatePerBlock() const override
Tells the host if it can operate on a block-by-block basis.
virtual MatcherFailureDetails getFailureDetails() const override
Returns a description of why the match has failed.
std::ostream & linPrecision(std::ostream &stream)
Sets number of decimal places for linear (sample) values.
std::ostream & dbPrecision(std::ostream &stream)
Sets number of decimal places for values in decibels.
static SampleType decibelsToRatio(SampleType valueDb)
Converts dB to linear value (ratio)
#define HART_MATCHER_DECLARE_ALIASES_FOR(ClassName)
size_t channel
Index of channel at which the failure was detected.
std::string description
Readable description of why the match has failed.
size_t frame
Index of frame at which the match has failed.