inputs: bpm: add support for configuring startup/idle BPM

This commit is contained in:
Torrie Fischer 2023-02-19 18:39:26 +01:00
parent 2a0d72f0a1
commit ae3abc3aa3

View File

@ -1,26 +1,42 @@
#pragma once #pragma once
#include <Figments.h> #include <Figments.h>
#include <ArduinoJson.h>
class BPM : public InputSource { class BPM : public InputSource, ConfigTaskMixin {
public: public:
BPM() : InputSource("BPM") {} BPM() : InputSource("BPM") {}
void handleEvent(const InputEvent& evt) override { void handleEvent(const InputEvent& evt) override {
if (evt.intent == InputEvent::BeatDetect) { if (evt.intent == InputEvent::BeatDetect) {
m_nextBpm = millis(); m_nextBpm = millis();
m_timings.insert(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) { if (m_timings.size() >= 5) {
updateBPM(); updateBPM();
} }
} }
ConfigTaskMixin::handleEvent(evt);
}
void loop() {
InputSource::loop();
ConfigTaskMixin::loop();
}
void handleConfigChange(const InputEvent& evt) override {
const JsonObject& cfg = *evt.as<JsonObject>();
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 { InputEvent read() override {
if (m_bpm > 0) { if (m_msPerBeat > 0) {
uint16_t now = millis(); uint16_t now = millis();
if (now >= m_nextBpm) { if (now >= m_nextBpm) {
m_nextBpm += m_bpm; m_nextBpm += m_msPerBeat;
return InputEvent{InputEvent::Beat, m_bpm}; return InputEvent{InputEvent::Beat, msToBPM(m_msPerBeat)};
} }
if (now >= m_nextLearn && m_nextLearn != 0) { if (now >= m_nextLearn && m_nextLearn != 0) {
m_timings.clear(); m_timings.clear();
@ -31,21 +47,28 @@ public:
} }
private: private:
uint16_t m_bpm = 0; uint16_t m_msPerBeat = 60000;
uint16_t m_nextBpm = 0; uint16_t m_nextBpm = 0;
uint16_t m_nextLearn = 0; uint16_t m_nextLearn = 0;
Ringbuf<uint16_t, 7> m_timings; Ringbuf<uint16_t, 7> m_timings;
constexpr uint16_t msToBPM(float msPerBeat) const {
if (msPerBeat == 0) {
return 0;
}
return 60000.0 / msPerBeat;
}
void updateBPM() { void updateBPM() {
uint16_t avgDelta = 0; uint16_t avgDelta = 0;
for(uint8_t i = 0; i < m_timings.size() - 1; i++) { for(uint8_t i = 0; i < m_timings.size() - 1; i++) {
uint16_t delta = m_timings.peek(i+1) - m_timings.peek(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; avgDelta += delta;
} }
m_bpm = avgDelta / 4; m_msPerBeat = avgDelta / 4;
m_nextLearn = m_bpm * 5 + millis(); m_nextLearn = m_msPerBeat * 5 + millis();
Log.notice("BPM is now %d", m_bpm); Log.notice("bpm: BPM is now %d", msToBPM(m_msPerBeat));
uint16_t trash; uint16_t trash;
m_timings.take(trash); m_timings.take(trash);
} }