44#include " pico/time.h"
55
66#include < array>
7- #include < list>
87#include < numeric>
98#include < string>
109
@@ -166,79 +165,56 @@ std::string modeToString(usb_mode_t mode) {
166165 return " ?" ;
167166}
168167
169- uint16_t calculateBpm (const Utils::InputState::Buttons &buttons) {
168+ } // namespace
169+
170+ void Display::BpmCounter::Buffer::insert (uint16_t value) {
171+ if (m_buffer.size () >= m_size_limit) {
172+ m_buffer.pop_back ();
173+ }
174+ m_buffer.push_front (value);
175+ }
176+
177+ uint16_t Display::BpmCounter::Buffer::getAvarage () const {
178+ if (!m_buffer.empty ()) {
179+ return std::accumulate (m_buffer.begin (), m_buffer.end (), 0 ) / m_buffer.size ();
180+ }
181+ return 0 ;
182+ }
183+
184+ void Display::BpmCounter::update (const Utils::InputState::Buttons &buttons) {
170185 // Somewhat ugly gimmick to calculate the how often the face buttons
171186 // are pressed per minute.
172187 //
173- // It records the average time between the last 'window_size ' button
188+ // It records the average time between the last 'WINDOW_SIZE ' button
174189 // presses for calculation. To avoid spikes caused by simultaneous
175- // button presses, all presses within 'double_hit_window ' are counted
190+ // button presses, all presses within 'DOUBLE_HIT_TIMEOUT_MS ' are counted
176191 // as a single press.
177192 //
178- // Counter resets after 'reset_after'.
179-
180- static const size_t window_size = 20 ;
181- static const uint32_t double_hit_window = 50 ;
182- static const uint32_t reset_after = 2000 ;
183-
184- static Utils::InputState::Buttons prev_buttons = {};
185- static uint32_t prev_press = 0 ;
186- static uint16_t current_bpm = 0 ;
187-
188- struct StatBuffer {
189- private:
190- std::list<uint16_t > m_buf;
191- size_t m_max_size;
192-
193- public:
194- StatBuffer (size_t max_size) : m_max_size(max_size) {}
195-
196- void clear () { m_buf.clear (); };
197-
198- void insert (uint16_t val) {
199- if (m_buf.size () >= m_max_size) {
200- m_buf.pop_back ();
201- }
202- m_buf.push_front (val);
203- };
204-
205- uint16_t avg () {
206- if (!m_buf.empty ()) {
207- return std::accumulate (m_buf.begin (), m_buf.end (), 0 ) / m_buf.size ();
208- }
209- return 0 ;
210- }
211- };
212- static StatBuffer stat_buffer (window_size);
213-
193+ // Counter resets after 'm_timeout_ms'.
214194 const uint32_t now = to_ms_since_boot (get_absolute_time ());
215- const uint32_t interval = now - prev_press ;
195+ const uint32_t interval = now - m_prev_press_time ;
216196
217- if (interval > reset_after ) {
218- stat_buffer .clear ();
219- current_bpm = 0 ;
220- prev_press = 0 ;
197+ if (interval > m_timeout_ms ) {
198+ m_buffer .clear ();
199+ m_current_bpm = 0 ;
200+ m_prev_press_time = 0 ;
221201 }
222202
223- if ((interval > double_hit_window ) &&
224- ((buttons.north && !prev_buttons .north ) || (buttons.east && !prev_buttons .east ) ||
225- (buttons.south && !prev_buttons .south ) || (buttons.west && !prev_buttons .west ))) {
203+ if ((interval > DOUBLE_HIT_TIMEOUT_MS ) &&
204+ ((buttons.north && !m_prev_buttons .north ) || (buttons.east && !m_prev_buttons .east ) ||
205+ (buttons.south && !m_prev_buttons .south ) || (buttons.west && !m_prev_buttons .west ))) {
226206
227- if (prev_press != 0 ) {
228- stat_buffer .insert (interval);
229- current_bpm = 60000 / stat_buffer. avg ();
207+ if (m_prev_press_time != 0 ) {
208+ m_buffer .insert (interval);
209+ m_current_bpm = 60000 / m_buffer. getAvarage ();
230210 }
231211
232- prev_press = now;
212+ m_prev_press_time = now;
233213 }
234214
235- prev_buttons = buttons;
236-
237- return current_bpm;
215+ m_prev_buttons = buttons;
238216}
239217
240- } // namespace
241-
242218Display::Display (const Config &config) : m_config(config) {
243219 i2c_init (m_config.i2c_block , m_config.i2c_speed_hz );
244220 gpio_set_function (m_config.sda_pin , GPIO_FUNC_I2C );
@@ -252,7 +228,7 @@ Display::Display(const Config &config) : m_config(config) {
252228}
253229
254230void Display::setTouched (uint32_t touched) { m_touched = touched; }
255- void Display::setButtons (const Utils::InputState::Buttons &buttons) { m_buttons = buttons; }
231+ void Display::setButtons (const Utils::InputState::Buttons &buttons) { m_bpm_counter. update ( buttons) ; }
256232void Display::setUsbMode (usb_mode_t mode) { m_usb_mode = mode; };
257233void Display::setPlayerId (uint8_t player_id) { m_player_id = player_id; };
258234
@@ -268,7 +244,7 @@ void Display::drawIdleScreen() {
268244 ssd1306_draw_line (&m_display, 0 , 10 , 128 , 10 );
269245
270246 // BPM
271- auto bpm_str = std::to_string (calculateBpm (m_buttons )) + " bpm" ;
247+ auto bpm_str = std::to_string (m_bpm_counter. getBpm ( )) + " bpm" ;
272248 ssd1306_draw_string (&m_display, (127 - (bpm_str.length () * 12 )) / 2 , 20 , 2 , bpm_str.c_str ());
273249
274250 // Player "LEDs"
@@ -360,13 +336,12 @@ void Display::drawMenuScreen() {
360336}
361337
362338void Display::update () {
363- static const uint32_t interval_ms = 20 ; // Limit to ~50fps
364- static uint32_t start_ms = 0 ;
339+ static const uint32_t interval_ms = 17 ; // Limit to ~60fps
365340
366- if (to_ms_since_boot (get_absolute_time ()) - start_ms < interval_ms) {
341+ if (to_ms_since_boot (get_absolute_time ()) - m_next_frame_time < interval_ms) {
367342 return ;
368343 }
369- start_ms += interval_ms;
344+ m_next_frame_time += interval_ms;
370345
371346 ssd1306_clear (&m_display);
372347
0 commit comments