Subversion Repositories svn.mios32

Rev

Rev 325 | Rev 327 | 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 326 2009-01-28 23:44:31Z 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>
134 tk 23
#include <blm8x8.h>
190 tk 24
#include <seq_midi_out.h>
25
#include <seq_bpm.h>
134 tk 26
 
290 tk 27
#include "tasks.h"
134 tk 28
#include "seq_ui.h"
29
#include "seq_lcd.h"
30
#include "seq_led.h"
186 tk 31
#include "seq_midply.h"
134 tk 32
#include "seq_core.h"
178 tk 33
#include "seq_layer.h"
184 tk 34
#include "seq_cc.h"
299 tk 35
#include "seq_file.h"
248 tk 36
#include "seq_file_b.h"
280 tk 37
#include "seq_file_m.h"
134 tk 38
 
39
 
40
/////////////////////////////////////////////////////////////////////////////
41
// Local types
42
/////////////////////////////////////////////////////////////////////////////
43
 
44
 
45
/////////////////////////////////////////////////////////////////////////////
46
// Local prototypes
47
/////////////////////////////////////////////////////////////////////////////
48
 
49
 
50
/////////////////////////////////////////////////////////////////////////////
51
// Global variables
52
/////////////////////////////////////////////////////////////////////////////
53
 
159 tk 54
u8 seq_ui_display_update_req;
55
u8 seq_ui_display_init_req;
134 tk 56
 
167 tk 57
seq_ui_button_state_t seq_ui_button_state;
58
 
134 tk 59
u8 ui_selected_group;
60
u8 ui_selected_tracks;
61
u8 ui_selected_par_layer;
62
u8 ui_selected_trg_layer;
63
u8 ui_selected_step_view;
64
u8 ui_selected_step;
168 tk 65
u8 ui_selected_item;
134 tk 66
 
168 tk 67
u8 ui_selected_item;
134 tk 68
 
240 tk 69
u16 ui_hold_msg_ctr;
70
 
206 tk 71
seq_ui_page_t ui_page;
272 tk 72
seq_ui_page_t ui_selected_page;
303 tk 73
seq_ui_page_t ui_stepview_prev_page;
326 tk 74
seq_ui_page_t ui_trglayer_prev_page;
75
seq_ui_page_t ui_parlayer_prev_page;
206 tk 76
 
173 tk 77
volatile u8 ui_cursor_flash;
78
u16 ui_cursor_flash_ctr;
134 tk 79
 
316 tk 80
char ui_edit_name[21];
81
u8 ui_edit_name_cursor;
82
u8 ui_edit_preset_num_category;
83
u8 ui_edit_preset_num_label;
84
 
193 tk 85
u8 ui_seq_pause;
86
 
87
 
134 tk 88
/////////////////////////////////////////////////////////////////////////////
89
// Local variables
90
/////////////////////////////////////////////////////////////////////////////
91
 
168 tk 92
static s32 (*ui_button_callback)(seq_ui_button_t button, s32 depressed);
93
static s32 (*ui_encoder_callback)(seq_ui_encoder_t encoder, s32 incrementer);
173 tk 94
static s32 (*ui_led_callback)(u16 *gp_leds);
167 tk 95
static s32 (*ui_lcd_callback)(u8 high_prio);
96
 
168 tk 97
static u16 ui_gp_leds;
167 tk 98
 
168 tk 99
 
299 tk 100
#define SDCARD_MSG_MAX_CHAR 21
101
static char sdcard_msg[2][SDCARD_MSG_MAX_CHAR];
102
static u16 sdcard_msg_ctr;
103
 
104
 
105
 
134 tk 106
/////////////////////////////////////////////////////////////////////////////
107
// Initialisation
108
/////////////////////////////////////////////////////////////////////////////
109
s32 SEQ_UI_Init(u32 mode)
110
{
111
  // init selection variables
112
  ui_selected_group = 0;
113
  ui_selected_tracks = (1 << 0);
114
  ui_selected_par_layer = 0;
115
  ui_selected_trg_layer = 0;
116
  ui_selected_step_view = 0;
117
  ui_selected_step = 0;
168 tk 118
  ui_selected_item = 0;
134 tk 119
 
240 tk 120
  ui_hold_msg_ctr = 0;
299 tk 121
  sdcard_msg_ctr = 0;
240 tk 122
 
168 tk 123
  ui_cursor_flash_ctr = 0;
173 tk 124
  ui_cursor_flash = 0;
168 tk 125
 
167 tk 126
  seq_ui_button_state.ALL = 0;
127
 
193 tk 128
  ui_seq_pause = 0;
129
 
134 tk 130
  // visible GP pattern
131
  ui_gp_leds = 0x0000;
132
 
167 tk 133
  // change to edit page
134
  ui_page = SEQ_UI_PAGE_NONE;
135
  SEQ_UI_PageSet(SEQ_UI_PAGE_EDIT);
134 tk 136
 
137
  return 0; // no error
138
}
139
 
140
 
141
/////////////////////////////////////////////////////////////////////////////
178 tk 142
// Inits the speed mode of all encoders
143
// Auto mode should be used whenever:
144
//    - the edit screen is entered
145
//    - the group is changed
146
//    - a track is changed
147
//    - a layer is changed
148
/////////////////////////////////////////////////////////////////////////////
149
s32 SEQ_UI_InitEncSpeed(u32 auto_config)
150
{
151
  mios32_enc_config_t enc_config;
152
 
153
  if( auto_config ) {
154
#if DEFAULT_AUTO_FAST_BUTTON
155
    switch( SEQ_LAYER_GetVControlType(SEQ_UI_VisibleTrackGet(), ui_selected_par_layer) ) {
156
      case SEQ_LAYER_ControlType_Velocity:
323 tk 157
      case SEQ_LAYER_ControlType_Chord_Velocity:
178 tk 158
      case SEQ_LAYER_ControlType_CC:
159
    seq_ui_button_state.FAST_ENCODERS = 1;
160
    break;
161
 
162
      default:
163
    seq_ui_button_state.FAST_ENCODERS = 0;
164
    }
165
#else
166
    // auto mode not enabled - ignore auto reconfiguration request
167
    return 0;
168
#endif
169
  }
170
 
171
  // change for datawheel and GP encoders
172
  int enc;
173
  for(enc=0; enc<17; ++enc) {
174
    enc_config = MIOS32_ENC_ConfigGet(enc);
175
    enc_config.cfg.speed = seq_ui_button_state.FAST_ENCODERS ? FAST : NORMAL;
176
    enc_config.cfg.speed_par = (enc == 0) ? DEFAULT_DATAWHEEL_SPEED_VALUE : DEFAULT_ENC_SPEED_VALUE;
177
    MIOS32_ENC_ConfigSet(enc, enc_config);
178
  }
179
 
180
  return 0; // no error
181
}
182
 
183
 
184
/////////////////////////////////////////////////////////////////////////////
167 tk 185
// Various installation routines for menu page LCD handlers
186
/////////////////////////////////////////////////////////////////////////////
168 tk 187
s32 SEQ_UI_InstallButtonCallback(void *callback)
167 tk 188
{
168 tk 189
  ui_button_callback = callback;
167 tk 190
  return 0; // no error
191
}
192
 
168 tk 193
s32 SEQ_UI_InstallEncoderCallback(void *callback)
167 tk 194
{
168 tk 195
  ui_encoder_callback = callback;
167 tk 196
  return 0; // no error
197
}
198
 
168 tk 199
s32 SEQ_UI_InstallLEDCallback(void *callback)
167 tk 200
{
168 tk 201
  ui_led_callback = callback;
167 tk 202
  return 0; // no error
203
}
204
 
168 tk 205
s32 SEQ_UI_InstallLCDCallback(void *callback)
167 tk 206
{
207
  ui_lcd_callback = callback;
208
  return 0; // no error
209
}
210
 
211
 
212
/////////////////////////////////////////////////////////////////////////////
213
// Change the menu page
214
/////////////////////////////////////////////////////////////////////////////
215
s32 SEQ_UI_PageSet(seq_ui_page_t page)
216
{
217
  if( page != ui_page ) {
218
    // disable hooks of previous page and request re-initialisation
318 tk 219
    portENTER_CRITICAL();
167 tk 220
    ui_page = page;
168 tk 221
    ui_button_callback = NULL;
222
    ui_encoder_callback = NULL;
223
    ui_led_callback = NULL;
167 tk 224
    ui_lcd_callback = NULL;
318 tk 225
    portEXIT_CRITICAL();
167 tk 226
 
178 tk 227
#if DEFAULT_BEHAVIOUR_BUTTON_MENU
168 tk 228
    seq_ui_button_state.MENU_PRESSED = 0; // MENU page selection finished
167 tk 229
#endif
230
 
231
    // request display initialisation
232
    seq_ui_display_init_req = 1;
233
  }
173 tk 234
 
306 tk 235
  // for MENU button:
236
  // first page has been selected - display new screen
237
  seq_ui_button_state.MENU_FIRST_PAGE_SELECTED = 1;
238
 
272 tk 239
  // for SEQ_UI_MENU which is accessible with EXIT button
240
  // remember the current selectable page
241
  if( ui_page >= SEQ_UI_FIRST_MENU_SELECTION_PAGE )
242
    ui_selected_page = ui_page;
243
 
184 tk 244
  return 0; // no error
167 tk 245
}
246
 
247
 
