input_event.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. #include "input_event.h"
  2. #include "diskop.h"
  3. #include <flizzer_tracker_icons.h>
  4. #define AUDIO_MODES_COUNT 2
  5. void return_from_keyboard_callback(void* ctx) {
  6. FlizzerTrackerApp* tracker = (FlizzerTrackerApp*)ctx;
  7. if(!tracker->is_loading && !tracker->is_saving && !tracker->is_loading_instrument &&
  8. !tracker->is_saving_instrument) {
  9. uint8_t string_length = 0;
  10. char* string = NULL;
  11. if(tracker->focus == EDIT_SONGINFO && tracker->mode == PATTERN_VIEW) {
  12. switch(tracker->selected_param) {
  13. case SI_SONGNAME: {
  14. string_length = MUS_SONG_NAME_LEN;
  15. string = (char*)&tracker->song.song_name;
  16. break;
  17. }
  18. case SI_INSTRUMENTNAME: {
  19. string_length = MUS_INST_NAME_LEN;
  20. string = (char*)&tracker->song.instrument[tracker->current_instrument]->name;
  21. break;
  22. }
  23. }
  24. }
  25. if(tracker->focus == EDIT_INSTRUMENT && tracker->mode == INST_EDITOR_VIEW) {
  26. switch(tracker->selected_param) {
  27. case INST_INSTRUMENTNAME: {
  28. string_length = MUS_INST_NAME_LEN;
  29. string = (char*)&tracker->song.instrument[tracker->current_instrument]->name;
  30. break;
  31. }
  32. }
  33. }
  34. if(string == NULL || string_length == 0) return;
  35. for(uint8_t i = 0; i < string_length;
  36. i++) // I tinyfied the font by deleting lowercase chars, and I don't like the lowercase chars of any 3x5 pixels font
  37. {
  38. string[i] = toupper(string[i]);
  39. }
  40. }
  41. view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_TRACKER);
  42. if(tracker->is_saving) {
  43. stop_song(tracker);
  44. tracker->filepath = furi_string_alloc();
  45. furi_string_cat_printf(
  46. tracker->filepath, "%s/%s%s", FLIZZER_TRACKER_FOLDER, tracker->filename, SONG_FILE_EXT);
  47. if(storage_file_exists(tracker->storage, furi_string_get_cstr(tracker->filepath))) {
  48. view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_FILE_OVERWRITE);
  49. return;
  50. }
  51. else {
  52. save_song(tracker, tracker->filepath);
  53. }
  54. }
  55. if(tracker->is_saving_instrument) {
  56. stop_song(tracker);
  57. tracker->filepath = furi_string_alloc();
  58. furi_string_cat_printf(
  59. tracker->filepath,
  60. "%s/%s%s",
  61. FLIZZER_TRACKER_INSTRUMENTS_FOLDER,
  62. tracker->filename,
  63. INST_FILE_EXT);
  64. if(storage_file_exists(tracker->storage, furi_string_get_cstr(tracker->filepath))) {
  65. view_dispatcher_switch_to_view(
  66. tracker->view_dispatcher, VIEW_INSTRUMENT_FILE_OVERWRITE);
  67. return;
  68. }
  69. else {
  70. save_instrument(tracker, tracker->filepath);
  71. }
  72. }
  73. }
  74. void overwrite_file_widget_yes_input_callback(GuiButtonType result, InputType type, void* ctx) {
  75. UNUSED(result);
  76. FlizzerTrackerApp* tracker = (FlizzerTrackerApp*)ctx;
  77. if(type == InputTypeShort) {
  78. tracker->is_saving = true;
  79. view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_TRACKER);
  80. save_song(tracker, tracker->filepath);
  81. }
  82. }
  83. void overwrite_file_widget_no_input_callback(GuiButtonType result, InputType type, void* ctx) {
  84. UNUSED(result);
  85. FlizzerTrackerApp* tracker = (FlizzerTrackerApp*)ctx;
  86. if(type == InputTypeShort) {
  87. tracker->is_saving = false;
  88. furi_string_free(tracker->filepath);
  89. view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_TRACKER);
  90. }
  91. }
  92. void overwrite_instrument_file_widget_yes_input_callback(
  93. GuiButtonType result,
  94. InputType type,
  95. void* ctx) {
  96. UNUSED(result);
  97. FlizzerTrackerApp* tracker = (FlizzerTrackerApp*)ctx;
  98. if(type == InputTypeShort) {
  99. tracker->is_saving_instrument = true;
  100. view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_TRACKER);
  101. // save_song(tracker, tracker->filepath);
  102. static FlizzerTrackerEvent event = {
  103. .type = EventTypeSaveInstrument, .input = {{0}}, .period = 0};
  104. furi_message_queue_put(tracker->event_queue, &event, FuriWaitForever);
  105. }
  106. }
  107. void overwrite_instrument_file_widget_no_input_callback(
  108. GuiButtonType result,
  109. InputType type,
  110. void* ctx) {
  111. UNUSED(result);
  112. FlizzerTrackerApp* tracker = (FlizzerTrackerApp*)ctx;
  113. if(type == InputTypeShort) {
  114. tracker->is_saving_instrument = false;
  115. furi_string_free(tracker->filepath);
  116. view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_TRACKER);
  117. }
  118. }
  119. uint32_t submenu_settings_exit_callback(void* context) {
  120. UNUSED(context);
  121. return VIEW_SUBMENU_PATTERN;
  122. }
  123. uint32_t submenu_exit_callback(void* context) {
  124. UNUSED(context);
  125. return VIEW_TRACKER;
  126. }
  127. void submenu_callback(void* context, uint32_t index) {
  128. FlizzerTrackerApp* tracker = (FlizzerTrackerApp*)context;
  129. switch(tracker->mode) {
  130. case PATTERN_VIEW: {
  131. switch(index) {
  132. case SUBMENU_PATTERN_EXIT: {
  133. tracker->quit = true;
  134. view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_TRACKER);
  135. view_dispatcher_stop(tracker->view_dispatcher);
  136. break;
  137. }
  138. case SUBMENU_PATTERN_HELP: {
  139. tracker->showing_help = true;
  140. view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_TRACKER);
  141. break;
  142. }
  143. case SUBMENU_PATTERN_SAVE_SONG: {
  144. text_input_set_header_text(tracker->text_input, "Song filename:");
  145. memset(&tracker->filename, 0, FILE_NAME_LEN);
  146. text_input_set_result_callback(
  147. tracker->text_input,
  148. return_from_keyboard_callback,
  149. tracker,
  150. (char*)&tracker->filename,
  151. FILE_NAME_LEN,
  152. true);
  153. tracker->is_saving = true;
  154. view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_KEYBOARD);
  155. break;
  156. }
  157. case SUBMENU_PATTERN_LOAD_SONG: {
  158. view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_TRACKER);
  159. stop_song(tracker);
  160. tracker->tracker_engine.sequence_position = tracker->tracker_engine.pattern_position =
  161. tracker->current_instrument = 0;
  162. tracker->dialogs = furi_record_open(RECORD_DIALOGS);
  163. tracker->is_loading = true;
  164. FuriString* path;
  165. path = furi_string_alloc();
  166. furi_string_set(path, FLIZZER_TRACKER_FOLDER);
  167. DialogsFileBrowserOptions browser_options;
  168. dialog_file_browser_set_basic_options(
  169. &browser_options, SONG_FILE_EXT, &I_flizzer_tracker_module);
  170. browser_options.base_path = FLIZZER_TRACKER_FOLDER;
  171. browser_options.hide_ext = false;
  172. bool ret = dialog_file_browser_show(tracker->dialogs, path, path, &browser_options);
  173. furi_record_close(RECORD_DIALOGS);
  174. const char* cpath = furi_string_get_cstr(path);
  175. if(ret && strcmp(&cpath[strlen(cpath) - 4], SONG_FILE_EXT) == 0) {
  176. bool result = load_song_util(tracker, path);
  177. UNUSED(result);
  178. }
  179. else {
  180. furi_string_free(path);
  181. tracker->is_loading = false;
  182. }
  183. break;
  184. }
  185. case SUBMENU_PATTERN_SETTINGS: {
  186. view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_SETTINGS);
  187. break;
  188. }
  189. default:
  190. break;
  191. }
  192. break;
  193. }
  194. case INST_EDITOR_VIEW: {
  195. switch(index) {
  196. case SUBMENU_INSTRUMENT_EXIT: {
  197. tracker->quit = true;
  198. view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_TRACKER);
  199. view_dispatcher_stop(tracker->view_dispatcher);
  200. break;
  201. }
  202. case SUBMENU_INSTRUMENT_SAVE: {
  203. text_input_set_header_text(tracker->text_input, "Instrument filename:");
  204. memset(&tracker->filename, 0, FILE_NAME_LEN);
  205. text_input_set_result_callback(
  206. tracker->text_input,
  207. return_from_keyboard_callback,
  208. tracker,
  209. (char*)&tracker->filename,
  210. FILE_NAME_LEN,
  211. true);
  212. tracker->is_saving_instrument = true;
  213. view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_KEYBOARD);
  214. break;
  215. }
  216. case SUBMENU_INSTRUMENT_LOAD: {
  217. view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_TRACKER);
  218. stop_song(tracker);
  219. tracker->dialogs = furi_record_open(RECORD_DIALOGS);
  220. tracker->is_loading_instrument = true;
  221. FuriString* path;
  222. path = furi_string_alloc();
  223. furi_string_set(path, FLIZZER_TRACKER_INSTRUMENTS_FOLDER);
  224. DialogsFileBrowserOptions browser_options;
  225. dialog_file_browser_set_basic_options(
  226. &browser_options, INST_FILE_EXT, &I_flizzer_tracker_instrument);
  227. browser_options.base_path = FLIZZER_TRACKER_FOLDER;
  228. browser_options.hide_ext = false;
  229. bool ret = dialog_file_browser_show(tracker->dialogs, path, path, &browser_options);
  230. furi_record_close(RECORD_DIALOGS);
  231. const char* cpath = furi_string_get_cstr(path);
  232. if(ret && strcmp(&cpath[strlen(cpath) - 4], INST_FILE_EXT) == 0) {
  233. bool result = load_instrument_util(tracker, path);
  234. UNUSED(result);
  235. }
  236. else {
  237. furi_string_free(path);
  238. tracker->is_loading = false;
  239. }
  240. break;
  241. }
  242. default:
  243. break;
  244. }
  245. break;
  246. }
  247. default:
  248. break;
  249. }
  250. }
  251. void submenu_copypaste_callback(void* context, uint32_t index) {
  252. FlizzerTrackerApp* tracker = (FlizzerTrackerApp*)context;
  253. uint8_t sequence_position = tracker->tracker_engine.sequence_position;
  254. uint8_t current_pattern_index =
  255. tracker->tracker_engine.song->sequence.sequence_step[sequence_position]
  256. .pattern_indices[tracker->current_channel];
  257. TrackerSongPattern* source_pattern;
  258. if(tracker->source_pattern_index >= 0) {
  259. source_pattern = &tracker->song.pattern[tracker->source_pattern_index];
  260. }
  261. TrackerSongPattern* current_pattern = &tracker->song.pattern[current_pattern_index];
  262. uint16_t pattern_length = tracker->tracker_engine.song->pattern_length;
  263. switch(index) {
  264. case SUBMENU_PATTERN_COPYPASTE_COPY: {
  265. tracker->source_pattern_index = current_pattern_index;
  266. tracker->cut_pattern = false;
  267. break;
  268. }
  269. case SUBMENU_PATTERN_COPYPASTE_PASTE: {
  270. if(tracker->source_pattern_index >= 0) {
  271. memcpy(
  272. current_pattern->step,
  273. source_pattern->step,
  274. sizeof(TrackerSongPatternStep) * pattern_length);
  275. if(tracker->cut_pattern) {
  276. set_empty_pattern(source_pattern, pattern_length);
  277. tracker->cut_pattern = false;
  278. }
  279. }
  280. break;
  281. }
  282. case SUBMENU_PATTERN_COPYPASTE_CUT: {
  283. tracker->source_pattern_index = current_pattern_index;
  284. tracker->cut_pattern = true;
  285. break;
  286. }
  287. case SUBMENU_PATTERN_COPYPASTE_CLEAR: {
  288. set_empty_pattern(current_pattern, pattern_length);
  289. break;
  290. }
  291. default:
  292. break;
  293. }
  294. view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_TRACKER);
  295. }
  296. void audio_output_changed_callback(VariableItem* item) {
  297. FlizzerTrackerApp* tracker = (FlizzerTrackerApp*)variable_item_get_context(item);
  298. uint8_t index = variable_item_get_current_value_index(item);
  299. variable_item_set_current_value_text(item, audio_modes_text[(index > 1 ? 1 : index)]);
  300. if(tracker) {
  301. tracker->external_audio = (bool)index;
  302. tracker->external_audio = audio_modes_values[(index > 1 ? 1 : index)];
  303. sound_engine_PWM_timer_init(tracker->external_audio);
  304. tracker->sound_engine.external_audio_output = tracker->external_audio;
  305. }
  306. }
  307. void cycle_focus(FlizzerTrackerApp* tracker) {
  308. switch(tracker->mode) {
  309. case PATTERN_VIEW: {
  310. tracker->focus++;
  311. if(tracker->focus > EDIT_SONGINFO) {
  312. tracker->focus = EDIT_PATTERN;
  313. }
  314. break;
  315. }
  316. case INST_EDITOR_VIEW: {
  317. tracker->focus++;
  318. if(tracker->focus > EDIT_PROGRAM) {
  319. tracker->focus = EDIT_INSTRUMENT;
  320. if(tracker->current_digit > 1) {
  321. tracker->current_digit = 1;
  322. }
  323. }
  324. break;
  325. }
  326. default:
  327. break;
  328. }
  329. }
  330. void cycle_view(FlizzerTrackerApp* tracker) {
  331. if(tracker->mode == PATTERN_VIEW) {
  332. tracker->mode = INST_EDITOR_VIEW;
  333. tracker->focus = EDIT_INSTRUMENT;
  334. tracker->selected_param = 0;
  335. tracker->current_digit = 0;
  336. return;
  337. }
  338. if(tracker->mode == INST_EDITOR_VIEW) {
  339. tracker->mode = PATTERN_VIEW;
  340. tracker->focus = EDIT_PATTERN;
  341. if(tracker->tracker_engine.song == NULL) {
  342. stop_song(tracker);
  343. tracker_engine_set_song(&tracker->tracker_engine, &tracker->song);
  344. }
  345. tracker->selected_param = 0;
  346. tracker->current_digit = 0;
  347. return;
  348. }
  349. }
  350. void process_input_event(FlizzerTrackerApp* tracker, FlizzerTrackerEvent* event) {
  351. if(event->input.key == InputKeyBack && event->input.type == InputTypeShort &&
  352. tracker->showing_help) {
  353. tracker->showing_help = false;
  354. return;
  355. }
  356. if(tracker->showing_help || tracker->is_loading || tracker->is_saving ||
  357. tracker->is_loading_instrument || tracker->is_saving_instrument)
  358. return; //do not react until these are finished
  359. if(event->input.key == InputKeyBack && event->input.type == InputTypeShort &&
  360. event->period > 0 && event->period < 300 && !(tracker->editing)) {
  361. cycle_view(tracker);
  362. stop_song(tracker);
  363. return;
  364. }
  365. else if(
  366. event->input.key == InputKeyBack && event->input.type == InputTypeShort &&
  367. !(tracker->editing)) {
  368. cycle_focus(tracker);
  369. //stop_song(tracker);
  370. return;
  371. }
  372. if(event->input.key == InputKeyBack && event->input.type == InputTypeLong) {
  373. switch(tracker->mode) {
  374. case PATTERN_VIEW: {
  375. if(tracker->focus == EDIT_PATTERN) {
  376. submenu_set_selected_item(
  377. tracker->pattern_copypaste_submenu, SUBMENU_PATTERN_COPYPASTE_COPY);
  378. view_dispatcher_switch_to_view(
  379. tracker->view_dispatcher, VIEW_SUBMENU_PATTERN_COPYPASTE);
  380. }
  381. else {
  382. submenu_set_selected_item(tracker->pattern_submenu, SUBMENU_PATTERN_LOAD_SONG);
  383. view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_SUBMENU_PATTERN);
  384. }
  385. break;
  386. }
  387. case INST_EDITOR_VIEW: {
  388. submenu_set_selected_item(tracker->instrument_submenu, SUBMENU_INSTRUMENT_LOAD);
  389. view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_SUBMENU_INSTRUMENT);
  390. break;
  391. }
  392. default:
  393. break;
  394. }
  395. return;
  396. }
  397. switch(tracker->focus) {
  398. case EDIT_PATTERN: {
  399. pattern_edit_event(tracker, event);
  400. break;
  401. }
  402. case EDIT_SEQUENCE: {
  403. sequence_edit_event(tracker, event);
  404. break;
  405. }
  406. case EDIT_SONGINFO: {
  407. songinfo_edit_event(tracker, event);
  408. break;
  409. }
  410. case EDIT_INSTRUMENT: {
  411. instrument_edit_event(tracker, event);
  412. break;
  413. }
  414. case EDIT_PROGRAM: {
  415. instrument_program_edit_event(tracker, event);
  416. break;
  417. }
  418. default:
  419. break;
  420. }
  421. }