Rev 690 | Rev 729 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
134 | tk | 1 | // $Id: seq_ui.c 728 2009-09-29 21:58:34Z tk $ |
2 | /* |
||
3 | * User Interface Routines |
||
4 | * |
||
5 | * ========================================================================== |
||
6 | * |
||
7 | * Copyright (C) 2008 Thorsten Klose (tk@midibox.org) |
||
8 | * Licensed for personal non-commercial use only. |
||
9 | * All other rights reserved. |
||
10 | * |
||
11 | * ========================================================================== |
||
12 | */ |
||
13 | |||
14 | ///////////////////////////////////////////////////////////////////////////// |
||
15 | // Include files |
||
16 | ///////////////////////////////////////////////////////////////////////////// |
||
17 | |||
272 | tk | 18 | // with this switch, seq_ui.h/seq_ui_pages.inc will create local variables |
19 | #define SEQ_UI_PAGES_INC_LOCAL_VARS 1 |
||
20 | |||
134 | tk | 21 | #include <mios32.h> |
299 | tk | 22 | #include <string.h> |
690 | tk | 23 | #include <blm.h> |
464 | tk | 24 | #include <blm_x.h> |
190 | tk | 25 | #include <seq_midi_out.h> |
625 | tk | 26 | #include <seq_midi_sysex.h> |
190 | tk | 27 | #include <seq_bpm.h> |
134 | tk | 28 | |
290 | tk | 29 | #include "tasks.h" |
134 | tk | 30 | #include "seq_ui.h" |
728 | tk | 31 | #include "seq_lcd.h" |
32 | #include "seq_lcd_logo.h" |
||
492 | tk | 33 | #include "seq_hwcfg.h" |
134 | tk | 34 | #include "seq_lcd.h" |
35 | #include "seq_led.h" |
||
186 | tk | 36 | #include "seq_midply.h" |
134 | tk | 37 | #include "seq_core.h" |
399 | tk | 38 | #include "seq_song.h" |
333 | tk | 39 | #include "seq_par.h" |
178 | tk | 40 | #include "seq_layer.h" |
184 | tk | 41 | #include "seq_cc.h" |
299 | tk | 42 | #include "seq_file.h" |
690 | tk | 43 | #include "seq_file_hw.h" |
134 | tk | 44 | |
45 | |||
46 | ///////////////////////////////////////////////////////////////////////////// |
||
47 | // Global variables |
||
48 | ///////////////////////////////////////////////////////////////////////////// |
||
49 | |||
159 | tk | 50 | u8 seq_ui_display_update_req; |
51 | u8 seq_ui_display_init_req; |
||
134 | tk | 52 | |
167 | tk | 53 | seq_ui_button_state_t seq_ui_button_state; |
54 | |||
134 | tk | 55 | u8 ui_selected_group; |
484 | tk | 56 | u16 ui_selected_tracks; |
134 | tk | 57 | u8 ui_selected_par_layer; |
58 | u8 ui_selected_trg_layer; |
||
328 | tk | 59 | u8 ui_selected_instrument; |
134 | tk | 60 | u8 ui_selected_step_view; |
61 | u8 ui_selected_step; |
||
168 | tk | 62 | u8 ui_selected_item; |
134 | tk | 63 | |
168 | tk | 64 | u8 ui_selected_item; |
134 | tk | 65 | |
240 | tk | 66 | u16 ui_hold_msg_ctr; |
67 | |||
206 | tk | 68 | seq_ui_page_t ui_page; |
272 | tk | 69 | seq_ui_page_t ui_selected_page; |
600 | tk | 70 | seq_ui_page_t ui_stepview_prev_page; |
71 | seq_ui_page_t ui_trglayer_prev_page; |
||
72 | seq_ui_page_t ui_parlayer_prev_page; |
||
206 | tk | 73 | |
173 | tk | 74 | volatile u8 ui_cursor_flash; |
75 | u16 ui_cursor_flash_ctr; |
||
134 | tk | 76 | |
316 | tk | 77 | u8 ui_edit_name_cursor; |
78 | u8 ui_edit_preset_num_category; |
||
79 | u8 ui_edit_preset_num_label; |
||
80 | |||
193 | tk | 81 | u8 ui_seq_pause; |
82 | |||
625 | tk | 83 | seq_ui_remote_mode_t seq_ui_remote_mode; |
626 | tk | 84 | seq_ui_remote_mode_t seq_ui_remote_active_mode; |
625 | tk | 85 | mios32_midi_port_t seq_ui_remote_port; |
626 | tk | 86 | mios32_midi_port_t seq_ui_remote_active_port; |
625 | tk | 87 | u8 seq_ui_remote_id; |
626 | tk | 88 | u16 seq_ui_remote_client_timeout_ctr; |
89 | u8 seq_ui_remote_force_lcd_update; |
||
90 | u8 seq_ui_remote_force_led_update; |
||
193 | tk | 91 | |
634 | tk | 92 | u8 seq_ui_backup_req; |
625 | tk | 93 | |
634 | tk | 94 | |
134 | tk | 95 | ///////////////////////////////////////////////////////////////////////////// |
96 | // Local variables |
||
97 | ///////////////////////////////////////////////////////////////////////////// |
||
98 | |||
168 | tk | 99 | static s32 (*ui_button_callback)(seq_ui_button_t button, s32 depressed); |
100 | static s32 (*ui_encoder_callback)(seq_ui_encoder_t encoder, s32 incrementer); |
||
173 | tk | 101 | static s32 (*ui_led_callback)(u16 *gp_leds); |
167 | tk | 102 | static s32 (*ui_lcd_callback)(u8 high_prio); |
352 | tk | 103 | static s32 (*ui_exit_callback)(void); |
167 | tk | 104 | |
168 | tk | 105 | static u16 ui_gp_leds; |
167 | tk | 106 | |
524 | tk | 107 | #define NUM_BLM_LED_SRS (2*4) |
108 | static u8 ui_blm_leds[NUM_BLM_LED_SRS]; |
||
109 | |||
596 | tk | 110 | #define UI_MSG_MAX_CHAR 21 |
111 | static char ui_msg[2][UI_MSG_MAX_CHAR]; |
||
112 | static u16 ui_msg_ctr; |
||
113 | static seq_ui_msg_type_t ui_msg_type; |
||
299 | tk | 114 | |
115 | |||
134 | tk | 116 | ///////////////////////////////////////////////////////////////////////////// |
117 | // Initialisation |
||
118 | ///////////////////////////////////////////////////////////////////////////// |
||
119 | s32 SEQ_UI_Init(u32 mode) |
||
120 | { |
||
626 | tk | 121 | int i; |
122 | // clear all LEDs |
||
123 | for(i=0; i<SEQ_LED_NUM_SR; ++i) |
||
124 | SEQ_LED_SRSet(i, 0x00); |
||
125 | |||
134 | tk | 126 | // init selection variables |
127 | ui_selected_group = 0; |
||
128 | ui_selected_tracks = (1 << 0); |
||
129 | ui_selected_par_layer = 0; |
||
130 | ui_selected_trg_layer = 0; |
||
328 | tk | 131 | ui_selected_instrument = 0; |
134 | tk | 132 | ui_selected_step_view = 0; |
133 | ui_selected_step = 0; |
||
168 | tk | 134 | ui_selected_item = 0; |
134 | tk | 135 | |
240 | tk | 136 | ui_hold_msg_ctr = 0; |
596 | tk | 137 | ui_msg_ctr = 0; |
240 | tk | 138 | |
168 | tk | 139 | ui_cursor_flash_ctr = 0; |
173 | tk | 140 | ui_cursor_flash = 0; |
168 | tk | 141 | |
167 | tk | 142 | seq_ui_button_state.ALL = 0; |
143 | |||
193 | tk | 144 | ui_seq_pause = 0; |
145 | |||
134 | tk | 146 | // visible GP pattern |
147 | ui_gp_leds = 0x0000; |
||
148 | |||
625 | tk | 149 | // default remote mode |
150 | seq_ui_remote_mode = SEQ_UI_REMOTE_MODE_AUTO; |
||
626 | tk | 151 | seq_ui_remote_active_mode = SEQ_UI_REMOTE_MODE_AUTO; |
625 | tk | 152 | seq_ui_remote_port = DEFAULT; |
626 | tk | 153 | seq_ui_remote_active_port = DEFAULT; |
625 | tk | 154 | seq_ui_remote_id = 0x00; |
626 | tk | 155 | seq_ui_remote_client_timeout_ctr = 0; |
156 | seq_ui_remote_force_lcd_update = 0; |
||
157 | seq_ui_remote_force_led_update = 0; |
||
625 | tk | 158 | |
634 | tk | 159 | // misc |
160 | seq_ui_backup_req = 0; |
||
161 | |||
167 | tk | 162 | // change to edit page |
163 | ui_page = SEQ_UI_PAGE_NONE; |
||
164 | SEQ_UI_PageSet(SEQ_UI_PAGE_EDIT); |
||
134 | tk | 165 | |
596 | tk | 166 | |
134 | tk | 167 | return 0; // no error |
168 | } |
||
169 | |||
170 | |||
171 | ///////////////////////////////////////////////////////////////////////////// |
||
178 | tk | 172 | // Inits the speed mode of all encoders |
173 | // Auto mode should be used whenever: |
||
174 | // - the edit screen is entered |
||
175 | // - the group is changed |
||
176 | // - a track is changed |
||
177 | // - a layer is changed |
||
178 | ///////////////////////////////////////////////////////////////////////////// |
||
179 | s32 SEQ_UI_InitEncSpeed(u32 auto_config) |
||
180 | { |
||
181 | mios32_enc_config_t enc_config; |
||
182 | |||
183 | if( auto_config ) { |
||
513 | tk | 184 | |
185 | if( !seq_hwcfg_enc.auto_fast ) |
||
186 | return 0; // auto mode not enabled - ignore auto reconfiguration request |
||
187 | |||
333 | tk | 188 | switch( SEQ_PAR_AssignmentGet(SEQ_UI_VisibleTrackGet(), ui_selected_par_layer) ) { |
189 | case SEQ_PAR_Type_Velocity: |
||
190 | case SEQ_PAR_Type_Length: |
||
191 | case SEQ_PAR_Type_CC: |
||
192 | case SEQ_PAR_Type_PitchBend: |
||
193 | case SEQ_PAR_Type_Probability: |
||
194 | case SEQ_PAR_Type_Delay: |
||
178 | tk | 195 | seq_ui_button_state.FAST_ENCODERS = 1; |
196 | break; |
||
197 | |||
198 | default: |
||
199 | seq_ui_button_state.FAST_ENCODERS = 0; |
||
200 | } |
||
201 | } |
||
202 | |||
203 | // change for datawheel and GP encoders |
||
204 | int enc; |
||
205 | for(enc=0; enc<17; ++enc) { |
||
206 | enc_config = MIOS32_ENC_ConfigGet(enc); |
||
207 | enc_config.cfg.speed = seq_ui_button_state.FAST_ENCODERS ? FAST : NORMAL; |
||
513 | tk | 208 | enc_config.cfg.speed_par = (enc == 0) ? seq_hwcfg_enc.datawheel_fast_speed : seq_hwcfg_enc.gp_fast_speed; |
178 | tk | 209 | MIOS32_ENC_ConfigSet(enc, enc_config); |
210 | } |
||
211 | |||
212 | return 0; // no error |
||
213 | } |
||
214 | |||
215 | |||
216 | ///////////////////////////////////////////////////////////////////////////// |
||
167 | tk | 217 | // Various installation routines for menu page LCD handlers |
218 | ///////////////////////////////////////////////////////////////////////////// |
||
168 | tk | 219 | s32 SEQ_UI_InstallButtonCallback(void *callback) |
167 | tk | 220 | { |
168 | tk | 221 | ui_button_callback = callback; |
167 | tk | 222 | return 0; // no error |
223 | } |
||
224 | |||
168 | tk | 225 | s32 SEQ_UI_InstallEncoderCallback(void *callback) |
167 | tk | 226 | { |
168 | tk | 227 | ui_encoder_callback = callback; |
167 | tk | 228 | return 0; // no error |
229 | } |
||
230 | |||
168 | tk | 231 | s32 SEQ_UI_InstallLEDCallback(void *callback) |
167 | tk | 232 | { |
168 | tk | 233 | ui_led_callback = callback; |
167 | tk | 234 | return 0; // no error |
235 | } |
||
236 | |||
168 | tk | 237 | s32 SEQ_UI_InstallLCDCallback(void *callback) |
167 | tk | 238 | { |
239 | ui_lcd_callback = callback; |
||
240 | return 0; // no error |
||
241 | } |
||
242 | |||
352 | tk | 243 | s32 SEQ_UI_InstallExitCallback(void *callback) |
244 | { |
||
245 | ui_exit_callback = callback; |
||
246 | return 0; // no error |
||
247 | } |
||
167 | tk | 248 | |
352 | tk | 249 | |
167 | tk | 250 | ///////////////////////////////////////////////////////////////////////////// |
251 | // Change the menu page |
||
252 | ///////////////////////////////////////////////////////////////////////////// |
||
253 | s32 SEQ_UI_PageSet(seq_ui_page_t page) |
||
254 | { |
||
255 | if( page != ui_page ) { |
||
352 | tk | 256 | |
257 | // call page exit callback |
||
258 | if( ui_exit_callback != NULL ) |
||
259 | ui_exit_callback(); |
||
260 | |||
167 | tk | 261 | // disable hooks of previous page and request re-initialisation |
318 | tk | 262 | portENTER_CRITICAL(); |
167 | tk | 263 | ui_page = page; |
168 | tk | 264 | ui_button_callback = NULL; |
265 | ui_encoder_callback = NULL; |
||
266 | ui_led_callback = NULL; |
||
167 | tk | 267 | ui_lcd_callback = NULL; |
352 | tk | 268 | ui_exit_callback = NULL; |
318 | tk | 269 | portEXIT_CRITICAL(); |
167 | tk | 270 | |
513 | tk | 271 | if( seq_hwcfg_button_beh.menu ) |
272 | seq_ui_button_state.MENU_PRESSED = 0; // MENU page selection finished |
||
167 | tk | 273 | |
274 | // request display initialisation |
||
275 | seq_ui_display_init_req = 1; |
||
276 | } |
||
173 | tk | 277 | |
306 | tk | 278 | // for MENU button: |
279 | // first page has been selected - display new screen |
||
280 | seq_ui_button_state.MENU_FIRST_PAGE_SELECTED = 1; |
||
281 | |||
272 | tk | 282 | // for SEQ_UI_MENU which is accessible with EXIT button |
283 | // remember the current selectable page |
||
284 | if( ui_page >= SEQ_UI_FIRST_MENU_SELECTION_PAGE ) |
||
285 | ui_selected_page = ui_page; |
||
286 | |||
184 | tk | 287 | return 0; // no error |
167 | tk | 288 | } |
289 | |||
290 | |||
291 | ///////////////////////////////////////////////////////////////////////////// |
||
272 | tk | 292 | // Returns name of menu page (18 characters) |
293 | ///////////////////////////////////////////////////////////////////////////// |
||
294 | char *SEQ_UI_PageNameGet(seq_ui_page_t page) |
||
295 | { |
||
690 | tk | 296 | return (char *)ui_menu_pages[page].name; |
272 | tk | 297 | } |
298 | |||
299 | |||
300 | ///////////////////////////////////////////////////////////////////////////// |
||
134 | tk | 301 | // Dedicated button functions |
302 | // Mapped to physical buttons in SEQ_UI_Button_Handler() |
||
303 | // Will also be mapped to MIDI keys later (for MIDI remote function) |
||
304 | ///////////////////////////////////////////////////////////////////////////// |
||
305 | static s32 SEQ_UI_Button_GP(s32 depressed, u32 gp) |
||
306 | { |
||
306 | tk | 307 | // in MENU page: overrule GP buttons so long MENU button is pressed/active |
308 | if( seq_ui_button_state.MENU_PRESSED ) { |
||
309 | if( depressed ) return -1; |
||
310 | SEQ_UI_PageSet(ui_shortcut_menu_pages[gp]); |
||
311 | } else { |
||
312 | // forward to menu page |
||
313 | if( ui_button_callback != NULL ) |
||
314 | ui_button_callback(gp, depressed); |
||
315 | ui_cursor_flash_ctr = 0; |
||
316 | } |
||
134 | tk | 317 | |
318 | return 0; // no error |
||
319 | } |
||
320 | |||
321 | static s32 SEQ_UI_Button_Left(s32 depressed) |
||
322 | { |
||
168 | tk | 323 | // forward to menu page |
306 | tk | 324 | if( !seq_ui_button_state.MENU_PRESSED && ui_button_callback != NULL ) |
168 | tk | 325 | ui_button_callback(SEQ_UI_BUTTON_Left, depressed); |
173 | tk | 326 | ui_cursor_flash_ctr = 0; |
134 | tk | 327 | |
328 | return 0; // no error |
||
329 | } |
||
330 | |||
331 | static s32 SEQ_UI_Button_Right(s32 depressed) |
||
332 | { |
||
168 | tk | 333 | // forward to menu page |
306 | tk | 334 | if( !seq_ui_button_state.MENU_PRESSED && ui_button_callback != NULL ) |
168 | tk | 335 | ui_button_callback(SEQ_UI_BUTTON_Right, depressed); |
173 | tk | 336 | ui_cursor_flash_ctr = 0; |
134 | tk | 337 | |
338 | return 0; // no error |
||
339 | } |
||
340 | |||
168 | tk | 341 | static s32 SEQ_UI_Button_Down(s32 depressed) |
342 | { |
||
240 | tk | 343 | seq_ui_button_state.DOWN = depressed ? 0 : 1; |
344 | |||
168 | tk | 345 | // forward to menu page |
306 | tk | 346 | if( !seq_ui_button_state.MENU_PRESSED && ui_button_callback != NULL ) |
168 | tk | 347 | ui_button_callback(SEQ_UI_BUTTON_Down, depressed); |
173 | tk | 348 | ui_cursor_flash_ctr = 0; |
168 | tk | 349 | |
350 | return 0; // no error |
||
351 | } |
||
352 | |||
353 | static s32 SEQ_UI_Button_Up(s32 depressed) |
||
354 | { |
||
240 | tk | 355 | seq_ui_button_state.UP = depressed ? 0 : 1; |
356 | |||
168 | tk | 357 | // forward to menu page |
306 | tk | 358 | if( !seq_ui_button_state.MENU_PRESSED && ui_button_callback != NULL ) |
168 | tk | 359 | ui_button_callback(SEQ_UI_BUTTON_Up, depressed); |
173 | tk | 360 | ui_cursor_flash_ctr = 0; |
168 | tk | 361 | |
362 | return 0; // no error |
||
363 | } |
||
364 | |||
134 | tk | 365 | static s32 SEQ_UI_Button_Stop(s32 depressed) |
366 | { |
||
367 | if( depressed ) return -1; // ignore when button depressed |
||
368 | |||
159 | tk | 369 | // if sequencer running: stop it |
370 | // if sequencer already stopped: reset song position |
||
186 | tk | 371 | #if MID_PLAYER_TEST |
193 | tk | 372 | if( SEQ_BPM_IsRunning() ) |
373 | SEQ_BPM_Stop(); |
||
186 | tk | 374 | else |
375 | SEQ_MIDPLY_Reset(); |
||
376 | #else |
||
193 | tk | 377 | if( SEQ_BPM_IsRunning() ) |
378 | SEQ_BPM_Stop(); |
||
159 | tk | 379 | else |
380 | SEQ_CORE_Reset(); |
||
186 | tk | 381 | #endif |
159 | tk | 382 | |
134 | tk | 383 | return 0; // no error |
384 | } |
||
385 | |||
386 | static s32 SEQ_UI_Button_Pause(s32 depressed) |
||
387 | { |
||
388 | if( depressed ) return -1; // ignore when button depressed |
||
389 | |||
193 | tk | 390 | // if in auto mode and BPM generator is clocked in slave mode: |
391 | // change to master mode |
||
392 | SEQ_BPM_CheckAutoMaster(); |
||
159 | tk | 393 | |
193 | tk | 394 | // toggle pause mode |
395 | ui_seq_pause ^= 1; |
||
396 | |||
397 | // execute stop/continue depending on new mode |
||
398 | if( ui_seq_pause ) |
||
399 | SEQ_BPM_Stop(); |
||
400 | else |
||
401 | SEQ_BPM_Cont(); |
||
402 | |||
134 | tk | 403 | return 0; // no error |
404 | } |
||
405 | |||
406 | static s32 SEQ_UI_Button_Play(s32 depressed) |
||
407 | { |
||
408 | if( depressed ) return -1; // ignore when button depressed |
||
409 | |||
186 | tk | 410 | // if in auto mode and BPM generator is clocked in slave mode: |
411 | // change to master mode |
||
412 | SEQ_BPM_CheckAutoMaster(); |
||
413 | |||
193 | tk | 414 | #if 0 |
415 | // if sequencer running: restart it |
||
416 | // if sequencer stopped: continue at last song position |
||
417 | if( SEQ_BPM_IsRunning() ) |
||
418 | SEQ_BPM_Start(); |
||
419 | else |
||
420 | SEQ_BPM_Cont(); |
||
186 | tk | 421 | #else |
193 | tk | 422 | // always restart sequencer |
423 | SEQ_BPM_Start(); |
||
186 | tk | 424 | #endif |
159 | tk | 425 | |
134 | tk | 426 | return 0; // no error |
427 | } |
||
428 | |||
429 | static s32 SEQ_UI_Button_Rew(s32 depressed) |
||
430 | { |
||
240 | tk | 431 | seq_ui_button_state.REW = depressed ? 0 : 1; |
432 | |||
134 | tk | 433 | if( depressed ) return -1; // ignore when button depressed |
434 | |||
607 | tk | 435 | if( SEQ_SONG_ActiveGet() ) { |
436 | portENTER_CRITICAL(); |
||
437 | SEQ_SONG_Rew(); |
||
438 | portEXIT_CRITICAL(); |
||
439 | } else |
||
440 | SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, "We are not", "in Song Mode!"); |
||
441 | |||
134 | tk | 442 | return 0; // no error |
443 | } |
||
444 | |||
445 | static s32 SEQ_UI_Button_Fwd(s32 depressed) |
||
446 | { |
||
240 | tk | 447 | seq_ui_button_state.FWD = depressed ? 0 : 1; |
448 | |||
134 | tk | 449 | if( depressed ) return -1; // ignore when button depressed |
450 | |||
607 | tk | 451 | if( SEQ_SONG_ActiveGet() ) { |
452 | portENTER_CRITICAL(); |
||
453 | SEQ_SONG_Fwd(); |
||
454 | portEXIT_CRITICAL(); |
||
455 | } else |
||
456 | SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, "We are not", "in Song Mode!"); |
||
457 | |||
134 | tk | 458 | return 0; // no error |
459 | } |
||
460 | |||
596 | tk | 461 | static s32 SEQ_UI_Button_Loop(s32 depressed) |
462 | { |
||
463 | if( seq_hwcfg_button_beh.loop ) { |
||
464 | // toggle mode |
||
465 | if( depressed ) return -1; // ignore when button depressed |
||
466 | // should be atomic |
||
467 | portENTER_CRITICAL(); |
||
468 | seq_core_state.LOOP ^= 1; |
||
469 | } else { |
||
470 | // should be atomic |
||
471 | portENTER_CRITICAL(); |
||
472 | // set mode |
||
473 | seq_core_state.LOOP = depressed ? 0 : 1; |
||
474 | } |
||
475 | portEXIT_CRITICAL(); |
||
476 | |||
477 | SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, "Loop Mode", seq_core_state.LOOP ? " on" : " off"); |
||
478 | |||
479 | return 0; // no error |
||
480 | } |
||
481 | |||
482 | static s32 SEQ_UI_Button_Scrub(s32 depressed) |
||
483 | { |
||
484 | // double function: -> Loop if menu button pressed |
||
485 | if( seq_ui_button_state.MENU_PRESSED ) |
||
486 | return SEQ_UI_Button_Loop(depressed); |
||
487 | |||
488 | if( seq_hwcfg_button_beh.scrub ) { |
||
489 | // toggle mode |
||
490 | if( depressed ) return -1; // ignore when button depressed |
||
491 | seq_ui_button_state.SCRUB ^= 1; |
||
492 | } else { |
||
493 | // set mode |
||
494 | seq_ui_button_state.SCRUB = depressed ? 0 : 1; |
||
495 | } |
||
496 | |||
497 | SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, "Scrub Mode", seq_ui_button_state.SCRUB ? " on" : " off"); |
||
498 | |||
499 | return 0; // no error |
||
500 | } |
||
501 | |||
513 | tk | 502 | static s32 SEQ_UI_Button_TempoPreset(s32 depressed) |
134 | tk | 503 | { |
513 | tk | 504 | static seq_ui_page_t prev_page = SEQ_UI_PAGE_NONE; |
240 | tk | 505 | |
513 | tk | 506 | if( seq_hwcfg_button_beh.tempo_preset ) { |
507 | if( depressed ) return -1; // ignore when button depressed |
||
678 | tk | 508 | if( !seq_ui_button_state.TEMPO_PRESET ) // due to page change: button going to be set, clear other toggle buttons |
509 | seq_ui_button_state.PAGE_CHANGE_BUTTON_FLAGS = 0; |
||
513 | tk | 510 | seq_ui_button_state.TEMPO_PRESET ^= 1; // toggle TEMPO_PRESET pressed (will also be released once GP button has been pressed) |
511 | } else { |
||
512 | // set mode |
||
513 | seq_ui_button_state.TEMPO_PRESET = depressed ? 0 : 1; |
||
514 | } |
||
134 | tk | 515 | |
513 | tk | 516 | if( seq_ui_button_state.TEMPO_PRESET ) { |
517 | prev_page = ui_page; |
||
518 | SEQ_UI_PageSet(SEQ_UI_PAGE_BPM_PRESETS); |
||
519 | } else { |
||
524 | tk | 520 | if( ui_page == SEQ_UI_PAGE_BPM_PRESETS ) |
521 | SEQ_UI_PageSet(prev_page); |
||
513 | tk | 522 | } |
240 | tk | 523 | |
134 | tk | 524 | return 0; // no error |
525 | } |
||
526 | |||
513 | tk | 527 | static s32 SEQ_UI_Button_TapTempo(s32 depressed) |
134 | tk | 528 | { |
513 | tk | 529 | seq_ui_button_state.TAP_TEMPO = depressed ? 0 : 1; |
240 | tk | 530 | |
134 | tk | 531 | if( depressed ) return -1; // ignore when button depressed |
532 | |||
533 | return 0; // no error |
||
534 | } |
||
535 | |||
524 | tk | 536 | static s32 SEQ_UI_Button_ExtRestart(s32 depressed) |
134 | tk | 537 | { |
538 | if( depressed ) return -1; // ignore when button depressed |
||
539 | |||
596 | tk | 540 | // should be atomic |
524 | tk | 541 | portENTER_CRITICAL(); |
542 | seq_core_state.EXT_RESTART_REQ = 1; |
||
543 | portEXIT_CRITICAL(); |
||
544 | |||
596 | tk | 545 | SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, "External Restart", "requested"); |
546 | |||
134 | tk | 547 | return 0; // no error |
548 | } |
||
549 | |||
596 | tk | 550 | static s32 SEQ_UI_Button_Metronome(s32 depressed) |
551 | { |
||
552 | // double function: -> ExtRestart if menu button pressed |
||
553 | if( seq_ui_button_state.MENU_PRESSED ) |
||
554 | return SEQ_UI_Button_ExtRestart(depressed); |
||
555 | |||
556 | if( seq_hwcfg_button_beh.metronome ) { |
||
557 | // toggle mode |
||
558 | if( depressed ) return -1; // ignore when button depressed |
||
559 | // should be atomic |
||
560 | portENTER_CRITICAL(); |
||
561 | seq_core_state.METRONOME ^= 1; |
||
562 | } else { |
||
563 | // should be atomic |
||
564 | portENTER_CRITICAL(); |
||
565 | // set mode |
||
566 | seq_core_state.METRONOME = depressed ? 0 : 1; |
||
567 | } |
||
568 | portEXIT_CRITICAL(); |
||
569 | |||
570 | SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, "Metronome", seq_core_state.METRONOME ? " on" : " off"); |
||
571 | |||
599 | tk | 572 | #if 0 |
573 | // metronome button can be used to trigger pattern file fixes |
||
574 | if( !depressed ) |
||
575 | SEQ_PATTERN_FixAll(); |
||
576 | #endif |
||
577 | |||
596 | tk | 578 | return 0; // no error |
579 | } |
||
580 | |||
630 | tk | 581 | static s32 SEQ_UI_Button_Record(s32 depressed) |
582 | { |
||
583 | if( depressed ) return -1; // ignore when button depressed |
||
584 | |||
585 | // change to utility page |
||
586 | SEQ_UI_PageSet(SEQ_UI_PAGE_TRKREC); |
||
587 | |||
588 | return 0; // no error |
||
589 | } |
||
590 | |||
134 | tk | 591 | static s32 SEQ_UI_Button_Utility(s32 depressed) |
592 | { |
||
593 | if( depressed ) return -1; // ignore when button depressed |
||
594 | |||
240 | tk | 595 | // change to utility page |
596 | SEQ_UI_PageSet(SEQ_UI_PAGE_UTIL); |
||
597 | |||
134 | tk | 598 | return 0; // no error |
599 | } |
||
600 | |||
601 | static s32 SEQ_UI_Button_Copy(s32 depressed) |
||
602 | { |
||
240 | tk | 603 | static seq_ui_page_t prev_page = SEQ_UI_PAGE_NONE; |
134 | tk | 604 | |
240 | tk | 605 | seq_ui_button_state.COPY = depressed ? 0 : 1; |
606 | |||
280 | tk | 607 | if( ui_page == SEQ_UI_PAGE_MIXER ) { |
608 | if( depressed ) return -1; |
||
609 | SEQ_UI_MIXER_Copy(); |
||
610 | return 1; |
||
611 | } else { |
||
612 | if( !depressed ) { |
||
613 | prev_page = ui_page; |
||
614 | SEQ_UI_PageSet(SEQ_UI_PAGE_UTIL); |
||
615 | } |
||
240 | tk | 616 | |
280 | tk | 617 | s32 status = SEQ_UI_UTIL_CopyButton(depressed); |
240 | tk | 618 | |
596 | tk | 619 | if( depressed ) { |
620 | if( prev_page != SEQ_UI_PAGE_UTIL ) |
||
621 | SEQ_UI_PageSet(prev_page); |
||
240 | tk | 622 | |
596 | tk | 623 | SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, "Track", "copied"); |
624 | } |
||
625 | |||
280 | tk | 626 | return status; |
627 | } |
||
134 | tk | 628 | } |
629 | |||
630 | static s32 SEQ_UI_Button_Paste(s32 depressed) |
||
631 | { |
||
240 | tk | 632 | static seq_ui_page_t prev_page = SEQ_UI_PAGE_NONE; |
134 | tk | 633 | |
240 | tk | 634 | seq_ui_button_state.PASTE = depressed ? 0 : 1; |
635 | |||
280 | tk | 636 | if( ui_page == SEQ_UI_PAGE_MIXER ) { |
637 | if( depressed ) return -1; |
||
638 | SEQ_UI_MIXER_Paste(); |
||
639 | return 1; |
||
640 | } else { |
||
641 | if( !depressed ) { |
||
642 | prev_page = ui_page; |
||
643 | SEQ_UI_PageSet(SEQ_UI_PAGE_UTIL); |
||
644 | } |
||
240 | tk | 645 | |
280 | tk | 646 | s32 status = SEQ_UI_UTIL_PasteButton(depressed); |
240 | tk | 647 | |
596 | tk | 648 | if( depressed ) { |
649 | if( prev_page != SEQ_UI_PAGE_UTIL ) |
||
650 | SEQ_UI_PageSet(prev_page); |
||
240 | tk | 651 | |
596 | tk | 652 | SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, "Track", "pasted"); |
653 | } |
||
654 | |||
280 | tk | 655 | return status; |
656 | } |
||
134 | tk | 657 | } |
658 | |||
659 | static s32 SEQ_UI_Button_Clear(s32 depressed) |
||
660 | { |
||
240 | tk | 661 | seq_ui_button_state.CLEAR = depressed ? 0 : 1; |
280 | tk | 662 | |
663 | if( ui_page == SEQ_UI_PAGE_MIXER ) { |
||
664 | if( depressed ) return -1; |
||
665 | SEQ_UI_MIXER_Clear(); |
||
596 | tk | 666 | |
667 | SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, "Track", "cleared"); |
||
668 | |||
280 | tk | 669 | return 1; |
670 | } else { |
||
671 | return SEQ_UI_UTIL_ClearButton(depressed); |
||
672 | } |
||
134 | tk | 673 | } |
674 | |||
675 | static s32 SEQ_UI_Button_Menu(s32 depressed) |
||
676 | { |
||
513 | tk | 677 | if( seq_hwcfg_button_beh.menu ) { |
678 | // toggle mode |
||
679 | if( depressed ) return -1; // ignore when button depressed |
||
680 | seq_ui_button_state.MENU_FIRST_PAGE_SELECTED = 0; |
||
678 | tk | 681 | if( !seq_ui_button_state.MENU_PRESSED ) // due to page change: button going to be set, clear other toggle buttons |
682 | seq_ui_button_state.PAGE_CHANGE_BUTTON_FLAGS = 0; |
||
513 | tk | 683 | seq_ui_button_state.MENU_PRESSED ^= 1; // toggle MENU pressed (will also be released once GP button has been pressed) |
684 | } else { |
||
685 | // set mode |
||
686 | seq_ui_button_state.MENU_FIRST_PAGE_SELECTED = 0; |
||
687 | seq_ui_button_state.MENU_PRESSED = depressed ? 0 : 1; |
||
688 | } |
||
134 | tk | 689 | |
690 | return 0; // no error |
||
691 | } |
||
692 | |||
693 | static s32 SEQ_UI_Button_Select(s32 depressed) |
||
694 | { |
||
168 | tk | 695 | // forward to menu page |
591 | tk | 696 | if( !seq_ui_button_state.MENU_PRESSED ) { |
697 | seq_ui_button_state.SELECT_PRESSED = depressed ? 0 : 1; |
||
698 | if( ui_button_callback != NULL ) |
||
699 | ui_button_callback(SEQ_UI_BUTTON_Select, depressed); |
||
700 | } |
||
173 | tk | 701 | ui_cursor_flash_ctr = 0; |
134 | tk | 702 | |
703 | return 0; // no error |
||
704 | } |
||
705 | |||
706 | static s32 SEQ_UI_Button_Exit(s32 depressed) |
||
707 | { |
||
272 | tk | 708 | if( depressed ) return -1; // ignore when button depressed |
709 | |||
710 | u8 prev_ui_page = ui_page; |
||
711 | |||
591 | tk | 712 | seq_ui_button_state.EXIT_PRESSED = depressed ? 0 : 1; |
713 | |||
168 | tk | 714 | // forward to menu page |
306 | tk | 715 | if( !seq_ui_button_state.MENU_PRESSED && ui_button_callback != NULL ) |
168 | tk | 716 | ui_button_callback(SEQ_UI_BUTTON_Exit, depressed); |
173 | tk | 717 | ui_cursor_flash_ctr = 0; |
134 | tk | 718 | |
167 | tk | 719 | // release all button states |
720 | seq_ui_button_state.ALL = 0; |
||
721 | |||
272 | tk | 722 | // enter menu page if we were not there before |
723 | if( prev_ui_page != SEQ_UI_PAGE_MENU ) |
||
724 | SEQ_UI_PageSet(SEQ_UI_PAGE_MENU); |
||
725 | |||
134 | tk | 726 | return 0; // no error |
727 | } |
||
728 | |||
729 | static s32 SEQ_UI_Button_Edit(s32 depressed) |
||
730 | { |
||
591 | tk | 731 | seq_ui_button_state.EXIT_PRESSED = depressed ? 0 : 1; |
732 | |||
134 | tk | 733 | if( depressed ) return -1; // ignore when button depressed |
734 | |||
167 | tk | 735 | // change to edit page |
736 | SEQ_UI_PageSet(SEQ_UI_PAGE_EDIT); |
||
737 | |||
178 | tk | 738 | // set/clear encoder fast function if required |
739 | SEQ_UI_InitEncSpeed(1); // auto config |
||
740 | |||
134 | tk | 741 | return 0; // no error |
742 | } |
||
743 | |||
744 | static s32 SEQ_UI_Button_Mute(s32 depressed) |
||
745 | { |
||
591 | tk | 746 | seq_ui_button_state.MUTE_PRESSED = depressed ? 0 : 1; |
747 | |||
134 | tk | 748 | if( depressed ) return -1; // ignore when button depressed |
749 | |||
184 | tk | 750 | SEQ_UI_PageSet(SEQ_UI_PAGE_MUTE); |
751 | |||
134 | tk | 752 | return 0; // no error |
753 | } |
||
754 | |||
755 | static s32 SEQ_UI_Button_Pattern(s32 depressed) |
||
756 | { |
||
591 | tk | 757 | seq_ui_button_state.PATTERN_PRESSED = depressed ? 0 : 1; |
758 | |||
134 | tk | 759 | if( depressed ) return -1; // ignore when button depressed |
760 | |||
184 | tk | 761 | SEQ_UI_PageSet(SEQ_UI_PAGE_PATTERN); |
762 | |||
134 | tk | 763 | return 0; // no error |
764 | } |
||
765 | |||
766 | static s32 SEQ_UI_Button_Song(s32 depressed) |
||
767 | { |
||
591 | tk | 768 | seq_ui_button_state.SONG_PRESSED = depressed ? 0 : 1; |
769 | |||
134 | tk | 770 | if( depressed ) return -1; // ignore when button depressed |
771 | |||
399 | tk | 772 | // toggle active mode if already in song page |
773 | if( ui_page == SEQ_UI_PAGE_SONG ) { |
||
774 | SEQ_SONG_ActiveSet(SEQ_SONG_ActiveGet() ? 0 : 1); |
||
775 | } |
||
776 | |||
777 | SEQ_UI_PageSet(SEQ_UI_PAGE_SONG); |
||
778 | |||
134 | tk | 779 | return 0; // no error |
780 | } |
||
781 | |||
782 | static s32 SEQ_UI_Button_Solo(s32 depressed) |
||
783 | { |
||
513 | tk | 784 | if( seq_hwcfg_button_beh.solo ) { |
785 | // toggle mode |
||
786 | if( depressed ) return -1; // ignore when button depressed |
||
787 | seq_ui_button_state.SOLO ^= 1; |
||
788 | } else { |
||
789 | // set mode |
||
790 | seq_ui_button_state.SOLO = depressed ? 0 : 1; |
||
791 | } |
||
134 | tk | 792 | |
793 | return 0; // no error |
||
794 | } |
||
795 | |||
796 | static s32 SEQ_UI_Button_Fast(s32 depressed) |
||
797 | { |
||
513 | tk | 798 | if( seq_hwcfg_button_beh.fast ) { |
799 | // toggle mode |
||
800 | if( depressed ) return -1; // ignore when button depressed |
||
801 | seq_ui_button_state.FAST_ENCODERS ^= 1; |
||
802 | } else { |
||
803 | // set mode |
||
804 | seq_ui_button_state.FAST_ENCODERS = depressed ? 0 : 1; |
||
805 | } |
||
134 | tk | 806 | |
178 | tk | 807 | SEQ_UI_InitEncSpeed(0); // no auto config |
808 | |||
134 | tk | 809 | return 0; // no error |
810 | } |
||
811 | |||
812 | static s32 SEQ_UI_Button_All(s32 depressed) |
||
813 | { |
||
178 | tk | 814 | seq_ui_button_state.CHANGE_ALL_STEPS_SAME_VALUE = depressed ? 0 : 1; |
134 | tk | 815 | |
513 | tk | 816 | if( seq_hwcfg_button_beh.all ) { |
817 | // toggle mode |
||
818 | if( depressed ) return -1; |
||
819 | seq_ui_button_state.CHANGE_ALL_STEPS ^= 1; |
||
820 | } else { |
||
821 | // set mode |
||
822 | seq_ui_button_state.CHANGE_ALL_STEPS = depressed ? 0 : 1; |
||
823 | } |
||
178 | tk | 824 | |
134 | tk | 825 | return 0; // no error |
826 | } |
||
827 | |||
828 | static s32 SEQ_UI_Button_StepView(s32 depressed) |
||
829 | { |
||
600 | tk | 830 | // static seq_ui_page_t prev_page = SEQ_UI_PAGE_NONE; |
831 | // also used by seq_ui_stepsel |
||
832 | |||
513 | tk | 833 | if( seq_hwcfg_button_beh.step_view ) { |
834 | if( depressed ) return -1; // ignore when button depressed |
||
678 | tk | 835 | if( !seq_ui_button_state.STEP_VIEW ) // due to page change: button going to be set, clear other toggle buttons |
836 | seq_ui_button_state.PAGE_CHANGE_BUTTON_FLAGS = 0; |
||
513 | tk | 837 | seq_ui_button_state.STEP_VIEW ^= 1; // toggle STEP_VIEW pressed (will also be released once GP button has been pressed) |
838 | } else { |
||
839 | // set mode |
||
840 | seq_ui_button_state.STEP_VIEW = depressed ? 0 : 1; |
||
841 | } |
||
134 | tk | 842 | |
513 | tk | 843 | if( seq_ui_button_state.STEP_VIEW ) { |
600 | tk | 844 | ui_stepview_prev_page = ui_page; |
303 | tk | 845 | SEQ_UI_PageSet(SEQ_UI_PAGE_STEPSEL); |
846 | } else { |
||
524 | tk | 847 | if( ui_page == SEQ_UI_PAGE_STEPSEL ) |
600 | tk | 848 | SEQ_UI_PageSet(ui_stepview_prev_page); |
303 | tk | 849 | } |
134 | tk | 850 | |
851 | return 0; // no error |
||
852 | } |
||
853 | |||
513 | tk | 854 | static s32 SEQ_UI_Button_TrackSel(s32 depressed) |
134 | tk | 855 | { |
513 | tk | 856 | static seq_ui_page_t prev_page = SEQ_UI_PAGE_NONE; |
134 | tk | 857 | |
513 | tk | 858 | if( seq_hwcfg_button_beh.track_sel ) { |
859 | if( depressed ) return -1; // ignore when button depressed |
||
678 | tk | 860 | if( !seq_ui_button_state.TRACK_SEL ) // due to page change: button going to be set, clear other toggle buttons |
861 | seq_ui_button_state.PAGE_CHANGE_BUTTON_FLAGS = 0; |
||
513 | tk | 862 | seq_ui_button_state.TRACK_SEL ^= 1; // toggle TRACKSEL status (will also be released once GP button has been pressed) |
863 | } else { |
||
864 | seq_ui_button_state.TRACK_SEL = depressed ? 0 : 1; |
||
865 | } |
||
866 | |||
867 | if( seq_ui_button_state.TRACK_SEL ) { |
||
868 | prev_page = ui_page; |
||
869 | SEQ_UI_PageSet(SEQ_UI_PAGE_TRACKSEL); |
||
870 | } else { |
||
524 | tk | 871 | if( ui_page == SEQ_UI_PAGE_TRACKSEL ) |
872 | SEQ_UI_PageSet(prev_page); |
||
513 | tk | 873 | } |
874 | |||
134 | tk | 875 | return 0; // no error |
876 | } |
||
877 | |||
484 | tk | 878 | static s32 SEQ_UI_Button_Track(s32 depressed, u32 track_button) |
134 | tk | 879 | { |
484 | tk | 880 | static u8 button_state = 0x0f; // all 4 buttons depressed |
134 | tk | 881 | |
484 | tk | 882 | if( track_button >= 4 ) return -2; // max. 4 track buttons |
134 | tk | 883 | |
484 | tk | 884 | if( depressed ) { |
885 | button_state |= (1 << track_button); |
||
886 | return 0; // no error |
||
887 | } |
||
134 | tk | 888 | |
484 | tk | 889 | button_state &= ~(1 << track_button); |
890 | |||
891 | if( button_state == (~(1 << track_button) & 0xf) ) { |
||
892 | // if only one select button pressed: radio-button function (1 of 4) |
||
893 | ui_selected_tracks = 1 << (track_button + 4*ui_selected_group); |
||
894 | } else { |
||
895 | // if more than one select button pressed: toggle function (4 of 4) |
||
896 | ui_selected_tracks ^= 1 << (track_button + 4*ui_selected_group); |
||
897 | } |
||
898 | |||
178 | tk | 899 | // set/clear encoder fast function if required |
900 | SEQ_UI_InitEncSpeed(1); // auto config |
||
901 | |||
134 | tk | 902 | return 0; // no error |
903 | } |
||
904 | |||
905 | static s32 SEQ_UI_Button_Group(s32 depressed, u32 group) |
||
906 | { |
||
907 | if( depressed ) return -1; // ignore when button depressed |
||
908 | |||
909 | if( group >= 4 ) return -2; // max. 4 group buttons |
||
910 | |||
484 | tk | 911 | // if group has changed: |
912 | if( group != ui_selected_group ) { |
||
913 | // get current track selection |
||
914 | u16 old_tracks = ui_selected_tracks >> (4*ui_selected_group); |
||
134 | tk | 915 | |
484 | tk | 916 | // select new group |
917 | ui_selected_group = group; |
||
918 | |||
919 | // take over old track selection |
||
920 | ui_selected_tracks = old_tracks << (4*ui_selected_group); |
||
921 | } |
||
922 | |||
178 | tk | 923 | // set/clear encoder fast function if required |
924 | SEQ_UI_InitEncSpeed(1); // auto config |
||
925 | |||
134 | tk | 926 | return 0; // no error |
927 | } |
||
928 | |||
513 | tk | 929 | static s32 SEQ_UI_Button_ParLayerSel(s32 depressed) |
930 | { |
||
600 | tk | 931 | // static seq_ui_page_t prev_page = SEQ_UI_PAGE_NONE; |
932 | // also used by seq_ui_parsel.c |
||
513 | tk | 933 | |
934 | if( seq_hwcfg_button_beh.par_layer ) { |
||
935 | if( depressed ) return -1; // ignore when button depressed |
||
678 | tk | 936 | if( !seq_ui_button_state.PAR_LAYER_SEL ) // due to page change: button going to be set, clear other toggle buttons |
937 | seq_ui_button_state.PAGE_CHANGE_BUTTON_FLAGS = 0; |
||
513 | tk | 938 | seq_ui_button_state.PAR_LAYER_SEL ^= 1; // toggle PARSEL status (will also be released once GP button has been pressed) |
939 | } else { |
||
940 | seq_ui_button_state.PAR_LAYER_SEL = depressed ? 0 : 1; |
||
941 | } |
||
942 | |||
943 | if( seq_ui_button_state.PAR_LAYER_SEL ) { |
||
600 | tk | 944 | ui_parlayer_prev_page = ui_page; |
513 | tk | 945 | SEQ_UI_PageSet(SEQ_UI_PAGE_PARSEL); |
946 | } else { |
||
524 | tk | 947 | if( ui_page == SEQ_UI_PAGE_PARSEL ) |
600 | tk | 948 | SEQ_UI_PageSet(ui_parlayer_prev_page); |
513 | tk | 949 | } |
950 | |||
951 | // set/clear encoder fast function if required |
||
952 | SEQ_UI_InitEncSpeed(1); // auto config |
||
953 | |||
954 | return 0; // no error |
||
955 | } |
||
956 | |||
134 | tk | 957 | static s32 SEQ_UI_Button_ParLayer(s32 depressed, u32 par_layer) |
958 | { |
||
959 | if( par_layer >= 3 ) return -2; // max. 3 parlayer buttons |
||
960 | |||
333 | tk | 961 | u8 visible_track = SEQ_UI_VisibleTrackGet(); |
962 | u8 num_p_layers = SEQ_PAR_NumLayersGet(visible_track); |
||
134 | tk | 963 | |
333 | tk | 964 | if( num_p_layers <= 3 ) { |
965 | // 3 layers: direct selection with LayerA/B/C button |
||
966 | if( depressed ) return -1; // ignore when button depressed |
||
596 | tk | 967 | if( par_layer >= num_p_layers ) { |
968 | char str1[21]; |
||
969 | sprintf(str1, "Parameter Layer %c", 'A'+par_layer); |
||
970 | SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, str1, "not available!"); |
||
971 | } else { |
||
972 | seq_ui_button_state.PAR_LAYER_SEL = 0; |
||
973 | ui_selected_par_layer = par_layer; |
||
974 | } |
||
333 | tk | 975 | } else if( num_p_layers <= 4 ) { |
976 | // 4 layers: LayerC Button toggles between C and D |
||
977 | if( depressed ) return -1; // ignore when button depressed |
||
978 | seq_ui_button_state.PAR_LAYER_SEL = 0; |
||
336 | tk | 979 | if( par_layer == 2 ) |
980 | ui_selected_par_layer = (ui_selected_par_layer == 2) ? 3 : 2; |
||
333 | tk | 981 | else |
982 | ui_selected_par_layer = par_layer; |
||
983 | } else { |
||
984 | // >4 layers: LayerA/B button selects directly, Layer C button enters layer selection page |
||
985 | if( par_layer <= 1 ) { |
||
986 | if( depressed ) return -1; // ignore when button depressed |
||
987 | seq_ui_button_state.PAR_LAYER_SEL = 0; |
||
988 | ui_selected_par_layer = par_layer; |
||
989 | } else { |
||
513 | tk | 990 | return SEQ_UI_Button_ParLayerSel(depressed); |
333 | tk | 991 | } |
992 | } |
||
993 | |||
178 | tk | 994 | // set/clear encoder fast function if required |
995 | SEQ_UI_InitEncSpeed(1); // auto config |
||
996 | |||
134 | tk | 997 | return 0; // no error |
998 | } |
||
999 | |||
513 | tk | 1000 | static s32 SEQ_UI_Button_TrgLayerSel(s32 depressed) |
1001 | { |
||
600 | tk | 1002 | // static seq_ui_page_t prev_page = SEQ_UI_PAGE_NONE; |
1003 | // also used by seq_ui_trgsel.c |
||
513 | tk | 1004 | |
1005 | if( seq_hwcfg_button_beh.trg_layer ) { |
||
1006 | if( depressed ) return -1; // ignore when button depressed |
||
678 | tk | 1007 | if( !seq_ui_button_state.TRG_LAYER_SEL ) // due to page change: button going to be set, clear other toggle buttons |
1008 | seq_ui_button_state.PAGE_CHANGE_BUTTON_FLAGS = 0; |
||
513 | tk | 1009 | seq_ui_button_state.TRG_LAYER_SEL ^= 1; // toggle TRGSEL status (will also be released once GP button has been pressed) |
1010 | } else { |
||
1011 | seq_ui_button_state.TRG_LAYER_SEL = depressed ? 0 : 1; |
||
1012 | } |
||
1013 | |||
1014 | if( seq_ui_button_state.TRG_LAYER_SEL ) { |
||
600 | tk | 1015 | ui_trglayer_prev_page = ui_page; |
513 | tk | 1016 | SEQ_UI_PageSet(SEQ_UI_PAGE_TRGSEL); |
1017 | } else { |
||
524 | tk | 1018 | if( ui_page == SEQ_UI_PAGE_TRGSEL ) |
600 | tk | 1019 | SEQ_UI_PageSet(ui_trglayer_prev_page); |
513 | tk | 1020 | } |
1021 | |||
1022 | return 0; // no error |
||
1023 | } |
||
1024 | |||
134 | tk | 1025 | static s32 SEQ_UI_Button_TrgLayer(s32 depressed, u32 trg_layer) |
1026 | { |
||
1027 | if( trg_layer >= 3 ) return -2; // max. 3 trglayer buttons |
||
1028 | |||
326 | tk | 1029 | u8 visible_track = SEQ_UI_VisibleTrackGet(); |
1030 | u8 event_mode = SEQ_CC_Get(visible_track, SEQ_CC_MIDI_EVENT_MODE); |
||
1031 | u8 num_t_layers = SEQ_TRG_NumLayersGet(visible_track); |
||
134 | tk | 1032 | |
328 | tk | 1033 | if( event_mode != SEQ_EVENT_MODE_Drum && num_t_layers <= 3 ) { |
326 | tk | 1034 | // 3 layers: direct selection with LayerA/B/C button |
1035 | if( depressed ) return -1; // ignore when button depressed |
||
596 | tk | 1036 | if( trg_layer >= num_t_layers ) { |
1037 | char str1[21]; |
||
1038 | sprintf(str1, "Trigger Layer %c", 'A'+trg_layer); |
||
1039 | SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, str1, "not available!"); |
||
1040 | } else { |
||
1041 | seq_ui_button_state.TRG_LAYER_SEL = 0; |
||
1042 | ui_selected_trg_layer = trg_layer; |
||
1043 | } |
||
328 | tk | 1044 | } else if( event_mode != SEQ_EVENT_MODE_Drum && num_t_layers <= 4 ) { |
326 | tk | 1045 | // 4 layers: LayerC Button toggles between C and D |
1046 | if( depressed ) return -1; // ignore when button depressed |
||
1047 | seq_ui_button_state.TRG_LAYER_SEL = 0; |
||
336 | tk | 1048 | if( trg_layer == 2 ) |
1049 | ui_selected_trg_layer = (ui_selected_trg_layer == 2) ? 3 : 2; |
||
326 | tk | 1050 | else |
1051 | ui_selected_trg_layer = trg_layer; |
||
1052 | } else { |
||
333 | tk | 1053 | // >4 layers or drum mode: LayerA/B button selects directly, Layer C button enters trigger selection page |
326 | tk | 1054 | // also used for drum tracks |
1055 | if( trg_layer <= 1 ) { |
||
1056 | if( depressed ) return -1; // ignore when button depressed |
||
328 | tk | 1057 | seq_ui_button_state.TRG_LAYER_SEL = 0; |
1058 | ui_selected_trg_layer = trg_layer; |
||
326 | tk | 1059 | } else { |
513 | tk | 1060 | return SEQ_UI_Button_TrgLayerSel(depressed); |
326 | tk | 1061 | } |
1062 | } |
||
1063 | |||
134 | tk | 1064 | return 0; // no error |
1065 | } |
||
1066 | |||
1067 | |||
544 | tk | 1068 | static s32 SEQ_UI_Button_Morph(s32 depressed) |
1069 | { |
||
1070 | if( depressed ) return -1; // ignore when button depressed |
||
134 | tk | 1071 | |
544 | tk | 1072 | SEQ_UI_PageSet(SEQ_UI_PAGE_TRKMORPH); |
1073 | |||
1074 | return 0; // no error |
||
1075 | } |
||
1076 | |||
1077 | static s32 SEQ_UI_Button_Mixer(s32 depressed) |
||
1078 | { |
||
1079 | if( depressed ) return -1; // ignore when button depressed |
||
1080 | |||
1081 | SEQ_UI_PageSet(SEQ_UI_PAGE_MIXER); |
||
1082 | |||
1083 | return 0; // no error |
||
1084 | } |
||
1085 | |||
1086 | static s32 SEQ_UI_Button_Transpose(s32 depressed) |
||
1087 | { |
||
1088 | if( depressed ) return -1; // ignore when button depressed |
||
1089 | |||
1090 | SEQ_UI_PageSet(SEQ_UI_PAGE_TRKTRAN); |
||
1091 | |||
1092 | return 0; // no error |
||
1093 | } |
||
1094 | |||
1095 | |||
1096 | |||
1097 | |||
134 | tk | 1098 | ///////////////////////////////////////////////////////////////////////////// |
1099 | // Button handler |
||
1100 | ///////////////////////////////////////////////////////////////////////////// |
||
1101 | s32 SEQ_UI_Button_Handler(u32 pin, u32 pin_value) |
||
1102 | { |
||
492 | tk | 1103 | int i; |
1104 | |||
625 | tk | 1105 | // send MIDI event in remote mode and exit |
626 | tk | 1106 | if( seq_ui_remote_active_mode == SEQ_UI_REMOTE_MODE_CLIENT ) |
625 | tk | 1107 | return SEQ_MIDI_SYSEX_REMOTE_Client_SendButton(pin, pin_value); |
1108 | |||
496 | tk | 1109 | // ignore so long hardware config hasn't been read |
1110 | if( !SEQ_FILE_HW_ConfigLocked() ) |
||
1111 | return -1; |
||
1112 | |||
634 | tk | 1113 | // ignore during a backup is created |
1114 | if( seq_ui_backup_req ) |
||
1115 | return -1; |
||
1116 | |||
328 | tk | 1117 | // ensure that selections are matching with track constraints |
1118 | SEQ_UI_CheckSelections(); |
||
1119 | |||
492 | tk | 1120 | // request display update |
1121 | seq_ui_display_update_req = 1; |
||
134 | tk | 1122 | |
596 | tk | 1123 | // stop current message if (new) button has been pressed |
1124 | if( pin_value == 0 ) |
||
1125 | SEQ_UI_MsgStop(); |
||
134 | tk | 1126 | |
596 | tk | 1127 | |
492 | tk | 1128 | // MEMO: we could also use a jump table with references to the functions |
1129 | // here, but this "spagetthi code" simplifies the configuration and |
||
1130 | // the resulting ASM doesn't look that bad! |
||
168 | tk | 1131 | |
492 | tk | 1132 | for(i=0; i<SEQ_HWCFG_NUM_GP; ++i) |
1133 | if( pin == seq_hwcfg_button.gp[i] ) |
||
1134 | return SEQ_UI_Button_GP(pin_value, i); |
||
134 | tk | 1135 | |
492 | tk | 1136 | for(i=0; i<SEQ_HWCFG_NUM_TRACK; ++i) |
1137 | if( pin == seq_hwcfg_button.track[i] ) |
||
1138 | return SEQ_UI_Button_Track(pin_value, i); |
||
513 | tk | 1139 | if( pin == seq_hwcfg_button.track_sel ) |
1140 | return SEQ_UI_Button_TrackSel(pin_value); |
||
134 | tk | 1141 | |
492 | tk | 1142 | for(i=0; i<SEQ_HWCFG_NUM_GROUP; ++i) |
1143 | if( pin == seq_hwcfg_button.group[i] ) |
||
1144 | return SEQ_UI_Button_Group(pin_value, i); |
||
134 | tk | 1145 | |
492 | tk | 1146 | for(i=0; i<SEQ_HWCFG_NUM_PAR_LAYER; ++i) |
1147 | if( pin == seq_hwcfg_button.par_layer[i] ) |
||
1148 | return SEQ_UI_Button_ParLayer(pin_value, i); |
||
513 | tk | 1149 | if( pin == seq_hwcfg_button.par_layer_sel ) |
1150 | return SEQ_UI_Button_ParLayerSel(pin_value); |
||
134 | tk | 1151 | |
492 | tk | 1152 | for(i=0; i<SEQ_HWCFG_NUM_TRG_LAYER; ++i) |
1153 | if( pin == seq_hwcfg_button.trg_layer[i] ) |
||
1154 | return SEQ_UI_Button_TrgLayer(pin_value, i); |
||
513 | tk | 1155 | if( pin == seq_hwcfg_button.trg_layer_sel ) |
1156 | return SEQ_UI_Button_TrgLayerSel(pin_value); |
||
134 | tk | 1157 | |
492 | tk | 1158 | if( pin == seq_hwcfg_button.left ) |
1159 | return SEQ_UI_Button_Left(pin_value); |
||
1160 | if( pin == seq_hwcfg_button.right ) |
||
1161 | return SEQ_UI_Button_Right(pin_value); |
||
1162 | if( pin == seq_hwcfg_button.down ) |
||
1163 | return SEQ_UI_Button_Down(pin_value); |
||
1164 | if( pin == seq_hwcfg_button.up ) |
||
1165 | return SEQ_UI_Button_Up(pin_value); |
||
134 | tk | 1166 | |
492 | tk | 1167 | if( pin == seq_hwcfg_button.scrub ) |
1168 | return SEQ_UI_Button_Scrub(pin_value); |
||
1169 | if( pin == seq_hwcfg_button.metronome ) |
||
1170 | return SEQ_UI_Button_Metronome(pin_value); |
||
134 | tk | 1171 | |
630 | tk | 1172 | if( pin == seq_hwcfg_button.record ) |
1173 | return SEQ_UI_Button_Record(pin_value); |
||
1174 | |||
492 | tk | 1175 | if( pin == seq_hwcfg_button.stop ) |
1176 | return SEQ_UI_Button_Stop(pin_value); |
||
1177 | if( pin == seq_hwcfg_button.pause ) |
||
1178 | return SEQ_UI_Button_Pause(pin_value); |
||
1179 | if( pin == seq_hwcfg_button.play ) |
||
1180 | return SEQ_UI_Button_Play(pin_value); |
||
1181 | if( pin == seq_hwcfg_button.rew ) |
||
1182 | return SEQ_UI_Button_Rew(pin_value); |
||
1183 | if( pin == seq_hwcfg_button.fwd ) |
||
1184 | return SEQ_UI_Button_Fwd(pin_value); |
||
596 | tk | 1185 | if( pin == seq_hwcfg_button.loop ) |
1186 | return SEQ_UI_Button_Loop(pin_value); |
||
134 | tk | 1187 | |
492 | tk | 1188 | if( pin == seq_hwcfg_button.utility ) |
1189 | return SEQ_UI_Button_Utility(pin_value); |
||
1190 | if( pin == seq_hwcfg_button.copy ) |
||
1191 | return SEQ_UI_Button_Copy(pin_value); |
||
1192 | if( pin == seq_hwcfg_button.paste ) |
||
1193 | return SEQ_UI_Button_Paste(pin_value); |
||
1194 | if( pin == seq_hwcfg_button.clear ) |
||
1195 | return SEQ_UI_Button_Clear(pin_value); |
||
134 | tk | 1196 | |
492 | tk | 1197 | if( pin == seq_hwcfg_button.menu ) |
1198 | return SEQ_UI_Button_Menu(pin_value); |
||
1199 | if( pin == seq_hwcfg_button.select ) |
||
1200 | return SEQ_UI_Button_Select(pin_value); |
||
1201 | if( pin == seq_hwcfg_button.exit ) |
||
1202 | return SEQ_UI_Button_Exit(pin_value); |
||
134 | tk | 1203 | |
513 | tk | 1204 | if( pin == seq_hwcfg_button.tap_tempo ) |
1205 | return SEQ_UI_Button_TapTempo(pin_value); |
||
1206 | if( pin == seq_hwcfg_button.tempo_preset ) |
||
1207 | return SEQ_UI_Button_TempoPreset(pin_value); |
||
524 | tk | 1208 | if( pin == seq_hwcfg_button.ext_restart ) |
1209 | return SEQ_UI_Button_ExtRestart(pin_value); |
||
134 | tk | 1210 | |
492 | tk | 1211 | if( pin == seq_hwcfg_button.edit ) |
1212 | return SEQ_UI_Button_Edit(pin_value); |
||
1213 | if( pin == seq_hwcfg_button.mute ) |
||
1214 | return SEQ_UI_Button_Mute(pin_value); |
||
1215 | if( pin == seq_hwcfg_button.pattern ) |
||
1216 | return SEQ_UI_Button_Pattern(pin_value); |
||
1217 | if( pin == seq_hwcfg_button.song ) |
||
1218 | return SEQ_UI_Button_Song(pin_value); |
||
134 | tk | 1219 | |
492 | tk | 1220 | if( pin == seq_hwcfg_button.solo ) |
1221 | return SEQ_UI_Button_Solo(pin_value); |
||
1222 | if( pin == seq_hwcfg_button.fast ) |
||
1223 | return SEQ_UI_Button_Fast(pin_value); |
||
1224 | if( pin == seq_hwcfg_button.all ) |
||
1225 | return SEQ_UI_Button_All(pin_value); |
||
134 | tk | 1226 | |
492 | tk | 1227 | if( pin == seq_hwcfg_button.step_view ) |
1228 | return SEQ_UI_Button_StepView(pin_value); |
||
1229 | if( pin == seq_hwcfg_button.tap_tempo ) |
||
1230 | return SEQ_UI_Button_TapTempo(pin_value); |
||
134 | tk | 1231 | |
544 | tk | 1232 | if( pin == seq_hwcfg_button.morph ) |
1233 | return SEQ_UI_Button_Morph(pin_value); |
||
1234 | if( pin == seq_hwcfg_button.mixer ) |
||
1235 | return SEQ_UI_Button_Mixer(pin_value); |
||
1236 | if( pin == seq_hwcfg_button.transpose ) |
||
1237 | return SEQ_UI_Button_Transpose(pin_value); |
||
1238 | |||
625 | tk | 1239 | // always print debugging message |
1240 | #if 1 |
||
1241 | MIOS32_MIDI_SendDebugMessage("[SEQ_UI_Button_Handler] Button SR:%d, Pin:%d not mapped, it has been %s.\n", |
||
1242 | (pin >> 3) + 1, |
||
1243 | pin & 7, |
||
1244 | pin_value ? "depressed" : "pressed"); |
||
1245 | #endif |
||
1246 | |||
492 | tk | 1247 | return -1; // button not mapped |
134 | tk | 1248 | } |
1249 | |||
1250 | |||
1251 | ///////////////////////////////////////////////////////////////////////////// |
||
524 | tk | 1252 | // BLM Button handler |
1253 | ///////////////////////////////////////////////////////////////////////////// |
||
1254 | s32 SEQ_UI_BLM_Button_Handler(u32 row, u32 pin, u32 pin_value) |
||
1255 | { |
||
625 | tk | 1256 | // send MIDI event in remote mode and exit |
626 | tk | 1257 | if( seq_ui_remote_active_mode == SEQ_UI_REMOTE_MODE_CLIENT ) |
625 | tk | 1258 | return SEQ_MIDI_SYSEX_REMOTE_Client_Send_BLM_Button(row, pin, pin_value); |
1259 | |||
524 | tk | 1260 | // ignore so long hardware config hasn't been read |
1261 | if( !SEQ_FILE_HW_ConfigLocked() ) |
||
1262 | return -1; |
||
1263 | |||
634 | tk | 1264 | // ignore during a backup is created |
1265 | if( seq_ui_backup_req ) |
||
1266 | return -1; |
||
1267 | |||
524 | tk | 1268 | if( row >= SEQ_CORE_NUM_TRACKS_PER_GROUP ) |
1269 | return -1; // more than 4 tracks not supported (yet) - could be done in this function w/o much effort |
||
1270 | |||
1271 | if( pin >= 16 ) |
||
1272 | return -1; // more than 16 step buttons not supported (yet) - could be done by selecting the step view |
||
1273 | |||
1274 | // select track depending on row |
||
1275 | ui_selected_tracks = 1 << (row + 4*ui_selected_group); |
||
1276 | |||
1277 | // ensure that selections are matching with track constraints |
||
1278 | SEQ_UI_CheckSelections(); |
||
1279 | |||
1280 | // request display update |
||
1281 | seq_ui_display_update_req = 1; |
||
1282 | |||
1283 | // emulate general purpose button |
||
1284 | return SEQ_UI_Button_GP(pin_value, pin); |
||
1285 | } |
||
1286 | |||
1287 | |||
1288 | ///////////////////////////////////////////////////////////////////////////// |
||
134 | tk | 1289 | // Encoder handler |
1290 | ///////////////////////////////////////////////////////////////////////////// |
||
1291 | s32 SEQ_UI_Encoder_Handler(u32 encoder, s32 incrementer) |
||
1292 | { |
||
625 | tk | 1293 | // send MIDI event in remote mode and exit |
626 | tk | 1294 | if( seq_ui_remote_active_mode == SEQ_UI_REMOTE_MODE_CLIENT ) |
625 | tk | 1295 | return SEQ_MIDI_SYSEX_REMOTE_Client_SendEncoder(encoder, incrementer); |
1296 | |||
496 | tk | 1297 | // ignore so long hardware config hasn't been read |
1298 | if( !SEQ_FILE_HW_ConfigLocked() ) |
||
1299 | return -1; |
||
1300 | |||
634 | tk | 1301 | // ignore during a backup is created |
1302 | if( seq_ui_backup_req ) |
||
1303 | return -1; |
||
1304 | |||
134 | tk | 1305 | if( encoder > 16 ) |
1306 | return -1; // encoder doesn't exist |
||
1307 | |||
328 | tk | 1308 | // ensure that selections are matching with track constraints |
1309 | SEQ_UI_CheckSelections(); |
||
1310 | |||
596 | tk | 1311 | // stop current message |
1312 | SEQ_UI_MsgStop(); |
||
1313 | |||
134 | tk | 1314 | // limit incrementer |
1315 | if( incrementer > 3 ) |
||
1316 | incrementer = 3; |
||
1317 | else if( incrementer < -3 ) |
||
1318 | incrementer = -3; |
||
1319 | |||
607 | tk | 1320 | if( seq_ui_button_state.SCRUB && encoder == 0 ) { |
1321 | // if sequencer isn't already running, continue it (don't restart) |
||
1322 | if( !SEQ_BPM_IsRunning() ) |
||
1323 | SEQ_BPM_Cont(); |
||
1324 | ui_seq_pause = 0; // clear pause mode |
||
1325 | // Scrub sequence back or forth |
||
1326 | portENTER_CRITICAL(); // should be atomic |
||
1327 | SEQ_CORE_Scrub(incrementer); |
||
1328 | portEXIT_CRITICAL(); |
||
1329 | } else if( !seq_ui_button_state.MENU_PRESSED && ui_encoder_callback != NULL ) { |
||
173 | tk | 1330 | ui_encoder_callback((encoder == 0) ? SEQ_UI_ENCODER_Datawheel : (encoder-1), incrementer); |
1331 | ui_cursor_flash_ctr = 0; // ensure that value is visible when it has been changed |
||
134 | tk | 1332 | } |
1333 | |||
1334 | // request display update |
||
159 | tk | 1335 | seq_ui_display_update_req = 1; |
134 | tk | 1336 | |
1337 | return 0; // no error |
||
1338 | } |
||
1339 | |||
1340 | |||
353 | tk | 1341 | |
134 | tk | 1342 | ///////////////////////////////////////////////////////////////////////////// |
626 | tk | 1343 | // Receives a MIDI package from APP_NotifyReceivedEvent (-> app.c) |
1344 | ///////////////////////////////////////////////////////////////////////////// |
||
1345 | s32 SEQ_UI_REMOTE_MIDI_Receive(mios32_midi_port_t port, mios32_midi_package_t midi_package) |
||
1346 | { |
||
1347 | #if 1 |
||
1348 | // check for active remote mode |
||
1349 | if( seq_ui_remote_active_mode != SEQ_UI_REMOTE_MODE_SERVER ) |
||
1350 | return 0; // no error |
||
1351 | #endif |
||
1352 | |||
1353 | if( (seq_ui_remote_port == DEFAULT && seq_ui_remote_active_port != port) || |
||
1354 | (seq_ui_remote_port != DEFAULT && port != seq_ui_remote_port) ) |
||
1355 | return 0; // wrong port |
||
1356 | |||
1357 | // for easier parsing: convert Note Off -> Note On with velocity 0 |
||
1358 | if( midi_package.event == NoteOff ) { |
||
1359 | midi_package.event = NoteOn; |
||
1360 | midi_package.velocity = 0; |
||
1361 | } |
||
1362 | |||
1363 | switch( midi_package.event ) { |
||
1364 | case NoteOn: { |
||
1365 | switch( midi_package.chn ) { |
||
1366 | case Chn1: |
||
1367 | SEQ_UI_Button_Handler(midi_package.note + 0x00, midi_package.velocity ? 0 : 1); |
||
1368 | break; |
||
1369 | case Chn2: |
||
1370 | SEQ_UI_Button_Handler(midi_package.note + 0x80, midi_package.velocity ? 0 : 1); |
||
1371 | break; |
||
1372 | case Chn3: |
||
1373 | SEQ_UI_BLM_Button_Handler(midi_package.note >> 5, midi_package.note & 0x1f, midi_package.velocity ? 0 : 1); |
||
1374 | break; |
||
1375 | } |
||
1376 | } break; |
||
1377 | |||
1378 | case CC: { |
||
1379 | if( midi_package.cc_number >= 15 && midi_package.cc_number <= 31 ) |
||
1380 | SEQ_UI_Encoder_Handler(midi_package.cc_number-15, (int)midi_package.value - 0x40); |
||
1381 | } break; |
||
1382 | } |
||
1383 | |||
632 | tk | 1384 | return 1; // MIDI event has been taken for remote function -> don't forward to router/MIDI event parser |
626 | tk | 1385 | } |
1386 | |||
1387 | |||
1388 | ///////////////////////////////////////////////////////////////////////////// |
||
134 | tk | 1389 | // Update LCD messages |
1390 | // Usually called from background task |
||
1391 | ///////////////////////////////////////////////////////////////////////////// |
||
1392 | s32 SEQ_UI_LCD_Handler(void) |
||
1393 | { |
||
728 | tk | 1394 | static u8 boot_animation_wait_ctr = 0; |
1395 | static u8 boot_animation_lcd_pos = 0; |
||
1396 | |||
625 | tk | 1397 | // special handling in remote client mode |
626 | tk | 1398 | if( seq_ui_remote_active_mode == SEQ_UI_REMOTE_MODE_CLIENT ) |
625 | tk | 1399 | return SEQ_UI_LCD_Update(); |
1400 | |||
159 | tk | 1401 | if( seq_ui_display_init_req ) { |
1402 | seq_ui_display_init_req = 0; // clear request |
||
134 | tk | 1403 | |
278 | tk | 1404 | // clear force update of LCD |
1405 | SEQ_LCD_Clear(); |
||
1406 | SEQ_LCD_Update(1); |
||
134 | tk | 1407 | |
168 | tk | 1408 | // select first menu item |
1409 | ui_selected_item = 0; |
||
1410 | |||
167 | tk | 1411 | // call init function of current page |
272 | tk | 1412 | if( ui_menu_pages[ui_page].init_callback != NULL ) |
1413 | ui_menu_pages[ui_page].init_callback(0); // mode |
||
134 | tk | 1414 | |
1415 | // request display update |
||
159 | tk | 1416 | seq_ui_display_update_req = 1; |
134 | tk | 1417 | } |
1418 | |||
496 | tk | 1419 | // print boot screen so long hardware config hasn't been read |
1420 | if( !SEQ_FILE_HW_ConfigLocked() ) { |
||
728 | tk | 1421 | if( boot_animation_lcd_pos < (40-3) ) { |
1422 | if( ++boot_animation_wait_ctr >= 75 ) { |
||
1423 | boot_animation_wait_ctr = 0; |
||
637 | tk | 1424 | |
728 | tk | 1425 | if( boot_animation_lcd_pos == 0 ) { |
1426 | SEQ_LCD_Clear(); |
||
1427 | SEQ_LCD_CursorSet(0, 0); |
||
1428 | SEQ_LCD_PrintString(MIOS32_LCD_BOOT_MSG_LINE1 " " MIOS32_LCD_BOOT_MSG_LINE2); |
||
1429 | SEQ_LCD_CursorSet(0, 1); |
||
1430 | SEQ_LCD_PrintString("Searching for SD Card..."); |
||
1431 | } |
||
1432 | |||
1433 | // logo is print on second LCD |
||
1434 | SEQ_LCD_LOGO_Print(boot_animation_lcd_pos++); |
||
1435 | } |
||
1436 | } |
||
634 | tk | 1437 | } else if( seq_ui_backup_req ) { |
1438 | SEQ_LCD_Clear(); |
||
1439 | SEQ_LCD_CursorSet(0, 0); |
||
1440 | // <--------------------------------------> |
||
1441 | // 0123456789012345678901234567890123456789 |
||
637 | tk | 1442 | SEQ_LCD_PrintString("Creating File Backup - be patient!!!"); |
1443 | |||
1444 | if( seq_file_backup_notification != NULL ) { |
||
1445 | int i; |
||
1446 | |||
1447 | SEQ_LCD_CursorSet(0, 1); |
||
634 | tk | 1448 | SEQ_LCD_PrintFormattedString("Creating '%s'", seq_file_backup_notification); |
637 | tk | 1449 | |
1450 | SEQ_LCD_CursorSet(40+3, 0); |
||
1451 | SEQ_LCD_PrintString("Total: ["); |
||
1452 | for(i=0; i<20; ++i) |
||
1453 | SEQ_LCD_PrintChar((i>(seq_file_backup_percentage/5)) ? ' ' : '#'); |
||
1454 | SEQ_LCD_PrintFormattedString("] %3d%%", seq_file_backup_percentage); |
||
1455 | |||
1456 | SEQ_LCD_CursorSet(40+3, 1); |
||
1457 | SEQ_LCD_PrintString("File: ["); |
||
1458 | for(i=0; i<20; ++i) |
||
1459 | SEQ_LCD_PrintChar((i>(seq_file_copy_percentage/5)) ? ' ' : '#'); |
||
1460 | SEQ_LCD_PrintFormattedString("] %3d%%", seq_file_copy_percentage); |
||
1461 | } |
||
1462 | |||
496 | tk | 1463 | } else if( seq_ui_button_state.MENU_PRESSED && !seq_ui_button_state.MENU_FIRST_PAGE_SELECTED ) { |
1464 | SEQ_LCD_CursorSet(0, 0); |
||
1465 | // <--------------------------------------> |
||
1466 | // 0123456789012345678901234567890123456789 |
||
306 | tk | 1467 | SEQ_LCD_PrintString("Menu Shortcuts:"); |
1468 | SEQ_LCD_PrintSpaces(25 + 40); |
||
1469 | SEQ_LCD_CursorSet(0, 1); |
||
1470 | SEQ_LCD_PrintString(UI_SHORTCUT_STR); // defined in seq_ui_pages.inc |
||
1471 | } else { |
||
1472 | // perform high priority LCD update request |
||
1473 | if( ui_lcd_callback != NULL ) |
||
1474 | ui_lcd_callback(1); // high_prio |
||
167 | tk | 1475 | |
306 | tk | 1476 | // perform low priority LCD update request if requested |
1477 | if( seq_ui_display_update_req ) { |
||
1478 | seq_ui_display_update_req = 0; // clear request |
||
328 | tk | 1479 | |
1480 | // ensure that selections are matching with track constraints |
||
1481 | SEQ_UI_CheckSelections(); |
||
1482 | |||
306 | tk | 1483 | if( ui_lcd_callback != NULL ) |
1484 | ui_lcd_callback(0); // no high_prio |
||
1485 | } |
||
134 | tk | 1486 | } |
1487 | |||
353 | tk | 1488 | // transfer all changed characters to LCD |
1489 | SEQ_UI_LCD_Update(); |
||
1490 | |||
1491 | return 0; // no error |
||
1492 | } |
||
1493 | |||
1494 | |||
1495 | ///////////////////////////////////////////////////////////////////////////// |
||
1496 | // Called from SEQ_UI_LCD_Handler(), but optionally also from other tasks |
||
1497 | // to update the LCD screen immediately |
||
1498 | ///////////////////////////////////////////////////////////////////////////// |
||
1499 | s32 SEQ_UI_LCD_Update(void) |
||
1500 | { |
||
625 | tk | 1501 | // special handling in remote client mode |
626 | tk | 1502 | if( seq_ui_remote_active_mode == SEQ_UI_REMOTE_MODE_CLIENT ) { |
1503 | MIOS32_IRQ_Disable(); |
||
1504 | u8 force = seq_ui_remote_force_lcd_update; |
||
1505 | seq_ui_remote_force_lcd_update = 0; |
||
1506 | MIOS32_IRQ_Enable(); |
||
1507 | return SEQ_LCD_Update(force); |
||
625 | tk | 1508 | } |
1509 | |||
596 | tk | 1510 | // if UI message active: copy over the text |
1511 | if( ui_msg_ctr ) { |
||
1512 | const char *animation_l_ptr; |
||
1513 | const char *animation_r_ptr; |
||
1514 | u8 msg_x = 0; |
||
1515 | u8 right_aligned = 0; |
||
299 | tk | 1516 | |
596 | tk | 1517 | switch( ui_msg_type ) { |
1518 | case SEQ_UI_MSG_SDCARD: { |
||
1519 | // 00112233 |
||
1520 | const char animation_l[2*4] = " >>>> "; |
||
1521 | // 00112233 |
||
1522 | const char animation_r[2*4] = " < << <"; |
||
1523 | animation_l_ptr = animation_l; |
||
1524 | animation_r_ptr = animation_r; |
||
1525 | msg_x = 0; // MEMO: print such important information at first LCD for the case the user hasn't connected the second LCD yet |
||
1526 | right_aligned = 0; |
||
1527 | } break; |
||
1528 | |||
1529 | default: { |
||
1530 | // 00112233 |
||
1531 | const char animation_l[2*4] = " **** "; |
||
1532 | // 00112233 |
||
1533 | const char animation_r[2*4] = " * ** *"; |
||
1534 | animation_l_ptr = animation_l; |
||
1535 | animation_r_ptr = animation_r; |
||
1536 | msg_x = 39; |
||
1537 | right_aligned = 1; |
||
1538 | } break; |
||
1539 | |||
1540 | } |
||
1541 | int anum = (ui_msg_ctr % 1000) / 250; |
||
1542 | |||
1543 | int len[2]; |
||
1544 | len[0] = strlen((char *)ui_msg[0]); |
||
1545 | len[1] = strlen((char *)ui_msg[1]); |
||
1546 | int len_max = len[0]; |
||
1547 | if( len[1] > len_max ) |
||
1548 | len_max = len[1]; |
||
1549 | |||
1550 | if( right_aligned ) |
||
1551 | msg_x -= (9 + len_max); |
||
1552 | |||
299 | tk | 1553 | int line; |
1554 | for(line=0; line<2; ++line) { |
||
596 | tk | 1555 | SEQ_LCD_CursorSet(msg_x, line); |
1556 | |||
1557 | // ensure that both lines are padded with same number of spaces |
||
1558 | int end_pos = len[line]; |
||
1559 | while( end_pos < len_max ) |
||
1560 | ui_msg[line][end_pos++] = ' '; |
||
1561 | ui_msg[line][end_pos] = 0; |
||
1562 | |||
1563 | SEQ_LCD_PrintFormattedString(" %c%c| %s |%c%c ", |
||
1564 | *(animation_l_ptr + 2*anum + 0), *(animation_l_ptr + 2*anum + 1), |
||
1565 | (char *)ui_msg[line], |
||
1566 | *(animation_r_ptr + 2*anum + 0), *(animation_r_ptr + 2*anum + 1)); |
||
299 | tk | 1567 | } |
1568 | } |
||
1569 | |||
637 | tk | 1570 | // MSD USB notification at right corner if not in Disk page |
1571 | // to warn user that USB MIDI is disabled and seq performance is bad now! |
||
638 | tk | 1572 | if( (TASK_MSD_EnableGet() > 0) && ui_page != SEQ_UI_PAGE_DISK ) { |
637 | tk | 1573 | SEQ_LCD_CursorSet(80-11, 0); |
1574 | if( ui_cursor_flash ) SEQ_LCD_PrintSpaces(13); else SEQ_LCD_PrintString(" [MSD USB] "); |
||
1575 | SEQ_LCD_CursorSet(80-11, 1); |
||
1576 | char str[5]; |
||
1577 | TASK_MSD_FlagStrGet(str); |
||
1578 | if( ui_cursor_flash ) SEQ_LCD_PrintSpaces(13); else SEQ_LCD_PrintFormattedString(" [ %s ] ", str); |
||
1579 | } |
||
596 | tk | 1580 | |
278 | tk | 1581 | // transfer all changed characters to LCD |
353 | tk | 1582 | // SEQ_LCD_Update provides a MUTEX handling to allow updates from different tasks |
1583 | return SEQ_LCD_Update(0); |
||
134 | tk | 1584 | } |
1585 | |||
1586 | |||
1587 | ///////////////////////////////////////////////////////////////////////////// |
||
1588 | // Update all LEDs |
||
1589 | // Usually called from background task |
||
1590 | ///////////////////////////////////////////////////////////////////////////// |
||
1591 | s32 SEQ_UI_LED_Handler(void) |
||
1592 | { |
||
626 | tk | 1593 | static u8 remote_led_sr[SEQ_LED_NUM_SR]; |
1594 | |||
524 | tk | 1595 | int i; |
1596 | |||
625 | tk | 1597 | // ignore in remote client mode |
626 | tk | 1598 | if( seq_ui_remote_active_mode == SEQ_UI_REMOTE_MODE_CLIENT ) |
625 | tk | 1599 | return 0; // no error |
1600 | |||
496 | tk | 1601 | // ignore so long hardware config hasn't been read |
1602 | if( !SEQ_FILE_HW_ConfigLocked() ) |
||
1603 | return -1; |
||
1604 | |||
134 | tk | 1605 | // track LEDs |
484 | tk | 1606 | u8 selected_tracks = ui_selected_tracks >> (4*ui_selected_group); |
492 | tk | 1607 | SEQ_LED_PinSet(seq_hwcfg_led.track[0], (selected_tracks & (1 << 0))); |
1608 | SEQ_LED_PinSet(seq_hwcfg_led.track[1], (selected_tracks & (1 << 1))); |
||
1609 | SEQ_LED_PinSet(seq_hwcfg_led.track[2], (selected_tracks & (1 << 2))); |
||
1610 | SEQ_LED_PinSet(seq_hwcfg_led.track[3], (selected_tracks & (1 << 3))); |
||
678 | tk | 1611 | SEQ_LED_PinSet(seq_hwcfg_led.track_sel, ui_page == SEQ_UI_PAGE_TRACKSEL); |
134 | tk | 1612 | |
1613 | // parameter layer LEDs |
||
492 | tk | 1614 | SEQ_LED_PinSet(seq_hwcfg_led.par_layer[0], (ui_selected_par_layer == 0)); |
1615 | SEQ_LED_PinSet(seq_hwcfg_led.par_layer[1], (ui_selected_par_layer == 1)); |
||
1616 | SEQ_LED_PinSet(seq_hwcfg_led.par_layer[2], (ui_selected_par_layer >= 2) || seq_ui_button_state.PAR_LAYER_SEL); |
||
678 | tk | 1617 | SEQ_LED_PinSet(seq_hwcfg_led.par_layer_sel, ui_page == SEQ_UI_PAGE_PARSEL); |
134 | tk | 1618 | |
1619 | // group LEDs |
||
492 | tk | 1620 | SEQ_LED_PinSet(seq_hwcfg_led.group[0], (ui_selected_group == 0)); |
1621 | SEQ_LED_PinSet(seq_hwcfg_led.group[1], (ui_selected_group == 1)); |
||
1622 | SEQ_LED_PinSet(seq_hwcfg_led.group[2], (ui_selected_group == 2)); |
||
1623 | SEQ_LED_PinSet(seq_hwcfg_led.group[3], (ui_selected_group == 3)); |
||
134 | tk | 1624 | |
1625 | // trigger layer LEDs |
||
492 | tk | 1626 | SEQ_LED_PinSet(seq_hwcfg_led.trg_layer[0], (ui_selected_trg_layer == 0)); |
1627 | SEQ_LED_PinSet(seq_hwcfg_led.trg_layer[1], (ui_selected_trg_layer == 1)); |
||
1628 | SEQ_LED_PinSet(seq_hwcfg_led.trg_layer[2], (ui_selected_trg_layer >= 2) || seq_ui_button_state.TRG_LAYER_SEL); |
||
678 | tk | 1629 | SEQ_LED_PinSet(seq_hwcfg_led.trg_layer_sel, ui_page == SEQ_UI_PAGE_TRGSEL); |
134 | tk | 1630 | |
1631 | // remaining LEDs |
||
492 | tk | 1632 | SEQ_LED_PinSet(seq_hwcfg_led.edit, ui_page == SEQ_UI_PAGE_EDIT); |
1633 | SEQ_LED_PinSet(seq_hwcfg_led.mute, ui_page == SEQ_UI_PAGE_MUTE); |
||
1634 | SEQ_LED_PinSet(seq_hwcfg_led.pattern, ui_page == SEQ_UI_PAGE_PATTERN); |
||
399 | tk | 1635 | if( SEQ_SONG_ActiveGet() ) |
492 | tk | 1636 | SEQ_LED_PinSet(seq_hwcfg_led.song, 1); |
399 | tk | 1637 | else |
492 | tk | 1638 | SEQ_LED_PinSet(seq_hwcfg_led.song, ui_cursor_flash ? 0 : (ui_page == SEQ_UI_PAGE_SONG)); |
134 | tk | 1639 | |
492 | tk | 1640 | SEQ_LED_PinSet(seq_hwcfg_led.solo, seq_ui_button_state.SOLO); |
1641 | SEQ_LED_PinSet(seq_hwcfg_led.fast, seq_ui_button_state.FAST_ENCODERS); |
||
1642 | SEQ_LED_PinSet(seq_hwcfg_led.all, seq_ui_button_state.CHANGE_ALL_STEPS); |
||
134 | tk | 1643 | |
492 | tk | 1644 | SEQ_LED_PinSet(seq_hwcfg_led.play, SEQ_BPM_IsRunning()); |
1645 | SEQ_LED_PinSet(seq_hwcfg_led.stop, !SEQ_BPM_IsRunning() && !ui_seq_pause); |
||
1646 | SEQ_LED_PinSet(seq_hwcfg_led.pause, ui_seq_pause); |
||
240 | tk | 1647 | |
492 | tk | 1648 | SEQ_LED_PinSet(seq_hwcfg_led.rew, seq_ui_button_state.REW); |
1649 | SEQ_LED_PinSet(seq_hwcfg_led.fwd, seq_ui_button_state.FWD); |
||
596 | tk | 1650 | |
1651 | SEQ_LED_PinSet(seq_hwcfg_led.loop, seq_core_state.LOOP); |
||
134 | tk | 1652 | |
678 | tk | 1653 | SEQ_LED_PinSet(seq_hwcfg_led.step_view, ui_page == SEQ_UI_PAGE_STEPSEL); |
134 | tk | 1654 | |
591 | tk | 1655 | SEQ_LED_PinSet(seq_hwcfg_led.exit, seq_ui_button_state.EXIT_PRESSED); |
1656 | SEQ_LED_PinSet(seq_hwcfg_led.select, seq_ui_button_state.SELECT_PRESSED); |
||
492 | tk | 1657 | SEQ_LED_PinSet(seq_hwcfg_led.menu, seq_ui_button_state.MENU_PRESSED); |
134 | tk | 1658 | |
596 | tk | 1659 | // handle double functions |
1660 | if( seq_ui_button_state.MENU_PRESSED ) { |
||
1661 | SEQ_LED_PinSet(seq_hwcfg_led.scrub, seq_core_state.LOOP); |
||
1662 | SEQ_LED_PinSet(seq_hwcfg_led.metronome, seq_core_state.EXT_RESTART_REQ); |
||
1663 | } else { |
||
1664 | SEQ_LED_PinSet(seq_hwcfg_led.scrub, seq_ui_button_state.SCRUB); |
||
1665 | SEQ_LED_PinSet(seq_hwcfg_led.metronome, seq_core_state.METRONOME); |
||
1666 | } |
||
1667 | |||
630 | tk | 1668 | SEQ_LED_PinSet(seq_hwcfg_led.record, ui_page == SEQ_UI_PAGE_TRKREC); |
1669 | |||
492 | tk | 1670 | SEQ_LED_PinSet(seq_hwcfg_led.utility, ui_page == SEQ_UI_PAGE_UTIL); |
1671 | SEQ_LED_PinSet(seq_hwcfg_led.copy, seq_ui_button_state.COPY); |
||
1672 | SEQ_LED_PinSet(seq_hwcfg_led.paste, seq_ui_button_state.PASTE); |
||
1673 | SEQ_LED_PinSet(seq_hwcfg_led.clear, seq_ui_button_state.CLEAR); |
||
240 | tk | 1674 | |
513 | tk | 1675 | SEQ_LED_PinSet(seq_hwcfg_led.tap_tempo, seq_ui_button_state.TAP_TEMPO); |
678 | tk | 1676 | SEQ_LED_PinSet(seq_hwcfg_led.tempo_preset, ui_page == SEQ_UI_PAGE_BPM_PRESETS); |
524 | tk | 1677 | SEQ_LED_PinSet(seq_hwcfg_led.ext_restart, seq_core_state.EXT_RESTART_REQ); |
240 | tk | 1678 | |
492 | tk | 1679 | SEQ_LED_PinSet(seq_hwcfg_led.down, seq_ui_button_state.DOWN); |
1680 | SEQ_LED_PinSet(seq_hwcfg_led.up, seq_ui_button_state.UP); |
||
240 | tk | 1681 | |
167 | tk | 1682 | |
306 | tk | 1683 | // in MENU page: overrule GP LEDs so long MENU button is pressed/active |
1684 | if( seq_ui_button_state.MENU_PRESSED ) { |
||
1685 | if( ui_cursor_flash ) // if flashing flag active: no LED flag set |
||
1686 | ui_gp_leds = 0x0000; |
||
1687 | else { |
||
1688 | int i; |
||
1689 | u16 new_ui_gp_leds = 0x0000; |
||
1690 | for(i=0; i<16; ++i) |
||
1691 | if( ui_page == ui_shortcut_menu_pages[i] ) |
||
1692 | new_ui_gp_leds |= (1 << i); |
||
1693 | ui_gp_leds = new_ui_gp_leds; |
||
1694 | } |
||
1695 | } else { |
||
1696 | // note: the background function is permanently interrupted - therefore we write the GP pattern |
||
1697 | // into a temporary variable, and take it over once completed |
||
1698 | u16 new_ui_gp_leds = 0x0000; |
||
1699 | // request GP LED values from current menu page |
||
1700 | // will be transfered to DOUT registers in SEQ_UI_LED_Handler_Periodic |
||
1701 | new_ui_gp_leds = 0x0000; |
||
206 | tk | 1702 | |
306 | tk | 1703 | if( ui_led_callback != NULL ) |
1704 | ui_led_callback(&new_ui_gp_leds); |
||
167 | tk | 1705 | |
306 | tk | 1706 | ui_gp_leds = new_ui_gp_leds; |
1707 | } |
||
1708 | |||
524 | tk | 1709 | |
1710 | // BLM LEDs |
||
1711 | u8 visible_track0 = 4*ui_selected_group; |
||
1712 | u8 visible_sr0 = 2*ui_selected_step_view; |
||
1713 | |||
1714 | for(i=0; i<NUM_BLM_LED_SRS; ++i) |
||
1715 | ui_blm_leds[i] = SEQ_TRG_Get8(visible_track0+(i>>1), visible_sr0+(i&1), ui_selected_trg_layer, ui_selected_instrument); |
||
1716 | |||
626 | tk | 1717 | |
1718 | // send LED changes in remote server mode |
||
1719 | if( seq_ui_remote_mode == SEQ_UI_REMOTE_MODE_SERVER || seq_ui_remote_active_mode == SEQ_UI_REMOTE_MODE_SERVER ) { |
||
1720 | int first_sr = -1; |
||
1721 | int last_sr = -1; |
||
1722 | int sr; |
||
1723 | for(sr=0; sr<SEQ_LED_NUM_SR; ++sr) { |
||
1724 | u8 value = SEQ_LED_SRGet(sr); |
||
1725 | if( value != remote_led_sr[sr] ) { |
||
1726 | if( first_sr == -1 ) |
||
1727 | first_sr = sr; |
||
1728 | last_sr = sr; |
||
1729 | remote_led_sr[sr] = value; |
||
1730 | } |
||
1731 | } |
||
1732 | |||
1733 | MIOS32_IRQ_Disable(); |
||
1734 | if( seq_ui_remote_force_led_update ) { |
||
1735 | first_sr = 0; |
||
1736 | last_sr = SEQ_LED_NUM_SR-1; |
||
1737 | } |
||
1738 | seq_ui_remote_force_led_update = 0; |
||
1739 | MIOS32_IRQ_Enable(); |
||
1740 | |||
1741 | if( first_sr >= 0 ) |
||
1742 | SEQ_MIDI_SYSEX_REMOTE_Server_SendLED(first_sr, (u8 *)&remote_led_sr[first_sr], last_sr-first_sr+1); |
||
1743 | } |
||
1744 | |||
1745 | |||
134 | tk | 1746 | return 0; // no error |
1747 | } |
||
1748 | |||
1749 | |||
1750 | ///////////////////////////////////////////////////////////////////////////// |
||
1751 | // updates high-prio LED functions (GP LEDs and Beat LED) |
||
168 | tk | 1752 | // called each mS |
134 | tk | 1753 | ///////////////////////////////////////////////////////////////////////////// |
1754 | s32 SEQ_UI_LED_Handler_Periodic() |
||
1755 | { |
||
625 | tk | 1756 | // ignore in remote client mode |
626 | tk | 1757 | if( seq_ui_remote_active_mode == SEQ_UI_REMOTE_MODE_CLIENT ) |
625 | tk | 1758 | return 0; // no error |
1759 | |||
496 | tk | 1760 | // ignore so long hardware config hasn't been read |
1761 | if( !SEQ_FILE_HW_ConfigLocked() ) |
||
1762 | return -1; |
||
1763 | |||
134 | tk | 1764 | // GP LEDs are only updated when ui_gp_leds or pos_marker_mask has changed |
1765 | static u16 prev_ui_gp_leds = 0x0000; |
||
1766 | static u16 prev_pos_marker_mask = 0x0000; |
||
1767 | |||
1768 | // beat LED: tmp. for demo w/o real sequencer |
||
193 | tk | 1769 | u8 sequencer_running = SEQ_BPM_IsRunning(); |
492 | tk | 1770 | SEQ_LED_PinSet(seq_hwcfg_led.beat, sequencer_running && ((seq_core_state.ref_step & 3) == 0)); |
134 | tk | 1771 | |
1772 | // for song position marker (supports 16 LEDs, check for selected step view) |
||
1773 | u16 pos_marker_mask = 0x0000; |
||
325 | tk | 1774 | u8 visible_track = SEQ_UI_VisibleTrackGet(); |
1775 | u8 played_step = seq_core_trk[visible_track].step; |
||
513 | tk | 1776 | if( seq_ui_button_state.STEP_VIEW ) { |
1777 | // if STEP_VIEW button pressed: pos marker correlated to zoom ratio |
||
325 | tk | 1778 | if( sequencer_running ) |
1779 | pos_marker_mask = 1 << (played_step / (SEQ_TRG_NumStepsGet(visible_track)/16)); |
||
1780 | } else { |
||
1781 | if( sequencer_running && (played_step >> 4) == ui_selected_step_view ) |
||
1782 | pos_marker_mask = 1 << (played_step & 0xf); |
||
1783 | } |
||
134 | tk | 1784 | |
1785 | // exit of pattern hasn't changed |
||
173 | tk | 1786 | if( prev_ui_gp_leds == ui_gp_leds && prev_pos_marker_mask == pos_marker_mask ) |
134 | tk | 1787 | return 0; |
173 | tk | 1788 | prev_ui_gp_leds = ui_gp_leds; |
134 | tk | 1789 | prev_pos_marker_mask = pos_marker_mask; |
1790 | |||
1791 | // transfer to GP LEDs |
||
514 | tk | 1792 | if( seq_hwcfg_led.gp_dout_l_sr ) { |
1793 | if( seq_hwcfg_led.gp_dout_l2_sr ) |
||
1794 | SEQ_LED_SRSet(seq_hwcfg_led.gp_dout_l_sr-1, (ui_gp_leds >> 0) & 0xff); |
||
496 | tk | 1795 | else |
514 | tk | 1796 | SEQ_LED_SRSet(seq_hwcfg_led.gp_dout_l_sr-1, ((ui_gp_leds ^ pos_marker_mask) >> 0) & 0xff); |
496 | tk | 1797 | } |
134 | tk | 1798 | |
514 | tk | 1799 | if( seq_hwcfg_led.gp_dout_r_sr ) { |
1800 | if( seq_hwcfg_led.gp_dout_r2_sr ) |
||
1801 | SEQ_LED_SRSet(seq_hwcfg_led.gp_dout_r_sr-1, (ui_gp_leds >> 8) & 0xff); |
||
496 | tk | 1802 | else |
514 | tk | 1803 | SEQ_LED_SRSet(seq_hwcfg_led.gp_dout_r_sr-1, ((ui_gp_leds ^ pos_marker_mask) >> 8) & 0xff); |
496 | tk | 1804 | } |
134 | tk | 1805 | |
514 | tk | 1806 | if( seq_hwcfg_led.gp_dout_l2_sr ) |
1807 | SEQ_LED_SRSet(seq_hwcfg_led.gp_dout_l2_sr-1, (pos_marker_mask >> 0) & 0xff); |
||
1808 | if( seq_hwcfg_led.gp_dout_r2_sr ) |
||
1809 | SEQ_LED_SRSet(seq_hwcfg_led.gp_dout_r2_sr-1, (pos_marker_mask >> 8) & 0xff); |
||
496 | tk | 1810 | |
524 | tk | 1811 | |
1812 | if( seq_hwcfg_blm.enabled ) { |
||
1813 | // Red LEDs (position marker) |
||
1814 | int track_ix; |
||
1815 | for(track_ix=0; track_ix<(NUM_BLM_LED_SRS/2); ++track_ix) { |
||
1816 | u16 pos_marker_mask = 0x0000; |
||
1817 | if( sequencer_running ) { |
||
1818 | u8 track = ui_selected_group + track_ix; |
||
1819 | u8 played_step = seq_core_trk[track].step; |
||
1820 | if( (played_step >> 4) == ui_selected_step_view ) |
||
1821 | pos_marker_mask = 1 << (played_step & 0xf); |
||
1822 | } |
||
1823 | |||
1824 | // Prepare Green LEDs (triggers) |
||
1825 | u8 green_l = ui_blm_leds[2*track_ix+0]; |
||
1826 | u8 green_r = ui_blm_leds[2*track_ix+1]; |
||
1827 | |||
1828 | // Red LEDs (position marker) |
||
1829 | if( seq_hwcfg_blm.dout_duocolour ) { |
||
1830 | BLM_DOUT_SRSet(1, 2*track_ix+0, pos_marker_mask & 0xff); |
||
1831 | BLM_DOUT_SRSet(1, 2*track_ix+1, (pos_marker_mask >> 8) & 0xff); |
||
1832 | |||
1833 | if( seq_hwcfg_blm.dout_duocolour == 2 ) { |
||
1834 | // Colour Mode 2: clear green LED, so that only one LED is lit |
||
1835 | if( pos_marker_mask & 0x00ff ) |
||
1836 | green_l &= ~pos_marker_mask; |
||
1837 | else if( pos_marker_mask & 0xff00 ) |
||
1838 | green_r &= ~(pos_marker_mask >> 8); |
||
1839 | } |
||
1840 | } else { |
||
1841 | // If Duo-LEDs not enabled: invert Green LEDs |
||
1842 | if( pos_marker_mask & 0x00ff ) |
||
1843 | green_l ^= pos_marker_mask; |
||
1844 | else if( pos_marker_mask & 0xff00 ) |
||
1845 | green_r ^= (pos_marker_mask >> 8); |
||
1846 | } |
||
1847 | |||
1848 | // Set Green LEDs |
||
1849 | BLM_DOUT_SRSet(0, 2*track_ix+0, green_l); |
||
1850 | BLM_DOUT_SRSet(0, 2*track_ix+1, green_r); |
||
1851 | } |
||
1852 | } |
||
1853 | |||
1854 | |||
514 | tk | 1855 | if( seq_hwcfg_blm8x8.enabled && seq_hwcfg_blm8x8.dout_gp_mapping ) { |
513 | tk | 1856 | // for wilba's frontpanel |
134 | tk | 1857 | |
513 | tk | 1858 | // BLM_X DOUT -> GP LED mapping |
1859 | // 0 = 15,16 1 = 13,14 2 = 11,12 3 = 9,10 |
||
1860 | // 4 = 1,2 5 = 3,4 6 = 5,6 7 = 7,8 |
||
134 | tk | 1861 | |
513 | tk | 1862 | // bit 7: first green (i.e. GP1-G) |
1863 | // bit 6: first red (i.e. GP1-R) |
||
1864 | // bit 5: second green (i.e. GP2-G) |
||
1865 | // bit 4: second red (i.e. GP2-R) |
||
134 | tk | 1866 | |
513 | tk | 1867 | // this mapping routine takes ca. 5 uS |
1868 | // since it's only executed when ui_gp_leds or gp_mask has changed, it doesn't really hurt |
||
134 | tk | 1869 | |
513 | tk | 1870 | u16 modified_gp_leds = ui_gp_leds; |
134 | tk | 1871 | #if 1 |
513 | tk | 1872 | // extra: red LED is lit exclusively for higher contrast |
1873 | modified_gp_leds &= ~pos_marker_mask; |
||
134 | tk | 1874 | #endif |
1875 | |||
513 | tk | 1876 | int sr; |
1877 | const u8 blm_x_sr_map[8] = {4, 5, 6, 7, 3, 2, 1, 0}; |
||
1878 | u16 gp_mask = 1 << 0; |
||
1879 | for(sr=0; sr<8; ++sr) { |
||
1880 | u8 pattern = 0; |
||
134 | tk | 1881 | |
513 | tk | 1882 | if( modified_gp_leds & gp_mask ) |
1883 | pattern |= 0x80; |
||
1884 | if( pos_marker_mask & gp_mask ) |
||
1885 | pattern |= 0x40; |
||
1886 | gp_mask <<= 1; |
||
1887 | if( modified_gp_leds & gp_mask ) |
||
1888 | pattern |= 0x20; |
||
1889 | if( pos_marker_mask & gp_mask ) |
||
1890 | pattern |= 0x10; |
||
1891 | gp_mask <<= 1; |
||
134 | tk | 1892 | |
513 | tk | 1893 | u8 mapped_sr = blm_x_sr_map[sr]; |
1894 | BLM_X_LED_rows[mapped_sr][0] = (BLM_X_LED_rows[mapped_sr][0] & 0x0f) | pattern; |
||
1895 | } |
||
134 | tk | 1896 | } |
1897 | |||
184 | tk | 1898 | return 0; // no error |
134 | tk | 1899 | } |
1900 | |||
1901 | |||
1902 | ///////////////////////////////////////////////////////////////////////////// |
||
168 | tk | 1903 | // for menu handling (e.g. flashing cursor, doubleclick counter, etc...) |
1904 | // called each mS |
||
1905 | ///////////////////////////////////////////////////////////////////////////// |
||
1906 | s32 SEQ_UI_MENU_Handler_Periodic() |
||
1907 | { |
||
625 | tk | 1908 | // ignore in remote client mode |
626 | tk | 1909 | if( seq_ui_remote_active_mode == SEQ_UI_REMOTE_MODE_CLIENT ) |
625 | tk | 1910 | return 0; // no error |
1911 | |||
652 | tk | 1912 | if( ++ui_cursor_flash_ctr >= SEQ_UI_CURSOR_FLASH_CTR_MAX ) |
168 | tk | 1913 | ui_cursor_flash_ctr = 0; |
173 | tk | 1914 | // important: flash flag has to be recalculated on each invocation of this |
1915 | // handler, since counter could also be reseted outside this function |
||
652 | tk | 1916 | u8 old_ui_cursor_flash = ui_cursor_flash; |
173 | tk | 1917 | ui_cursor_flash = ui_cursor_flash_ctr >= SEQ_UI_CURSOR_FLASH_CTR_LED_OFF; |
652 | tk | 1918 | if( old_ui_cursor_flash != ui_cursor_flash ) |
1919 | seq_ui_display_update_req = 1; |
||
168 | tk | 1920 | |
240 | tk | 1921 | // used in some pages for temporary messages |
416 | tk | 1922 | if( ui_hold_msg_ctr ) { |
240 | tk | 1923 | --ui_hold_msg_ctr; |
1924 | |||
416 | tk | 1925 | if( !ui_hold_msg_ctr ) |
1926 | seq_ui_display_update_req = 1; |
||
1927 | } |
||
1928 | |||
596 | tk | 1929 | // used for temporary messages |
1930 | if( ui_msg_ctr ) |
||
1931 | --ui_msg_ctr; |
||
299 | tk | 1932 | |
184 | tk | 1933 | // VU meters (used in MUTE menu, could also be available as LED matrix...) |
1934 | static u8 vu_meter_prediv = 0; // predivider for VU meters |
||
1935 | |||
1936 | if( ++vu_meter_prediv >= 4 ) { |
||
1937 | vu_meter_prediv = 0; |
||
1938 | |||
333 | tk | 1939 | |
1940 | portENTER_CRITICAL(); |
||
1941 | |||
184 | tk | 1942 | u8 track; |
1943 | seq_core_trk_t *t = &seq_core_trk[0]; |
||
1944 | for(track=0; track<SEQ_CORE_NUM_TRACKS; ++t, ++track) |
||
1945 | if( t->vu_meter ) |
||
1946 | --t->vu_meter; |
||
333 | tk | 1947 | |
1948 | int i; |
||
1949 | u8 *vu_meter = (u8 *)&seq_layer_vu_meter[0]; |
||
1950 | for(i=0; i<sizeof(seq_layer_vu_meter); ++i, ++vu_meter) { |
||
1951 | if( *vu_meter && !(*vu_meter & 0x80) ) // if bit 7 set: static value |
||
1952 | *vu_meter -= 1; |
||
1953 | } |
||
1954 | |||
318 | tk | 1955 | portEXIT_CRITICAL(); |
184 | tk | 1956 | } |
1957 | |||
168 | tk | 1958 | return 0; |
1959 | } |
||
1960 | |||
1961 | |||
1962 | ///////////////////////////////////////////////////////////////////////////// |
||
328 | tk | 1963 | // Should be regulary called to check if the layer/instrument/step selection |
1964 | // is valid for the current track |
||
1965 | // At least executed before button/encoder and LCD function calls |
||
1966 | ///////////////////////////////////////////////////////////////////////////// |
||
1967 | s32 SEQ_UI_CheckSelections(void) |
||
1968 | { |
||
492 | tk | 1969 | if( (ui_selected_tracks >> (4*ui_selected_group)) == 0 ) |
1970 | ui_selected_tracks = 1 << (4*ui_selected_group); |
||
1971 | |||
328 | tk | 1972 | u8 visible_track = SEQ_UI_VisibleTrackGet(); |
1973 | |||
1974 | if( ui_selected_instrument >= SEQ_PAR_NumInstrumentsGet(visible_track) ) |
||
1975 | ui_selected_instrument = 0; |
||
1976 | |||
1977 | if( ui_selected_par_layer >= SEQ_PAR_NumLayersGet(visible_track) ) |
||
1978 | ui_selected_par_layer = 0; |
||
1979 | |||
1980 | if( ui_selected_trg_layer >= SEQ_TRG_NumLayersGet(visible_track) ) |
||
1981 | ui_selected_trg_layer = 0; |
||
1982 | |||
1983 | if( ui_selected_step >= SEQ_TRG_NumStepsGet(visible_track) ) |
||
1984 | ui_selected_step = 0; |
||
1985 | |||
1986 | if( ui_selected_step_view >= (SEQ_TRG_NumStepsGet(visible_track)/16) ) { |
||
1987 | ui_selected_step_view = 0; |
||
1988 | ui_selected_step %= 16; |
||
1989 | } |
||
1990 | |||
336 | tk | 1991 | if( ui_selected_step < (16*ui_selected_step_view) || |
1992 | ui_selected_step >= (16*(ui_selected_step_view+1)) ) |
||
328 | tk | 1993 | ui_selected_step_view = ui_selected_step / 16; |
1994 | |||
1995 | return 0; // no error |
||
1996 | } |
||
1997 | |||
1998 | |||
1999 | ///////////////////////////////////////////////////////////////////////////// |
||
134 | tk | 2000 | // Returns the currently visible track |
2001 | ///////////////////////////////////////////////////////////////////////////// |
||
2002 | u8 SEQ_UI_VisibleTrackGet(void) |
||
2003 | { |
||
2004 | u8 offset = 0; |
||
2005 | |||
484 | tk | 2006 | u8 selected_tracks = ui_selected_tracks >> (4*ui_selected_group); |
2007 | if( selected_tracks & (1 << 3) ) |
||
134 | tk | 2008 | offset = 3; |
484 | tk | 2009 | if( selected_tracks & (1 << 2) ) |
134 | tk | 2010 | offset = 2; |
484 | tk | 2011 | if( selected_tracks & (1 << 1) ) |
134 | tk | 2012 | offset = 1; |
484 | tk | 2013 | if( selected_tracks & (1 << 0) ) |
134 | tk | 2014 | offset = 0; |
2015 | |||
2016 | return 4*ui_selected_group + offset; |
||
2017 | } |
||
2018 | |||
168 | tk | 2019 | |
2020 | ///////////////////////////////////////////////////////////////////////////// |
||
178 | tk | 2021 | // Returns 1 if 'track' is selected |
2022 | ///////////////////////////////////////////////////////////////////////////// |
||
2023 | s32 SEQ_UI_IsSelectedTrack(u8 track) |
||
2024 | { |
||
484 | tk | 2025 | return (ui_selected_tracks & (1 << track)) ? 1 : 0; |
178 | tk | 2026 | } |
2027 | |||
2028 | |||
2029 | ///////////////////////////////////////////////////////////////////////////// |
||
240 | tk | 2030 | // Sets a new selected step and updates the step view |
2031 | ///////////////////////////////////////////////////////////////////////////// |
||
2032 | s32 SEQ_UI_SelectedStepSet(u8 step) |
||
2033 | { |
||
2034 | ui_selected_step = step; |
||
328 | tk | 2035 | SEQ_UI_CheckSelections(); |
2036 | |||
240 | tk | 2037 | return 0; // no error |
2038 | } |
||
2039 | |||
2040 | |||
2041 | ///////////////////////////////////////////////////////////////////////////// |
||
168 | tk | 2042 | // Increments the selected tracks/groups |
2043 | // OUT: 1 if value has been changed, otherwise 0 |
||
2044 | ///////////////////////////////////////////////////////////////////////////// |
||
2045 | s32 SEQ_UI_GxTyInc(s32 incrementer) |
||
2046 | { |
||
2047 | int gxty = SEQ_UI_VisibleTrackGet(); |
||
2048 | int prev_gxty = gxty; |
||
2049 | |||
2050 | if( incrementer >= 0 ) { |
||
2051 | if( (gxty += incrementer) >= SEQ_CORE_NUM_TRACKS ) |
||
2052 | gxty = SEQ_CORE_NUM_TRACKS-1; |
||
2053 | } else { |
||
2054 | if( (gxty += incrementer) < 0 ) |
||
2055 | gxty = 0; |
||
2056 | } |
||
2057 | |||
2058 | if( gxty == prev_gxty ) |
||
2059 | return 0; // no change |
||
2060 | |||
484 | tk | 2061 | ui_selected_tracks = 1 << gxty; |
168 | tk | 2062 | ui_selected_group = gxty / 4; |
2063 | |||
2064 | return 1; // value changed |
||
2065 | } |
||
2066 | |||
2067 | |||
2068 | ///////////////////////////////////////////////////////////////////////////// |
||
236 | tk | 2069 | // Increments a 16bit variable within given min/max range |
2070 | // OUT: 1 if value has been changed, otherwise 0 |
||
2071 | ///////////////////////////////////////////////////////////////////////////// |
||
240 | tk | 2072 | s32 SEQ_UI_Var16_Inc(u16 *value, u16 min, u16 max, s32 incrementer) |
236 | tk | 2073 | { |
2074 | int new_value = *value; |
||
2075 | int prev_value = new_value; |
||
2076 | |||
2077 | if( incrementer >= 0 ) { |
||
2078 | if( (new_value += incrementer) >= max ) |
||
2079 | new_value = max; |
||
2080 | } else { |
||
2081 | if( (new_value += incrementer) < min ) |
||
2082 | new_value = min; |
||
2083 | } |
||
2084 | |||
2085 | if( new_value == prev_value ) |
||
2086 | return 0; // no change |
||
2087 | |||
2088 | *value = new_value; |
||
2089 | |||
2090 | return 1; // value changed |
||
2091 | } |
||
2092 | |||
240 | tk | 2093 | ///////////////////////////////////////////////////////////////////////////// |
2094 | // Increments an 8bit variable within given min/max range |
||
2095 | // OUT: 1 if value has been changed, otherwise 0 |
||
2096 | ///////////////////////////////////////////////////////////////////////////// |
||
2097 | s32 SEQ_UI_Var8_Inc(u8 *value, u16 min, u16 max, s32 incrementer) |
||
2098 | { |
||
2099 | u16 tmp = *value; |
||
2100 | if( SEQ_UI_Var16_Inc(&tmp, min, max, incrementer) ) { |
||
2101 | *value = tmp; |
||
2102 | return 1; // value changed |
||
2103 | } |
||
236 | tk | 2104 | |
240 | tk | 2105 | return 0; // value hasn't been changed |
2106 | } |
||
2107 | |||
2108 | |||
236 | tk | 2109 | ///////////////////////////////////////////////////////////////////////////// |
168 | tk | 2110 | // Increments a CC within given min/max range |
2111 | // OUT: 1 if value has been changed, otherwise 0 |
||
2112 | ///////////////////////////////////////////////////////////////////////////// |
||
248 | tk | 2113 | s32 SEQ_UI_CC_Inc(u8 cc, u8 min, u8 max, s32 incrementer) |
168 | tk | 2114 | { |
2115 | u8 visible_track = SEQ_UI_VisibleTrackGet(); |
||
173 | tk | 2116 | int new_value = SEQ_CC_Get(visible_track, cc); |
2117 | int prev_value = new_value; |
||
168 | tk | 2118 | |
2119 | if( incrementer >= 0 ) { |
||
173 | tk | 2120 | if( (new_value += incrementer) >= max ) |
2121 | new_value = max; |
||
168 | tk | 2122 | } else { |
173 | tk | 2123 | if( (new_value += incrementer) < min ) |
2124 | new_value = min; |
||
168 | tk | 2125 | } |
2126 | |||
173 | tk | 2127 | if( new_value == prev_value ) |
168 | tk | 2128 | return 0; // no change |
2129 | |||
173 | tk | 2130 | SEQ_CC_Set(visible_track, cc, new_value); |
168 | tk | 2131 | |
179 | tk | 2132 | // set same value for all selected tracks |
2133 | u8 track; |
||
2134 | for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track) |
||
2135 | if( track != visible_track && SEQ_UI_IsSelectedTrack(track) ) |
||
2136 | SEQ_CC_Set(track, cc, new_value); |
||
2137 | |||
168 | tk | 2138 | return 1; // value changed |
2139 | } |
||
2140 | |||
173 | tk | 2141 | |
2142 | ///////////////////////////////////////////////////////////////////////////// |
||
179 | tk | 2143 | // Sets a CC value on all selected tracks |
2144 | // OUT: 1 if value has been changed, otherwise 0 |
||
2145 | ///////////////////////////////////////////////////////////////////////////// |
||
248 | tk | 2146 | s32 SEQ_UI_CC_Set(u8 cc, u8 value) |
179 | tk | 2147 | { |
2148 | u8 visible_track = SEQ_UI_VisibleTrackGet(); |
||
2149 | int prev_value = SEQ_CC_Get(visible_track, cc); |
||
2150 | |||
2151 | if( value == prev_value ) |
||
2152 | return 0; // no change |
||
2153 | |||
2154 | SEQ_CC_Set(visible_track, cc, value); |
||
2155 | |||
2156 | // set same value for all selected tracks |
||
2157 | u8 track; |
||
2158 | for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track) |
||
2159 | if( track != visible_track && SEQ_UI_IsSelectedTrack(track) ) |
||
2160 | SEQ_CC_Set(track, cc, value); |
||
2161 | |||
2162 | return 1; // value changed |
||
2163 | } |
||
2164 | |||
2165 | ///////////////////////////////////////////////////////////////////////////// |
||
173 | tk | 2166 | // Modifies a bitfield in a CC value to a given value |
2167 | // OUT: 1 if value has been changed, otherwise 0 |
||
2168 | ///////////////////////////////////////////////////////////////////////////// |
||
248 | tk | 2169 | s32 SEQ_UI_CC_SetFlags(u8 cc, u8 flag_mask, u8 value) |
173 | tk | 2170 | { |
2171 | u8 visible_track = SEQ_UI_VisibleTrackGet(); |
||
2172 | int new_value = SEQ_CC_Get(visible_track, cc); |
||
2173 | int prev_value = new_value; |
||
2174 | |||
2175 | new_value = (new_value & ~flag_mask) | value; |
||
2176 | |||
2177 | if( new_value == prev_value ) |
||
2178 | return 0; // no change |
||
2179 | |||
2180 | SEQ_CC_Set(visible_track, cc, new_value); |
||
2181 | |||
179 | tk | 2182 | // do same modification for all selected tracks |
2183 | u8 track; |
||
2184 | for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track) |
||
2185 | if( track != visible_track && SEQ_UI_IsSelectedTrack(track) ) { |
||
2186 | int new_value = SEQ_CC_Get(track, cc); |
||
2187 | new_value = (new_value & ~flag_mask) | value; |
||
2188 | SEQ_CC_Set(track, cc, new_value); |
||
2189 | } |
||
2190 | |||
173 | tk | 2191 | return 1; // value changed |
2192 | } |
||
2193 | |||
2194 | |||
299 | tk | 2195 | ///////////////////////////////////////////////////////////////////////////// |
596 | tk | 2196 | // Print temporary user messages (e.g. warnings, errors) |
299 | tk | 2197 | // expects mS delay and two lines, each up to 20 characters |
2198 | ///////////////////////////////////////////////////////////////////////////// |
||
596 | tk | 2199 | s32 SEQ_UI_Msg(seq_ui_msg_type_t msg_type, u16 delay, char *line1, char *line2) |
299 | tk | 2200 | { |
596 | tk | 2201 | ui_msg_type = msg_type; |
2202 | ui_msg_ctr = delay; |
||
2203 | strncpy((char *)ui_msg[0], line1, UI_MSG_MAX_CHAR); |
||
2204 | strncpy((char *)ui_msg[1], line2, UI_MSG_MAX_CHAR); |
||
299 | tk | 2205 | |
2206 | return 0; // no error |
||
2207 | } |
||
2208 | |||
2209 | ///////////////////////////////////////////////////////////////////////////// |
||
596 | tk | 2210 | // Stops temporary message if no SD card warning |
2211 | ///////////////////////////////////////////////////////////////////////////// |
||
2212 | s32 SEQ_UI_MsgStop(void) |
||
2213 | { |
||
2214 | if( ui_msg_type != SEQ_UI_MSG_SDCARD ) |
||
2215 | ui_msg_ctr = 0; |
||
2216 | |||
2217 | return 0; // no error |
||
2218 | } |
||
2219 | |||
2220 | ///////////////////////////////////////////////////////////////////////////// |
||
299 | tk | 2221 | // Prints a temporary error messages after file operation |
2222 | // Expects error status number (as defined in seq_file.h) |
||
2223 | ///////////////////////////////////////////////////////////////////////////// |
||
2224 | s32 SEQ_UI_SDCardErrMsg(u16 delay, s32 status) |
||
2225 | { |
||
2226 | // TODO: add more verbose error messages, they are clearly defined in seq_file.h) |
||
2227 | char str[21]; |
||
2228 | sprintf(str, "E%3d (DOSFS: D%3d)", -status, seq_file_dfs_errno < 1000 ? seq_file_dfs_errno : 999); |
||
596 | tk | 2229 | return SEQ_UI_Msg(SEQ_UI_MSG_SDCARD, delay, "!! SD Card Error !!!", str); |
299 | tk | 2230 | } |