pattern_editor.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. #include "pattern_editor.h"
  2. #include <flizzer_tracker_icons.h>
  3. #define PATTERN_EDITOR_Y (64 - (6 * 5) - 1)
  4. static const char* notenames[] =
  5. {
  6. "C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-",
  7. };
  8. char* notename(uint8_t note)
  9. {
  10. static char buffer[4];
  11. if(note == MUS_NOTE_CUT)
  12. {
  13. snprintf(buffer, sizeof(buffer), "%s", "OFF");
  14. }
  15. if(note == MUS_NOTE_RELEASE)
  16. {
  17. snprintf(buffer, sizeof(buffer), " ");
  18. }
  19. else
  20. {
  21. snprintf(buffer, sizeof(buffer), "%s%d", notenames[note % 12], note / 12);
  22. }
  23. return buffer;
  24. }
  25. static const char to_char_array[] =
  26. {
  27. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  28. 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
  29. 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
  30. 'U', 'V', 'W', 'X', 'Y', 'Z',
  31. };
  32. char to_char(uint8_t number)
  33. {
  34. return to_char_array[number];
  35. }
  36. void draw_pattern_view(Canvas* canvas, FlizzerTrackerApp* tracker)
  37. {
  38. char command_buffer[6] = {0};
  39. char buffer[11] = {0};
  40. canvas_draw_line(canvas, 0, PATTERN_EDITOR_Y, 127, PATTERN_EDITOR_Y);
  41. for(int i = 1; i < SONG_MAX_CHANNELS; ++i)
  42. {
  43. for(int y = PATTERN_EDITOR_Y + 1; y < 64; y += 2)
  44. {
  45. canvas_draw_dot(canvas, i * 32 - 1, y);
  46. }
  47. }
  48. for(int i = 0; i < SONG_MAX_CHANNELS; ++i)
  49. {
  50. uint8_t sequence_position = tracker->tracker_engine.sequence_position;
  51. uint8_t current_pattern = tracker->tracker_engine.song->sequence.sequence_step[sequence_position].pattern_indices[i];
  52. uint8_t pattern_step = tracker->tracker_engine.pattern_position;
  53. uint8_t pattern_length = tracker->tracker_engine.song->pattern_length;
  54. TrackerSongPattern* pattern = &tracker->tracker_engine.song->pattern[current_pattern];
  55. for(uint8_t pos = 0; pos < 5; ++pos)
  56. {
  57. TrackerSongPatternStep* step = NULL;
  58. if(pattern_step - 2 + pos >= 0 && pattern_step - 2 + pos < pattern_length)
  59. {
  60. step = &pattern->step[pattern_step + pos - 2];
  61. }
  62. uint8_t string_x = i * 32;
  63. uint8_t string_y = PATTERN_EDITOR_Y + 6 * pos + 6 + 1;
  64. if(step)
  65. {
  66. uint8_t note = tracker_engine_get_note(step);
  67. uint8_t inst = tracker_engine_get_instrument(step);
  68. uint8_t vol = tracker_engine_get_volume(step);
  69. uint16_t command = tracker_engine_get_command(step);
  70. char inst_ch = to_char(inst);
  71. char vol_ch = to_char(vol);
  72. char command_ch = to_char(command >> 8);
  73. if(inst == MUS_NOTE_INSTRUMENT_NONE)
  74. {
  75. inst_ch = '-';
  76. }
  77. if(vol == MUS_NOTE_VOLUME_NONE)
  78. {
  79. vol_ch = '-';
  80. }
  81. if(command == 0)
  82. {
  83. snprintf(command_buffer, sizeof(command_buffer), "---");
  84. }
  85. else
  86. {
  87. snprintf(command_buffer, sizeof(command_buffer), "%c%02X", command_ch, (command & 0xff));
  88. }
  89. snprintf(buffer, sizeof(buffer), "%s%c%c%s", (note == MUS_NOTE_NONE ? "---" : notename(note)), inst_ch, vol_ch, command_buffer);
  90. canvas_draw_str(canvas, string_x, string_y, buffer);
  91. if(note == MUS_NOTE_RELEASE)
  92. {
  93. canvas_draw_icon(canvas, string_x, string_y - 5, &I_note_release);
  94. }
  95. }
  96. }
  97. }
  98. if(tracker->editing && tracker->focus == EDIT_PATTERN)
  99. {
  100. uint8_t x = tracker->current_channel * 32 + tracker->patternx * 4 + (tracker->patternx > 0 ? 4 : 0) - 1;
  101. uint8_t y = PATTERN_EDITOR_Y + 6 * 2 + 1;
  102. canvas_draw_box(canvas, x, y, (tracker->patternx > 0 ? 5 : 9), 7);
  103. }
  104. }
  105. #define SEQ_SLIDER_X (4 * (4 * 2 + 1) + 2)
  106. #define SEQ_SLIDER_Y (32)
  107. void draw_sequence_view(Canvas* canvas, FlizzerTrackerApp* tracker)
  108. {
  109. char buffer[4];
  110. uint8_t sequence_position = tracker->tracker_engine.sequence_position;
  111. for(int pos = sequence_position - 2; pos < sequence_position + 3; pos++)
  112. {
  113. if(pos >= 0 && pos < tracker->song.num_sequence_steps)
  114. {
  115. for(int i = 0; i < SONG_MAX_CHANNELS; ++i)
  116. {
  117. uint8_t current_pattern = tracker->tracker_engine.song->sequence.sequence_step[pos].pattern_indices[i];
  118. uint8_t x = i * (4 * 2 + 1) + 3;
  119. uint8_t y = (pos - (sequence_position - 2)) * 6 + 5;
  120. snprintf(buffer, sizeof(buffer), "%02X", current_pattern);
  121. canvas_draw_str(canvas, x, y, buffer);
  122. }
  123. }
  124. }
  125. //TODO: add song loop indication
  126. canvas_set_color(canvas, ColorBlack);
  127. canvas_draw_line(canvas, SEQ_SLIDER_X, 0, SEQ_SLIDER_X + 2, 0);
  128. canvas_draw_line(canvas, SEQ_SLIDER_X, SEQ_SLIDER_Y, SEQ_SLIDER_X + 2, SEQ_SLIDER_Y);
  129. canvas_draw_line(canvas, SEQ_SLIDER_X, 0, SEQ_SLIDER_X, SEQ_SLIDER_Y);
  130. canvas_draw_line(canvas, SEQ_SLIDER_X + 2, 0, SEQ_SLIDER_X + 2, SEQ_SLIDER_Y);
  131. uint8_t start_pos = sequence_position * (SEQ_SLIDER_Y - 2) / tracker->song.num_sequence_steps + 1;
  132. uint8_t slider_length = (SEQ_SLIDER_Y - 2) / tracker->song.num_sequence_steps + 1;
  133. canvas_draw_line(canvas, SEQ_SLIDER_X + 1, start_pos, SEQ_SLIDER_X + 1, (start_pos + slider_length));
  134. canvas_set_color(canvas, ColorXOR);
  135. if(tracker->editing && tracker->focus == EDIT_SEQUENCE)
  136. {
  137. uint8_t x = tracker->current_channel * (4 + 4 + 1) + (tracker->current_digit ? 4 : 0) + 2;
  138. uint8_t y = 11;
  139. canvas_draw_box(canvas, x, y, 5, 7);
  140. }
  141. }
  142. #define member_size(type, member) sizeof(((type *)0)->member)
  143. #define SONG_HEADER_SIZE (member_size(TrackerSong, song_name) + member_size(TrackerSong, speed) + member_size(TrackerSong, rate) \
  144. + member_size(TrackerSong, loop_start) + member_size(TrackerSong, loop_end) + member_size(TrackerSong, num_patterns) \
  145. + member_size(TrackerSong, num_sequence_steps) + member_size(TrackerSong, num_instruments) + member_size(TrackerSong, pattern_length))
  146. uint32_t calculate_song_size(TrackerSong* song)
  147. {
  148. uint32_t song_size = SONG_HEADER_SIZE + sizeof(Instrument) * song->num_instruments + sizeof(TrackerSongPatternStep) * song->num_patterns * song->pattern_length + sizeof(TrackerSongSequenceStep) * song->num_sequence_steps;
  149. return song_size;
  150. }
  151. void draw_generic_n_digit_field(FlizzerTrackerApp* tracker, Canvas* canvas, uint8_t focus, uint8_t param, const char* text, uint8_t x, uint8_t y, uint8_t digits) //last 1-2 symbols are digits we are editing
  152. {
  153. canvas_draw_str(canvas, x, y, text);
  154. if(tracker->focus == focus && tracker->selected_param == param && tracker->editing)
  155. {
  156. if(param != SI_SONGNAME && param != SI_INSTRUMENTNAME)
  157. {
  158. canvas_draw_box(canvas, x + strlen(text) * 4 - digits * 4 + tracker->current_digit * 4 - 1, y - 6, 5, 7);
  159. }
  160. else
  161. {
  162. canvas_draw_box(canvas, x - 1, y - 6, strlen(text) * 4 + 2, 7);
  163. }
  164. }
  165. }
  166. void draw_songinfo_view(Canvas* canvas, FlizzerTrackerApp* tracker)
  167. {
  168. char buffer[30];
  169. snprintf(buffer, sizeof(buffer), "PAT.P.%02X/%02X", tracker->tracker_engine.pattern_position, tracker->song.pattern_length - 1);
  170. draw_generic_n_digit_field(tracker, canvas, EDIT_SONGINFO, SI_PATTERNPOS, buffer, 42, 5, 2);
  171. snprintf(buffer, sizeof(buffer), "SEQ.P.%02X/%02X", tracker->tracker_engine.sequence_position, tracker->song.num_sequence_steps);
  172. draw_generic_n_digit_field(tracker, canvas, EDIT_SONGINFO, SI_SEQUENCEPOS, buffer, 42, 11, 2);
  173. snprintf(buffer, sizeof(buffer), "SPD.%02X", tracker->song.speed);
  174. draw_generic_n_digit_field(tracker, canvas, EDIT_SONGINFO, SI_SONGSPEED, buffer, 42, 17, 2);
  175. snprintf(buffer, sizeof(buffer), "RATE %02X", tracker->song.rate);
  176. draw_generic_n_digit_field(tracker, canvas, EDIT_SONGINFO, SI_SONGRATE, buffer, 42 + 4 * 7, 17, 2);
  177. snprintf(buffer, sizeof(buffer), "VOL %02X", tracker->tracker_engine.master_volume);
  178. draw_generic_n_digit_field(tracker, canvas, EDIT_SONGINFO, SI_MASTERVOL, buffer, 42 + 4 * 7 + 4 * 8, 17, 2);
  179. snprintf(buffer, sizeof(buffer), "SONG:%s", tracker->song.song_name);
  180. draw_generic_n_digit_field(tracker, canvas, EDIT_SONGINFO, SI_SONGNAME, buffer, 42, 23, 1);
  181. snprintf(buffer, sizeof(buffer), "INST:%s", tracker->song.instrument[tracker->current_instrument]->name);
  182. draw_generic_n_digit_field(tracker, canvas, EDIT_SONGINFO, SI_INSTRUMENTNAME, buffer, 42, 29, 1);
  183. uint32_t song_size = calculate_song_size(&tracker->song);
  184. uint32_t free_bytes = memmgr_get_free_heap();
  185. canvas_draw_line(canvas, 128 - 4 * 10 - 2, 0, 128 - 4 * 10 - 2, 10);
  186. char song_size_buffer[12];
  187. char free_bytes_buffer[12];
  188. if(song_size > 999)
  189. {
  190. snprintf(song_size_buffer, sizeof(song_size_buffer), "TUNE:%.1fK", (double)song_size / (double)1024.0);
  191. }
  192. else
  193. {
  194. snprintf(song_size_buffer, sizeof(song_size_buffer), "TUNE:%ld", song_size);
  195. }
  196. if(free_bytes > 999)
  197. {
  198. snprintf(free_bytes_buffer, sizeof(song_size_buffer), "FREE:%.1fK", (double)free_bytes / (double)1024.0);
  199. }
  200. else
  201. {
  202. snprintf(free_bytes_buffer, sizeof(song_size_buffer), "FREE:%ld", free_bytes);
  203. }
  204. canvas_draw_str(canvas, 128 - 4 * 10, 5, song_size_buffer);
  205. canvas_draw_str(canvas, 128 - 4 * 10, 11, free_bytes_buffer);
  206. }