248
/////////////////////////////////////////////////////////////////////////////
272 tk 249
// Returns name of menu page (18 characters)
250
/////////////////////////////////////////////////////////////////////////////
251
char *SEQ_UI_PageNameGet(seq_ui_page_t page)
252
{
253
  return ui_menu_pages[page].name;
254
}
255
 
256
 
257
/////////////////////////////////////////////////////////////////////////////
134 tk 258
// Dedicated button functions
259
// Mapped to physical buttons in SEQ_UI_Button_Handler()
260
// Will also be mapped to MIDI keys later (for MIDI remote function)
261
/////////////////////////////////////////////////////////////////////////////
262
static s32 SEQ_UI_Button_GP(s32 depressed, u32 gp)
263
{
306 tk 264
  // in MENU page: overrule GP buttons so long MENU button is pressed/active
265
  if( seq_ui_button_state.MENU_PRESSED ) {
266
    if( depressed ) return -1;
267
    SEQ_UI_PageSet(ui_shortcut_menu_pages[gp]);
268
  } else {
269
    // forward to menu page
270
    if( ui_button_callback != NULL )
271
      ui_button_callback(gp, depressed);
272
    ui_cursor_flash_ctr = 0;
273
  }
134 tk 274
 
275
  return 0; // no error
276
}
277
 
278
static s32 SEQ_UI_Button_Left(s32 depressed)
279
{
168 tk 280
  // forward to menu page
306 tk 281
  if( !seq_ui_button_state.MENU_PRESSED && ui_button_callback != NULL )
168 tk 282
    ui_button_callback(SEQ_UI_BUTTON_Left, depressed);
173 tk 283
  ui_cursor_flash_ctr = 0;
134 tk 284
 
285
  return 0; // no error
286
}
287
 
288
static s32 SEQ_UI_Button_Right(s32 depressed)
289
{
168 tk 290
  // forward to menu page
306 tk 291
  if( !seq_ui_button_state.MENU_PRESSED && ui_button_callback != NULL )
168 tk 292
    ui_button_callback(SEQ_UI_BUTTON_Right, depressed);
173 tk 293
  ui_cursor_flash_ctr = 0;
134 tk 294
 
295
  return 0; // no error
296
}
297
 
168 tk 298
static s32 SEQ_UI_Button_Down(s32 depressed)
299
{
240 tk 300
  seq_ui_button_state.DOWN = depressed ? 0 : 1;
301
 
168 tk 302
  // forward to menu page
306 tk 303
  if( !seq_ui_button_state.MENU_PRESSED && ui_button_callback != NULL )
168 tk 304
    ui_button_callback(SEQ_UI_BUTTON_Down, depressed);
173 tk 305
  ui_cursor_flash_ctr = 0;
168 tk 306
 
307
  return 0; // no error
308
}
309
 
310
static s32 SEQ_UI_Button_Up(s32 depressed)
311
{
240 tk 312
  seq_ui_button_state.UP = depressed ? 0 : 1;
313
 
168 tk 314
  // forward to menu page
306 tk 315
  if( !seq_ui_button_state.MENU_PRESSED && ui_button_callback != NULL )
168 tk 316
    ui_button_callback(SEQ_UI_BUTTON_Up, depressed);
173 tk 317
  ui_cursor_flash_ctr = 0;
168 tk 318
 
319
  return 0; // no error
320
}
321
 
134 tk 322
static s32 SEQ_UI_Button_Scrub(s32 depressed)
323
{
178 tk 324
#if DEFAULT_BEHAVIOUR_BUTTON_SCRUB
325
  // toggle mode
134 tk 326
  if( depressed ) return -1; // ignore when button depressed
178 tk 327
  seq_ui_button_state.SCRUB ^= 1;
137 tk 328
#else
178 tk 329
  // set mode
330
  seq_ui_button_state.SCRUB = depressed ? 0 : 1;
137 tk 331
#endif
332
 
134 tk 333
  return 0; // no error
334
}
335
 
336
static s32 SEQ_UI_Button_Metronome(s32 depressed)
337
{
178 tk 338
#if DEFAULT_BEHAVIOUR_BUTTON_METRON
339
  // toggle mode
134 tk 340
  if( depressed ) return -1; // ignore when button depressed
178 tk 341
  seq_ui_button_state.METRONOME ^= 1;
290 tk 342
 
248 tk 343
#if 1
290 tk 344
  MUTEX_SDCARD_TAKE;
280 tk 345
 
319 tk 346
#if 0
249 tk 347
  u8 bank;
348
  for(bank=0; bank<SEQ_FILE_B_NUM_BANKS; ++bank) {
349
    SEQ_FILE_B_Create(bank);
350
    SEQ_FILE_B_Open(bank);
351
  }
280 tk 352
#else
353
    SEQ_FILE_M_Create();
354
    SEQ_FILE_M_Open();
355
#endif
356
 
290 tk 357
  MUTEX_SDCARD_GIVE;
248 tk 358
#endif
359
 
137 tk 360
#else
178 tk 361
  // set mode
362
  seq_ui_button_state.METRONOME = depressed ? 0 : 1;
137 tk 363
#endif
134 tk 364
 
365
  return 0; // no error
366
}
367
 
368
static s32 SEQ_UI_Button_Stop(s32 depressed)
369
{
370
  if( depressed ) return -1; // ignore when button depressed
371
 
159 tk 372
  // if sequencer running: stop it
373
  // if sequencer already stopped: reset song position
186 tk 374
#if MID_PLAYER_TEST
193 tk 375
  if( SEQ_BPM_IsRunning() )
376
    SEQ_BPM_Stop();
186 tk 377
  else
378
    SEQ_MIDPLY_Reset();
379
#else
193 tk 380
  if( SEQ_BPM_IsRunning() )
381
    SEQ_BPM_Stop();
159 tk 382
  else
383
    SEQ_CORE_Reset();
186 tk 384
#endif
159 tk 385
 
134 tk 386
  return 0; // no error
387
}
388
 
389
static s32 SEQ_UI_Button_Pause(s32 depressed)
390
{
391
  if( depressed ) return -1; // ignore when button depressed
392
 
193 tk 393
  // if in auto mode and BPM generator is clocked in slave mode:
394
  // change to master mode
395
  SEQ_BPM_CheckAutoMaster();
159 tk 396
 
193 tk 397
  // toggle pause mode
398
  ui_seq_pause ^= 1;
399
 
400
  // execute stop/continue depending on new mode
401
  if( ui_seq_pause )
402
    SEQ_BPM_Stop();
403
  else
404
    SEQ_BPM_Cont();
405
 
134 tk 406
  return 0; // no error
407
}
408
 
409
static s32 SEQ_UI_Button_Play(s32 depressed)
410
{
411
  if( depressed ) return -1; // ignore when button depressed
412
 
186 tk 413
  // if in auto mode and BPM generator is clocked in slave mode:
414
  // change to master mode
415
  SEQ_BPM_CheckAutoMaster();
416
 
193 tk 417
#if 0
418
  // if sequencer running: restart it
419
  // if sequencer stopped: continue at last song position
420
  if( SEQ_BPM_IsRunning() )
421
    SEQ_BPM_Start();
422
  else
423
    SEQ_BPM_Cont();
186 tk 424
#else
193 tk 425
  // always restart sequencer
426
  SEQ_BPM_Start();
186 tk 427
#endif
159 tk 428
 
134 tk 429
  return 0; // no error
430
}
431
 
432
static s32 SEQ_UI_Button_Rew(s32 depressed)
433
{
240 tk 434
  seq_ui_button_state.REW = depressed ? 0 : 1;
435
 
134 tk 436
  if( depressed ) return -1; // ignore when button depressed
437
 
438
  return 0; // no error
439
}
440
 
441
static s32 SEQ_UI_Button_Fwd(s32 depressed)
442
{
240 tk 443
  seq_ui_button_state.FWD = depressed ? 0 : 1;
444
 
134 tk 445
  if( depressed ) return -1; // ignore when button depressed
446
 
447
  return 0; // no error
448
}
449
 
450
static s32 SEQ_UI_Button_F1(s32 depressed)
451
{
240 tk 452
  seq_ui_button_state.F1 = depressed ? 0 : 1;
453
 
134 tk 454
  if( depressed ) return -1; // ignore when button depressed
455
 
240 tk 456
  // change to utility page
457
  SEQ_UI_PageSet(SEQ_UI_PAGE_UTIL);
458
 
134 tk 459
  return 0; // no error
460
}
461
 
462
static s32 SEQ_UI_Button_F2(s32 depressed)
463
{
240 tk 464
  seq_ui_button_state.F2 = depressed ? 0 : 1;
465
 
134 tk 466
  if( depressed ) return -1; // ignore when button depressed
467
 
468
  return 0; // no error
469
}
470
 
471
static s32 SEQ_UI_Button_F3(s32 depressed)
472
{
240 tk 473
  seq_ui_button_state.F3 = depressed ? 0 : 1;
474
 
134 tk 475
  if( depressed ) return -1; // ignore when button depressed
476
 
477
  return 0; // no error
478
}
479
 
480
static s32 SEQ_UI_Button_F4(s32 depressed)
481
{
240 tk 482
  seq_ui_button_state.F4 = depressed ? 0 : 1;
483
 
134 tk 484
  if( depressed ) return -1; // ignore when button depressed
485
 
486
  return 0; // no error
487
}
488
 
489
static s32 SEQ_UI_Button_Utility(s32 depressed)
490
{
491
  if( depressed ) return -1; // ignore when button depressed
492
 
240 tk 493
  // change to utility page
494
  SEQ_UI_PageSet(SEQ_UI_PAGE_UTIL);
495
 
134 tk 496
  return 0; // no error
497
}
498
 
