16template <
typename SampleType>
17class OnsetLatencyDetector :
18 public LatencyDetector<SampleType>
21 OnsetLatencyDetector (
double maxLatencySeconds,
SilencePolicy silencePolicy,
double absThresholdDb):
22 m_maxLatencySeconds (maxLatencySeconds),
23 m_silencePolicy (silencePolicy),
34 m_sampleRateHz = sampleRateHz;
35 m_numChannels = numChannels;
40 m_noOnsetsDetected =
false;
41 m_allChannelsFailed =
false;
42 m_detectedLatencyFrames = 0;
43 m_detectedInputOnsetFrames = 0;
44 m_detectedOutputOnsetFrames = 0;
52 const std::function<
bool (size_t)>& appliesToChannel
55 const size_t numChannels = inputAudio.getNumChannels();
56 std::vector<
long long int> validLatenciesFrames;
57 std::vector<size_t> usedChannels;
58 std::vector<size_t> ignoredChannels;
59 std::vector<std::pair<size_t, size_t>> onsetsFrames (numChannels);
61 for (size_t channel = 0; channel < numChannels; ++channel)
63 if (! appliesToChannel (channel))
66 const OnsetDetails inputOnset = findOnsetFrame (inputAudio, channel);
67 const OnsetDetails outputOnset = findOnsetFrame (observedOutputAudio, channel);
69 if (inputOnset.found && outputOnset.found)
72 const long long int latencyFrames =
73 static_cast<
long long int> (outputOnset.frame) - inputOnset.frame;
75 validLatenciesFrames.push_back (latencyFrames);
76 usedChannels.push_back (channel);
77 onsetsFrames[channel] = { inputOnset.frame, outputOnset.frame };
81 ignoredChannels.push_back (channel);
85 m_noOnsetsDetected =
true;
86 m_allChannelsFailed =
false;
87 m_failureChannel = channel;
88 m_detectedInputOnsetFrames = 0;
89 m_detectedOutputOnsetFrames = 0;
97 if (validLatenciesFrames.empty())
99 m_noOnsetsDetected =
true;
100 m_allChannelsFailed =
true;
101 m_failureChannel = 0;
102 m_detectedInputOnsetFrames = 0;
103 m_detectedOutputOnsetFrames = 0;
110 long long int latencyFrames = validLatenciesFrames[0];
111 size_t latencyChannel = usedChannels[0];
113 for (size_t i = 1; i < validLatenciesFrames.size(); ++i)
115 if (validLatenciesFrames[i] > latencyFrames)
117 latencyFrames = validLatenciesFrames[i];
118 latencyChannel = usedChannels[i];
122 m_detectedLatencyFrames = latencyFrames;
123 const double detectedLatencySeconds = latencyFrames / m_sampleRateHz;
125 if (detectedLatencySeconds <= m_maxLatencySeconds)
128 m_noOnsetsDetected =
false;
129 m_failureChannel = latencyChannel;
130 m_detectedInputOnsetFrames = onsetsFrames[latencyChannel].first;
131 m_detectedOutputOnsetFrames = onsetsFrames[latencyChannel].second;
132 m_failureFrame = m_detectedOutputOnsetFrames;
140 details
.frame = m_failureFrame;
142 std::stringstream detailsStream;
144 if (m_noOnsetsDetected)
147 <<
"Latency could not be determined: "
148 << (m_allChannelsFailed ?
"no channels exceeded threshold" :
"one of the channels does not exceed threshold");
152 const double detectedLatencySeconds = m_detectedLatencyFrames / m_sampleRateHz;
155 <<
"Detected latency: "
156 <<
secPrecision << detectedLatencySeconds <<
" seconds ("
157 << m_detectedLatencyFrames <<
" frames)";
159 if (m_detectedInputOnsetFrames != 0)
161 const double detectedInputOnsetSeconds = m_detectedInputOnsetFrames / m_sampleRateHz;
162 const double detectedOutputOnsetSeconds = m_detectedOutputOnsetFrames / m_sampleRateHz;
165 <<
",\nInput onset: "
166 << detectedInputOnsetSeconds <<
" seconds ("
167 << m_detectedInputOnsetFrames <<
" frames),\n"
169 << detectedOutputOnsetSeconds <<
" seconds ("
170 << m_detectedOutputOnsetFrames <<
" frames)\n";
179 std::unique_ptr<LatencyDetector<SampleType>> copy()
const override
181 return hart::make_unique<OnsetLatencyDetector<SampleType>> (*
this);
191 const double m_maxLatencySeconds;
193 const double m_absThresholdLinear;
195 double m_sampleRateHz = 0.0;
196 size_t m_numChannels = 0;
198 bool m_noOnsetsDetected =
false;
199 bool m_allChannelsFailed =
false;
200 long long int m_detectedLatencyFrames = 0;
201 size_t m_detectedInputOnsetFrames = 0;
202 size_t m_detectedOutputOnsetFrames = 0;
203 size_t m_failureChannel = 0;
204 size_t m_failureFrame = 0;
206 OnsetDetails findOnsetFrame (
const AudioBuffer<SampleType>& buffer, size_t channel)
const
208 const size_t numFrames = buffer.getNumFrames();
210 for (size_t frame = 0; frame < numFrames; ++frame)
211 if (std::abs (
static_cast<
double> (buffer[channel][frame])) > m_absThresholdLinear)
212 return {
true, frame };
Container for audio data.
std::ostream & secPrecision(std::ostream &stream)
Sets number of decimal places for values in seconds.
SilencePolicy
Defines how silence in various algorithms.
static SampleType decibelsToRatio(SampleType valueDb)
Converts dB to linear value (ratio)
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.