9#include "metrics/hart_interpolated_peak_frequency.hpp"
10#include "matchers/hart_matcher.hpp"
25template<
typename SampleType>
34 m_expectedFundamentalHz (expectedFundamentalHz),
35 m_toleranceCents (toleranceCents)
37 if (expectedFundamentalHz <= 0.0)
41 void prepare (
double sampleRateHz, size_t , size_t , size_t )
override
43 m_sampleRateHz = sampleRateHz;
48 if (context.outputAudio().getNumFrames() < 64)
52 channelsToCheck
.resize (context.outputAudio().getNumChannels()
);
58 m_observedHz = interpolatedPeakFrequency (context.outputSpectrum()).ch (channelsToCheck).get (
mean());
59 const double deviationCents = 1200.0 * std::log2 (m_observedHz / m_expectedFundamentalHz);
61 if (std::abs (deviationCents) > m_toleranceCents)
63 m_centsError = deviationCents;
79 std::stringstream stream;
80 stream <<
"Observed fundamental "
93 s <<
"FundamentalEquals ("
94 <<
hzPrecision << m_expectedFundamentalHz <<
"_Hz, "
99 const double m_expectedFundamentalHz;
100 const double m_toleranceCents;
101 double m_sampleRateHz = 44100.0;
102 double m_observedHz = 0.0;
103 double m_centsError = 0.0;
105 static void calculateFFTInPlace (std::vector<std::complex<
double>>& spectrum)
110 for (size_t temp = spectrum.size(); temp > 1; temp >>= 1)
113 for (size_t i = 0; i < spectrum.size(); ++i)
117 for (size_t j = 0; j < log2n; ++j)
118 if (i & (size_t (1) << j))
119 rev |= size_t (1) << (log2n - 1 - j);
122 std::swap (spectrum[i], spectrum[rev]);
126 for (size_t len = 2; len <= spectrum.size(); len <<= 1)
129 const std::complex<
double> wlen (std::cos (angleRadians), std::sin (angleRadians));
131 for (size_t i = 0; i < spectrum.size(); i += len)
133 std::complex<
double> w (1.0);
134 for (size_t j = 0; j < len / 2; ++j)
136 std::complex<
double> u = spectrum[i + j];
137 std::complex<
double> v = spectrum[i + j + len / 2] * w;
138 spectrum[i + j] = u + v;
139 spectrum[i + j + len / 2] = u - v;
Contains audio-related artefacts useful for analysis by matchers.
A set of boolean flags mapped to each audio channel.
void resize(size_t newNumChannels)
Resizes the container.
bool anyTrue() const noexcept
Checks if any of the flags is set to true
Checks the fundamental frequency of the signal.
void represent(std::ostream &s) const override
Makes a text representation of this Matcher for test failure outputs.
MatcherFailureDetails getFailureDetails() const override
Returns a description of why the match has failed.
FundamentalEquals(double expectedFundamentalHz, double toleranceCents=1.0)
Creates a matcher for a specific fundamental frequency.
bool match(AnalysisContext< SampleType > context) override
Tells the host if the piece of audio satisfies Matcher's condition or not.
bool canOperatePerBlock() const override
Tells the host if it can operate on a block-by-block basis.
void reset() override
Resets the matcher to its initial state.
void prepare(double sampleRateHz, size_t, size_t, size_t) override
Prepare for processing It is guaranteed that all subsequent process() calls will be in line with the ...
Thrown when an unexpected container size is encountered.
Thrown when an inappropriate value is encountered.
#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 ...
#define HART_THROW(ExceptionType, message)
Throws an exception if HART_DO_NOT_THROW_EXCEPTIONS is set, prints a message otherwise.
std::ostream & centsPrecision(std::ostream &stream)
Sets number of decimal places for values in cents (frequency deviation)
std::ostream & hzPrecision(std::ostream &stream)
Sets number of decimal places for values in hertz.
constexpr double twoPi
2 * pi
#define HART_MATCHER_DECLARE_ALIASES_FOR(ClassName)
Details about matcher failure.
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.
Returns the arithmetic mean of all elements in the range.