diff --git a/src/inputs/BPM.h b/src/inputs/BPM.h index a7ba0fc..df23c4c 100644 --- a/src/inputs/BPM.h +++ b/src/inputs/BPM.h @@ -1,26 +1,42 @@ #pragma once #include +#include -class BPM : public InputSource { +class BPM : public InputSource, ConfigTaskMixin { public: BPM() : InputSource("BPM") {} void handleEvent(const InputEvent& evt) override { if (evt.intent == InputEvent::BeatDetect) { m_nextBpm = millis(); m_timings.insert(millis()); - Log.notice("%d timings", m_timings.size()); + Log.trace("bpm: %d timings", m_timings.size()); if (m_timings.size() >= 5) { updateBPM(); } } + ConfigTaskMixin::handleEvent(evt); + } + + void loop() { + InputSource::loop(); + ConfigTaskMixin::loop(); + } + + void handleConfigChange(const InputEvent& evt) override { + const JsonObject& cfg = *evt.as(); + if (cfg.containsKey("bpm.idle")) { + double requestedBPM = cfg["bpm.idle"]; + m_msPerBeat = 60000.0 / (double)requestedBPM; + Log.notice("bpm: idle BPM set to %u (requested %lf)", msToBPM(m_msPerBeat), requestedBPM); + } } InputEvent read() override { - if (m_bpm > 0) { + if (m_msPerBeat > 0) { uint16_t now = millis(); if (now >= m_nextBpm) { - m_nextBpm += m_bpm; - return InputEvent{InputEvent::Beat, m_bpm}; + m_nextBpm += m_msPerBeat; + return InputEvent{InputEvent::Beat, msToBPM(m_msPerBeat)}; } if (now >= m_nextLearn && m_nextLearn != 0) { m_timings.clear(); @@ -31,21 +47,28 @@ public: } private: - uint16_t m_bpm = 0; + uint16_t m_msPerBeat = 60000; uint16_t m_nextBpm = 0; uint16_t m_nextLearn = 0; Ringbuf m_timings; + constexpr uint16_t msToBPM(float msPerBeat) const { + if (msPerBeat == 0) { + return 0; + } + return 60000.0 / msPerBeat; + } + void updateBPM() { uint16_t avgDelta = 0; for(uint8_t i = 0; i < m_timings.size() - 1; i++) { uint16_t delta = m_timings.peek(i+1) - m_timings.peek(i); - Log.notice("Timing %d Delta %d", m_timings.peek(i), delta); + Log.trace("bpm: Timing %d Delta %d", m_timings.peek(i), delta); avgDelta += delta; } - m_bpm = avgDelta / 4; - m_nextLearn = m_bpm * 5 + millis(); - Log.notice("BPM is now %d", m_bpm); + m_msPerBeat = avgDelta / 4; + m_nextLearn = m_msPerBeat * 5 + millis(); + Log.notice("bpm: BPM is now %d", msToBPM(m_msPerBeat)); uint16_t trash; m_timings.take(trash); }