499
static s32 SEQ_UI_Button_Copy(s32 depressed)
500
{
240 tk 501
  static seq_ui_page_t prev_page = SEQ_UI_PAGE_NONE;
134 tk 502
 
240 tk 503
  seq_ui_button_state.COPY = depressed ? 0 : 1;
504
 
280 tk 505
  if( ui_page == SEQ_UI_PAGE_MIXER ) {
506
    if( depressed ) return -1;
507
    SEQ_UI_MIXER_Copy();
508
    return 1;
509
  } else {
510
    if( !depressed ) {
511
      prev_page = ui_page;
512
      SEQ_UI_PageSet(SEQ_UI_PAGE_UTIL);
513
    }
240 tk 514
 
280 tk 515
    s32 status = SEQ_UI_UTIL_CopyButton(depressed);
240 tk 516
 
280 tk 517
    if( depressed )
518
      SEQ_UI_PageSet(prev_page);
240 tk 519
 
280 tk 520
    return status;
521
  }
134 tk 522
}
523
 
524
static s32 SEQ_UI_Button_Paste(s32 depressed)
525
{
240 tk 526
  static seq_ui_page_t prev_page = SEQ_UI_PAGE_NONE;
134 tk 527
 
240 tk 528
  seq_ui_button_state.PASTE = depressed ? 0 : 1;
529
 
280 tk 530
  if( ui_page == SEQ_UI_PAGE_MIXER ) {
531
    if( depressed ) return -1;
532
    SEQ_UI_MIXER_Paste();
533
    return 1;
534
  } else {
535
    if( !depressed ) {
536
      prev_page = ui_page;
537
      SEQ_UI_PageSet(SEQ_UI_PAGE_UTIL);
538
    }
240 tk 539
 
280 tk 540
    s32 status = SEQ_UI_UTIL_PasteButton(depressed);
240 tk 541
 
280 tk 542
    if( depressed )
543
      SEQ_UI_PageSet(prev_page);
240 tk 544
 
280 tk 545
    return status;
546
  }
134 tk 547
}
548
 
549
static s32 SEQ_UI_Button_Clear(s32 depressed)
550
{
240 tk 551
  seq_ui_button_state.CLEAR = depressed ? 0 : 1;
280 tk 552
 
553
  if( ui_page == SEQ_UI_PAGE_MIXER ) {
554
    if( depressed ) return -1;
555
    SEQ_UI_MIXER_Clear();
556
    return 1;
557
  } else {
558
    return SEQ_UI_UTIL_ClearButton(depressed);
559
  }
134 tk 560
}
561
 
562
static s32 SEQ_UI_Button_Menu(s32 depressed)
563
{
167 tk 564
  // TODO: define generic #define for this button behaviour
178 tk 565
#if DEFAULT_BEHAVIOUR_BUTTON_MENU
566
  // toggle mode
134 tk 567
  if( depressed ) return -1; // ignore when button depressed
306 tk 568
  seq_ui_button_state.MENU_FIRST_PAGE_SELECTED = 0;
167 tk 569
  seq_ui_button_state.MENU_PRESSED ^= 1; // toggle MENU pressed (will also be released once GP button has been pressed)
570
#else
178 tk 571
  // set mode
306 tk 572
  seq_ui_button_state.MENU_FIRST_PAGE_SELECTED = 0;
167 tk 573
  seq_ui_button_state.MENU_PRESSED = depressed ? 0 : 1;
574
#endif
134 tk 575
 
576
  return 0; // no error
577
}
578
 
579
static s32 SEQ_UI_Button_Select(s32 depressed)
580
{
168 tk 581
  // forward to menu page
306 tk 582
  if( !seq_ui_button_state.MENU_PRESSED && ui_button_callback != NULL )
168 tk 583
    ui_button_callback(SEQ_UI_BUTTON_Select, depressed);
173 tk 584
  ui_cursor_flash_ctr = 0;
134 tk 585
 
586
  return 0; // no error
587
}
588
 
589
static s32 SEQ_UI_Button_Exit(s32 depressed)
590
{
272 tk 591
  if( depressed ) return -1; // ignore when button depressed
592
 
593
  u8 prev_ui_page = ui_page;
594
 
168 tk 595
  // forward to menu page
306 tk 596
  if( !seq_ui_button_state.MENU_PRESSED && ui_button_callback != NULL )
168 tk 597
    ui_button_callback(SEQ_UI_BUTTON_Exit, depressed);
173 tk 598
  ui_cursor_flash_ctr = 0;
134 tk 599
 
167 tk 600
  // release all button states
601
  seq_ui_button_state.ALL = 0;
602
 
272 tk 603
  // enter menu page if we were not there before
604
  if( prev_ui_page != SEQ_UI_PAGE_MENU )
605
    SEQ_UI_PageSet(SEQ_UI_PAGE_MENU);
606
 
134 tk 607
  return 0; // no error
608
}
609
 
610
static s32 SEQ_UI_Button_Edit(s32 depressed)
611
{
612
  if( depressed ) return -1; // ignore when button depressed
613
 
167 tk 614
  // change to edit page
615
  SEQ_UI_PageSet(SEQ_UI_PAGE_EDIT);
616
 
178 tk 617
  // set/clear encoder fast function if required
618
  SEQ_UI_InitEncSpeed(1); // auto config
619
 
134 tk 620
  return 0; // no error
621
}
622
 
623
static s32 SEQ_UI_Button_Mute(s32 depressed)
624
{
625
  if( depressed ) return -1; // ignore when button depressed
626
 
184 tk 627
  SEQ_UI_PageSet(SEQ_UI_PAGE_MUTE);
628
 
134 tk 629
  return 0; // no error
630
}
631
 
632
static s32 SEQ_UI_Button_Pattern(s32 depressed)
633
{
634
  if( depressed ) return -1; // ignore when button depressed
635
 
184 tk 636
  SEQ_UI_PageSet(SEQ_UI_PAGE_PATTERN);
637
 
134 tk 638
  return 0; // no error
639
}
640
 
641
static s32 SEQ_UI_Button_Song(s32 depressed)
642
{
643
  if( depressed ) return -1; // ignore when button depressed
644
 
645
  return 0; // no error
646
}
647
 
648
static s32 SEQ_UI_Button_Solo(s32 depressed)
649
{
178 tk 650
#if DEFAULT_BEHAVIOUR_BUTTON_ALL
651
  // toggle mode
134 tk 652
  if( depressed ) return -1; // ignore when button depressed
178 tk 653
  seq_ui_button_state.SOLO ^= 1;
654
#else
655
  // set mode
656
  seq_ui_button_state.SOLO = depressed ? 0 : 1;
657
#endif
134 tk 658
 
659
  return 0; // no error
660
}
661
 
662
static s32 SEQ_UI_Button_Fast(s32 depressed)
663
{
178 tk 664
#if DEFAULT_BEHAVIOUR_BUTTON_FAST
665
  // toggle mode
134 tk 666
  if( depressed ) return -1; // ignore when button depressed
178 tk 667
  seq_ui_button_state.FAST_ENCODERS ^= 1;
668
#else
669
  // set mode
670
  seq_ui_button_state.FAST_ENCODERS = depressed ? 0 : 1;
671
#endif
134 tk 672
 
178 tk 673
  SEQ_UI_InitEncSpeed(0); // no auto config
674
 
134 tk 675
  return 0; // no error
676
}
677
 
678
static s32 SEQ_UI_Button_All(s32 depressed)
679
{
178 tk 680
  seq_ui_button_state.CHANGE_ALL_STEPS_SAME_VALUE = depressed ? 0 : 1;
134 tk 681
 
178 tk 682
#if DEFAULT_BEHAVIOUR_BUTTON_ALL
683
  // toggle mode
684
  if( depressed ) return -1;
685
  seq_ui_button_state.CHANGE_ALL_STEPS ^= 1;
686
#else
687
  // set mode
688
  seq_ui_button_state.CHANGE_ALL_STEPS = depressed ? 0 : 1;
689
#endif
690
 
134 tk 691
  return 0; // no error
692
}
693
 
694
static s32 SEQ_UI_Button_StepView(s32 depressed)
695
{
326 tk 696
 
303 tk 697
#if DEFAULT_BEHAVIOUR_BUTTON_STEPVIEW
134 tk 698
  if( depressed ) return -1; // ignore when button depressed
303 tk 699
  seq_ui_button_state.STEPVIEW ^= 1; // toggle STEPVIEW pressed (will also be released once GP button has been pressed)
700
#else
701
  // set mode
702
  seq_ui_button_state.STEPVIEW = depressed ? 0 : 1;
703
#endif
134 tk 704
 
303 tk 705
  if( seq_ui_button_state.STEPVIEW ) {
706
    ui_stepview_prev_page = ui_page;
707
    SEQ_UI_PageSet(SEQ_UI_PAGE_STEPSEL);
708
  } else {
709
    SEQ_UI_PageSet(ui_stepview_prev_page);
710
  }
134 tk 711
 
712
  return 0; // no error
713
}
714
 
715
static s32 SEQ_UI_Button_TapTempo(s32 depressed)
716
{
717
  if( depressed ) return -1; // ignore when button depressed
718
 
719
  return 0; // no error
720
}
721
 
