HART  0.2.0
High level Audio Regression and Testing
Loading...
Searching...
No Matches
hart_equalsto.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cmath> // abs()
4#include <iomanip>
5#include <sstream>
6
7#include "matchers/hart_matcher.hpp"
9#include "signals/hart_signal.hpp"
10#include "hart_utils.hpp"
11
12namespace hart
13{
14
15/// @brief Checks whether the audio is identical to some signal
16/// @details Holds an internal Signal instance, and gets it to generate reference audio as
17/// the matcher receives new audio blocks through match(). Reports mismatch if even
18/// one of the frames in the audio does not match the reference signal within tolerance
19/// specified in @c epsilon during its instantiation.
20/// @ingroup Matchers
21template<typename SampleType>
23 public Matcher<SampleType, EqualsTo<SampleType>>
24{
25public:
26 /// @brief Creates a matcher for a specific signal by transfering smart pointer
27 /// details The reference signal can be something simple like a @ref SineWave, or more
28 /// complex signal with DSP effects chain and automation envelopes.
29 /// @note Tip: To compare audio to a pre-recorded wav file, you can use @ref WavFile.
30 /// @param referenceSignal Signal to compare the incoming audio against
31 /// @param toleranceLinear Absolute tolerance for comparing frames, in linear domain (not decibels)
32 EqualsTo (std::unique_ptr<SignalBase<SampleType>>&& referenceSignal, double toleranceLinear = (SampleType) 1e-5):
33 m_referenceSignal (std::move (referenceSignal)),
34 m_toleranceLinear ((SampleType) toleranceLinear)
35 {
36 }
37
38 /// @brief Creates a matcher for a specific signal by copying it
39 /// details The reference signal can be something simple like a @ref SineWave, or more
40 /// complex signal with DSP effects chain and automation envelopes.
41 /// @note Tip: To compare audio to a pre-recorded wav file, you can use @ref WavFile.
42 /// @param referenceSignal Signal to compare the incoming audio against
43 /// @param toleranceLinear Absolute tolerance for comparing frames, in linear domain (not decibels)
44 EqualsTo (const SignalBase<SampleType>& referenceSignal, double toleranceLinear = (SampleType) 1e-5):
45 EqualsTo (referenceSignal.copy(), toleranceLinear)
46 {
47 }
48
49 /// @brief Creates a matcher for a specific signal by moving it
50 /// details The reference signal can be something simple like a @ref SineWave, or more
51 /// complex signal with DSP effects chain and automation envelopes.
52 /// @note Tip: To compare audio to a pre-recorded wav file, you can use @ref WavFile.
53 /// @param referenceSignal Signal to compare the incoming audio against
54 /// @param toleranceLinear Absolute tolerance for comparing frames, in linear domain (not decibels)
55 EqualsTo (SignalBase<SampleType>&& referenceSignal, double toleranceLinear = (SampleType) 1e-5):
56 EqualsTo (referenceSignal.move(), toleranceLinear)
57 {
58 }
59
60 EqualsTo (EqualsTo&& other) noexcept:
61 Matcher<SampleType, EqualsTo<SampleType>> (std::move (other)),
62 m_referenceSignal (std::move (other.m_referenceSignal)),
63 m_toleranceLinear (other.m_toleranceLinear)
64 {
65 }
66
67 EqualsTo (const EqualsTo& other):
68 Matcher<SampleType, EqualsTo<SampleType>> (other),
69 m_referenceSignal (other.m_referenceSignal != nullptr ? other.m_referenceSignal->copy() : nullptr),
70 m_toleranceLinear (other.m_toleranceLinear)
71 {
72 }
73
74 EqualsTo& operator= (const EqualsTo& other)
75 {
76 if (this == &other)
77 return *this;
78
79 Matcher<SampleType, EqualsTo<SampleType>>::operator= (other);
80
81 m_referenceSignal = other.m_referenceSignal != nullptr ? other.m_referenceSignal->copy() : nullptr;
82 m_toleranceLinear = other.m_toleranceLinear;
83
84 return *this;
85 }
86
87 EqualsTo& operator= (EqualsTo&& other) noexcept
88 {
89 if (this == &other)
90 return *this;
91
92 // Move base first
93 Matcher<SampleType, EqualsTo<SampleType>>::operator=(std::move(other));
94
95 // Then move our members
96 m_referenceSignal = std::move(other.m_referenceSignal);
97 m_toleranceLinear = other.m_toleranceLinear;
98
99 return *this;
100 }
101
102 ~EqualsTo() override = default;
103
104 void prepare (double sampleRateHz, size_t numChannels, size_t maxBlockSizeFrames) override
105 {
106 m_referenceSignal->prepareWithDSPChain (sampleRateHz, numChannels, maxBlockSizeFrames);
107 }
108
109 bool match (const AudioBuffer<SampleType>& observedAudio) override
110 {
111 auto referenceAudio = AudioBuffer<SampleType>::emptyLike (observedAudio);
112 m_referenceSignal->renderNextBlockWithDSPChain (referenceAudio);
113
114 for (size_t channel = 0; channel < referenceAudio.getNumChannels(); ++channel)
115 {
116 if (! this->appliesToChannel (channel))
117 continue;
118
119 for (size_t frame = 0; frame < referenceAudio.getNumFrames(); ++frame)
120 {
121 if (notEqual (observedAudio[channel][frame], referenceAudio[channel][frame]))
122 {
123 m_failedFrame = frame;
124 m_failedChannel = (int) channel;
125 m_failedObservedValue = observedAudio[channel][frame];
126 m_failedExpectedValue = referenceAudio[channel][frame];
127 return false;
128 }
129 }
130 }
131
132 return true;
133 }
134
135 bool canOperatePerBlock() override
136 {
137 return true;
138 }
139
140 void reset() override
141 {
142 m_referenceSignal->resetWithDSPChain();
143 }
144
146 {
147 const SampleType m_differenceLinear = std::abs (m_failedExpectedValue - m_failedObservedValue);
148 std::stringstream stream;
149 stream << linPrecision << "Expected sample value: " << m_failedExpectedValue
150 << dbPrecision << " (" << ratioToDecibels (m_failedExpectedValue) << " dB)"
151 << linPrecision << ", difference: " << m_differenceLinear
152 << dbPrecision << " (" << ratioToDecibels (m_differenceLinear) << " dB)";
153
154 MatcherFailureDetails details;
155 details.frame = m_failedFrame;
156 details.channel = m_failedChannel;
157 details.description = stream.str();
158 return details;
159 }
160
161 void represent (std::ostream& stream) const override
162 {
163 stream << "EqualsTo (" << *m_referenceSignal
164 << linPrecision << ", " << m_toleranceLinear << ')';
165 }
166
167private:
168 std::unique_ptr<SignalBase<SampleType>> m_referenceSignal;
169 const SampleType m_toleranceLinear;
170
171 size_t m_failedFrame = 0;
172 size_t m_failedChannel = 0;
173 SampleType m_failedObservedValue = (SampleType) 0;
174 SampleType m_failedExpectedValue = (SampleType) 0;
175
176 inline bool notEqual (SampleType x, SampleType y)
177 {
178 return std::abs (x - y) > m_toleranceLinear;
179 }
180};
181
183
184} // namespace hart
Checks whether the audio is identical to some signal.
EqualsTo(std::unique_ptr< SignalBase< SampleType > > &&referenceSignal, double toleranceLinear=(SampleType) 1e-5)
Creates a matcher for a specific signal by transfering smart pointer details The reference signal can...
bool match(const AudioBuffer< SampleType > &observedAudio) override
Tells the host if the piece of audio satisfies Matcher's condition or not.
EqualsTo(SignalBase< SampleType > &&referenceSignal, double toleranceLinear=(SampleType) 1e-5)
Creates a matcher for a specific signal by moving it details The reference signal can be something si...
~EqualsTo() override=default
void represent(std::ostream &stream) const override
Makes a text representation of this Matcher for test failure outputs.
EqualsTo & operator=(const EqualsTo &other)
EqualsTo(const SignalBase< SampleType > &referenceSignal, double toleranceLinear=(SampleType) 1e-5)
Creates a matcher for a specific signal by copying it details The reference signal can be something s...
EqualsTo(EqualsTo &&other) noexcept
bool canOperatePerBlock() 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.
EqualsTo(const EqualsTo &other)
void reset() override
Resets the matcher to its initial state.
void prepare(double sampleRateHz, size_t numChannels, size_t maxBlockSizeFrames) override
Prepare for processing It is guaranteed that all subsequent process() calls will be in line with the ...
EqualsTo & operator=(EqualsTo &&other) noexcept
Base for audio matchers.
Polymorphic base for all signals.
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.
#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.