21 #ifndef ESSENTIA_BPMUTILS_H
22 #define ESSENTIA_BPMUTILS_H
24 #include "../essentiamath.h"
31 return 60.0*sampleRate/lag/hopSize;
36 return lagToBpm(bpm, sampleRate, hopSize);
42 Real ubound = period*(1+tolerance);
43 Real lbound = period*(1-tolerance);
44 while ((pos < (
int)dticks.size()) &&
45 (lbound < dticks[pos] && dticks[pos] < ubound)) {
49 return pos - startpos;
57 ratio =
round(1./ratio);
58 error=(x*ratio-y)/std::min(y,
Real(x*ratio))*100;
62 error = (x-y*ratio)/std::min(x,
Real(y*ratio))*100;
69 Real epsilon = std::max(tolerance, std::numeric_limits<Real>::epsilon());
73 return (std::fabs(error) <= epsilon &&
int(ratio)==1);
79 epsilon = std::max(epsilon, std::numeric_limits<Real>::epsilon());
83 error = std::fabs(error);
84 if (error <= epsilon) {
85 if (bPower2)
return isPowerTwo(
int(fabs(ratio)));
94 epsilon = std::max(epsilon, std::numeric_limits<Real>::epsilon());
97 Real error = std::numeric_limits<int>::max();
98 Real ratio = std::numeric_limits<int>::max();
100 if (fabs(error) <= epsilon)
return y;
103 while (fabs(error) > epsilon) {
114 std::vector<Real>
roundBpms(
const std::vector<Real>& bpms) {
116 Real mainBpm=bpms[0];
117 std::vector<Real> harmonicBpms;
118 harmonicBpms.reserve(bpms.size());
119 for (
int i=0; i<int(bpms.size()); i++) {
120 Real ratio=bpms[0]/mainBpm;
121 if (ratio <
Real(1.0)) ratio = 1.0/ratio;
122 ratio =
round(ratio*10.)/10.;
123 int iRatio = int(ratio);
124 if (ratio-iRatio <= 0.100001) {
125 harmonicBpms.push_back(bpms[i]);
128 if ((ratio-iRatio) == 0.5) {
129 harmonicBpms.push_back(bpms[i]);
141 if (origticks.size() < 3)
return origticks;
144 const int nticks = origticks.size();
145 std::vector<Real> dticks(nticks-1);
147 for (
int i=0; i<nticks-1; i++) dticks[i] = origticks[i+1] - origticks[i];
151 for (
int i=0; i<(int)dticks.size(); i++) {
152 if (dticks[i] > 2.) {
153 dticks.erase(dticks.begin() + i);
158 const int nbins = 100;
159 std::vector<int> dist(nbins);
160 std::vector<Real> distx(nbins);
162 hist(&dticks[0], nticks-1, &dist[0], &distx[0], nbins);
164 int maxidx = max_element(dist.begin(), dist.end()) - dist.begin();
165 Real maxbinCenter = distx[maxidx];
172 Real period = maxbinCenter;
174 for (
int startpos = 0; startpos < nticks-1; startpos++) {
182 if (idx == 0 && maxl == 0) {
183 std::cerr <<
"Internal error while processing the beats, returning the original ones" << std::endl;
189 std::deque<Real> ticks(origticks.begin() + idx,
190 origticks.begin() + idx + maxl + 1);
193 Real targetPeriod =
mean(dticks, idx, idx+maxl);
195 Real tolerance = 0.15 * targetPeriod;
199 Real cpos = ticks.back() + targetPeriod;
200 std::deque<Real> remaining(origticks.begin() + idx + maxl + 1,
203 while (!remaining.empty()) {
204 Real nbeat = remaining.front();
206 if (nbeat < cpos - tolerance) {
208 remaining.pop_front();
214 if (nbeat < cpos + tolerance) {
216 remaining.pop_front();
220 ticks.push_back(cpos);
221 cpos += targetPeriod;
226 cpos = ticks.front() - targetPeriod;
227 remaining = std::deque<Real>(origticks.begin(),
228 origticks.begin() + idx);
230 while (!remaining.empty()) {
231 Real nbeat = remaining.back();
233 if (nbeat > cpos + tolerance) {
235 remaining.pop_back();
240 if (nbeat > cpos - tolerance) {
242 remaining.pop_back();
246 ticks.push_front(cpos);
247 cpos -= targetPeriod;
252 return std::vector<Real>(ticks.begin(), ticks.end());
259 const std::vector<Real>& ticksAmplitudes,
260 const Real& preferredPeriod) {
261 if (origticks.size() < 3)
return origticks;
264 const int nticks = origticks.size();
265 std::vector<Real> dticks(nticks-1);
267 for (
int i=0; i<nticks-1; i++) dticks[i] = origticks[i+1] - origticks[i];
271 for (
int i=0; i<(int)dticks.size(); i++) {
272 if (dticks[i] > 2.) {
273 dticks.erase(dticks.begin() + i);
278 const int nbins = 100;
279 std::vector<int> dist(nbins);
280 std::vector<Real> distx(nbins);
282 hist(&dticks[0], dticks.size(), &dist[0], &distx[0], nbins);
284 int maxidx = max_element(dist.begin(), dist.end()) - dist.begin();
285 Real maxbinCenter = distx[maxidx];
292 Real period = maxbinCenter;
295 for (
int startpos = 0; startpos < nticks-1; startpos++) {
303 Real targetPeriod = preferredPeriod;
304 if (idx ==0 && maxl==0) {
305 idx =
argmax(ticksAmplitudes);
308 else targetPeriod =
mean(dticks, idx, idx+maxl);
310 targetPeriod = (targetPeriod+preferredPeriod)/2.0;
314 if (targetPeriod < 0.95*preferredPeriod || targetPeriod > 1.05*preferredPeriod) {
315 idx = idx +
argmax(std::vector<Real>(ticksAmplitudes.begin()+idx, ticksAmplitudes.begin()+idx+maxl+1));
317 targetPeriod = preferredPeriod;
321 Real originalTargetPeriod = targetPeriod;
325 std::deque<Real> ticks(origticks.begin() + idx,
326 origticks.begin() + idx + maxl + 1);
329 Real tolerance =0.03;
331 if (targetPeriod < 0.05) {
332 std::cout <<
"PostProcessTicks: target Period too short. Returning the original ticks" << std::endl;
335 Real cummulatedPeriod = targetPeriod;
336 int nAccumulations = 1;
340 Real cpos = ticks.back() + targetPeriod;
341 std::deque<Real> remaining(origticks.begin() + idx + maxl + 1,
344 while (!remaining.empty()) {
345 Real nbeat = remaining.front();
347 if (nbeat < cpos - tolerance) {
349 remaining.pop_front();
355 if (nbeat < cpos + tolerance) {
356 cummulatedPeriod += (nbeat - (cpos - targetPeriod));
358 targetPeriod = cummulatedPeriod/nAccumulations;
362 remaining.pop_front();
366 ticks.push_back(cpos);
367 cpos += targetPeriod;
372 cpos = ticks.front() - targetPeriod;
373 remaining = std::deque<Real>(origticks.begin(),
374 origticks.begin() + idx);
376 targetPeriod = originalTargetPeriod;
377 cummulatedPeriod = targetPeriod;
380 while (!remaining.empty()) {
381 Real nbeat = remaining.back();
383 if (nbeat > cpos + tolerance) {
385 remaining.pop_back();
390 if (nbeat > cpos - tolerance) {
391 cummulatedPeriod += ((cpos + targetPeriod)-nbeat);
393 targetPeriod = cummulatedPeriod/nAccumulations;
397 remaining.pop_back();
401 ticks.push_front(cpos);
402 cpos -= targetPeriod;
406 return std::vector<Real>(ticks.begin(), ticks.end());
Definition: algorithm.h:28
void hist(const T *array, uint n, int *n_array, T *x_array, uint n_bins)
Definition: essentiamath.h:983
T round(const T value)
Definition: essentiamath.h:539
T mean(const std::vector< T > &array, int start, int end)
Definition: essentiamath.h:143
void bpmDistance(Real x, Real y, Real &error, Real &ratio)
Definition: bpmutil.h:53
std::vector< Real > roundBpms(const std::vector< Real > &bpms)
Definition: bpmutil.h:114
std::vector< Real > postProcessTicks(const std::vector< Real > &origticks)
Definition: bpmutil.h:140
Real bpmToLag(Real bpm, Real sampleRate, Real hopSize)
Definition: bpmutil.h:35
Real lagToBpm(Real lag, Real sampleRate, Real hopSize)
Definition: bpmutil.h:30
Real greatestCommonDivisor(Real x, Real y, Real epsilon)
Definition: bpmutil.h:92
bool areEqual(Real a, Real b, Real tolerance)
Definition: bpmutil.h:67
float Real
Definition: types.h:69
bool isPowerTwo(T n)
Definition: essentiamath.h:46
bool areHarmonics(Real x, Real y, Real epsilon, bool bPower2)
Definition: bpmutil.h:77
int argmax(const std::vector< Real > &input)
Definition: essentiamath.h:835
int longestChain(const std::vector< Real > &dticks, int startpos, Real period, Real tolerance)
Definition: bpmutil.h:40