722
static s32 SEQ_UI_Button_Track(s32 depressed, u32 track)
723
{
724
  if( depressed ) return -1; // ignore when button depressed
725
 
726
  if( track >= 4 ) return -2; // max. 4 track buttons
727
 
728
  ui_selected_tracks = (1 << track); // TODO: multi-selections!
729
 
178 tk 730
  // set/clear encoder fast function if required
731
  SEQ_UI_InitEncSpeed(1); // auto config
732
 
134 tk 733
  return 0; // no error
734
}
735
 
736
static s32 SEQ_UI_Button_Group(s32 depressed, u32 group)
737
{
738
  if( depressed ) return -1; // ignore when button depressed
739
 
740
  if( group >= 4 ) return -2; // max. 4 group buttons
741
 
742
  ui_selected_group = group;
743
 
178 tk 744
  // set/clear encoder fast function if required
745
  SEQ_UI_InitEncSpeed(1); // auto config
746
 
134 tk 747
  return 0; // no error
748
}
749
 
750
static s32 SEQ_UI_Button_ParLayer(s32 depressed, u32 par_layer)
751
{
752
  if( depressed ) return -1; // ignore when button depressed
753
 
754
  if( par_layer >= 3 ) return -2; // max. 3 parlayer buttons
755
 
756
  ui_selected_par_layer = par_layer;
757
 
178 tk 758
  // set/clear encoder fast function if required
759
  SEQ_UI_InitEncSpeed(1); // auto config
760
 
134 tk 761
  return 0; // no error
762
}
763
 
764
static s32 SEQ_UI_Button_TrgLayer(s32 depressed, u32 trg_layer)
765
{
766
  if( trg_layer >= 3 ) return -2; // max. 3 trglayer buttons
767
 
326 tk 768
  u8 visible_track = SEQ_UI_VisibleTrackGet();
769
  u8 event_mode = SEQ_CC_Get(visible_track, SEQ_CC_MIDI_EVENT_MODE);
770
  u8 num_t_layers = SEQ_TRG_NumLayersGet(visible_track);
134 tk 771
 
326 tk 772
  if( num_t_layers <= 3 ) {
773
    // 3 layers: direct selection with LayerA/B/C button
774
    if( depressed ) return -1; // ignore when button depressed
775
    seq_ui_button_state.TRG_LAYER_SEL = 0;
776
    ui_selected_trg_layer = trg_layer;
777
  } else if( num_t_layers <= 4 ) {
778
    // 4 layers: LayerC Button toggles between C and D
779
    if( depressed ) return -1; // ignore when button depressed
780
    seq_ui_button_state.TRG_LAYER_SEL = 0;
781
    if( trg_layer == 3 )
782
      ui_selected_trg_layer = (ui_selected_trg_layer == 3) ? 4 : 3;
783
    else
784
      ui_selected_trg_layer = trg_layer;
785
  } else {
786
    // >4 layers: LayerA/B button selects directly, Layer C button enters trigger assignment screen
787
    // also used for drum tracks
788
    if( trg_layer <= 1 ) {
789
      if( depressed ) return -1; // ignore when button depressed
790
      if( event_mode == SEQ_EVENT_MODE_Drum ) {
791
    u8 accent_available = SEQ_TRG_AssignmentGet(visible_track, 1);
792
    if( accent_available )
793
      num_t_layers /= 2;
794
 
795
    ui_selected_trg_layer %= num_t_layers;
796
    if( trg_layer == 1 && accent_available )
797
      ui_selected_trg_layer += num_t_layers;
798
      } else {
799
    seq_ui_button_state.TRG_LAYER_SEL = 0;
800
    ui_selected_trg_layer = trg_layer;
801
      }
802
    } else {
803
#if DEFAULT_BEHAVIOUR_BUTTON_TRG_LAYER
804
      if( depressed ) return -1; // ignore when button depressed
805
      seq_ui_button_state.TRG_LAYER_SEL ^= 1; // toggle TRGSEL status (will also be released once GP button has been pressed)
806
#else
807
      // set mode
808
      seq_ui_button_state.TRG_LAYER_SEL = depressed ? 0 : 1;
809
#endif
810
 
811
      if( seq_ui_button_state.TRG_LAYER_SEL ) {
812
    ui_trglayer_prev_page = ui_page;
813
    SEQ_UI_PageSet(SEQ_UI_PAGE_TRGSEL);
814
      } else {
815
    SEQ_UI_PageSet(ui_trglayer_prev_page);
816
      }
817
    }
818
  }
819
 
134 tk 820
  return 0; // no error
821
}
822
 
823
 
824
 
