Subversion Repositories svn.mios32

Rev

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