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