825
/////////////////////////////////////////////////////////////////////////////
826
// Button handler
827
/////////////////////////////////////////////////////////////////////////////
828
s32 SEQ_UI_Button_Handler(u32 pin, u32 pin_value)
829
{
830
  switch( pin ) {
168 tk 831
#if BUTTON_GP1 != BUTTON_DISABLED
134 tk 832
    case BUTTON_GP1:   SEQ_UI_Button_GP(pin_value, 0); break;
833
#endif
168 tk 834
#if BUTTON_GP2 != BUTTON_DISABLED
134 tk 835
    case BUTTON_GP2:   SEQ_UI_Button_GP(pin_value, 1); break;
836
#endif
168 tk 837
#if BUTTON_GP3 != BUTTON_DISABLED
134 tk 838
    case BUTTON_GP3:   SEQ_UI_Button_GP(pin_value, 2); break;
839
#endif
168 tk 840
#if BUTTON_GP4 != BUTTON_DISABLED
134 tk 841
    case BUTTON_GP4:   SEQ_UI_Button_GP(pin_value, 3); break;
842
#endif
168 tk 843
#if BUTTON_GP5 != BUTTON_DISABLED
134 tk 844
    case BUTTON_GP5:   SEQ_UI_Button_GP(pin_value, 4); break;
845
#endif
168 tk 846
#if BUTTON_GP6 != BUTTON_DISABLED
134 tk 847
    case BUTTON_GP6:   SEQ_UI_Button_GP(pin_value, 5); break;
848
#endif
168 tk 849
#if BUTTON_GP7 != BUTTON_DISABLED
134 tk 850
    case BUTTON_GP7:   SEQ_UI_Button_GP(pin_value, 6); break;
851
#endif
168 tk 852
#if BUTTON_GP8 != BUTTON_DISABLED
134 tk 853
    case BUTTON_GP8:   SEQ_UI_Button_GP(pin_value, 7); break;
854
#endif
168 tk 855
#if BUTTON_GP9 != BUTTON_DISABLED
134 tk 856
    case BUTTON_GP9:   SEQ_UI_Button_GP(pin_value, 8); break;
857
#endif
168 tk 858
#if BUTTON_GP10 != BUTTON_DISABLED
134 tk 859
    case BUTTON_GP10:  SEQ_UI_Button_GP(pin_value, 9); break;
860
#endif
168 tk 861
#if BUTTON_GP11 != BUTTON_DISABLED
134 tk 862
    case BUTTON_GP11:  SEQ_UI_Button_GP(pin_value, 10); break;
863
#endif
168 tk 864
#if BUTTON_GP12 != BUTTON_DISABLED
134 tk 865
    case BUTTON_GP12:  SEQ_UI_Button_GP(pin_value, 11); break;
866
#endif
168 tk 867
#if BUTTON_GP13 != BUTTON_DISABLED
134 tk 868
    case BUTTON_GP13:  SEQ_UI_Button_GP(pin_value, 12); break;
869
#endif
168 tk 870
#if BUTTON_GP14 != BUTTON_DISABLED
134 tk 871
    case BUTTON_GP14:  SEQ_UI_Button_GP(pin_value, 13); break;
872
#endif
168 tk 873
#if BUTTON_GP15 != BUTTON_DISABLED
134 tk 874
    case BUTTON_GP15:  SEQ_UI_Button_GP(pin_value, 14); break;
875
#endif
168 tk 876
#if BUTTON_GP16 != BUTTON_DISABLED
134 tk 877
    case BUTTON_GP16:  SEQ_UI_Button_GP(pin_value, 15); break;
878
#endif
879
 
168 tk 880
#if BUTTON_LEFT != BUTTON_DISABLED
134 tk 881
    case BUTTON_LEFT:  SEQ_UI_Button_Left(pin_value); break;
882
#endif
168 tk 883
#if BUTTON_RIGHT != BUTTON_DISABLED
134 tk 884
    case BUTTON_RIGHT: SEQ_UI_Button_Right(pin_value); break;
885
#endif
886
 
168 tk 887
#if BUTTON_DOWN != BUTTON_DISABLED
888
    case BUTTON_DOWN:  SEQ_UI_Button_Down(pin_value); break;
889
#endif
890
#if BUTTON_UP != BUTTON_DISABLED
891
    case BUTTON_UP:    SEQ_UI_Button_Up(pin_value); break;
892
#endif
893
 
894
#if BUTTON_SCRUB != BUTTON_DISABLED
134 tk 895
    case BUTTON_SCRUB: SEQ_UI_Button_Scrub(pin_value); break;
896
#endif
168 tk 897
#if BUTTON_METRONOME != BUTTON_DISABLED
134 tk 898
    case BUTTON_METRONOME: SEQ_UI_Button_Metronome(pin_value); break;
899
#endif
900
 
168 tk 901
#if BUTTON_STOP != BUTTON_DISABLED
134 tk 902
    case BUTTON_STOP:  SEQ_UI_Button_Stop(pin_value); break;
903
#endif
168 tk 904
#if BUTTON_PAUSE != BUTTON_DISABLED
134 tk 905
    case BUTTON_PAUSE: SEQ_UI_Button_Pause(pin_value); break;
906
#endif
168 tk 907
#if BUTTON_PLAY != BUTTON_DISABLED
134 tk 908
    case BUTTON_PLAY:  SEQ_UI_Button_Play(pin_value); break;
909
#endif
168 tk 910
#if BUTTON_REW != BUTTON_DISABLED
134 tk 911
    case BUTTON_REW:   SEQ_UI_Button_Rew(pin_value); break;
912
#endif
168 tk 913
#if BUTTON_FWD != BUTTON_DISABLED
134 tk 914
    case BUTTON_FWD:   SEQ_UI_Button_Fwd(pin_value); break;
915
#endif
916
 
168 tk 917
#if BUTTON_F1 != BUTTON_DISABLED
134 tk 918
    case BUTTON_F1:    SEQ_UI_Button_F1(pin_value); break;
919
#endif
168 tk 920
#if BUTTON_F2 != BUTTON_DISABLED
134 tk 921
    case BUTTON_F2:    SEQ_UI_Button_F2(pin_value); break;
922
#endif
168 tk 923
#if BUTTON_F3 != BUTTON_DISABLED
134 tk 924
    case BUTTON_F3:    SEQ_UI_Button_F3(pin_value); break;
925
#endif
168 tk 926
#if BUTTON_F4 != BUTTON_DISABLED
134 tk 927
    case BUTTON_F4:    SEQ_UI_Button_F4(pin_value); break;
928
#endif
929
 
168 tk 930
#if BUTTON_UTILITY != BUTTON_DISABLED
134 tk 931
    case BUTTON_UTILITY: SEQ_UI_Button_Utility(pin_value); break;
932
#endif
168 tk 933
#if BUTTON_COPY != BUTTON_DISABLED
134 tk 934
    case BUTTON_COPY:  SEQ_UI_Button_Copy(pin_value); break;
935
#endif
168 tk 936
#if BUTTON_PASTE != BUTTON_DISABLED
134 tk 937
    case BUTTON_PASTE: SEQ_UI_Button_Paste(pin_value); break;
938
#endif
168 tk 939
#if BUTTON_CLEAR != BUTTON_DISABLED
134 tk 940
    case BUTTON_CLEAR: SEQ_UI_Button_Clear(pin_value); break;
941
#endif
942
 
168 tk 943
#if BUTTON_MENU != BUTTON_DISABLED
134 tk 944
    case BUTTON_MENU:  SEQ_UI_Button_Menu(pin_value); break;
945
#endif
168 tk 946
#if BUTTON_SELECT != BUTTON_DISABLED
134 tk 947
    case BUTTON_SELECT:SEQ_UI_Button_Select(pin_value); break;
948
#endif
168 tk 949
#if BUTTON_EXIT != BUTTON_DISABLED
134 tk 950
    case BUTTON_EXIT:  SEQ_UI_Button_Exit(pin_value); break;
951
#endif
952
 
168 tk 953
#if BUTTON_TRACK1 != BUTTON_DISABLED
134 tk 954
    case BUTTON_TRACK1: SEQ_UI_Button_Track(pin_value, 0); break;
955
#endif
168 tk 956
#if BUTTON_TRACK2 != BUTTON_DISABLED
134 tk 957
    case BUTTON_TRACK2: SEQ_UI_Button_Track(pin_value, 1); break;
958
#endif
168 tk 959
#if BUTTON_TRACK3 != BUTTON_DISABLED
134 tk 960
    case BUTTON_TRACK3: SEQ_UI_Button_Track(pin_value, 2); break;
961
#endif
168 tk 962
#if BUTTON_TRACK4 != BUTTON_DISABLED
134 tk 963
    case BUTTON_TRACK4: SEQ_UI_Button_Track(pin_value, 3); break;
964
#endif
965
 
168 tk 966
#if BUTTON_PAR_LAYER_A != BUTTON_DISABLED
134 tk 967
    case BUTTON_PAR_LAYER_A: SEQ_UI_Button_ParLayer(pin_value, 0); break;
968
#endif
168 tk 969
#if BUTTON_PAR_LAYER_B != BUTTON_DISABLED
134 tk 970
    case BUTTON_PAR_LAYER_B: SEQ_UI_Button_ParLayer(pin_value, 1); break;
971
#endif
168 tk 972
#if BUTTON_PAR_LAYER_C != BUTTON_DISABLED
134 tk 973
    case BUTTON_PAR_LAYER_C: SEQ_UI_Button_ParLayer(pin_value, 2); break;
974
#endif
975
 
168 tk 976
#if BUTTON_EDIT != BUTTON_DISABLED
134 tk 977
    case BUTTON_EDIT:   SEQ_UI_Button_Edit(pin_value); break;
978
#endif
168 tk 979
#if BUTTON_MUTE != BUTTON_DISABLED
134 tk 980
    case BUTTON_MUTE:   SEQ_UI_Button_Mute(pin_value); break;
981
#endif
168 tk 982
#if BUTTON_PATTERN != BUTTON_DISABLED
134 tk 983
    case BUTTON_PATTERN:SEQ_UI_Button_Pattern(pin_value); break;
984
#endif
168 tk 985
#if BUTTON_SONG != BUTTON_DISABLED
134 tk 986
    case BUTTON_SONG:   SEQ_UI_Button_Song(pin_value); break;
987
#endif
988
 
168 tk 989
#if BUTTON_SOLO != BUTTON_DISABLED
134 tk 990
    case BUTTON_SOLO:   SEQ_UI_Button_Solo(pin_value); break;
991
#endif
168 tk 992
#if BUTTON_FAST != BUTTON_DISABLED
134 tk 993
    case BUTTON_FAST:   SEQ_UI_Button_Fast(pin_value); break;
994
#endif
168 tk 995
#if BUTTON_ALL != BUTTON_DISABLED
134 tk 996
    case BUTTON_ALL:    SEQ_UI_Button_All(pin_value); break;
997
#endif
998
 
168 tk 999
#if BUTTON_GROUP1 != BUTTON_DISABLED
134 tk 1000
    case BUTTON_GROUP1: SEQ_UI_Button_Group(pin_value, 0); break;
1001
#endif
168 tk 1002
#if BUTTON_GROUP2 != BUTTON_DISABLED
134 tk 1003
    case BUTTON_GROUP2: SEQ_UI_Button_Group(pin_value, 1); break;
1004
#endif
168 tk 1005
#if BUTTON_GROUP3 != BUTTON_DISABLED
134 tk 1006
    case BUTTON_GROUP3: SEQ_UI_Button_Group(pin_value, 2); break;
1007
#endif
168 tk 1008
#if BUTTON_GROUP4 != BUTTON_DISABLED
134 tk 1009
    case BUTTON_GROUP4: SEQ_UI_Button_Group(pin_value, 3); break;
1010
#endif
1011
 
168 tk 1012
#if BUTTON_TRG_LAYER_A != BUTTON_DISABLED
134 tk 1013
    case BUTTON_TRG_LAYER_A: SEQ_UI_Button_TrgLayer(pin_value, 0); break;
1014
#endif
168 tk 1015
#if BUTTON_TRG_LAYER_B != BUTTON_DISABLED
134 tk 1016
    case BUTTON_TRG_LAYER_B: SEQ_UI_Button_TrgLayer(pin_value, 1); break;
1017
#endif
168 tk 1018
#if BUTTON_TRG_LAYER_C != BUTTON_DISABLED
134 tk 1019
    case BUTTON_TRG_LAYER_C: SEQ_UI_Button_TrgLayer(pin_value, 2); break;
1020
#endif
1021
 
168 tk 1022
#if BUTTON_STEP_VIEW != BUTTON_DISABLED
134 tk 1023
    case BUTTON_STEP_VIEW: SEQ_UI_Button_StepView(pin_value); break;
1024
#endif
1025
 
168 tk 1026
#if BUTTON_TAP_TEMPO != BUTTON_DISABLED
134 tk 1027
    case BUTTON_TAP_TEMPO:   SEQ_UI_Button_TapTempo(pin_value); break;
1028
#endif
1029
 
1030
    default:
1031
      return -1; // button function not mapped to physical button
1032
  }
1033
 
1034
  // request display update
159 tk 1035
  seq_ui_display_update_req = 1;
134 tk 1036
 
1037
  return 0; // no error
1038
}
1039
 
1040
 
1041
/////////////////////////////////////////////////////////////////////////////
1042
// Encoder handler
1043
/////////////////////////////////////////////////////////////////////////////
1044
s32 SEQ_UI_Encoder_Handler(u32 encoder, s32 incrementer)
1045
{
1046
  if( encoder > 16 )
1047
    return -1; // encoder doesn't exist
1048
 
1049
  // limit incrementer
1050
  if( incrementer > 3 )
1051
    incrementer = 3;
1052
  else if( incrementer < -3 )
1053
    incrementer = -3;
1054
 
306 tk 1055
  if( !seq_ui_button_state.MENU_PRESSED && ui_encoder_callback != NULL ) {
173 tk 1056
    ui_encoder_callback((encoder == 0) ? SEQ_UI_ENCODER_Datawheel : (encoder-1), incrementer);
1057
    ui_cursor_flash_ctr = 0; // ensure that value is visible when it has been changed
134 tk 1058
  }
1059
 
1060
  // request display update
159 tk 1061
  seq_ui_display_update_req = 1;
134 tk 1062
 
1063
  return 0; // no error
1064
}
1065
 
1066
 
