tracker_view.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #include "tracker_view.h"
  2. #include <gui/elements.h>
  3. #include <furi.h>
  4. typedef struct {
  5. const Song* song;
  6. uint8_t order_list_index;
  7. uint8_t row;
  8. } TrackerViewModel;
  9. struct TrackerView {
  10. View* view;
  11. void* back_context;
  12. TrackerViewCallback back_callback;
  13. };
  14. static Channel* get_current_channel(TrackerViewModel* model) {
  15. uint8_t channel_id = 0;
  16. uint8_t pattern_id = model->song->order_list[model->order_list_index];
  17. Pattern* pattern = &model->song->patterns[pattern_id];
  18. return &pattern->channels[channel_id];
  19. }
  20. static const char* get_note_from_id(uint8_t note) {
  21. #define NOTE_COUNT 12
  22. const char* notes[NOTE_COUNT] = {
  23. "C ",
  24. "C#",
  25. "D ",
  26. "D#",
  27. "E ",
  28. "F ",
  29. "F#",
  30. "G ",
  31. "G#",
  32. "A ",
  33. "A#",
  34. "B ",
  35. };
  36. return notes[(note) % NOTE_COUNT];
  37. #undef NOTE_COUNT
  38. }
  39. static uint8_t get_octave_from_id(uint8_t note) {
  40. return ((note) / 12) + 2;
  41. }
  42. static uint8_t get_first_row_id(uint8_t row) {
  43. return (row / 10) * 10;
  44. }
  45. static void
  46. draw_row(Canvas* canvas, uint8_t i, Channel* channel, uint8_t row, FuriString* buffer) {
  47. uint8_t x = 12 * (i + 1);
  48. uint8_t first_row_id = get_first_row_id(row);
  49. uint8_t current_row_id = first_row_id + i;
  50. if((current_row_id) >= 64) {
  51. return;
  52. }
  53. Row current_row = channel->rows[current_row_id];
  54. uint8_t note = current_row & ROW_NOTE_MASK;
  55. uint8_t effect = (current_row >> 6) & ROW_EFFECT_MASK;
  56. uint8_t data = (current_row >> 10) & ROW_EFFECT_DATA_MASK;
  57. if(current_row_id == row) {
  58. canvas_set_color(canvas, ColorBlack);
  59. canvas_draw_line(canvas, x - 9, 1, x - 9, 62);
  60. canvas_draw_box(canvas, x - 8, 0, 9, 64);
  61. canvas_draw_line(canvas, x + 1, 1, x + 1, 62);
  62. canvas_set_color(canvas, ColorWhite);
  63. }
  64. furi_string_printf(buffer, "%02X", current_row_id);
  65. canvas_draw_str(canvas, x, 61, furi_string_get_cstr(buffer));
  66. if(note > 0 && note < NOTE_OFF) {
  67. furi_string_printf(
  68. buffer, "%s%d", get_note_from_id(note - 1), get_octave_from_id(note - 1));
  69. canvas_draw_str(canvas, x, 44, furi_string_get_cstr(buffer));
  70. } else if(note == NOTE_OFF) {
  71. canvas_draw_str(canvas, x, 44, "OFF");
  72. } else {
  73. canvas_draw_str(canvas, x, 44, "---");
  74. }
  75. if(effect == 0 && data == 0) {
  76. canvas_draw_str(canvas, x, 21, "-");
  77. canvas_draw_str(canvas, x, 12, "--");
  78. } else {
  79. furi_string_printf(buffer, "%X", effect);
  80. canvas_draw_str(canvas, x, 21, furi_string_get_cstr(buffer));
  81. if(effect == EffectArpeggio || effect == EffectVibrato) {
  82. uint8_t data_x = EFFECT_DATA_GET_X(data);
  83. uint8_t data_y = EFFECT_DATA_GET_Y(data);
  84. furi_string_printf(buffer, "%d%d", data_x, data_y);
  85. canvas_draw_str(canvas, x, 12, furi_string_get_cstr(buffer));
  86. } else {
  87. furi_string_printf(buffer, "%02X", data);
  88. canvas_draw_str(canvas, x, 12, furi_string_get_cstr(buffer));
  89. }
  90. }
  91. if(current_row_id == row) {
  92. canvas_set_color(canvas, ColorBlack);
  93. }
  94. }
  95. static void tracker_view_draw_callback(Canvas* canvas, void* _model) {
  96. TrackerViewModel* model = _model;
  97. if(model->song == NULL) {
  98. return;
  99. }
  100. canvas_set_font_direction(canvas, CanvasDirectionBottomToTop);
  101. canvas_set_font(canvas, FontKeyboard);
  102. Channel* channel = get_current_channel(model);
  103. FuriString* buffer = furi_string_alloc();
  104. for(uint8_t i = 0; i < 10; i++) {
  105. draw_row(canvas, i, channel, model->row, buffer);
  106. }
  107. furi_string_free(buffer);
  108. }
  109. static bool tracker_view_input_callback(InputEvent* event, void* context) {
  110. TrackerView* tracker_view = context;
  111. if(tracker_view->back_callback) {
  112. if(event->type == InputTypeShort && event->key == InputKeyBack) {
  113. tracker_view->back_callback(tracker_view->back_context);
  114. return true;
  115. }
  116. }
  117. return false;
  118. }
  119. TrackerView* tracker_view_alloc() {
  120. TrackerView* tracker_view = malloc(sizeof(TrackerView));
  121. tracker_view->view = view_alloc();
  122. view_allocate_model(tracker_view->view, ViewModelTypeLocking, sizeof(TrackerViewModel));
  123. view_set_context(tracker_view->view, tracker_view);
  124. view_set_draw_callback(tracker_view->view, (ViewDrawCallback)tracker_view_draw_callback);
  125. view_set_input_callback(tracker_view->view, (ViewInputCallback)tracker_view_input_callback);
  126. return tracker_view;
  127. }
  128. void tracker_view_free(TrackerView* tracker_view) {
  129. view_free(tracker_view->view);
  130. free(tracker_view);
  131. }
  132. View* tracker_view_get_view(TrackerView* tracker_view) {
  133. return tracker_view->view;
  134. }
  135. void tracker_view_set_back_callback(
  136. TrackerView* tracker_view,
  137. TrackerViewCallback callback,
  138. void* context) {
  139. tracker_view->back_callback = callback;
  140. tracker_view->back_context = context;
  141. }
  142. void tracker_view_set_song(TrackerView* tracker_view, const Song* song) {
  143. with_view_model(
  144. tracker_view->view, TrackerViewModel * model, { model->song = song; }, true);
  145. }
  146. void tracker_view_set_position(TrackerView* tracker_view, uint8_t order_list_index, uint8_t row) {
  147. with_view_model(
  148. tracker_view->view,
  149. TrackerViewModel * model,
  150. {
  151. model->order_list_index = order_list_index;
  152. model->row = row;
  153. },
  154. true);
  155. }