#pragma once #include "config.h" #include #include #include #include #include "Touchpad.h" #include "Temperature.h" using clock_type = std::chrono::high_resolution_clock; struct IntervalCounter { public: IntervalCounter(); int get_count_per_second(); void count(uint64_t n = 1); private: uint64_t m_count{}; uint64_t m_count_checkpoint{}; std::chrono::time_point m_checkpoint_timestamp{}; }; template class AgeOutValue { public: AgeOutValue(std::chrono::milliseconds timeout): m_timeout(timeout), m_checkpoint_timestamp(clock_type::now()), m_value{} { } bool is_current() { return clock_type::now() - m_checkpoint_timestamp < m_timeout; } // returns value, or 0 if aged-out T value() { T result{}; if (is_current()) { result = m_value; } return result; } void update(const T& value) { m_value = value; m_checkpoint_timestamp = clock_type::now(); } T& update() { m_checkpoint_timestamp = clock_type::now(); return m_value; } private: const std::chrono::milliseconds m_timeout; std::chrono::time_point m_checkpoint_timestamp{}; T m_value; }; class UI { public: UI(Config& config); void draw(); void handle_input(); bool key_available(); // signals, from user input boost::signals2::signal signal_bpm; boost::signals2::signal signal_note_set_from_midi; boost::signals2::signal signal_mode; boost::signals2::signal signal_output; // slots void count_main_loops(); void count_midi_events(size_t size); void count_midi_notes(); void slot_active_sensing(); void slot_midi_note(int channel, int note, uint64_t timestamp); void slot_note_bpm(int bpm); void slot_clock_bpm(int bpm); private: Config& m_config; IntervalCounter m_main_loops; IntervalCounter m_midi_events; IntervalCounter m_midi_bytes; IntervalCounter m_midi_notes; std::chrono::time_point m_active_sensing_timestamp; uint64_t m_midi_timestamp; AgeOutValue>> m_midi_monitor; AgeOutValue m_note_bpm; AgeOutValue m_clock_bpm; Touchpad m_touchpad; Temperature m_temperature; };