53 D(
float inputSampleRate);
65 bool initialise(
size_t channels,
size_t stepSize,
size_t blockSize);
99 m_inputSampleRate(inputSampleRate),
105 m_priorMagnitudes(0),
116 delete[] m_priorMagnitudes;
130 d.
name =
"Minimum estimated tempo";
131 d.
description =
"Minimum beat-per-minute value which the tempo estimator is able to return";
140 d.
name =
"Maximum estimated tempo";
141 d.
description =
"Maximum beat-per-minute value which the tempo estimator is able to return";
146 d.
name =
"Input duration to study";
147 d.
description =
"Length of audio input, in seconds, which should be taken into account when estimating tempo. There is no need to supply the plugin with any further input once this time has elapsed since the start of the audio. The tempo estimator may use only the first part of this, up to eight times the slowest beat duration: increasing this value further than that is unlikely to improve results.";
160 if (
id ==
"minbpm") {
162 }
else if (
id ==
"maxbpm") {
164 }
else if (
id ==
"maxdflen") {
173 if (
id ==
"minbpm") {
175 }
else if (
id ==
"maxbpm") {
177 }
else if (
id ==
"maxdflen") {
208 d.
name =
"Tempo candidates";
209 d.
description =
"Possible tempo estimates, one per bin with the most likely in the first bin";
215 d.
name =
"Detection Function";
235 d.
name =
"Autocorrelation Function";
236 d.
description =
"Autocorrelation of onset detection function";
242 d.
name =
"Filtered Autocorrelation";
243 d.
description =
"Filtered autocorrelation of onset detection function";
253 m_stepSize = stepSize;
254 m_blockSize = blockSize;
256 float dfLengthSecs = m_maxdflen;
259 m_priorMagnitudes =
new float[m_blockSize/2];
260 m_df =
new float[m_dfsize];
262 for (
size_t i = 0; i < m_blockSize/2; ++i) {
263 m_priorMagnitudes[i] = 0.f;
265 for (
size_t i = 0; i < m_dfsize; ++i) {
277 if (!m_priorMagnitudes)
return;
279 for (
size_t i = 0; i < m_blockSize/2; ++i) {
280 m_priorMagnitudes[i] = 0.f;
282 for (
size_t i = 0; i < m_dfsize; ++i) {
297 m_start = RealTime::zeroTime;
298 m_lasttime = RealTime::zeroTime;
306 if (m_stepSize == 0) {
307 cerr <<
"ERROR: FixedTempoEstimator::process: "
308 <<
"FixedTempoEstimator has not been initialised"
313 if (m_n == 0) m_start = ts;
316 if (m_n == m_dfsize) {
319 fs = assembleFeatures();
333 for (
size_t i = 1; i < m_blockSize/2; ++i) {
335 float real = inputBuffers[0][i*2];
336 float imag = inputBuffers[0][i*2 + 1];
338 float sqrmag = real * real + imag * imag;
339 value += fabsf(sqrmag - m_priorMagnitudes[i]);
341 m_priorMagnitudes[i] = sqrmag;
354 if (m_n > m_dfsize)
return fs;
356 fs = assembleFeatures();
377 cerr <<
"FixedTempoEstimator::calculate: calculation already happened?" << endl;
381 if (m_n < m_dfsize / 9 &&
383 cerr <<
"FixedTempoEstimator::calculate: Input is too short" << endl;
394 m_r =
new float[n/2];
395 m_fr =
new float[n/2];
396 m_t =
new float[n/2];
398 for (
int i = 0; i < n/2; ++i) {
401 m_t[i] = lag2tempo(i);
406 for (
int i = 0; i < n/2; ++i) {
408 for (
int j = i; j < n; ++j) {
409 m_r[i] += m_df[j] * m_df[j - i];
417 float related[] = { 0.5, 2, 4, 8 };
419 for (
int i = 1; i < n/2-1; ++i) {
425 for (
int j = 0; j < int(
sizeof(related)/
sizeof(related[0])); ++j) {
429 int k0 = int(i * related[j] + 0.5);
431 if (k0 >= 0 && k0 <
int(n/2)) {
433 int kmax = 0, kmin = 0;
434 float kvmax = 0, kvmin = 0;
437 for (
int k = k0 - 1; k <= k0 + 1; ++k) {
439 if (k < 0 || k >= n/2)
continue;
441 if (!have || (m_r[k] > kvmax)) { kmax = k; kvmax = m_r[k]; }
442 if (!have || (m_r[k] < kvmin)) { kmin = k; kvmin = m_r[k]; }
450 m_fr[i] += m_r[kmax] / 5;
452 if ((kmax == 0 || m_r[kmax] > m_r[kmax-1]) &&
453 (kmax == n/2-1 || m_r[kmax] > m_r[kmax+1]) &&
454 kvmax > kvmin * 1.05) {
460 m_t[i] = m_t[i] + lag2tempo(kmax) * related[j];
471 float weight = 1.f - fabsf(128.f - lag2tempo(i)) * 0.005;
472 if (weight < 0.f) weight = 0.f;
473 weight = weight * weight * weight;
475 m_fr[i] += m_fr[i] * (weight / 3);
490 feature.
values.push_back(0.f);
496 for (
int i = 0; i < n; ++i) {
502 feature.
values[0] = m_df[i];
507 for (
int i = 1; i < n/2; ++i) {
514 feature.
values[0] = m_r[i];
515 sprintf(buffer,
"%.1f bpm", lag2tempo(i));
516 if (i == n/2-1) feature.
label =
"";
517 else feature.
label = buffer;
524 int p0 = tempo2lag(t1);
525 int p1 = tempo2lag(t0);
527 std::map<float, int> candidates;
529 for (
int i = p0; i <= p1 && i+1 < n/2; ++i) {
531 if (m_fr[i] > m_fr[i-1] &&
532 m_fr[i] > m_fr[i+1]) {
538 candidates[m_fr[i]] = i;
545 feature.
values[0] = m_fr[i];
546 sprintf(buffer,
"%.1f bpm", lag2tempo(i));
547 if (i == p1 || i == n/2-2) feature.
label =
"";
548 else feature.
label = buffer;
552 if (candidates.empty()) {
553 cerr <<
"No tempo candidates!" << endl;
561 feature.
duration = m_lasttime - m_start;
566 std::map<float, int>::const_iterator ci = candidates.end();
568 int maxpi = ci->second;
570 if (m_t[maxpi] > 0) {
575 feature.
values[0] = m_t[maxpi];
582 feature.
values[0] = lag2tempo(maxpi);
583 cerr <<
"WARNING: No stored tempo for index " << maxpi << endl;
586 sprintf(buffer,
"%.1f bpm", feature.
values[0]);
587 feature.
label = buffer;
599 while (feature.
values.size() < 10) {
600 if (m_t[ci->second] > 0) {
601 feature.
values.push_back(m_t[ci->second]);
603 feature.
values.push_back(lag2tempo(ci->second));
605 if (ci == candidates.begin())
break;
618 m_d(new
D(inputSampleRate))
636 return "Simple Fixed Tempo Estimator";
642 return "Study a short section of audio and estimate its tempo, assuming the tempo is constant";
648 return "Vamp SDK Example Plugins";
660 return "Code copyright 2008 Queen Mary, University of London. Freely redistributable (BSD license)";