HART  0.1.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/// @attention It checks the sample peaks, not the inter-sample peaks (a popular metric in audio
19/// mastering community). Fon inter-sample peak checking, you can make your own custom Matcher.
20/// @ingroup Matchers
21template<typename SampleType>
22class PeaksAt:
23 public Matcher<SampleType>
24{
25public:
26 /// @brief Creates a matcher for a specific peak level
27 /// @param targetDb Expected sample peak value in decibels
28 /// @param toleranceLinear Absolute tolerance for comparing frames, in linear domain (not decibels)
29 PeaksAt (double targetDb, double toleranceLinear = 1e-3):
30 m_targetDb ((SampleType) targetDb),
31 m_targetLinear ((SampleType) decibelsToRatio (targetDb)),
32 m_toleranceLinear ((SampleType) toleranceLinear)
33 {
34 }
35
36 void prepare (double /*sampleRateHz*/, size_t /* numChannels */, size_t /* maxBlockSizeFrames */) override {}
37
38 bool match (const AudioBuffer<SampleType>& observedAudio) override
39 {
40 SampleType observedPeakLinear = 0;
41 size_t frameOfObservedPeakLinear = 0;
42 size_t channelOfObservedPeakLinear = 0;
43
44 for (size_t channel = 0; channel < observedAudio.getNumChannels(); ++channel)
45 {
46 for (size_t frame = 0; frame < observedAudio.getNumFrames(); ++frame)
47 {
48 const SampleType currentPeakLinear = std::abs (observedAudio[channel][frame]);
49
50 if (currentPeakLinear > observedPeakLinear)
51 {
52 observedPeakLinear = currentPeakLinear;
53 frameOfObservedPeakLinear = frame;
54 channelOfObservedPeakLinear = channel;
55 }
56 }
57 }
58
59 if (std::abs (observedPeakLinear - m_targetLinear) > m_toleranceLinear)
60 {
61 m_failedFrame = frameOfObservedPeakLinear;
62 m_failedChannel = (int) channelOfObservedPeakLinear;
63 m_observedPeakDb = ratioToDecibels (observedPeakLinear);
64 return false;
65 }
66
67 return true;
68 }
69
70 bool canOperatePerBlock() override
71 {
72 return false;
73 }
74
75 void reset() override {}
76
78 {
79 std::stringstream stream;
80 stream << dbPrecision << "Observed audio peaks at " << m_observedPeakDb << " dB";
81
83 details.frame = m_failedFrame;
84 details.channel = m_failedChannel;
85 details.description = std::move (stream.str());
86 return details;
87 }
88
89 void represent (std::ostream& stream) const override
90 {
91 stream << "PeaksAt ("
92 << dbPrecision << m_targetDb << "_dB, "
93 << linPrecision << m_toleranceLinear << ')';
94 }
95
97
98private:
99 const SampleType m_targetDb;
100 const SampleType m_targetLinear;
101 const SampleType m_toleranceLinear;
102
103 size_t m_failedFrame = 0;
104 size_t m_failedChannel = 0;
105 SampleType m_observedPeakDb = (SampleType) 0;
106};
107
109
110} // namespace hart
Base for audio matchers.
Checks whether the audio peaks at specific level.
bool match(const AudioBuffer< SampleType > &observedAudio) override
Tells the host if the piece of audio satisfies Matcher's condition or not.
void represent(std::ostream &stream) const override
Makes a text representation of this Macther for test failure outputs.
PeaksAt(double targetDb, double toleranceLinear=1e-3)
Creates a matcher for a specific peak level.
bool canOperatePerBlock() override
Tells the host is if can operate on a block-by-block basis.
virtual MatcherFailureDetails getFailureDetails() const override
Returns a description of why the match has failed.
void prepare(double, size_t, size_t) override
Prepare for processing It is guaranteed that all subsequent process() calls will be in line with the ...
void reset() override
Resets the matcher to its initial state.
#define HART_MATCHER_DEFINE_COPY_AND_MOVE(ClassName)
Defines hart::Matcher::copy() and hart::Matcher::move() methods.
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.