metronome.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #include <furi.h>
  2. #include <gui/gui.h>
  3. #include <input/input.h>
  4. #include <m-string.h>
  5. #include <stdlib.h>
  6. const double BPM_STEP_SIZE = 0.5;
  7. typedef enum {
  8. EventTypeTick,
  9. EventTypeKey,
  10. } EventType;
  11. typedef struct {
  12. EventType type;
  13. InputEvent input;
  14. } PluginEvent;
  15. typedef struct {
  16. double bpm;
  17. bool playing;
  18. } MetronomeState;
  19. static void render_callback(Canvas* const canvas, void* ctx) {
  20. const MetronomeState* metronome_state = acquire_mutex((ValueMutex*)ctx, 25);
  21. if(metronome_state == NULL) {
  22. return;
  23. }
  24. char* play_state;
  25. string_t tempStr;
  26. string_init(tempStr);
  27. // border around the edge of the screen
  28. canvas_draw_frame(canvas, 0, 0, 128, 64);
  29. canvas_set_font(canvas, FontPrimary);
  30. // draw playing state
  31. if (metronome_state->playing) {
  32. play_state = "Playing";
  33. } else {
  34. play_state = "Paused";
  35. }
  36. canvas_draw_str_aligned(canvas, 5, 10, AlignLeft, AlignBottom, play_state);
  37. // draw BPM value
  38. string_printf(tempStr, "%.2f", metronome_state->bpm);
  39. canvas_set_font(canvas, FontBigNumbers);
  40. canvas_draw_str_aligned(canvas, 64, 40, AlignCenter, AlignCenter, string_get_cstr(tempStr));
  41. string_reset(tempStr);
  42. string_clear(tempStr);
  43. release_mutex((ValueMutex*)ctx, metronome_state);
  44. }
  45. static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
  46. furi_assert(event_queue);
  47. PluginEvent event = {.type = EventTypeKey, .input = *input_event};
  48. furi_message_queue_put(event_queue, &event, FuriWaitForever);
  49. }
  50. static void metronome_state_init(MetronomeState* const metronome_state) {
  51. metronome_state->bpm = 120.0;
  52. metronome_state->playing = false;
  53. }
  54. int32_t metronome_app() {
  55. FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
  56. MetronomeState* metronome_state = malloc(sizeof(MetronomeState));
  57. metronome_state_init(metronome_state);
  58. ValueMutex state_mutex;
  59. if(!init_mutex(&state_mutex, metronome_state, sizeof(MetronomeState))) {
  60. FURI_LOG_E("Metronome", "cannot create mutex\r\n");
  61. free(metronome_state);
  62. return 255;
  63. }
  64. // Set system callbacks
  65. ViewPort* view_port = view_port_alloc();
  66. view_port_draw_callback_set(view_port, render_callback, &state_mutex);
  67. view_port_input_callback_set(view_port, input_callback, event_queue);
  68. // Open GUI and register view_port
  69. Gui* gui = furi_record_open("gui");
  70. gui_add_view_port(gui, view_port, GuiLayerFullscreen);
  71. PluginEvent event;
  72. for(bool processing = true; processing;) {
  73. FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
  74. MetronomeState* metronome_state = (MetronomeState*)acquire_mutex_block(&state_mutex);
  75. if(event_status == FuriStatusOk) {
  76. // press events
  77. if(event.type == EventTypeKey) {
  78. if(event.input.type == InputTypePress) {
  79. switch(event.input.key) {
  80. case InputKeyUp:
  81. break;
  82. case InputKeyDown:
  83. break;
  84. case InputKeyRight:
  85. metronome_state->bpm += BPM_STEP_SIZE;
  86. break;
  87. case InputKeyLeft:
  88. metronome_state->bpm -= BPM_STEP_SIZE;
  89. break;
  90. case InputKeyOk:
  91. metronome_state->playing = !metronome_state->playing;
  92. break;
  93. case InputKeyBack:
  94. processing = false;
  95. break;
  96. }
  97. }
  98. }
  99. } else {
  100. FURI_LOG_D("Hello_world", "FuriMessageQueue: event timeout");
  101. // event timeout
  102. }
  103. view_port_update(view_port);
  104. release_mutex(&state_mutex, metronome_state);
  105. }
  106. view_port_enabled_set(view_port, false);
  107. gui_remove_view_port(gui, view_port);
  108. furi_record_close("gui");
  109. view_port_free(view_port);
  110. furi_message_queue_free(event_queue);
  111. delete_mutex(&state_mutex);
  112. free(metronome_state);
  113. return 0;
  114. }