54 D(
float inputSampleRate);
66 bool initialise(
size_t channels,
size_t stepSize,
size_t blockSize);
100 m_inputSampleRate(inputSampleRate),
106 m_priorMagnitudes(0),
117 delete[] m_priorMagnitudes;
131 d.
name =
"Minimum estimated tempo";
132 d.
description =
"Minimum beat-per-minute value which the tempo estimator is able to return";
141 d.
name =
"Maximum estimated tempo";
142 d.
description =
"Maximum beat-per-minute value which the tempo estimator is able to return";
147 d.
name =
"Input duration to study";
148 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.";
161 if (
id ==
"minbpm") {
163 }
else if (
id ==
"maxbpm") {
165 }
else if (
id ==
"maxdflen") {
174 if (
id ==
"minbpm") {
176 }
else if (
id ==
"maxbpm") {
178 }
else if (
id ==
"maxdflen") {
209 d.
name =
"Tempo candidates";
210 d.
description =
"Possible tempo estimates, one per bin with the most likely in the first bin";
216 d.
name =
"Detection Function";
236 d.
name =
"Autocorrelation Function";
237 d.
description =
"Autocorrelation of onset detection function";
243 d.
name =
"Filtered Autocorrelation";
244 d.
description =
"Filtered autocorrelation of onset detection function";
254 m_stepSize = stepSize;
255 m_blockSize = blockSize;
257 float dfLengthSecs = m_maxdflen;
260 m_priorMagnitudes =
new float[m_blockSize/2];
261 m_df =
new float[m_dfsize];
263 for (
size_t i = 0; i < m_blockSize/2; ++i) {
264 m_priorMagnitudes[i] = 0.f;
266 for (
size_t i = 0; i < m_dfsize; ++i) {
278 if (!m_priorMagnitudes)
return;
280 for (
size_t i = 0; i < m_blockSize/2; ++i) {
281 m_priorMagnitudes[i] = 0.f;
283 for (
size_t i = 0; i < m_dfsize; ++i) {
298 m_start = RealTime::zeroTime;
299 m_lasttime = RealTime::zeroTime;
307 if (m_stepSize == 0) {
308 cerr <<
"ERROR: FixedTempoEstimator::process: "
309 <<
"FixedTempoEstimator has not been initialised"
314 if (m_n == 0) m_start = ts;
317 if (m_n == m_dfsize) {
320 fs = assembleFeatures();
334 for (
size_t i = 1; i < m_blockSize/2; ++i) {
336 float real = inputBuffers[0][i*2];
337 float imag = inputBuffers[0][i*2 + 1];
339 float sqrmag = real * real + imag * imag;
340 value += fabsf(sqrmag - m_priorMagnitudes[i]);
342 m_priorMagnitudes[i] = sqrmag;
355 if (m_n > m_dfsize)
return fs;
357 fs = assembleFeatures();
378 cerr <<
"FixedTempoEstimator::calculate: calculation already happened?" << endl;
382 if (m_n < m_dfsize / 9 &&
384 cerr <<
"FixedTempoEstimator::calculate: Input is too short" << endl;
395 m_r =
new float[n/2];
396 m_fr =
new float[n/2];
397 m_t =
new float[n/2];
399 for (
int i = 0; i < n/2; ++i) {
402 m_t[i] = lag2tempo(i);
407 for (
int i = 0; i < n/2; ++i) {
409 for (
int j = i; j < n; ++j) {
410 m_r[i] += m_df[j] * m_df[j - i];
418 float related[] = { 0.5, 2, 4, 8 };
420 for (
int i = 1; i < n/2-1; ++i) {
426 for (
int j = 0; j < int(
sizeof(related)/
sizeof(related[0])); ++j) {
430 int k0 = int(i * related[j] + 0.5);
432 if (k0 >= 0 && k0 <
int(n/2)) {
434 int kmax = 0, kmin = 0;
435 float kvmax = 0, kvmin = 0;
438 for (
int k = k0 - 1; k <= k0 + 1; ++k) {
440 if (k < 0 || k >= n/2)
continue;
442 if (!have || (m_r[k] > kvmax)) { kmax = k; kvmax = m_r[k]; }
443 if (!have || (m_r[k] < kvmin)) { kmin = k; kvmin = m_r[k]; }
451 m_fr[i] += m_r[kmax] / 5;
453 if ((kmax == 0 || m_r[kmax] > m_r[kmax-1]) &&
454 (kmax == n/2-1 || m_r[kmax] > m_r[kmax+1]) &&
455 kvmax > kvmin * 1.05) {
461 m_t[i] = m_t[i] + lag2tempo(kmax) * related[j];
472 float weight = 1.f - fabsf(128.f - lag2tempo(i)) * 0.005;
473 if (weight < 0.f) weight = 0.f;
474 weight = weight * weight * weight;
476 m_fr[i] += m_fr[i] * (weight / 3);
491 feature.
values.push_back(0.f);
497 for (
int i = 0; i < n; ++i) {
503 feature.
values[0] = m_df[i];
508 for (
int i = 1; i < n/2; ++i) {
515 feature.
values[0] = m_r[i];
516 sprintf(buffer,
"%.1f bpm", lag2tempo(i));
517 if (i == n/2-1) feature.
label =
"";
518 else feature.
label = buffer;
525 int p0 = tempo2lag(t1);
526 int p1 = tempo2lag(t0);
528 std::map<float, int> candidates;
530 for (
int i = p0; i <= p1 && i+1 < n/2; ++i) {
532 if (m_fr[i] > m_fr[i-1] &&
533 m_fr[i] > m_fr[i+1]) {
539 candidates[m_fr[i]] = i;
546 feature.
values[0] = m_fr[i];
547 sprintf(buffer,
"%.1f bpm", lag2tempo(i));
548 if (i == p1 || i == n/2-2) feature.
label =
"";
549 else feature.
label = buffer;
553 if (candidates.empty()) {
554 cerr <<
"No tempo candidates!" << endl;
562 feature.
duration = m_lasttime - m_start;
567 std::map<float, int>::const_iterator ci = candidates.end();
569 int maxpi = ci->second;
571 if (m_t[maxpi] > 0) {
576 feature.
values[0] = m_t[maxpi];
583 feature.
values[0] = lag2tempo(maxpi);
584 cerr <<
"WARNING: No stored tempo for index " << maxpi << endl;
587 sprintf(buffer,
"%.1f bpm", feature.
values[0]);
588 feature.
label = buffer;
600 while (feature.
values.size() < 10) {
601 if (m_t[ci->second] > 0) {
602 feature.
values.push_back(m_t[ci->second]);
604 feature.
values.push_back(lag2tempo(ci->second));
606 if (ci == candidates.begin())
break;
619 m_d(new
D(inputSampleRate))
637 return "Simple Fixed Tempo Estimator";
643 return "Study a short section of audio and estimate its tempo, assuming the tempo is constant";
649 return "Vamp SDK Example Plugins";
661 return "Code copyright 2008 Queen Mary, University of London. Freely redistributable (BSD license)";