1067
/////////////////////////////////////////////////////////////////////////////
1068
// Update LCD messages
1069
// Usually called from background task
1070
/////////////////////////////////////////////////////////////////////////////
1071
s32 SEQ_UI_LCD_Handler(void)
1072
{
159 tk 1073
  if( seq_ui_display_init_req ) {
1074
    seq_ui_display_init_req = 0; // clear request
134 tk 1075
 
278 tk 1076
    // clear force update of LCD
1077
    SEQ_LCD_Clear();
1078
    SEQ_LCD_Update(1);
134 tk 1079
 
168 tk 1080
    // select first menu item
1081
    ui_selected_item = 0;
1082
 
167 tk 1083
    // call init function of current page
272 tk 1084
    if( ui_menu_pages[ui_page].init_callback != NULL )
1085
      ui_menu_pages[ui_page].init_callback(0); // mode
134 tk 1086
 
1087
    // request display update
159 tk 1088
    seq_ui_display_update_req = 1;
134 tk 1089
  }
1090
 
306 tk 1091
  // in MENU page: overrule LCD output so long MENU button is pressed/active
1092
  if( seq_ui_button_state.MENU_PRESSED && !seq_ui_button_state.MENU_FIRST_PAGE_SELECTED ) {
1093
    SEQ_LCD_CursorSet(0, 0);
1094
    //                      <-------------------------------------->
1095
    //                      0123456789012345678901234567890123456789
1096
    SEQ_LCD_PrintString("Menu Shortcuts:");
1097
    SEQ_LCD_PrintSpaces(25 + 40);
1098
    SEQ_LCD_CursorSet(0, 1);
1099
    SEQ_LCD_PrintString(UI_SHORTCUT_STR); // defined in seq_ui_pages.inc
1100
  } else {
1101
    // perform high priority LCD update request
1102
    if( ui_lcd_callback != NULL )
1103
      ui_lcd_callback(1); // high_prio
167 tk 1104
 
306 tk 1105
    // perform low priority LCD update request if requested
1106
    if( seq_ui_display_update_req ) {
1107
      seq_ui_display_update_req = 0; // clear request
1108
 
1109
      if( ui_lcd_callback != NULL )
1110
    ui_lcd_callback(0); // no high_prio
1111
    }
134 tk 1112
  }
1113
 
299 tk 1114
  // if SD card message active: copy over the text
1115
  if( sdcard_msg_ctr ) {
1116
    const char animation_l[4][3] = {
1117
      "  ", " >", ">>", "> " };
1118
    const char animation_r[4][3] = {
1119
      "  ", "< ", "<<", " <" };
1120
    int anum = (sdcard_msg_ctr % 1000) / 250;
1121
 
1122
    int line;
1123
    for(line=0; line<2; ++line) {
1124
      SEQ_LCD_CursorSet(40, line);
1125
      SEQ_LCD_PrintFormattedString(" %s| %-20s |%s ",
1126
                   (char *)animation_l[anum],
1127
                   (char *)sdcard_msg[line],
1128
                   (char *)animation_r[anum]);
1129
    }
1130
  }
1131
 
278 tk 1132
  // transfer all changed characters to LCD
1133
  SEQ_LCD_Update(0);
159 tk 1134
 
134 tk 1135
  return 0; // no error
1136
}
1137
 
1138
 
1139
 
1140
/////////////////////////////////////////////////////////////////////////////
1141
// Update all LEDs
1142
// Usually called from background task
1143
/////////////////////////////////////////////////////////////////////////////
1144
s32 SEQ_UI_LED_Handler(void)
1145
{
326 tk 1146
  u8 visible_track = SEQ_UI_VisibleTrackGet();
1147
  u8 event_mode = SEQ_CC_Get(visible_track, SEQ_CC_MIDI_EVENT_MODE);
1148
 
134 tk 1149
  // track LEDs
167 tk 1150
  SEQ_LED_PinSet(LED_TRACK1, (ui_selected_tracks & (1 << 0)));
1151
  SEQ_LED_PinSet(LED_TRACK2, (ui_selected_tracks & (1 << 1)));
1152
  SEQ_LED_PinSet(LED_TRACK3, (ui_selected_tracks & (1 << 2)));
1153
  SEQ_LED_PinSet(LED_TRACK4, (ui_selected_tracks & (1 << 3)));
134 tk 1154
 
1155
  // parameter layer LEDs
167 tk 1156
  SEQ_LED_PinSet(LED_PAR_LAYER_A, (ui_selected_par_layer == 0));
1157
  SEQ_LED_PinSet(LED_PAR_LAYER_B, (ui_selected_par_layer == 1));
326 tk 1158
  SEQ_LED_PinSet(LED_PAR_LAYER_C, (ui_selected_par_layer >= 2) || seq_ui_button_state.PAR_LAYER_SEL);
134 tk 1159
 
1160
  // group LEDs
167 tk 1161
  SEQ_LED_PinSet(LED_GROUP1, (ui_selected_group == 0));
1162
  SEQ_LED_PinSet(LED_GROUP2, (ui_selected_group == 1));
1163
  SEQ_LED_PinSet(LED_GROUP3, (ui_selected_group == 2));
1164
  SEQ_LED_PinSet(LED_GROUP4, (ui_selected_group == 3));
134 tk 1165
 
1166
  // trigger layer LEDs
326 tk 1167
  if( event_mode == SEQ_EVENT_MODE_Drum ) {
1168
    u8 accent_available = SEQ_TRG_AssignmentGet(visible_track, 1);
1169
    u8 selected_trg_layer = accent_available ? (ui_selected_trg_layer >= (SEQ_TRG_NumLayersGet(visible_track)/2)) : 0;
1170
    SEQ_LED_PinSet(LED_TRG_LAYER_A, (selected_trg_layer == 0));
1171
    SEQ_LED_PinSet(LED_TRG_LAYER_B, (selected_trg_layer == 1));
1172
    SEQ_LED_PinSet(LED_TRG_LAYER_C, seq_ui_button_state.TRG_LAYER_SEL);
1173
  } else {
1174
    SEQ_LED_PinSet(LED_TRG_LAYER_A, (ui_selected_trg_layer == 0));
1175
    SEQ_LED_PinSet(LED_TRG_LAYER_B, (ui_selected_trg_layer == 1));
1176
    SEQ_LED_PinSet(LED_TRG_LAYER_C, (ui_selected_trg_layer >= 2) || seq_ui_button_state.TRG_LAYER_SEL);
1177
  }
134 tk 1178
 
1179
  // remaining LEDs
167 tk 1180
  SEQ_LED_PinSet(LED_EDIT, ui_page == SEQ_UI_PAGE_EDIT);
184 tk 1181
  SEQ_LED_PinSet(LED_MUTE, ui_page == SEQ_UI_PAGE_MUTE);
1182
  SEQ_LED_PinSet(LED_PATTERN, ui_page == SEQ_UI_PAGE_PATTERN);
134 tk 1183
  SEQ_LED_PinSet(LED_SONG, 0);
1184
 
178 tk 1185
  SEQ_LED_PinSet(LED_SOLO, seq_ui_button_state.SOLO);
1186
  SEQ_LED_PinSet(LED_FAST, seq_ui_button_state.FAST_ENCODERS);
1187
  SEQ_LED_PinSet(LED_ALL, seq_ui_button_state.CHANGE_ALL_STEPS);
134 tk 1188
 
193 tk 1189
  SEQ_LED_PinSet(LED_PLAY, SEQ_BPM_IsRunning());
1190
  SEQ_LED_PinSet(LED_STOP, !SEQ_BPM_IsRunning() && !ui_seq_pause);
1191
  SEQ_LED_PinSet(LED_PAUSE, ui_seq_pause);
240 tk 1192
 
1193
  SEQ_LED_PinSet(LED_REW, seq_ui_button_state.REW);
1194
  SEQ_LED_PinSet(LED_FWD, seq_ui_button_state.FWD);
134 tk 1195
 
303 tk 1196
  SEQ_LED_PinSet(LED_STEPVIEW, seq_ui_button_state.STEPVIEW);
134 tk 1197
 
167 tk 1198
  SEQ_LED_PinSet(LED_MENU, seq_ui_button_state.MENU_PRESSED);
178 tk 1199
  SEQ_LED_PinSet(LED_SCRUB, seq_ui_button_state.SCRUB);
1200
  SEQ_LED_PinSet(LED_METRONOME, seq_ui_button_state.METRONOME);
134 tk 1201
 
240 tk 1202
  SEQ_LED_PinSet(LED_UTILITY, ui_page == SEQ_UI_PAGE_UTIL);
1203
  SEQ_LED_PinSet(LED_COPY, seq_ui_button_state.COPY);
1204
  SEQ_LED_PinSet(LED_PASTE, seq_ui_button_state.PASTE);
1205
  SEQ_LED_PinSet(LED_CLEAR, seq_ui_button_state.CLEAR);
1206
 
1207
  SEQ_LED_PinSet(LED_F1, seq_ui_button_state.F1);
1208
  SEQ_LED_PinSet(LED_F2, seq_ui_button_state.F2);
1209
  SEQ_LED_PinSet(LED_F3, seq_ui_button_state.F3);
1210
  SEQ_LED_PinSet(LED_F4, seq_ui_button_state.F4);
1211
 
1212
  SEQ_LED_PinSet(LED_DOWN, seq_ui_button_state.DOWN);
1213
  SEQ_LED_PinSet(LED_UP, seq_ui_button_state.UP);
1214
 
167 tk 1215
 
306 tk 1216
  // in MENU page: overrule GP LEDs so long MENU button is pressed/active
1217
  if( seq_ui_button_state.MENU_PRESSED ) {
1218
    if( ui_cursor_flash ) // if flashing flag active: no LED flag set
1219
      ui_gp_leds = 0x0000;
1220
    else {
1221
      int i;
1222
      u16 new_ui_gp_leds = 0x0000;
1223
      for(i=0; i<16; ++i)
1224
    if( ui_page == ui_shortcut_menu_pages[i] )
1225
      new_ui_gp_leds |= (1 << i);
1226
      ui_gp_leds = new_ui_gp_leds;
1227
    }
1228
  } else {
1229
    // note: the background function is permanently interrupted - therefore we write the GP pattern
1230
    // into a temporary variable, and take it over once completed
1231
    u16 new_ui_gp_leds = 0x0000;
1232
    // request GP LED values from current menu page
1233
    // will be transfered to DOUT registers in SEQ_UI_LED_Handler_Periodic
1234
    new_ui_gp_leds = 0x0000;
206 tk 1235
 
306 tk 1236
    if( ui_led_callback != NULL )
1237
      ui_led_callback(&new_ui_gp_leds);
167 tk 1238
 
306 tk 1239
    ui_gp_leds = new_ui_gp_leds;
1240
  }
1241
 
134 tk 1242
  return 0; // no error
1243
}
1244
 
