9#include "metrics/hart_metric_query.hpp"
10#include "metrics/hart_metrics_common.hpp"
98template <
typename SampleType>
102 double maxLagSeconds,
103 double minAbsBestCorrelation = 0.5,
107 if (maxLagSeconds < 0.0)
110 if ((bufferA.hasSampleRate() || bufferB.hasSampleRate()) && bufferA.getSampleRateHz() != bufferB.getSampleRateHz())
113 if (minAbsBestCorrelation < 0 || minAbsBestCorrelation > 1.0)
116 typename MetricQuery<
double>::ChannelPairMetricEvaluator evaluator =
117 [&bufferA, &bufferB, maxLagSeconds, minAbsBestCorrelation, searchMode]
118 (size_t channelA, size_t channelB,
Slice slice,
Unit requestedUnit)
122 hassert (channelA < bufferA.getNumChannels());
123 hassert (channelB < bufferB.getNumChannels());
135 if (! bufferA.hasSampleRate()
136 || ! bufferB.hasSampleRate()
142 if (
hart::floatsEqual (bufferA.getSampleRateHz(), 0.0)
143 ||
hart::floatsEqual (bufferB.getSampleRateHz(), 0.0)
152 if (bufferA.getNumFrames() != bufferB.getNumFrames())
158 const auto sliceFrameIndices = bufferA.getFrameIndices (slice);
159 const size_t sliceStart = sliceFrameIndices.first;
160 const size_t sliceStop = sliceFrameIndices.second;
161 hassert (sliceStop > sliceStart);
162 hassert (sliceStop <= bufferA.getNumFrames());
163 hassert (sliceStop <= bufferB.getNumFrames());
165 const size_t numFrames = sliceStop - sliceStart;
168 const double sampleRateHz = bufferA.getSampleRateHz();
169 const size_t maxLagFrames =
static_cast<size_t> (std::round (maxLagSeconds * sampleRateHz));
171 const SampleType* x = bufferA[channelA] + sliceStart;
172 const SampleType* y = bufferB[channelB] + sliceStart;
174 double bestCorrelation =
179 int bestLagFrames = 0;
180 bool hadValidOverlap =
false;
182 for (
int lag = -
static_cast<
int> (maxLagFrames); lag <=
static_cast<
int> (maxLagFrames); ++lag)
184 const bool lagIsNegative = lag < 0;
185 const size_t lagAbsFrames =
static_cast<size_t> (lagIsNegative ? -lag : lag);
187 if (lagAbsFrames >= numFrames)
190 const size_t xBegin = lagIsNegative ? lagAbsFrames : 0;
191 const size_t yBegin = lagIsNegative ? 0 : lagAbsFrames;
192 const size_t overlapFrames = numFrames - lagAbsFrames;
197 for (size_t frame = 0; frame < overlapFrames; ++frame)
199 const double xn =
static_cast<
double> (x[xBegin + frame]);
200 const double yn =
static_cast<
double> (y[yBegin + frame]);
202 dotProduct
+= xn * yn;
203 sumSquaresX
+= xn * xn;
204 sumSquaresY
+= yn * yn;
213 hadValidOverlap =
true;
215 const double correlation = dotProduct
.getValue() / std::sqrt (energyX * energyY);
219 ? correlation > bestCorrelation
220 : std::abs (correlation) > std::abs (bestCorrelation);
224 bestCorrelation = correlation;
232 if (std::abs (bestCorrelation) < minAbsBestCorrelation)
233 hadValidOverlap =
false;
235 if (! hadValidOverlap)
238 switch (requestedUnit)
242 return static_cast<
double> (bestLagFrames);
245 return bestLagFrames / sampleRateHz;
252 const size_t numPairs = std::min (bufferA.getNumChannels(), bufferB.getNumChannels());
254 std::move (evaluator),
255 bufferA.getNumChannels(),
256 bufferB.getNumChannels(),
Implements Kahan algorithm for floating point accumulations.
SampleType getValue() const
AccurateSum & operator+=(SampleType value)
Adds a value to a sum, tracking the potential floating point error.
Container for audio data.
Manages the metrics calculations.
Thrown when sample rate is mismatched.
Thrown when an unexpected container size is encountered.
Thrown when some metric is requested to return a value in an unsupported unit.
Thrown when an inappropriate value is encountered.
#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 > lagAtMaxCrossCorrelation(const AudioBuffer< SampleType > &bufferA, const AudioBuffer< SampleType > &bufferB, double maxLagSeconds, double minAbsBestCorrelation=0.5, CorrelationSearchMode searchMode=bestAbsoluteCorrelation)
Calculates lag corresponding to maximum normalized cross-correlation between two audio buffers.
FloatType nan()
Returns a quiet NaN value for the given floating-point type.
constexpr double inf
Infinity.
static SampleType floatsEqual(SampleType a, SampleType b, SampleType epsilon=(SampleType) 1e-8)
Compares two floating point numbers within a given tolerance.
CorrelationSearchMode
Describes how to look for best cross-correlation.
@ bestAbsoluteCorrelation
Unit
Represents a physical unit.
@ seconds
Time stamps, intervals, durations.
@ native
Default (native) unit of whatever returns some value.
@ frames
Value of something in frames (samples)
Helpers to generate common default channel subsets.
static std::vector< std::pair< size_t, size_t > > diagonalChannelPairs(size_t numChannels)
Represents a slice of analysis data.