Subversion Repositories svn.mios32

Rev

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