Subversion Repositories svn.mios32

Rev

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