diff --git a/include/tools/beatutils.h b/include/tools/beatutils.h new file mode 100644 index 0000000..4adf37e --- /dev/null +++ b/include/tools/beatutils.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include "mathutils.h" + +namespace beat_utils +{ + struct BeatInfo + { + long double rate_per_microsecond = 0.; + microsec average_interval = 0; + }; + + BeatInfo calculateBeatRateInfo(const std::vector& approximate_deltas); +} diff --git a/include/tools/bpmcalculator.h b/include/tools/bpmcalculator.h index 7e2325d..31bf18f 100644 --- a/include/tools/bpmcalculator.h +++ b/include/tools/bpmcalculator.h @@ -1,8 +1,8 @@ #pragma once #include "tools/music.h" +#include "tools/beatutils.h" #include -#include class BPMCalculator { @@ -15,15 +15,14 @@ public: void start(); void stop(); void click(); - float fetchCurrentBPMApproximation(); + + const beat_utils::BeatInfo& fetchApproximatedInfo(); + microsec fetchTimeUntilNextBeat(); microsec getStartingOffset() const; void setStartingOffset(microsec offset); void moveStartingOffsetBy(microsec shift); - microsec fetchTimeUntilNextBeat(); - microsec fetchBeatInterval(); - private: bool _need_recalculate; bool _calculating; @@ -33,8 +32,7 @@ private: microsec _previous_click_offset; microsec _first_click_offset; - int _approximated_bpm; + beat_utils::BeatInfo _approximated_info; - inline float calculateBPM(microsec all_microseconds, std::size_t beats_amount) const; inline void reset(); }; diff --git a/src/gui/editor.cpp b/src/gui/editor.cpp index a99704d..0f678e2 100644 --- a/src/gui/editor.cpp +++ b/src/gui/editor.cpp @@ -34,7 +34,7 @@ void Editor::enter() { auto& group = _group; auto& music = _music; - _music->openFromFile("40mp.ogg"); + _music->openFromFile("Uta-test.flac"); _music->setVolume(5); _bpm_calculator = std::make_shared(_music); diff --git a/src/gui/widgets/bpmcalculatorwidget.cpp b/src/gui/widgets/bpmcalculatorwidget.cpp index a3585e3..7f70cdc 100644 --- a/src/gui/widgets/bpmcalculatorwidget.cpp +++ b/src/gui/widgets/bpmcalculatorwidget.cpp @@ -1,15 +1,21 @@ #include "bpmcalculatorwidget.h" #include "tools/bpmcalculator.h" +#include + BPMCalculatorWidget::BPMCalculatorWidget(const std::shared_ptr& bpm_calculator, const std::shared_ptr& font) : Window("BPM Calculation", font), _bpm_calculator(bpm_calculator), - _slider(std::make_shared()) + _slider(std::make_shared()), + _ticked(false) { _bpm_value.setFont(*_font); _bpm_value.setCharacterSize(40); _bpm_value.setFillColor(sf::Color::Black); _bpm_value.setString("--"); + _slap_buffer.loadFromFile("Tick.ogg"); + _slap.setBuffer(_slap_buffer); + _slap.setVolume(30.); } void BPMCalculatorWidget::input(const sf::Event& event) @@ -34,16 +40,22 @@ void BPMCalculatorWidget::update(const sf::Time& dt) { Window::update(dt); - const auto approximation = _bpm_calculator->fetchCurrentBPMApproximation(); - if (approximation != 0) + const auto beat_info = _bpm_calculator->fetchApproximatedInfo(); + if (beat_info.rate_per_microsecond != 0) { - _bpm_value.setString(std::to_string(approximation)); + _bpm_value.setString(std::to_string(static_cast(beat_info.rate_per_microsecond))); const microsec until_beat = _bpm_calculator->fetchTimeUntilNextBeat(); - const microsec beat_interval = _bpm_calculator->fetchBeatInterval(); - - const auto time_relation = beat_interval / until_beat; - const auto slider_path_left = Window::rect().width / time_relation; + const auto time_relation = static_cast(beat_info.average_interval) / static_cast(until_beat); + const auto slider_path_left = _slider->rect().width / time_relation; + if (slider_path_left < 50) + { + if (!_ticked) + _slap.play(); + _ticked = true; + } + else + _ticked = false; _slider->setTickPosition(slider_path_left); } diff --git a/src/gui/widgets/bpmcalculatorwidget.h b/src/gui/widgets/bpmcalculatorwidget.h index a3aa616..61433e9 100644 --- a/src/gui/widgets/bpmcalculatorwidget.h +++ b/src/gui/widgets/bpmcalculatorwidget.h @@ -6,6 +6,8 @@ #include #include #include +#include +#include class BPMCalculator; @@ -28,6 +30,10 @@ private: std::shared_ptr _bpm_calculator; std::shared_ptr _slider; + sf::SoundBuffer _slap_buffer; + sf::Sound _slap; + bool _ticked; + sf::Text _bpm_value; }; diff --git a/src/tools/beatutils.cpp b/src/tools/beatutils.cpp new file mode 100644 index 0000000..86275be --- /dev/null +++ b/src/tools/beatutils.cpp @@ -0,0 +1,23 @@ +#include "tools/beatutils.h" +#include +#include + +auto beat_utils::calculateBeatRateInfo(const std::vector& approximate_deltas) -> BeatInfo +{ + if (approximate_deltas.empty()) + return {}; + + const microsec sum = std::accumulate(approximate_deltas.begin(), approximate_deltas.end(), 0); + const std::size_t amount = approximate_deltas.size(); + + long double average = static_cast(sum) + / static_cast(amount); + + + + return BeatInfo + { + 60000000. / average, + static_cast(average) + }; +} diff --git a/src/tools/bpmcalculator.cpp b/src/tools/bpmcalculator.cpp index fde8b9d..6970ab7 100644 --- a/src/tools/bpmcalculator.cpp +++ b/src/tools/bpmcalculator.cpp @@ -3,8 +3,6 @@ #include #include -constexpr float MICROSECONDS_IN_MINUTE_f = 60000000.; - BPMCalculator::BPMCalculator(const std::shared_ptr& music) : _music(music) { @@ -16,7 +14,7 @@ void BPMCalculator::reset() _calculating = false; _deltas.clear(); _previous_click_offset = 0; - _approximated_bpm = 0; + _first_click_offset = 0; _need_recalculate = true; } @@ -54,6 +52,7 @@ void BPMCalculator::click() if (_previous_click_offset == 0) { _previous_click_offset = click_offset; + _first_click_offset = click_offset; return; } @@ -63,32 +62,20 @@ void BPMCalculator::click() _previous_click_offset = click_offset; } -float BPMCalculator::fetchCurrentBPMApproximation() +const beat_utils::BeatInfo& BPMCalculator::fetchApproximatedInfo() { - if (!_need_recalculate) - return _approximated_bpm; + //if (!_need_recalculate) + //return _approximated_info; - _need_recalculate = false; + //_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()); + _approximated_info = (!hasEnoughDeltas) + ? beat_utils::BeatInfo{} + : beat_utils::calculateBeatRateInfo(_deltas); - 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); + return _approximated_info; } microsec BPMCalculator::getStartingOffset() const @@ -110,10 +97,5 @@ microsec BPMCalculator::fetchTimeUntilNextBeat() { const microsec actual_offset = _music->fetchOffset() - _first_click_offset; - return fetchBeatInterval() % actual_offset; -} - -microsec BPMCalculator::fetchBeatInterval() -{ - return static_cast(1. / fetchCurrentBPMApproximation()); + return actual_offset % fetchApproximatedInfo().average_interval; }