1245
 
1246
/////////////////////////////////////////////////////////////////////////////
1247
// updates high-prio LED functions (GP LEDs and Beat LED)
168 tk 1248
// called each mS
134 tk 1249
/////////////////////////////////////////////////////////////////////////////
1250
s32 SEQ_UI_LED_Handler_Periodic()
1251
{
1252
  // GP LEDs are only updated when ui_gp_leds or pos_marker_mask has changed
1253
  static u16 prev_ui_gp_leds = 0x0000;
1254
  static u16 prev_pos_marker_mask = 0x0000;
1255
 
1256
  // beat LED: tmp. for demo w/o real sequencer
193 tk 1257
  u8 sequencer_running = SEQ_BPM_IsRunning();
325 tk 1258
  SEQ_LED_PinSet(LED_BEAT, sequencer_running && ((seq_core_state.ref_step & 3) == 0));
134 tk 1259
 
1260
  // for song position marker (supports 16 LEDs, check for selected step view)
1261
  u16 pos_marker_mask = 0x0000;
325 tk 1262
  u8 visible_track = SEQ_UI_VisibleTrackGet();
1263
  u8 played_step = seq_core_trk[visible_track].step;
1264
  if( seq_ui_button_state.STEPVIEW ) {
1265
    // if STEPVIEW button pressed: pos marker correlated to zoom ratio
1266
    if( sequencer_running )
1267
      pos_marker_mask = 1 << (played_step / (SEQ_TRG_NumStepsGet(visible_track)/16));
1268
  } else {
1269
    if( sequencer_running && (played_step >> 4) == ui_selected_step_view )
1270
      pos_marker_mask = 1 << (played_step & 0xf);
1271
  }
134 tk 1272
 
1273
  // exit of pattern hasn't changed
173 tk 1274
  if( prev_ui_gp_leds == ui_gp_leds && prev_pos_marker_mask == pos_marker_mask )
134 tk 1275
    return 0;
173 tk 1276
  prev_ui_gp_leds = ui_gp_leds;
134 tk 1277
  prev_pos_marker_mask = pos_marker_mask;
1278
 
1279
  // transfer to GP LEDs
1280
 
1281
#ifdef DEFAULT_GP_DOUT_SR_L
1282
# ifdef DEFAULT_GP_DOUT_SR_L2
173 tk 1283
  SEQ_LED_SRSet(DEFAULT_GP_DOUT_SR_L-1, (ui_gp_leds >> 0) & 0xff);
134 tk 1284
# else
173 tk 1285
  SEQ_LED_SRSet(DEFAULT_GP_DOUT_SR_L-1, ((ui_gp_leds ^ pos_marker_mask) >> 0) & 0xff);
134 tk 1286
# endif
1287
#endif
1288
#ifdef DEFAULT_GP_DOUT_SR_R
1289
# ifdef DEFAULT_GP_DOUT_SR_R2
173 tk 1290
  SEQ_LED_SRSet(DEFAULT_GP_DOUT_SR_R-1, (ui_gp_leds >> 8) & 0xff);
134 tk 1291
#else
173 tk 1292
  SEQ_LED_SRSet(DEFAULT_GP_DOUT_SR_R-1, ((ui_gp_leds ^ pos_marker_mask) >> 8) & 0xff);
134 tk 1293
#endif
1294
#endif
1295
 
1296
#ifdef DEFAULT_GP_DOUT_SR_L2
1297
  SEQ_LED_SRSet(DEFAULT_GP_DOUT_SR_L2-1, (pos_marker_mask >> 0) & 0xff);
1298
#endif
1299
#ifdef DEFAULT_GP_DOUT_SR_R2
1300
  SEQ_LED_SRSet(DEFAULT_GP_DOUT_SR_R2-1, (pos_marker_mask >> 8) & 0xff);
1301
#endif
1302
 
1303
#if DEFAULT_SRM_ENABLED && DEFAULT_SRM_DOUT_M_MAPPING == 1
1304
  // for wilba's frontpanel
1305
 
1306
  // BLM8X8 DOUT -> GP LED mapping
1307
  // 0 = 15,16  1 = 13,14   2 = 11,12   3 = 9,10
1308
  // 4 = 1,2    5 = 3,4     6 = 5,6     7 = 7,8
1309
 
1310
  // bit 7: first green (i.e. GP1-G)
1311
  // bit 6: first red (i.e. GP1-R)
1312
  // bit 5: second green (i.e. GP2-G)
1313
  // bit 4: second red (i.e. GP2-R)
1314
 
1315
  // this mapping routine takes ca. 5 uS
173 tk 1316
  // since it's only executed when ui_gp_leds or gp_mask has changed, it doesn't really hurt
134 tk 1317
 
173 tk 1318
  u16 modified_gp_leds = ui_gp_leds;
134 tk 1319
#if 1
1320
  // extra: red LED is lit exclusively for higher contrast
1321
  modified_gp_leds &= ~pos_marker_mask;
1322
#endif
1323
 
1324
  int sr;
1325
  const u8 blm8x8_sr_map[8] = {4, 5, 6, 7, 3, 2, 1, 0};
1326
  u16 gp_mask = 1 << 0;
1327
  for(sr=0; sr<8; ++sr) {
1328
    u8 pattern = 0;
1329
 
1330
    if( modified_gp_leds & gp_mask )
1331
      pattern |= 0x80;
1332
    if( pos_marker_mask & gp_mask )
1333
      pattern |= 0x40;
1334
    gp_mask <<= 1;
1335
    if( modified_gp_leds & gp_mask )
1336
      pattern |= 0x20;
1337
    if( pos_marker_mask & gp_mask )
1338
      pattern |= 0x10;
1339
    gp_mask <<= 1;
1340
 
1341
    u8 mapped_sr = blm8x8_sr_map[sr];
1342
    blm8x8_led_row[mapped_sr] = (blm8x8_led_row[mapped_sr] & 0x0f) | pattern;
1343
  }
1344
#endif
1345
 
184 tk 1346
  return 0; // no error
134 tk 1347
}
1348
 
1349
 
1350
/////////////////////////////////////////////////////////////////////////////
168 tk 1351
// for menu handling (e.g. flashing cursor, doubleclick counter, etc...)
1352
// called each mS
1353
/////////////////////////////////////////////////////////////////////////////
1354
s32 SEQ_UI_MENU_Handler_Periodic()
1355
{
1356
  if( ++ui_cursor_flash_ctr >= SEQ_UI_CURSOR_FLASH_CTR_MAX ) {
1357
    ui_cursor_flash_ctr = 0;
1358
    seq_ui_display_update_req = 1;
173 tk 1359
  } else if( ui_cursor_flash_ctr == SEQ_UI_CURSOR_FLASH_CTR_LED_OFF ) {
168 tk 1360
    seq_ui_display_update_req = 1;
173 tk 1361
  }
1362
  // important: flash flag has to be recalculated on each invocation of this
1363
  // handler, since counter could also be reseted outside this function
1364
  ui_cursor_flash = ui_cursor_flash_ctr >= SEQ_UI_CURSOR_FLASH_CTR_LED_OFF;
168 tk 1365
 
184 tk 1366
 
240 tk 1367
  // used in some pages for temporary messages
1368
  if( ui_hold_msg_ctr )
1369
    --ui_hold_msg_ctr;
1370
 
299 tk 1371
  // used for temporary SD Card messages
1372
  if( sdcard_msg_ctr )
1373
    --sdcard_msg_ctr;
1374
 
184 tk 1375
  // VU meters (used in MUTE menu, could also be available as LED matrix...)
1376
  static u8 vu_meter_prediv = 0; // predivider for VU meters
1377
 
1378
  if( ++vu_meter_prediv >= 4 ) {
1379
    vu_meter_prediv = 0;
1380
 
1381
    u8 track;
1382
    seq_core_trk_t *t = &seq_core_trk[0];
318 tk 1383
    portENTER_CRITICAL();
184 tk 1384
    for(track=0; track<SEQ_CORE_NUM_TRACKS; ++t, ++track)
1385
      if( t->vu_meter )
1386
    --t->vu_meter;
318 tk 1387
    portEXIT_CRITICAL();
184 tk 1388
  }
1389
 
168 tk 1390
  return 0;
1391
}
1392
 
1393
 
