#include "tools/bpmcalculator.h" #include #include #include constexpr float MICROSECONDS_IN_MINUTE_f = 60000000.; BPMCalculator::BPMCalculator(const std::shared_ptr& music) : _music(music) { reset(); } void BPMCalculator::reset() { _calculating = false; _deltas.clear(); _previous_click_offset = 0; _approximated_bpm = 0; _need_recalculate = true; } void BPMCalculator::setMusic(const std::shared_ptr& music) { _music = music; reset(); } std::shared_ptr BPMCalculator::music() const { return _music; } void BPMCalculator::start() { reset(); _calculating = true; } void BPMCalculator::stop() { _calculating = false; } void BPMCalculator::click() { if (!_calculating) return; const microsec click_offset = _music->fetchOffset(); _need_recalculate = true; if (_previous_click_offset == 0) { _previous_click_offset = click_offset; return; } const microsec delta = click_offset - _previous_click_offset; _deltas.emplace_back(delta); _previous_click_offset = click_offset; } float BPMCalculator::fetchCurrentBPMApproximation() { if (!_need_recalculate) return _approximated_bpm; _need_recalculate = false; const microsec sum = std::accumulate(_deltas.begin(), _deltas.end(), 0); bool hasEnoughDeltas = _deltas.size() >= 8; _approximated_bpm = (!hasEnoughDeltas) ? 0. : calculateBPM(sum, _deltas.size()); return _approximated_bpm; } float BPMCalculator::calculateBPM(microsec all_microseconds, std::size_t beats_amount) const { if (beats_amount == 0) return 0; float relation = static_cast(all_microseconds) / static_cast(beats_amount); return static_cast(1. / relation); } microsec BPMCalculator::getStartingOffset() const { return _first_click_offset; } void BPMCalculator::setStartingOffset(microsec offset) { _first_click_offset = offset; } void BPMCalculator::moveStartingOffsetBy(microsec shift) { _first_click_offset += shift; } microsec BPMCalculator::fetchTimeUntilNextBeat() { const microsec actual_offset = _music->fetchOffset() - _first_click_offset; return fetchBeatInterval() % actual_offset; } microsec BPMCalculator::fetchBeatInterval() { return static_cast(1. / fetchCurrentBPMApproximation()); }