1394
/////////////////////////////////////////////////////////////////////////////
134 tk 1395
// Returns the currently visible track
1396
/////////////////////////////////////////////////////////////////////////////
1397
u8 SEQ_UI_VisibleTrackGet(void)
1398
{
1399
  u8 offset = 0;
1400
 
1401
  if( ui_selected_tracks & (1 << 3) )
1402
    offset = 3;
1403
  if( ui_selected_tracks & (1 << 2) )
1404
    offset = 2;
1405
  if( ui_selected_tracks & (1 << 1) )
1406
    offset = 1;
1407
  if( ui_selected_tracks & (1 << 0) )
1408
    offset = 0;
1409
 
1410
  return 4*ui_selected_group + offset;
1411
}
1412
 
168 tk 1413
 
1414
/////////////////////////////////////////////////////////////////////////////
178 tk 1415
// Returns 1 if 'track' is selected
1416
/////////////////////////////////////////////////////////////////////////////
1417
s32 SEQ_UI_IsSelectedTrack(u8 track)
1418
{
1419
  if( (track>>2) != ui_selected_group )
1420
    return 0;
1421
  return (ui_selected_tracks & (1 << (track&3))) ? 1 : 0;
1422
}
1423
 
1424
 
1425
/////////////////////////////////////////////////////////////////////////////
240 tk 1426
// Sets a new selected step and updates the step view
1427
/////////////////////////////////////////////////////////////////////////////
1428
s32 SEQ_UI_SelectedStepSet(u8 step)
1429
{
1430
  ui_selected_step = step;
1431
  ui_selected_step_view = (ui_selected_step >= 16) ? 1 : 0;
1432
  return 0; // no error
1433
}
1434
 
1435
 
1436
/////////////////////////////////////////////////////////////////////////////
168 tk 1437
// Increments the selected tracks/groups
1438
// OUT: 1 if value has been changed, otherwise 0
1439
/////////////////////////////////////////////////////////////////////////////
1440
s32 SEQ_UI_GxTyInc(s32 incrementer)
1441
{
1442
  int gxty = SEQ_UI_VisibleTrackGet();
1443
  int prev_gxty = gxty;
1444
 
1445
  if( incrementer >= 0 ) {
1446
    if( (gxty += incrementer) >= SEQ_CORE_NUM_TRACKS )
1447
      gxty = SEQ_CORE_NUM_TRACKS-1;
1448
  } else {
1449
    if( (gxty += incrementer) < 0 )
1450
      gxty = 0;
1451
  }
1452
 
1453
  if( gxty == prev_gxty )
1454
    return 0; // no change
1455
 
1456
  ui_selected_tracks = 1 << (gxty % 4);
1457
  ui_selected_group = gxty / 4;
1458
 
1459
  return 1; // value changed
1460
}
1461
 
1462
 
1463
/////////////////////////////////////////////////////////////////////////////
236 tk 1464
// Increments a 16bit variable within given min/max range
1465
// OUT: 1 if value has been changed, otherwise 0
1466
/////////////////////////////////////////////////////////////////////////////
240 tk 1467
s32 SEQ_UI_Var16_Inc(u16 *value, u16 min, u16 max, s32 incrementer)
236 tk 1468
{
1469
  int new_value = *value;
1470
  int prev_value = new_value;
1471
 
1472
  if( incrementer >= 0 ) {
1473
    if( (new_value += incrementer) >= max )
1474
      new_value = max;
1475
  } else {
1476
    if( (new_value += incrementer) < min )
1477
      new_value = min;
1478
  }
1479
 
1480
  if( new_value == prev_value )
1481
    return 0; // no change
1482
 
1483
  *value = new_value;
1484
 
1485
  return 1; // value changed
1486
}
1487
 
240 tk 1488
/////////////////////////////////////////////////////////////////////////////
1489
// Increments an 8bit variable within given min/max range
1490
// OUT: 1 if value has been changed, otherwise 0
1491
/////////////////////////////////////////////////////////////////////////////
1492
s32 SEQ_UI_Var8_Inc(u8 *value, u16 min, u16 max, s32 incrementer)
1493
{
1494
  u16 tmp = *value;
1495
  if( SEQ_UI_Var16_Inc(&tmp, min, max, incrementer) ) {
1496
    *value = tmp;
1497
    return 1; // value changed
1498
  }
236 tk 1499
 
240 tk 1500
  return 0; // value hasn't been changed
1501
}
1502
 
1503
 
236 tk 1504
/////////////////////////////////////////////////////////////////////////////
168 tk 1505
// Increments a CC within given min/max range
1506
// OUT: 1 if value has been changed, otherwise 0
1507
/////////////////////////////////////////////////////////////////////////////
248 tk 1508
s32 SEQ_UI_CC_Inc(u8 cc, u8 min, u8 max, s32 incrementer)
168 tk 1509
{
1510
  u8 visible_track = SEQ_UI_VisibleTrackGet();
173 tk 1511
  int new_value = SEQ_CC_Get(visible_track, cc);
1512
  int prev_value = new_value;
168 tk 1513
 
1514
  if( incrementer >= 0 ) {
173 tk 1515
    if( (new_value += incrementer) >= max )
1516
      new_value = max;
168 tk 1517
  } else {
173 tk 1518
    if( (new_value += incrementer) < min )
1519
      new_value = min;
168 tk 1520
  }
1521
 
173 tk 1522
  if( new_value == prev_value )
168 tk 1523
    return 0; // no change
1524
 
173 tk 1525
  SEQ_CC_Set(visible_track, cc, new_value);
168 tk 1526
 
179 tk 1527
  // set same value for all selected tracks
1528
  u8 track;
1529
  for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track)
1530
    if( track != visible_track && SEQ_UI_IsSelectedTrack(track) )
1531
      SEQ_CC_Set(track, cc, new_value);
1532
 
168 tk 1533
  return 1; // value changed
1534
}
1535
 
173 tk 1536
 
1537
/////////////////////////////////////////////////////////////////////////////
179 tk 1538
// Sets a CC value on all selected tracks
1539
// OUT: 1 if value has been changed, otherwise 0
1540
/////////////////////////////////////////////////////////////////////////////
248 tk 1541
s32 SEQ_UI_CC_Set(u8 cc, u8 value)
179 tk 1542
{
1543
  u8 visible_track = SEQ_UI_VisibleTrackGet();
1544
  int prev_value = SEQ_CC_Get(visible_track, cc);
1545
 
1546
  if( value == prev_value )
1547
    return 0; // no change
1548
 
1549
  SEQ_CC_Set(visible_track, cc, value);
1550
 
1551
  // set same value for all selected tracks
1552
  u8 track;
1553
  for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track)
1554
    if( track != visible_track && SEQ_UI_IsSelectedTrack(track) )
1555
      SEQ_CC_Set(track, cc, value);
1556
 
1557
  return 1; // value changed
1558
}
1559
 
1560
/////////////////////////////////////////////////////////////////////////////
173 tk 1561
// Modifies a bitfield in a CC value to a given value
1562
// OUT: 1 if value has been changed, otherwise 0
1563
/////////////////////////////////////////////////////////////////////////////
248 tk 1564
s32 SEQ_UI_CC_SetFlags(u8 cc, u8 flag_mask, u8 value)
173 tk 1565
{
1566
  u8 visible_track = SEQ_UI_VisibleTrackGet();
1567
  int new_value = SEQ_CC_Get(visible_track, cc);
1568
  int prev_value = new_value;
1569
 
1570
  new_value = (new_value & ~flag_mask) | value;
1571
 
1572
  if( new_value == prev_value )
1573
    return 0; // no change
1574
 
1575
  SEQ_CC_Set(visible_track, cc, new_value);
1576
 
179 tk 1577
  // do same modification for all selected tracks
1578
  u8 track;
1579
  for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track)
1580
    if( track != visible_track && SEQ_UI_IsSelectedTrack(track) ) {
1581
      int new_value = SEQ_CC_Get(track, cc);
1582
      new_value = (new_value & ~flag_mask) | value;
1583
      SEQ_CC_Set(track, cc, new_value);
1584
    }
1585
 
173 tk 1586
  return 1; // value changed
1587
}
1588
 
1589
 
299 tk 1590
/////////////////////////////////////////////////////////////////////////////
1591
// Print temporary messages after file operations
1592
// expects mS delay and two lines, each up to 20 characters
1593
/////////////////////////////////////////////////////////////////////////////
1594
s32 SEQ_UI_SDCardMsg(u16 delay, char *line1, char *line2)
1595
{
1596
  sdcard_msg_ctr = delay;
1597
  strncpy((char *)sdcard_msg[0], line1, SDCARD_MSG_MAX_CHAR);
1598
  strncpy((char *)sdcard_msg[1], line2, SDCARD_MSG_MAX_CHAR);
1599
 
1600
  return 0; // no error
1601
}
1602
 
1603
/////////////////////////////////////////////////////////////////////////////
1604
// Prints a temporary error messages after file operation
1605
// Expects error status number (as defined in seq_file.h)
1606
/////////////////////////////////////////////////////////////////////////////
1607
s32 SEQ_UI_SDCardErrMsg(u16 delay, s32 status)
1608
{
1609
  // TODO: add more verbose error messages, they are clearly defined in seq_file.h)
1610
  char str[21];
1611
  sprintf(str, "E%3d (DOSFS: D%3d)", -status, seq_file_dfs_errno < 1000 ? seq_file_dfs_errno : 999);
1612
  return SEQ_UI_SDCardMsg(delay, "!! SD Card Error !!!", str);
1613
}