/////////////////////////////////////////////////////////////////////////////
// Local LED handler function
/////////////////////////////////////////////////////////////////////////////
static s32 LED_Handler(u16 *gp_leds)
{
  u8 track;

  if( seq_ui_button_state.CHANGE_ALL_STEPS ) {
    u8 visible_track = SEQ_UI_VisibleTrackGet();
    *gp_leds = 0;

    u16 all_layers_muted_mask = 0;
    int track;
    for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track)
      all_layers_muted_mask |= seq_core_trk[track].layer_muted;

#if 1
    if( seq_core_trk_muted == 0xffff )
      *gp_leds |= 0x0003;
    if( seq_core_trk[visible_track].layer_muted == 0xffff )
      *gp_leds |= 0x001c;
    if( seq_core_trk_muted == 0xffff && all_layers_muted_mask == 0xffff )
      *gp_leds |= 0x00e0;

    if( seq_core_trk_muted == 0x0000 )
      *gp_leds |= 0x0300;
    if( seq_core_trk[visible_track].layer_muted == 0x0000 )
      *gp_leds |= 0x1c00;
    if( seq_core_trk_muted == 0x0000 && all_layers_muted_mask == 0x0000 )
      *gp_leds |= 0xe000;
#else
    // Better? Mayber to difficult to understand for users, therefore disabled by default
    // e.g. all tracks muted: activate LEDs of the "all tracks unmuted" button.
    // it should signal: something will happen when you push here...
    if( seq_core_trk_muted == 0xffff )
      *gp_leds |= 0x0300;
    if( seq_core_trk[visible_track].layer_muted == 0xffff )
      *gp_leds |= 0x1c00;
    if( seq_core_trk_muted == 0xffff && all_layers_muted_mask == 0xffff )
      *gp_leds |= 0xe000;

    if( seq_core_trk_muted == 0x0000 )
      *gp_leds |= 0x0003;
    if( seq_core_trk[visible_track].layer_muted == 0x0000 )
      *gp_leds |= 0x001c;
    if( seq_core_trk_muted == 0x0000 && all_layers_muted_mask == 0x0000 )
      *gp_leds |= 0x00e0;
#endif

  } else if( !ui_cursor_flash && seq_ui_button_state.SELECT_PRESSED ) {
    *gp_leds = latched_mute;
  } else {
    if( seq_ui_button_state.MUTE_PRESSED ) {
      track = SEQ_UI_VisibleTrackGet();
      *gp_leds = seq_core_trk[track].layer_muted | seq_core_trk[track].layer_muted_from_midi;
    } else {
      *gp_leds = seq_core_trk_muted;
    }
  }

  return 0; // no error
}
/////////////////////////////////////////////////////////////////////////////
// Local LED handler function
/////////////////////////////////////////////////////////////////////////////
static s32 LED_Handler(u16 *gp_leds)
{
  if( ui_cursor_flash ) // if flashing flag active: no LED flag set
    return 0;

  switch( ui_selected_item ) {
    case ITEM_GXTY: *gp_leds = 0x0001; break;
    case ITEM_WAVEFORM: *gp_leds = 0x0002; break;
    case ITEM_AMPLITUDE: *gp_leds = 0x0004; break;
    case ITEM_PHASE: *gp_leds = 0x0008; break;
    case ITEM_STEPS: *gp_leds = 0x0010; break;
    case ITEM_STEPS_RST: *gp_leds = 0x0020; break;
    case ITEM_ENABLE_ONE_SHOT: *gp_leds = 0x0040; break;
    case ITEM_ENABLE_NOTE: *gp_leds = 0x0100; break;
    case ITEM_ENABLE_VELOCITY: *gp_leds = 0x0200; break;
    case ITEM_ENABLE_LENGTH: *gp_leds = 0x0400; break;
    case ITEM_ENABLE_CC: *gp_leds = 0x0800; break;
    case ITEM_CC: *gp_leds = 0x2000; break;
    case ITEM_CC_OFFSET: *gp_leds = 0x2000; break;
    case ITEM_CC_PPQN: *gp_leds = 0x8000; break;
  }

#if 0
  // inconsistent and doesn't look so nice
  u8 visible_track = SEQ_UI_VisibleTrackGet();
  u8 flags = SEQ_CC_Get(visible_track, SEQ_CC_LFO_ENABLE_FLAGS);
  *gp_leds |= (((u16)(flags & 0x1e)) << 7) | (((u16)(flags & 0x01)) << 6);
#endif

  return 0; // no error
}
/////////////////////////////////////////////////////////////////////////////
// Local button callback function
// Should return:
//   1 if value has been changed
//   0 if value hasn't been changed
//  -1 if invalid or unsupported button
/////////////////////////////////////////////////////////////////////////////
static s32 Button_Handler(seq_ui_button_t button, s32 depressed)
{
  if( button <= SEQ_UI_BUTTON_GP16 ) {
    if( !seq_midi_in_options[selected_bus].MODE_PLAY )
      return -1;

    u8 visible_track = SEQ_UI_VisibleTrackGet();
    mios32_midi_package_t p;

    if( depressed )
      gp_button_pressed &= ~(1 << button);
    else
      gp_button_pressed |= (1 << button);

    p.type = NoteOn;
    p.event = NoteOn;
    p.chn = Chn1; // will be overruled anyhow by SEQ_LIVE_PlayEvent()
    p.note = 0x30 + (u8)button;
    p.velocity = depressed ? 0x00 : seq_live_options.VELOCITY;
    SEQ_LIVE_PlayEvent(visible_track, p);
    return 0;
  }

  // exit if button depressed
  if( depressed )
    return -1;

  // remaining buttons:
  switch( button ) {
    case SEQ_UI_BUTTON_Select:
    case SEQ_UI_BUTTON_Right:
      if( ++ui_selected_item >= NUM_OF_ITEMS )
	ui_selected_item = 0;
      return 1; // value always changed

    case SEQ_UI_BUTTON_Left:
      if( ui_selected_item == 0 )
	ui_selected_item = NUM_OF_ITEMS-1;
      else
	--ui_selected_item;
      return 1; // value always changed

    case SEQ_UI_BUTTON_Up:
      return Encoder_Handler(SEQ_UI_ENCODER_Datawheel, 1);

    case SEQ_UI_BUTTON_Down:
      return Encoder_Handler(SEQ_UI_ENCODER_Datawheel, -1);
  }

  return -1; // invalid or unsupported button
}
示例#4
0
/////////////////////////////////////////////////////////////////////////////
// Local LED handler function
/////////////////////////////////////////////////////////////////////////////
static s32 LED_Handler(u16 *gp_leds)
{
  if( ui_cursor_flash ) // if flashing flag active: no LED flag set
    return 0;

  u8 visible_track = SEQ_UI_VisibleTrackGet();
  u8 event_mode = SEQ_CC_Get(visible_track, SEQ_CC_MIDI_EVENT_MODE);

  if( event_mode == SEQ_EVENT_MODE_Drum )
    *gp_leds = 1 << ui_selected_instrument;
  else
    *gp_leds = 1 << ui_selected_trg_layer;

  return 0; // no error
}
/////////////////////////////////////////////////////////////////////////////
// Local LED handler function
/////////////////////////////////////////////////////////////////////////////
static s32 LED_Handler(u16 *gp_leds)
{
  if( ui_cursor_flash ) // if flashing flag active: no LED flag set
    return 0;

  u8 visible_track = SEQ_UI_VisibleTrackGet();
  int num_steps = SEQ_TRG_NumStepsGet(visible_track);

  if( num_steps > 128 )
    *gp_leds = 1 << ui_selected_step_view;
  else if( num_steps > 64 )
    *gp_leds = 3 << (2*ui_selected_step_view);
  else
    *gp_leds = 15 << (4*ui_selected_step_view);

  return 0; // no error
}
示例#6
0
/////////////////////////////////////////////////////////////////////////////
// Local LED handler function
/////////////////////////////////////////////////////////////////////////////
static s32 LED_Handler(u16 *gp_leds)
{
  u8 track;

  if( !ui_cursor_flash && seq_ui_button_state.SELECT_PRESSED ) {
    *gp_leds = latched_mute;
  } else {
    if( seq_ui_button_state.MUTE_PRESSED ) {
      track = SEQ_UI_VisibleTrackGet();
      *gp_leds = seq_core_trk[track].layer_muted;
    } else {
      *gp_leds = seq_core_trk_muted;
    }
  }

  return 0; // no error
}
/////////////////////////////////////////////////////////////////////////////
// Local LED handler function
/////////////////////////////////////////////////////////////////////////////
static s32 LED_Handler(u16 *gp_leds)
{
  if( ui_cursor_flash ) // if flashing flag active: no LED flag set
    return 0;

  switch( ui_selected_item ) {
    case ITEM_GXTY: *gp_leds = 0x0001; break;
    case ITEM_LENGTH: *gp_leds = 0x0006; break;
    case ITEM_LOOP: *gp_leds = 0x0018; break;
    case ITEM_QUICKSEL_MODE: *gp_leds = 0x00c0; break;
  }

  s32 quicksel_item = QUICKSEL_SearchItem(SEQ_UI_VisibleTrackGet());
  if( quicksel_item >= 0 )
      *gp_leds |= 1 << (quicksel_item+8);

  return 0; // no error
}
示例#8
0
/////////////////////////////////////////////////////////////////////////////
// Local encoder callback function
// Should return:
//   1 if value has been changed
//   0 if value hasn't been changed
//  -1 if invalid or unsupported encoder
/////////////////////////////////////////////////////////////////////////////
static s32 Encoder_Handler(seq_ui_encoder_t encoder, s32 incrementer)
{
  u8 visible_track = SEQ_UI_VisibleTrackGet();
  u8 event_mode = SEQ_CC_Get(visible_track, SEQ_CC_MIDI_EVENT_MODE);

  if( encoder <= SEQ_UI_ENCODER_GP16 ) {
    // select new layer/instrument

    if( event_mode == SEQ_EVENT_MODE_Drum ) {
      if( encoder >= SEQ_TRG_NumInstrumentsGet(visible_track) )
	return -1;
      ui_selected_instrument = encoder;
    } else {
      if( encoder >= SEQ_TRG_NumLayersGet(visible_track) )
	return -1;
      ui_selected_trg_layer = encoder;
    }

    if( seq_hwcfg_button_beh.par_layer ) {
      // if toggle function active: jump back to previous menu
      // this is especially useful for the emulated MBSEQ, where we can only click on a single button
      // (trigger gets deactivated when clicking on GP button or moving encoder)
      seq_ui_button_state.TRG_LAYER_SEL = 0;
      SEQ_UI_PageSet(ui_trglayer_prev_page);
    }

    return 1; // value changed
  } else if( encoder == SEQ_UI_ENCODER_Datawheel ) {
    if( event_mode == SEQ_EVENT_MODE_Drum ) {
      return SEQ_UI_Var8_Inc(&ui_selected_instrument, 0, SEQ_TRG_NumInstrumentsGet(visible_track)-1, incrementer);
    } else {
      return SEQ_UI_Var8_Inc(&ui_selected_trg_layer, 0, SEQ_TRG_NumLayersGet(visible_track)-1, incrementer);
    }
  }

  return -1; // invalid or unsupported encoder
}
/////////////////////////////////////////////////////////////////////////////
// Local LED handler function
/////////////////////////////////////////////////////////////////////////////
static s32 LED_Handler(u16 *gp_leds)
{
    if( ui_cursor_flash ) // if flashing flag active: no LED flag set
        return 0;

    switch( ui_selected_item ) {
    case ITEM_GXTY:
        *gp_leds = 0x0001;
        break;
    case ITEM_MODE: {
        int selected_mode = SEQ_CC_Get(SEQ_UI_VisibleTrackGet(), SEQ_CC_MODE);
        *gp_leds = (1 << (selected_mode+1));
    }
    break;
    case ITEM_BUS:
        *gp_leds = 0x0080;
        break;
    case ITEM_HOLD:
        *gp_leds = 0x0100;
        break;
    case ITEM_SORT:
        *gp_leds = 0x0200;
        break;
    case ITEM_RESTART:
        *gp_leds = 0x0c00;
        break;
    case ITEM_FORCE_SCALE:
        *gp_leds = 0x3000;
        break;
    case ITEM_SUSTAIN:
        *gp_leds = 0xc000;
        break;
    }

    return 0; // no error
}
示例#10
0
/////////////////////////////////////////////////////////////////////////////
// Local button callback function
// Should return:
//   1 if value has been changed
//   0 if value hasn't been changed
//  -1 if invalid or unsupported button
/////////////////////////////////////////////////////////////////////////////
static s32 Button_Handler(seq_ui_button_t button, s32 depressed)
{
  if( depressed ) return 0; // ignore when button depressed

  if( button <= SEQ_UI_BUTTON_GP8 || button == SEQ_UI_BUTTON_Select ) {
    if( button != SEQ_UI_BUTTON_Select )
      ui_selected_item = button / 2;

    SEQ_UI_Msg(SEQ_UI_MSG_USER_R, 10000, "Sending Informations", "to MIOS Terminal!");

    switch( ui_selected_item + list_view_offset ) {

      //////////////////////////////////////////////////////////////////////////////////////////////
      case LIST_ITEM_SYSTEM:
	SEQ_TERMINAL_PrintSystem(DEBUG_MSG);
	break;

      //////////////////////////////////////////////////////////////////////////////////////////////
      case LIST_ITEM_GLOBALS:
	SEQ_TERMINAL_PrintGlobalConfig(DEBUG_MSG);
	break;

      //////////////////////////////////////////////////////////////////////////////////////////////
      case LIST_ITEM_CONFIG:
	SEQ_TERMINAL_PrintSessionConfig(DEBUG_MSG);
	break;

      //////////////////////////////////////////////////////////////////////////////////////////////
      case LIST_ITEM_TRACKS:
	SEQ_TERMINAL_PrintTracks(DEBUG_MSG);
	break;

      //////////////////////////////////////////////////////////////////////////////////////////////
      case LIST_ITEM_TRACK_INFO:
	SEQ_TERMINAL_PrintTrack(DEBUG_MSG, SEQ_UI_VisibleTrackGet());
	break;

      //////////////////////////////////////////////////////////////////////////////////////////////
      case LIST_ITEM_MIXER_MAP:
	SEQ_TERMINAL_PrintCurrentMixerMap(DEBUG_MSG);
	break;

      //////////////////////////////////////////////////////////////////////////////////////////////
      case LIST_ITEM_SONG:
	SEQ_TERMINAL_PrintCurrentSong(DEBUG_MSG);
	break;

      //////////////////////////////////////////////////////////////////////////////////////////////
      case LIST_ITEM_GROOVES:
	SEQ_TERMINAL_PrintGrooveTemplates(DEBUG_MSG);
	break;

      //////////////////////////////////////////////////////////////////////////////////////////////
      case LIST_ITEM_BOOKMARKS:
	SEQ_TERMINAL_PrintBookmarks(DEBUG_MSG);
	break;

      //////////////////////////////////////////////////////////////////////////////////////////////
      case LIST_ITEM_SD_CARD:
	SEQ_TERMINAL_PrintSdCardInfo(DEBUG_MSG);
	break;

      //////////////////////////////////////////////////////////////////////////////////////////////
      case LIST_ITEM_NETWORK:
#if !defined(MIOS32_FAMILY_EMULATION)
	UIP_TERMINAL_PrintNetwork(DEBUG_MSG);
#endif
	break;

      //////////////////////////////////////////////////////////////////////////////////////////////
      default:
	DEBUG_MSG("No informations available.");
    }

    SEQ_UI_Msg(SEQ_UI_MSG_USER_R, 1000, "Sent Informations", "to MIOS Terminal!");

    return 1;
  }

  if( button >= SEQ_UI_BUTTON_GP9 && button <= SEQ_UI_BUTTON_GP16 ) {
    // re-using encoder handler
    return Encoder_Handler(button, 0);
  }

  switch( button ) {
    case SEQ_UI_BUTTON_Right:
    case SEQ_UI_BUTTON_Up:
      return Encoder_Handler(SEQ_UI_ENCODER_Datawheel, 1);

    case SEQ_UI_BUTTON_Left:
    case SEQ_UI_BUTTON_Down:
      return Encoder_Handler(SEQ_UI_ENCODER_Datawheel, -1);
  }

  return -1; // invalid or unsupported button
}
示例#11
0
/////////////////////////////////////////////////////////////////////////////
// Local encoder callback function
// Should return:
//   1 if value has been changed
//   0 if value hasn't been changed
//  -1 if invalid or unsupported encoder
/////////////////////////////////////////////////////////////////////////////
static s32 Encoder_Handler(seq_ui_encoder_t encoder, s32 incrementer)
{
#if 0
  // leads to: comparison is always true due to limited range of data type
  if( (encoder >= SEQ_UI_ENCODER_GP1 && encoder <= SEQ_UI_ENCODER_GP16) ) {
#else
  if( encoder <= SEQ_UI_ENCODER_GP16 ) {
#endif
    if( seq_ui_button_state.SELECT_PRESSED && !seq_ui_button_state.CHANGE_ALL_STEPS ) {
	// select button pressed: indirect MUTED flag modification (taken over when select button depressed)
	u16 mask = 1 << encoder;
	if( incrementer < 0 || (incrementer == 0 && !(latched_mute & mask)) )
	  latched_mute |= mask;
	else
	  latched_mute &= ~mask;
    } else {
      // select button not pressed: direct MUTED flag modification
      // access to seq_core_trk[] must be atomic!
      portENTER_CRITICAL();

      u8 visible_track = SEQ_UI_VisibleTrackGet();
      u16 mask = 1 << encoder;
      u16 *muted = (u16 *)&seq_core_trk_muted;

      if( seq_ui_button_state.CHANGE_ALL_STEPS ) {
	switch( encoder ) {
	case SEQ_UI_ENCODER_GP1:
	case SEQ_UI_ENCODER_GP2:
	  *muted = 0xffff;
	  SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, "All Tracks", "muted");
	  break;

	case SEQ_UI_ENCODER_GP3:
	case SEQ_UI_ENCODER_GP4:
	case SEQ_UI_ENCODER_GP5:
	  muted = (u16 *)&seq_core_trk[visible_track].layer_muted;
	  *muted = 0xffff;
	  SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, "All Layers", "of current Track muted");
	  break;

	case SEQ_UI_ENCODER_GP6:
	case SEQ_UI_ENCODER_GP7:
	case SEQ_UI_ENCODER_GP8: {
	  *muted = 0xffff;

	  int track;
	  for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track) {
	    seq_core_trk[track].layer_muted = 0xffff;
	  }
	  SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, "All Layers", "and Tracks muted");
	} break;

	case SEQ_UI_ENCODER_GP9:
	case SEQ_UI_ENCODER_GP10:
	  *muted = 0x0000;
	  SEQ_UI_Msg(SEQ_UI_MSG_USER_R, 1000, "All Tracks", "unmuted");
	  break;

	case SEQ_UI_ENCODER_GP11:
	case SEQ_UI_ENCODER_GP12:
	case SEQ_UI_ENCODER_GP13:
	  muted = (u16 *)&seq_core_trk[visible_track].layer_muted;
	  *muted = 0x0000;
	  SEQ_UI_Msg(SEQ_UI_MSG_USER_R, 1000, "All Layers", "of current Track unmuted");
	  break;

	case SEQ_UI_ENCODER_GP14:
	case SEQ_UI_ENCODER_GP15:
	case SEQ_UI_ENCODER_GP16: {
	  *muted = 0x0000;

	  int track;
	  for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track) {
	    seq_core_trk[track].layer_muted = 0x0000;
	  }
	  SEQ_UI_Msg(SEQ_UI_MSG_USER_R, 1000, "All Layers", "and Tracks unmuted");
	} break;
	}
      } else {
	if( seq_ui_button_state.MUTE_PRESSED )
	  muted = (u16 *)&seq_core_trk[visible_track].layer_muted;
	else if( SEQ_BPM_IsRunning() ) { // Synched Mutes only when sequencer is running
	  if( !(*muted & mask) && seq_core_options.SYNCHED_MUTE && !seq_ui_button_state.FAST_ENCODERS ) { // Fast button will disable synched mute
	    muted = (u16 *)&seq_core_trk_synched_mute;
	  } else if( (*muted & mask) && seq_core_options.SYNCHED_UNMUTE && !seq_ui_button_state.FAST_ENCODERS ) { // Fast button will disable synched unmute
	    muted = (u16 *)&seq_core_trk_synched_unmute;
	  }
	} else {
	  // clear synched mutes/unmutes if sequencer not running
	  seq_core_trk_synched_mute = 0;
	  seq_core_trk_synched_unmute = 0;
	}
	  
	if( incrementer < 0 )
	  *muted |= mask;
	else if( incrementer > 0 )
	  *muted &= ~mask;
	else
	  *muted ^= mask;
      }

      portEXIT_CRITICAL();

      if( muted == ((u16 *)&seq_core_trk_muted) ) {
	// send to external
	SEQ_MIDI_IN_ExtCtrlSend(SEQ_MIDI_IN_EXT_CTRL_MUTES, (*muted & mask) ? 127 : 0, encoder);
      }
    }

    return 1; // value changed
  }

  return -1; // invalid or unsupported encoder
}


/////////////////////////////////////////////////////////////////////////////
// Local button callback function
// Should return:
//   1 if value has been changed
//   0 if value hasn't been changed
//  -1 if invalid or unsupported button
/////////////////////////////////////////////////////////////////////////////
static s32 Button_Handler(seq_ui_button_t button, s32 depressed)
{
#if 0
  // leads to: comparison is always true due to limited range of data type
  if( button >= SEQ_UI_BUTTON_GP1 && button <= SEQ_UI_BUTTON_GP16 ) {
#else
  if( button <= SEQ_UI_BUTTON_GP16 ) {
#endif
    if( depressed ) return 0; // ignore when button depressed

    // re-using encoder routine
    return Encoder_Handler(button, 0);
  }

  switch( button ) {
    case SEQ_UI_BUTTON_Select:
      portENTER_CRITICAL();
      if( depressed ) {
	// select button released: take over latched mutes
	if( seq_ui_button_state.MUTE_PRESSED ) {
	  u8 visible_track = SEQ_UI_VisibleTrackGet();
	  seq_core_trk[visible_track].layer_muted = latched_mute;
	} else {
	  u16 new_mutes = latched_mute & ~seq_core_trk_muted;
	  if( SEQ_BPM_IsRunning() && seq_core_options.SYNCHED_MUTE && !seq_ui_button_state.FAST_ENCODERS ) // Fast button will disable synched mute
	    seq_core_trk_synched_mute |= new_mutes;
	  else
	    seq_core_trk_muted |= new_mutes;

	  u16 new_unmutes = ~latched_mute & seq_core_trk_muted;
	  if( SEQ_BPM_IsRunning() && seq_core_options.SYNCHED_UNMUTE && !seq_ui_button_state.FAST_ENCODERS ) // Fast button will disable synched unmute
	    seq_core_trk_synched_unmute |= new_unmutes;
	  else
	    seq_core_trk_muted &= ~new_unmutes;
	}
      } else {
	// select pressed: init latched mutes which will be taken over once SELECT button released
	if( seq_ui_button_state.MUTE_PRESSED ) {
	  u8 visible_track = SEQ_UI_VisibleTrackGet();
	  latched_mute = seq_core_trk[visible_track].layer_muted;
	} else {
	  latched_mute = seq_core_trk_muted;
	}
      }

      portEXIT_CRITICAL();
      return 1;
  }

  return -1; // invalid or unsupported button
}


/////////////////////////////////////////////////////////////////////////////
// Local Display Handler function
// IN: <high_prio>: if set, a high-priority LCD update is requested
/////////////////////////////////////////////////////////////////////////////
static s32 LCD_Handler(u8 high_prio)
{
  // layout:
  // 00000000001111111111222222222233333333330000000000111111111122222222223333333333
  // 01234567890123456789012345678901234567890123456789012345678901234567890123456789
  // <--------------------------------------><-------------------------------------->
  //  > 1<   2    3    4    5    6    7    8    9   10   11   12   13   14   15   16 
  // ...horizontal VU meters...

  // Mute All screen:
  // 00000000001111111111222222222233333333330000000000111111111122222222223333333333
  // 01234567890123456789012345678901234567890123456789012345678901234567890123456789
  // <--------------------------------------><-------------------------------------->
  //    Mute       Mute       Mute all Tracks  Unmute      Unmute   Unmute all Tracks
  // all Tracks G1T1 Layers    and all Layersall Tracks G1T1 Layers    and all Layers

  if( seq_ui_button_state.CHANGE_ALL_STEPS ) {
    if( high_prio )
      return 0;

    SEQ_LCD_CursorSet(0, 0);
    SEQ_LCD_PrintString("   Mute       Mute       Mute all Tracks  Unmute      Unmute   Unmute all Tracks");
    SEQ_LCD_CursorSet(0, 1);
    SEQ_LCD_PrintString("all Tracks ");
    SEQ_LCD_PrintGxTy(ui_selected_group, ui_selected_tracks);
    SEQ_LCD_PrintString(" Layers    and all Layersall Tracks ");
    SEQ_LCD_PrintGxTy(ui_selected_group, ui_selected_tracks);
    SEQ_LCD_PrintString(" Layers    and all Layers");

    return 0;
  }

  if( high_prio ) {
    ///////////////////////////////////////////////////////////////////////////
    // frequently update VU meters
    SEQ_LCD_CursorSet(0, 1);

    u8 track;
    u16 mute_flags = 0;
    u16 mute_flags_from_midi = 0;

    if( !ui_cursor_flash && seq_ui_button_state.SELECT_PRESSED ) {
      mute_flags = latched_mute;
    } else {
      if( seq_ui_button_state.MUTE_PRESSED ) {
	u8 visible_track = SEQ_UI_VisibleTrackGet();
	mute_flags = seq_core_trk[visible_track].layer_muted;
	mute_flags_from_midi = seq_core_trk[visible_track].layer_muted_from_midi;
      } else {
	mute_flags = seq_core_trk_muted;
      }
    }

    if( seq_ui_button_state.MUTE_PRESSED ) {
      u8 layer;
      u16 mask = (1 << 0);
      for(layer=0; layer<16; ++layer, mask <<= 1)
	if( mute_flags_from_midi & mask ) {
	  SEQ_LCD_PrintString("MIDI ");
	} else if( mute_flags & mask ) {
	  SEQ_LCD_PrintString("Mute ");
	} else {
	  SEQ_LCD_PrintHBar((seq_layer_vu_meter[layer] >> 3) & 0xf);
	}
    } else {
      int remaining_steps = (seq_core_steps_per_measure - seq_core_state.ref_step) + 1;
      seq_core_trk_t *t = &seq_core_trk[0];
      u16 mask = (1 << 0);
      for(track=0; track<16; ++t, ++track, mask <<= 1)
	if( mute_flags & mask ) {
	  if( !seq_ui_button_state.SELECT_PRESSED && (seq_core_trk_synched_unmute & mask) ) {
	    SEQ_LCD_PrintFormattedString("U%3d ", remaining_steps);
	  } else {
	    SEQ_LCD_PrintString("Mute ");
	  }
	} else {
	  if( !seq_ui_button_state.SELECT_PRESSED && (seq_core_trk_synched_mute & mask) ) {
	    SEQ_LCD_PrintFormattedString("M%3d ", remaining_steps);
	  } else {
	    SEQ_LCD_PrintHBar(t->vu_meter >> 3);
	  }
	}
    }
  } else {
示例#12
0
	    SEQ_LCD_PrintString("Mute ");
	  }
	} else {
	  if( !seq_ui_button_state.SELECT_PRESSED && (seq_core_trk_synched_mute & mask) ) {
	    SEQ_LCD_PrintFormattedString("M%3d ", remaining_steps);
	  } else {
	    SEQ_LCD_PrintHBar(t->vu_meter >> 3);
	  }
	}
    }
  } else {
    ///////////////////////////////////////////////////////////////////////////
    SEQ_LCD_CursorSet(0, 0);

    u8 track;
    u8 visible_track = SEQ_UI_VisibleTrackGet();
    u8 event_mode = SEQ_CC_Get(visible_track, SEQ_CC_MIDI_EVENT_MODE);
    u8 num_layers = (event_mode == SEQ_EVENT_MODE_Drum) ? SEQ_TRG_NumInstrumentsGet(visible_track) : SEQ_PAR_NumLayersGet(visible_track);

    for(track=0; track<16; ++track) {
      if( ui_cursor_flash && seq_ui_button_state.SELECT_PRESSED )
	SEQ_LCD_PrintSpaces(5);
      else {
	if( seq_ui_button_state.MUTE_PRESSED ) {
	  if( track >= num_layers )
	    SEQ_LCD_PrintSpaces(5);
	  else {
	    if( event_mode == SEQ_EVENT_MODE_Drum )
	      SEQ_LCD_PrintTrackDrum(visible_track, track, (char *)seq_core_trk[visible_track].name);
	    else
	      SEQ_LCD_PrintString(SEQ_PAR_AssignedTypeStr(visible_track, track));
/////////////////////////////////////////////////////////////////////////////
// Local encoder callback function
// Should return:
//   1 if value has been changed
//   0 if value hasn't been changed
//  -1 if invalid or unsupported encoder
/////////////////////////////////////////////////////////////////////////////
static s32 Encoder_Handler(seq_ui_encoder_t encoder, s32 incrementer)
{
  u8 visible_track = SEQ_UI_VisibleTrackGet();
  int num_steps = SEQ_TRG_NumStepsGet(visible_track);
  int track_length = (int)SEQ_CC_Get(visible_track, SEQ_CC_LENGTH) + 1;

#if 0
  // leads to: comparison is always true due to limited range of data type
  if( (encoder >= SEQ_UI_ENCODER_GP1 && encoder <= SEQ_UI_ENCODER_GP16) ) {
#else
  if( encoder <= SEQ_UI_ENCODER_GP16 ) {
#endif
    if( seq_ui_button_state.SELECT_PRESSED ) {
      int section;
      if( num_steps > 128 )
	section = encoder / (track_length / 16);
      else if( num_steps > 64 )
	section = encoder / ((2 * track_length) / 16);
      else
	section = encoder / ((4 * track_length) / 16);

      // operation should be atomic (change all selected tracks)
      u8 track;
      seq_core_trk_t *t = &seq_core_trk[0];
      MIOS32_IRQ_Disable();
      for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track, ++t)
	if( ui_selected_tracks & (1 << track) )
	  t->play_section = section;
      MIOS32_IRQ_Enable();
    } else {
      // won't work if Follow function active!
      if( seq_core_state.FOLLOW ) {
	// print message and exit
	SEQ_UI_Msg((encoder <= SEQ_UI_ENCODER_GP8) ? SEQ_UI_MSG_USER : SEQ_UI_MSG_USER_R, 2000, "\"Follow\" active!", "Please deactivate!");
	return 1;
      }
    }

    // select new step view
    ui_selected_step_view = (encoder * (num_steps/16)) / 16;

    // select step within view
    if( !seq_ui_button_state.CHANGE_ALL_STEPS ) { // don't change the selected step if ALL function is active, otherwise the ramp can't be changed over multiple views
      ui_selected_step = (ui_selected_step_view << 4) | (ui_selected_step & 0xf);
    }

    if( seq_hwcfg_button_beh.step_view ) {
      // if toggle function active: jump back to previous menu
      // this is especially useful for the emulated MBSEQ, where we can only click on a single button
      // (stepview gets deactivated when clicking on GP button)
      if( seq_ui_button_state.STEP_VIEW ) {
	seq_ui_button_state.STEP_VIEW = 0;
	SEQ_UI_PageSet(ui_stepview_prev_page);
      }
    }

    return 1; // value changed
  } else if( encoder == SEQ_UI_ENCODER_Datawheel ) {
    if( SEQ_UI_Var8_Inc(&ui_selected_step_view, 0, (num_steps-1)/16, incrementer) >= 1 ) {
      // select step within view
      if( !seq_ui_button_state.CHANGE_ALL_STEPS ) { // don't change the selected step if ALL function is active, otherwise the ramp can't be changed over multiple views
	ui_selected_step = (ui_selected_step_view << 4) | (ui_selected_step & 0xf);
      }
    } else {
      return 0;
    }
  }

  return -1; // invalid or unsupported encoder
}


/////////////////////////////////////////////////////////////////////////////
// Local button callback function
// Should return:
//   1 if value has been changed
//   0 if value hasn't been changed
//  -1 if invalid or unsupported button
/////////////////////////////////////////////////////////////////////////////
static s32 Button_Handler(seq_ui_button_t button, s32 depressed)
{
  if( depressed ) return 0; // ignore when button depressed

#if 0
  // leads to: comparison is always true due to limited range of data type
  if( button >= SEQ_UI_BUTTON_GP1 && button <= SEQ_UI_BUTTON_GP16 ) {
#else
  if( button <= SEQ_UI_BUTTON_GP16 ) {
#endif
    // -> same handling like for encoders
    return Encoder_Handler(button, 0);
  }

  switch( button ) {
    case SEQ_UI_BUTTON_Select:
      return 1; // selects section mode, checked via seq_ui_button_state.SELECT_PRESSED

    case SEQ_UI_BUTTON_Right:
    case SEQ_UI_BUTTON_Up:
      if( depressed ) return 0; // ignore when button depressed
      return Encoder_Handler(SEQ_UI_ENCODER_Datawheel, 1);

    case SEQ_UI_BUTTON_Left:
    case SEQ_UI_BUTTON_Down:
      if( depressed ) return 0; // ignore when button depressed
      return Encoder_Handler(SEQ_UI_ENCODER_Datawheel, -1);
  }

  return -1; // invalid or unsupported button
}


/////////////////////////////////////////////////////////////////////////////
// Local Display Handler function
// IN: <high_prio>: if set, a high-priority LCD update is requested
/////////////////////////////////////////////////////////////////////////////
static s32 LCD_Handler(u8 high_prio)
{
  // layout:
  // 00000000001111111111222222222233333333330000000000111111111122222222223333333333
  // 01234567890123456789012345678901234567890123456789012345678901234567890123456789
  // <--------------------------------------><-------------------------------------->
  // 1                   17                  33                  49
  // *... *... *... *... *... *... *... *... *... *... *... *... *... *... *... *... 


  // 5 character usage in 256 step view (5 chars have to display 16 steps, 8 special chars available,
  // due to this limitation, we only display 15 steps (shouldn't really hurt))
  // 43210 43210 43210 43210 43210
  // * * * * . . . * . . . * . . .  (Small charset)

  // 5 character usage in 128 step view (5 chars have to display 8 steps):
  // 43210 43210 43210 43210 43210
  //  * *   . *   * .   . .         (Medium charset)

  // 5 character usage in 64 step view (5 chars have to display 4 steps):
  // 43210 43210 43210 43210 43210
  //   *     *     *     *     *    (Big charset)

  u8 visible_track = SEQ_UI_VisibleTrackGet();
  u8 event_mode = SEQ_CC_Get(visible_track, SEQ_CC_MIDI_EVENT_MODE);
  int num_steps = SEQ_TRG_NumStepsGet(visible_track);
  int steps_per_item = num_steps / 16;
  int played_step = SEQ_BPM_IsRunning() ? seq_core_trk[visible_track].step : -1;

  int i;

  if( !high_prio ) {
    SEQ_LCD_CursorSet(0, 0);
    for(i=0; i<16; ++i)
      if( ((i*steps_per_item) % 16) || ((((i*steps_per_item)/16) == ui_selected_step_view) && ui_cursor_flash) )
	SEQ_LCD_PrintSpaces(5);
      else
	SEQ_LCD_PrintFormattedString("%-3d  ", i*steps_per_item+1);

    // print flashing *LOOPED* at right corner if loop mode activated to remind that steps will be played differntly
    if( (ui_cursor_flash_overrun_ctr & 1) && seq_core_state.LOOP ) {
      SEQ_LCD_CursorSet(71, 0);
      SEQ_LCD_PrintString(" *LOOPED*");
    } else if( (ui_cursor_flash_overrun_ctr & 1) && seq_core_trk[visible_track].play_section > 0 ) {
      SEQ_LCD_CursorSet(71, 0);
      SEQ_LCD_PrintFormattedString(" *Sect.%c*", 'A'+seq_core_trk[visible_track].play_section);
    } else {
      if( event_mode == SEQ_EVENT_MODE_Drum ) {
	// print drum name at the rightmost side
	SEQ_LCD_CursorSet(75, 0);
	SEQ_LCD_PrintTrackDrum(visible_track, ui_selected_instrument, (char *)seq_core_trk[visible_track].name);
      } else {
	// print trigger layer and name at the rightmost side
	SEQ_LCD_CursorSet(73, 0);
	SEQ_LCD_PrintFormattedString("%c:%s", 'A' + ui_selected_trg_layer, SEQ_TRG_AssignedTypeStr(visible_track, ui_selected_trg_layer));
      }
    }
  }

  SEQ_LCD_CursorSet(0, 1);

  if( steps_per_item > 8 ) {
    SEQ_LCD_InitSpecialChars(SEQ_LCD_CHARSET_DrumSymbolsSmall);

    for(i=0; i<16; ++i) {
      u16 step = i*steps_per_item;
      u8 step8 = step / 8;

      u8 layer = (event_mode == SEQ_EVENT_MODE_Drum) ? 0 : ui_selected_trg_layer;
      u16 steps = (SEQ_TRG_Get8(visible_track, step8+1, layer, ui_selected_instrument) << 8) |
	          (SEQ_TRG_Get8(visible_track, step8+0, layer, ui_selected_instrument) << 0);

      if( played_step >= step && played_step < (step+16) )
	steps ^= (1 << (played_step % 16));

      int j;
      for(j=0; j<5; ++j) {
	SEQ_LCD_PrintChar(steps & 0x7);
	steps >>= 3;
      }
    }
  } else if( steps_per_item > 4 ) {
示例#14
0
/////////////////////////////////////////////////////////////////////////////
// Receives a MIDI package from APP_NotifyReceivedEvent (-> app.c)
/////////////////////////////////////////////////////////////////////////////
s32 SEQ_MIDI_IN_Receive(mios32_midi_port_t port, mios32_midi_package_t midi_package)
{
  s32 status = 0;

  // check if we should record this event
  u8 should_be_recorded =
    ui_page == SEQ_UI_PAGE_TRKREC &&
    ((!seq_midi_in_rec_port || port == seq_midi_in_rec_port) &&
     midi_package.chn == (seq_midi_in_rec_channel-1));

  // search for matching ports
  // status[0] set if at least one port matched
  // status[1] set if remote function active
  int bus;
  for(bus=0; bus<SEQ_MIDI_IN_NUM_BUSSES; ++bus) {
    // filter MIDI port (if 0: no filter, listen to all ports)
    if( (!seq_midi_in_port[bus] || port == seq_midi_in_port[bus]) &&
	midi_package.chn == (seq_midi_in_channel[bus]-1) ) {

      switch( midi_package.event ) {
      case NoteOff: 
	if( remote_active ) {
	  if( seq_hwcfg_midi_remote.key && midi_package.note == seq_hwcfg_midi_remote.key ) {
	    remote_active = 0;

	    // send "button depressed" state to all remote functions
	    int i;
	    for(i=0; i<128; ++i)
	      SEQ_UI_REMOTE_MIDI_Keyboard(i, 1); // depressed
	  } else {
	    SEQ_UI_REMOTE_MIDI_Keyboard(midi_package.note, 1); // depressed
	  }
	  status |= 2;
	} else {
	  if( !should_be_recorded &&
	      midi_package.note >= seq_midi_in_lower[bus] &&
	      (!seq_midi_in_upper[bus] || midi_package.note <= seq_midi_in_upper[bus]) ) {
	    if( seq_midi_in_options[bus].MODE_PLAY ) {
	      MUTEX_MIDIOUT_TAKE;
	      SEQ_CORE_PlayLive(SEQ_UI_VisibleTrackGet(), midi_package);
	      MUTEX_MIDIOUT_GIVE;
	    } else {
#if 0
	      // octave normalisation - too complicated for normal users...
	      mios32_midi_package_t p = midi_package;
	      if( seq_midi_in_lower[bus] ) { // normalize to first octave
		int normalized_note = 0x30 + p.note - ((int)seq_midi_in_lower[bus]/12)*12;
		while( normalized_note > 127 ) normalized_note -= 12;
		while( normalized_note < 0 ) normalized_note += 12;
		p.note = normalized_note;
	      }
	      SEQ_MIDI_IN_BusReceive(0xf0+bus, p, 0);
#else
	      SEQ_MIDI_IN_BusReceive(0xf0+bus, midi_package, 0);
#endif
	    }
	    status |= 1;
	  }
	}
	break;

      case NoteOn:
	if( remote_active )
	  SEQ_UI_REMOTE_MIDI_Keyboard(midi_package.note, midi_package.velocity ? 0 : 1); // depressed
	else {
	  if( seq_hwcfg_midi_remote.key && midi_package.note == seq_hwcfg_midi_remote.key ) {
	    remote_active = 1;
	    status |= 2;
	  } else {
	    if( !should_be_recorded &&
		midi_package.note >= seq_midi_in_lower[bus] &&
		(!seq_midi_in_upper[bus] || midi_package.note <= seq_midi_in_upper[bus]) ) {
	      if( seq_midi_in_options[bus].MODE_PLAY ) {
		MUTEX_MIDIOUT_TAKE;
		SEQ_CORE_PlayLive(SEQ_UI_VisibleTrackGet(), midi_package);
		MUTEX_MIDIOUT_GIVE;
	      } else {
#if 0
		// octave normalisation - too complicated for normal users...
		mios32_midi_package_t p = midi_package;
		if( seq_midi_in_lower[bus] ) { // normalize to first octave
		  int normalized_note = 0x30 + p.note - ((int)seq_midi_in_lower[bus]/12)*12;
		  while( normalized_note > 127 ) normalized_note -= 12;
		  while( normalized_note < 0 ) normalized_note += 12;
		  p.note = normalized_note;
		}
		SEQ_MIDI_IN_BusReceive(0xf0+bus, p, 0);
#else
		SEQ_MIDI_IN_BusReceive(0xf0+bus, midi_package, 0);
#endif
	      }
	      status |= 1;
	    }
	  }
	}
	break;

      case CC:
	if( !should_be_recorded ) {
	  if( seq_midi_in_options[bus].MODE_PLAY ) {
	    MUTEX_MIDIOUT_TAKE;
	    SEQ_CORE_PlayLive(SEQ_UI_VisibleTrackGet(), midi_package);
	    MUTEX_MIDIOUT_GIVE;
	  } else {
	    SEQ_MIDI_IN_BusReceive(0xf0+bus, midi_package, 0);
	  }
	}
	status |= 1;
	break;

      default:
	if( seq_midi_in_options[bus].MODE_PLAY ) {
	  MUTEX_MIDIOUT_TAKE;
	  SEQ_CORE_PlayLive(SEQ_UI_VisibleTrackGet(), midi_package);
	  MUTEX_MIDIOUT_GIVE;
	}
      }
    }
  }


  // record function
  if( !(status & 2) && should_be_recorded ) {
    SEQ_RECORD_Receive(midi_package, SEQ_UI_VisibleTrackGet());
  }

  // Section Changer
  if( !(status & 2) &&
      (seq_midi_in_sect_port && port == seq_midi_in_sect_port &&
       midi_package.chn == (seq_midi_in_sect_channel-1)) ) {
    u8 forward_event = 1;

    switch( midi_package.event ) {
      case NoteOff: 
	MUTEX_MIDIIN_TAKE;
	if( (status = SEQ_MIDI_IN_Receive_NoteSC(midi_package.note, 0x00)) >= 1 )
	  forward_event = 0;
	MUTEX_MIDIIN_GIVE;
	break;

      case NoteOn:
	MUTEX_MIDIIN_TAKE;
	if( (status = SEQ_MIDI_IN_Receive_NoteSC(midi_package.note, midi_package.velocity)) >= 1 )
	  forward_event = 0;
	MUTEX_MIDIIN_GIVE;
	break;
    }

    if( seq_midi_in_sect_fwd_port && forward_event ) { // octave hasn't been taken, optionally forward to forwarding port
      MUTEX_MIDIOUT_TAKE;
      MIOS32_MIDI_SendPackage(seq_midi_in_sect_fwd_port, midi_package);
      MUTEX_MIDIOUT_GIVE;
    }
  }

#if PATCH_CHANGER_ENABLED
  // Patch Changer (currently assigned to channel+1)
  if( !(status & 2) &&
      (seq_midi_in_sect_port && port == seq_midi_in_sect_port &&
       midi_package.chn == (seq_midi_in_sect_channel)) ) {
    u8 forward_event = 1;

    switch( midi_package.event ) {
      case NoteOff: 
	MUTEX_MIDIIN_TAKE;
	if( (status = SEQ_MIDI_IN_Receive_NotePC(midi_package.note, 0x00)) >= 1 )
	  forward_event = 0;
	MUTEX_MIDIIN_GIVE;
	break;

      case NoteOn:
	MUTEX_MIDIIN_TAKE;
	if( (status = SEQ_MIDI_IN_Receive_NotePC(midi_package.note, midi_package.velocity)) >= 1 )
	  forward_event = 0;
	MUTEX_MIDIIN_GIVE;
	break;
    }

    if( seq_midi_in_sect_fwd_port && forward_event ) { // octave hasn't been taken, optionally forward to forwarding port
      MUTEX_MIDIOUT_TAKE;
      MIOS32_MIDI_SendPackage(seq_midi_in_sect_fwd_port, midi_package);
      MUTEX_MIDIOUT_GIVE;
    }
  }
#endif

  return status;
}
/////////////////////////////////////////////////////////////////////////////
// Local button callback function
// Should return:
//   1 if value has been changed
//   0 if value hasn't been changed
//  -1 if invalid or unsupported button
/////////////////////////////////////////////////////////////////////////////
static s32 Button_Handler(seq_ui_button_t button, s32 depressed)
{

  if( SEQ_FILE_FormattingRequired() )
    return 0; // no button action as long as files not available
	
	u8 group;
	s32 status;
	
  switch( button ) {
		
		case SEQ_UI_BUTTON_Edit: {
			
			
			if ( depressed && (selected_page == PAGE_REMIX) ) {
					
				// we want to show vertical VU meters normal mode
				SEQ_LCD_InitSpecialChars(SEQ_LCD_CHARSET_VBars);
				
				selected_page = PAGE_MAIN;		
				
				//
				// here we run the commands for remix states
				//
				u16 remix_map_tmp;
				
				// if we are in no preview_mode them call the demix procedment in case we got some request
				if ( (seq_pattern_remix_map != seq_pattern_demix_map) && ( remix_mode ) ) {
					remix_map_tmp = seq_pattern_remix_map;
					seq_pattern_remix_map = ~(seq_pattern_remix_map ^ seq_pattern_demix_map);
					
          if (ableton_api) {
						
            // TODO: implements a ableton remotescript to the clip control functionality
						
						u8 track;
						for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track) {
						 
						 // if we got the track bit setup inside our remix_map, them do not send mixer data for that track channel, let it be mixed down
						 if ( ((1 << track) | seq_pattern_remix_map) == seq_pattern_remix_map ) {
							 // do nothing...
						 } else {
							 // delay our task for ableton get a breath before change the pattern line
							 vTaskDelay(50);
							 // send slot play envet to ableton: cc (111 + track) with value 127 to channel 16
							 MIOS32_MIDI_SendCC(ableton_port, 15, (111 + track), 127);
						 }
						 
						}           
						
          }
					
					// if we are in remix mode lets start the process
					if (remix_map_tmp == 0) {
												
						//pattern_name = pattern_name_remix;
						preview_mode = 0;
						remix_mode = 0;
						// set the pattern_remix_timer reference
						pattern_remix_timer = MIOS32_SYS_TimeGet();
						
					}
					
					// Change Pattern
					u8 group;
					for(group=0; group<SEQ_CORE_NUM_GROUPS; ++group) {
						// change pattern
						SEQ_PATTERN_Change(group, seq_pattern[group], 0);
					}
					
					// copy the pattern name for future reference
					sprintf(pattern_name, seq_pattern_name[0]);
					
					// getting back
					seq_pattern_remix_map = remix_map_tmp;
					seq_pattern_demix_map = seq_pattern_remix_map;
					
				}
				
			} else if ( !depressed ) {		
				
				// we want to show horizontal VU meters in remix mode
				SEQ_LCD_InitSpecialChars(SEQ_LCD_CHARSET_HBars);
				
				selected_page = PAGE_REMIX;
			}
				
			return 1;	
				
		} break;				
			
    case SEQ_UI_BUTTON_Select: {
			
      if(!depressed) {
        selected_page = PAGE_OPTION;
        return 1;
      }
			
      if( (depressed) && (selected_page == PAGE_OPTION) ) {
        selected_page = PAGE_MAIN;
      }
			
		} break;
			
		default:
			break;
			
			
  }

  if( depressed ) return 0; // ignore when button depressed if its not SEQ_UI_BUTTON_Select or SEQ_UI_BUTTON_Edit
	
  switch( selected_page ) {

    ///////////////////////////////////////////////////////////////////////////
    // REMIX PAGE
    case PAGE_REMIX: {

      if( button <= SEQ_UI_BUTTON_GP16 ) {
        // re-using encoder routine
        return Encoder_Handler(button, 0);
      }			
			
    } break;

    ///////////////////////////////////////////////////////////////////////////
    // OPTION PAGE
    case PAGE_OPTION: {

      switch( button ) {

        case SEQ_UI_BUTTON_GP1:
          // Save Pattern(all 4 groups at once)
          for(group=0; group<SEQ_CORE_NUM_GROUPS; ++group) {
						
            if( (status=SEQ_PATTERN_Save(group, seq_pattern[group])) < 0 ) {
              SEQ_UI_SDCardErrMsg(2000, status);
              return 0;
            }
						
          }
					
          // Save the pattern mixer
          SEQ_MIXER_Save(SEQ_MIXER_NumGet());
					
          break;

        case SEQ_UI_BUTTON_GP2:
          // Edit Pattern Name
					//SEQ_LCD_Clear();
          selected_page = PAGE_NAME_EDIT;
          break;

        case SEQ_UI_BUTTON_GP3:
          // Copy Pattern
					// We are going to use the multicopy procedure
					SEQ_UI_PATTERN_Copy();

					// coping mixer
					SEQ_UI_MIXER_Copy();

          break;

        case SEQ_UI_BUTTON_GP4:
          // Paste Pattern
					// We are going to use the multicopy procedure
					SEQ_UI_PATTERN_Paste();

					// paste mixer
					SEQ_UI_MIXER_Paste();
			
          break;

        case SEQ_UI_BUTTON_GP5:
        case SEQ_UI_BUTTON_GP6:
          return -1; // not mapped

        case SEQ_UI_BUTTON_GP7:
        case SEQ_UI_BUTTON_GP8:
          // Track Delay Page
					//SEQ_LCD_Clear();
          //selected_page = PAGE_TRK_DELAY;
          //break;
					return -1; // not mapped

        case SEQ_UI_BUTTON_GP9:
        case SEQ_UI_BUTTON_GP10:
					return -1; // not mapped

        case SEQ_UI_BUTTON_GP11:
        case SEQ_UI_BUTTON_GP12:
					return -1; // not mapped

        case SEQ_UI_BUTTON_GP13:
        case SEQ_UI_BUTTON_GP14:
          // Auto Save switch
          auto_save ^= 1;
          break;
          break;

        case SEQ_UI_BUTTON_GP15:
        case SEQ_UI_BUTTON_GP16:
					// Ableton API switch
          ableton_api ^= 1;
          return -1; // not mapped
      }

      return 0;

    } break;

    ///////////////////////////////////////////////////////////////////////////
    // PATTERN NAME EDIT PAGE
    case PAGE_NAME_EDIT: {

      return Encoder_Handler((seq_ui_encoder_t)button, 0);

    } break;

    ///////////////////////////////////////////////////////////////////////////
    // TRACK DELAY PAGE
    case PAGE_TRK_DELAY: {

    } break;

    ///////////////////////////////////////////////////////////////////////////
    // MAIN PAGE
    case PAGE_MAIN: {

      // Pattern Change Group Requests
      if( button <= SEQ_UI_BUTTON_GP8 ) {

        u8 group;
				
        for(group=0; group<SEQ_CORE_NUM_GROUPS; ++group) {
          if( selected_pattern[group].group == button ) {
            if( SEQ_FILE_B_NumPatterns(selected_pattern[group].bank) > 64 ) {
              selected_pattern[group].lower ^= 1;
            } else {
              selected_pattern[group].lower = 0; // toggling not required
            }
          } else {
            selected_pattern[group].group = button;
            preview_bank = button;
            //preview_mode = 0;
          }
        }
				
				SEQ_PATTERN_PeekName(selected_pattern[0], preview_name);
				preview_mode = 1;
				
        return 1; // value always changed
      }

      // Pattern Change Request
      if( button >= SEQ_UI_BUTTON_GP9 && button <= SEQ_UI_BUTTON_GP16 ) {

        //u8 group;

        s32 status = 0;

        // setting save patterns for later autosave procedure
        //for(group=0; group<SEQ_CORE_NUM_GROUPS; ++group)
        //  save_pattern[group] = seq_pattern[group];
				
        // change preview pattern
        selected_pattern[0].num = button-8;
        selected_pattern[1].num = button-8;
        selected_pattern[2].num = button-8;
        selected_pattern[3].num = button-8;

        if ( !preview_mode )
        {
          preview_num = button-8;
          SEQ_PATTERN_PeekName(selected_pattern[0], preview_name);
          preview_mode = 1;
					
					// for security reasons in live environment, we can not accept rapid 2x press of pattern button.
					// if the buttons are not good quality they can send a 2x rapid signal os pressing in just one physical pressing
					// the time we need is bassicly the human time to read the name of patterns requested
			    // start time in count
			    pc_time_control = seq_core_timestamp_ms + 200;
					// vTaksDelay(200);
        } else {

					// 
					if ( remix_mode == 0 ) {
					
						//char str[30];
						//sprintf(str, "%d = %d %d = %d", selected_pattern[0].num, preview_num, selected_pattern[0].group, preview_bank);
						//SEQ_UI_Msg(SEQ_UI_MSG_USER, 2000, str, "debug");
						
						// Check for remix state
						if ( (selected_pattern[0].num == preview_num) &&  (selected_pattern[0].group == preview_bank) ) {
						
							//if ( pc_time_control >= seq_core_timestamp_ms )
							//	return 0; // do nothing, just to be shure we are not handle acidental double clicks, it happens!					
							
							// if we got some remix bit setup, enter in remix mode
							if (seq_pattern_remix_map != 0) {
								// set the remix mode
								remix_mode = 1;
							}
						
						}
						
					}
					
          // Change Pattern
          if ( (selected_pattern[0].num == preview_num) &&  (selected_pattern[0].group == preview_bank) ) {

  	        if ( pc_time_control >= seq_core_timestamp_ms )
	            return 0; // do nothing, just to be shure we are not handle acidental double clicks

						if (ableton_api) {
							
							u8 ableton_pattern_number = 0;
							
							//
							// ABLETON API PATTERN CHANGE HANDLE
							//
							// send ableton event to change the line clips
							if (selected_pattern[0].lower) {
						  	ableton_pattern_number = ((selected_pattern[0].group - 1) * 8) + button;
							} else {
						  	ableton_pattern_number = (((selected_pattern[0].group - 1) + 8) * 8) + button;
							}
							
							// midi_cc to send = 110
							// midi_chn = 16
							// midi_port = ableton_port
							// here we need to send a clip line change request
							MIOS32_MIDI_SendCC(ableton_port, 15, 110, ableton_pattern_number);
						
							// delay our task for ableton get a breath before change the pattern line
							vTaskDelay(50);

							// clip triggering
							u8 track;
            	for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track) {
              
              	// if we got the track bit setup inside our remix_map, them do not send mixer data for that track channel, let it be mixed down
              	if ( ((1 << track) | seq_pattern_remix_map) == seq_pattern_remix_map ) {
                	// do nothing...
              	} else {
									// delay our task for ableton get a breath before change the pattern line
									vTaskDelay(50);									
									// send clip slot play envet to ableton cc (111 + track) with value 127 to channel 16
                	MIOS32_MIDI_SendCC(ableton_port, 15, (111 + track), 127);
              	}
              
            	}           

							// send a global clip change(all clips in the clip line)	
							// send play envet to ableton cc 20 with value 127 to channel 16
							//MIOS32_MIDI_SendCC(ableton_port, 15, 20, 127);

						}
						
						//
						// Autosave Pattern
						//
						if (auto_save) {
							
							// Autosave all 4 group of patterns
							for(group=0; group<SEQ_CORE_NUM_GROUPS; ++group) {
								
								// Save to SD Card
								if( (status=SEQ_PATTERN_Save(group, seq_pattern[group])) < 0 ) {
									SEQ_UI_SDCardErrMsg(2000, status);
								}
								
							}
							
							// Autosave Mixer Map
							SEQ_MIXER_Save(SEQ_MIXER_NumGet());
							
						}							
						
						// if we are not in remix mode 
						if (seq_pattern_remix_map == 0) {
							
							// keep the name of old pattern(because we still got 1 or more tracks belongs to this pattern)
							//pattern_name = seq_pattern_name;
							// set timer for mixed pattern
							pattern_remix_timer = MIOS32_SYS_TimeGet();
						}								
						
						//
						// Pattern change request
						//
            for(group=0; group<SEQ_CORE_NUM_GROUPS; ++group) {

              // change pattern
              //selected_pattern[group].num = button-8;
              SEQ_PATTERN_Change(group, selected_pattern[group], 0);

							//if ( remix_mode ) {
								// keep the pattern name...
								//sprintf(seq_pattern_name[group], pattern_name);
							//}
							
            }
						
						if ( !remix_mode ) {
							// copy the pattern name for future reference
							//sprintf(pattern_name, seq_pattern_name[0]);	
							SEQ_PATTERN_PeekName(selected_pattern[0], pattern_name);
							// TODO: sync this with the pattern change handled by SEQ_PATTERN_Handler()
							//pattern_timer.seconds = 0;		
							preview_mode = 0;
						}
						
						// support for demix
            seq_pattern_demix_map = seq_pattern_remix_map;

            //preview_mode = 0;
						
          // Request a Pattern Preview
          } else {
            preview_num = button-8;
            SEQ_PATTERN_PeekName(selected_pattern[0], preview_name);

        	  // for security reasons in live environment, we can not accept 2x rapid press of pattern button.
      	    // if the buttons are not good quality they can send a 2x rapid signal os pressing in just one physical pressing
    	      // the time we need is bassicly the human time to read the name of patterns requested
  	        // start time in count
	          pc_time_control = seq_core_timestamp_ms + 200;

          }

        }			
				
        return 1; // value always changed
      }

      u8 visible_track = SEQ_UI_VisibleTrackGet();

      switch( button ) {

        case SEQ_UI_BUTTON_Right:
          // switch to next track
          if( visible_track < (SEQ_CORE_NUM_TRACKS - 1) )
            visible_track++;
					
          ui_selected_tracks = (1 << visible_track);
          ui_selected_group = visible_track / 4;

          return 1; // value always changed

        case SEQ_UI_BUTTON_Left:
          // switch to previous track
          if( visible_track >= 1 )
            visible_track--;
					
          ui_selected_tracks = (1 << visible_track);
          ui_selected_group = visible_track / 4;

          return 1; // value always changed

        case SEQ_UI_BUTTON_Up:
          return Encoder_Handler(SEQ_UI_ENCODER_Datawheel, 1);

        case SEQ_UI_BUTTON_Down:
          return Encoder_Handler(SEQ_UI_ENCODER_Datawheel, -1);
      }

      return -1; // invalid or unsupported button

    } break;

    ///////////////////////////////////////////////////////////////////////////
    // Page do not exist
    default:
      break;

  }
	
	return 0;

}
/////////////////////////////////////////////////////////////////////////////
// Local button callback function
// Should return:
//   1 if value has been changed
//   0 if value hasn't been changed
//  -1 if invalid or unsupported button
/////////////////////////////////////////////////////////////////////////////
static s32 Button_Handler(seq_ui_button_t button, s32 depressed)
{
  if( depressed ) return 0; // ignore when button depressed

#if 0
  // leads to: comparison is always true due to limited range of data type
  if( button >= SEQ_UI_BUTTON_GP1 && button <= SEQ_UI_BUTTON_GP16 ) {
#else
  if( button <= SEQ_UI_BUTTON_GP16 ) {
#endif
    // re-use encoder handler - only select UI item, don't increment
    return Encoder_Handler((int)button, 0);
  }

  // remaining buttons:
  switch( button ) {
    case SEQ_UI_BUTTON_Select:
    case SEQ_UI_BUTTON_Right:
      if( ++ui_selected_item >= NUM_OF_ITEMS )
	ui_selected_item = 0;
      return 1; // value always changed

    case SEQ_UI_BUTTON_Left:
      if( ui_selected_item == 0 )
	ui_selected_item = NUM_OF_ITEMS-1;
      else
	--ui_selected_item;
      return 1; // value always changed

    case SEQ_UI_BUTTON_Up:
      return Encoder_Handler(SEQ_UI_ENCODER_Datawheel, 1);

    case SEQ_UI_BUTTON_Down:
      return Encoder_Handler(SEQ_UI_ENCODER_Datawheel, -1);
  }

  return -1; // invalid or unsupported button
}


/////////////////////////////////////////////////////////////////////////////
// Local Display Handler function
// IN: <high_prio>: if set, a high-priority LCD update is requested
/////////////////////////////////////////////////////////////////////////////
static s32 LCD_Handler(u8 high_prio)
{
  if( high_prio )
    return 0; // there are no high-priority updates

  // layout:
  // 00000000001111111111222222222233333333330000000000111111111122222222223333333333
  // 01234567890123456789012345678901234567890123456789012345678901234567890123456789
  // <--------------------------------------><-------------------------------------->
  // Trk.        Repeats   Delay   Vel.Level  FB Velocity  Note   Gatelen.    Ticks  
  // GxTy           3       1/16      75%        120%       + 0     100%       100%

  u8 visible_track = SEQ_UI_VisibleTrackGet();

  ///////////////////////////////////////////////////////////////////////////
  SEQ_LCD_CursorSet(0, 0);
  SEQ_LCD_PrintString("Trk.        Repeats   Delay   Vel.Level  FB Velocity  Note   Gatelen.    Ticks  ");

  ///////////////////////////////////////////////////////////////////////////
  SEQ_LCD_CursorSet(0, 1);

  if( ui_selected_item == ITEM_GXTY && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(4);
  } else {
    SEQ_LCD_PrintGxTy(ui_selected_group, ui_selected_tracks);
  }
  SEQ_LCD_PrintSpaces(10);

  ///////////////////////////////////////////////////////////////////////////

  if( ui_selected_item == ITEM_REPEATS && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(2);
  } else {
    SEQ_LCD_PrintFormattedString("%2d", SEQ_CC_Get(visible_track, SEQ_CC_ECHO_REPEATS));
  }
  SEQ_LCD_PrintSpaces(7);

  ///////////////////////////////////////////////////////////////////////////

  if( ui_selected_item == ITEM_DELAY && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(4);
  } else {
    SEQ_LCD_PrintString((char *)SEQ_CORE_Echo_GetDelayModeName(SEQ_CC_Get(visible_track, SEQ_CC_ECHO_DELAY)));
  }
  SEQ_LCD_PrintSpaces(6);

  ///////////////////////////////////////////////////////////////////////////

  if( ui_selected_item == ITEM_VELOCITY && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(4);
  } else {
    SEQ_LCD_PrintFormattedString("%3d%%", 5*SEQ_CC_Get(visible_track, SEQ_CC_ECHO_VELOCITY));
  }
  SEQ_LCD_PrintSpaces(2);

  ///////////////////////////////////////////////////////////////////////////

  SEQ_LCD_CursorSet(40, 1);
  SEQ_LCD_PrintSpaces(4);

  if( ui_selected_item == ITEM_FB_VELOCITY && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(4);
  } else {
    SEQ_LCD_PrintFormattedString("%3d%%", 5*SEQ_CC_Get(visible_track, SEQ_CC_ECHO_FB_VELOCITY));
  }
  SEQ_LCD_PrintSpaces(7);

  ///////////////////////////////////////////////////////////////////////////

  if( ui_selected_item == ITEM_FB_NOTE && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(3);
  } else {
    u8 note_delta = SEQ_CC_Get(visible_track, SEQ_CC_ECHO_FB_NOTE);
    if( note_delta < 24 )
      SEQ_LCD_PrintFormattedString("-%2d", 24-note_delta);
    else if( note_delta < 49 )
      SEQ_LCD_PrintFormattedString("+%2d", note_delta-24);
    else
      SEQ_LCD_PrintString("Rnd");
  }
  SEQ_LCD_PrintSpaces(5);

  ///////////////////////////////////////////////////////////////////////////

  if( ui_selected_item == ITEM_FB_GATELENGTH && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(4);
  } else {
    SEQ_LCD_PrintFormattedString("%3d%%", 5*SEQ_CC_Get(visible_track, SEQ_CC_ECHO_FB_GATELENGTH));
  }
  SEQ_LCD_PrintSpaces(7);

  ///////////////////////////////////////////////////////////////////////////

  if( ui_selected_item == ITEM_FB_TICKS && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(4);
  } else {
    SEQ_LCD_PrintFormattedString("%3d%%", 5*SEQ_CC_Get(visible_track, SEQ_CC_ECHO_FB_TICKS));
  }
  SEQ_LCD_PrintSpaces(2);


  return 0; // no error
}


/////////////////////////////////////////////////////////////////////////////
// Initialisation
/////////////////////////////////////////////////////////////////////////////
s32 SEQ_UI_FX_ECHO_Init(u32 mode)
{
  // install callback routines
  SEQ_UI_InstallButtonCallback(Button_Handler);
  SEQ_UI_InstallEncoderCallback(Encoder_Handler);
  SEQ_UI_InstallLEDCallback(LED_Handler);
  SEQ_UI_InstallLCDCallback(LCD_Handler);

  return 0; // no error
}
示例#17
0
/////////////////////////////////////////////////////////////////////////////
// Local button callback function
// Should return:
//   1 if value has been changed
//   0 if value hasn't been changed
//  -1 if invalid or unsupported button
/////////////////////////////////////////////////////////////////////////////
static s32 Button_Handler(seq_ui_button_t button, s32 depressed)
{
  if( depressed ) return 0; // ignore when button depressed

  u8 visible_track = SEQ_UI_VisibleTrackGet();

#if 0
  // leads to: comparison is always true due to limited range of data type
  if( button >= SEQ_UI_BUTTON_GP1 && button <= SEQ_UI_BUTTON_GP16 ) {
#else
  if( button <= SEQ_UI_BUTTON_GP15 ) {
#endif
    // re-use encoder handler - only select UI item, don't increment
    return Encoder_Handler((int)button, 0);
  }

  // remaining buttons:
  switch( button ) {
    case SEQ_UI_BUTTON_GP16: {
      if( SEQ_GROOVE_Clear(SEQ_CC_Get(visible_track, SEQ_CC_GROOVE_STYLE)) < 0 )
	SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, "Preset", "not editable!");
      else
	SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, "Groove", "cleared!");
    } break;

    case SEQ_UI_BUTTON_Select:
    case SEQ_UI_BUTTON_Right:
      if( ++ui_selected_item >= NUM_OF_ITEMS )
	ui_selected_item = 0;

      return 1; // value always changed

    case SEQ_UI_BUTTON_Left:
      if( ui_selected_item == 0 )
	ui_selected_item = NUM_OF_ITEMS-1;
      else
	--ui_selected_item;
      return 1; // value always changed

    case SEQ_UI_BUTTON_Up:
      return Encoder_Handler(SEQ_UI_ENCODER_Datawheel, 1);

    case SEQ_UI_BUTTON_Down:
      return Encoder_Handler(SEQ_UI_ENCODER_Datawheel, -1);
  }

  return -1; // invalid or unsupported button
}


/////////////////////////////////////////////////////////////////////////////
// Local Display Handler function
// IN: <high_prio>: if set, a high-priority LCD update is requested
/////////////////////////////////////////////////////////////////////////////
static s32 LCD_Handler(u8 high_prio)
{
  if( high_prio )
    return 0; // there are no high-priority updates

  // layout:
  // 00000000001111111111222222222233333333330000000000111111111122222222223333333333
  // 01234567890123456789012345678901234567890123456789012345678901234567890123456789
  // <--------------------------------------><-------------------------------------->
  // Trk.  Groove Style  Intensity Change forStep Dly. Len. Vel. NumSteps        Clr 
  // G1T1  Inv. Shuffle     15     all Tracks  1    0    0    0  Preset not editable!


  u8 visible_track = SEQ_UI_VisibleTrackGet();
  u8 selected_groove = SEQ_CC_Get(visible_track, SEQ_CC_GROOVE_STYLE);
  seq_groove_entry_t *g;
  if( selected_groove >= SEQ_GROOVE_NUM_PRESETS )
    g = (seq_groove_entry_t *)&seq_groove_templates[selected_groove-SEQ_GROOVE_NUM_PRESETS];
  else
    g = (seq_groove_entry_t *)&seq_groove_presets[selected_groove];


  ///////////////////////////////////////////////////////////////////////////
  SEQ_LCD_CursorSet(0, 0);

  SEQ_LCD_PrintString("Trk.  Groove Style  Intensity ");
  if( ui_selected_item == ITEM_GROOVE_VALUE_GLB && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(10);
  } else {
    SEQ_LCD_PrintString("Change for");
  }
  SEQ_LCD_PrintString("Step Dly. Len. Vel. NumSteps        Clr ");


  ///////////////////////////////////////////////////////////////////////////
  SEQ_LCD_CursorSet(0, 1);

  if( ui_selected_item == ITEM_GXTY && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(4);
  } else {
    SEQ_LCD_PrintGxTy(ui_selected_group, ui_selected_tracks);
  }
  SEQ_LCD_PrintSpaces(2);

  ///////////////////////////////////////////////////////////////////////////
  if( ui_selected_item == ITEM_GROOVE_STYLE && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(12);
  } else {
    SEQ_LCD_PrintString(SEQ_GROOVE_NameGet(selected_groove));
  }
  SEQ_LCD_PrintSpaces(5);

  ///////////////////////////////////////////////////////////////////////////
  if( ui_selected_item == ITEM_GROOVE_VALUE && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(3);
  } else {
    SEQ_LCD_PrintFormattedString("%3d", SEQ_CC_Get(visible_track, SEQ_CC_GROOVE_VALUE));
  }
  SEQ_LCD_PrintSpaces(4);


  ///////////////////////////////////////////////////////////////////////////
  if( ui_selected_item == ITEM_GROOVE_VALUE_GLB && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(10);
  } else {
    SEQ_LCD_PrintString("all Tracks");
  }

  ///////////////////////////////////////////////////////////////////////////
  if( ui_selected_item == ITEM_GROOVE_STEP && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(4);
  } else {
    SEQ_LCD_PrintFormattedString(" %2d ", edit_step+1);
  }

  ///////////////////////////////////////////////////////////////////////////
  if( ui_selected_item == ITEM_GROOVE_DELAY && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(5);
  } else {
    int value = g->add_step_delay[edit_step];
    if( value <= -128 )
      SEQ_LCD_PrintString("VNEG ");
    else if( value >= 127 )
      SEQ_LCD_PrintString("VPOS ");
    else
      SEQ_LCD_PrintFormattedString("%4d ", value);
  }

  ///////////////////////////////////////////////////////////////////////////
  if( ui_selected_item == ITEM_GROOVE_LENGTH && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(5);
  } else {
    int value = g->add_step_length[edit_step];
    if( value <= -128 )
      SEQ_LCD_PrintString("VNEG ");
    else if( value >= 127 )
      SEQ_LCD_PrintString("VPOS ");
    else
      SEQ_LCD_PrintFormattedString("%4d ", value);
  }

  ///////////////////////////////////////////////////////////////////////////
  if( ui_selected_item == ITEM_GROOVE_VELOCITY && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(5);
  } else {
    int value = g->add_step_velocity[edit_step];
    if( value <= -128 )
      SEQ_LCD_PrintString("VNEG ");
    else if( value >= 127 )
      SEQ_LCD_PrintString("VPOS ");
    else
      SEQ_LCD_PrintFormattedString("%4d ", value);
  }

  ///////////////////////////////////////////////////////////////////////////
  if( selected_groove >= SEQ_GROOVE_NUM_PRESETS ) {
    if( ui_selected_item == ITEM_GROOVE_NUM_STEPS && ui_cursor_flash ) {
      SEQ_LCD_PrintSpaces(6);
    } else {
      SEQ_LCD_PrintFormattedString("  %2d  ", g->num_steps);
    }    
    SEQ_LCD_PrintSpaces(15);
  } else {
    if( ui_cursor_flash && ui_selected_item >= ITEM_GROOVE_LENGTH && ui_selected_item <= ITEM_GROOVE_DELAY )
      SEQ_LCD_PrintSpaces(21);
    else
      SEQ_LCD_PrintString(" Preset not editable!");
  }

  return 0; // no error
}


/////////////////////////////////////////////////////////////////////////////
// Local exit function
/////////////////////////////////////////////////////////////////////////////
static s32 EXIT_Handler(void)
{
  s32 status = 0;

  if( ui_store_file_required ) {
    // write config file
    MUTEX_SDCARD_TAKE;
    if( (status=SEQ_FILE_G_Write(seq_file_session_name)) < 0 )
      SEQ_UI_SDCardErrMsg(2000, status);
    MUTEX_SDCARD_GIVE;

    ui_store_file_required = 0;
  }

  return status;
}
/////////////////////////////////////////////////////////////////////////////
// Local Display Handler function
// IN: <high_prio>: if set, a high-priority LCD update is requested
/////////////////////////////////////////////////////////////////////////////
static s32 LCD_Handler(u8 high_prio)
{
  if( high_prio )
    return 0; // there are no high-priority updates

  // layout:
  // 00000000001111111111222222222233333333330000000000111111111122222222223333333333
  // 01234567890123456789012345678901234567890123456789012345678901234567890123456789
  // <--------------------------------------><-------------------------------------->
  // Trk.   Length  Loop             QuickSel        Quick Selection: Length         
  // G1T1   256/256   1               Length    4    8   16   24   32   64  128  256

  // Trk.   Length  Loop             QuickSel   1    5    9   13    1    1   17   25 
  // G1T1   256/256   1               Loops     4    8   12   16   16   32   32   32 

  u8 visible_track = SEQ_UI_VisibleTrackGet();
  s32 quicksel_item = QUICKSEL_SearchItem(SEQ_UI_VisibleTrackGet());

  ///////////////////////////////////////////////////////////////////////////
  SEQ_LCD_CursorSet(0, 0);
  SEQ_LCD_PrintString("Trk.   Length  Loop  ");
	
	SEQ_LCD_CursorSet(0, 2);
	SEQ_LCD_PrintString("QuickSel: ");
 
	SEQ_LCD_CursorSet(0, 3);
	SEQ_LCD_PrintSpaces(21);
	SEQ_LCD_CursorSet(0, 4);	
 
  if( quicksel_mode == QUICKSEL_MODE_LENGTH ) {
    //SEQ_LCD_PrintString("Quick Selection: Length         ");
	SEQ_LCD_PrintSpaces(21);
  } else {
    int i;
    for(i=0; i<8; ++i) {
 		switch( i ) {
			case 0:
				SEQ_LCD_CursorSet(0, 4);
				break;
			case 4:
				SEQ_LCD_CursorSet(0, 6);
				break;
		}
	if( quicksel_item == i && ui_cursor_flash ) {
	SEQ_LCD_PrintSpaces(5);
      } else {
	int loop = (int)ui_quicksel_loop_loop[i] + 1;
	PrintLengthOrLoop(loop);
      }
    }
  }


  ///////////////////////////////////////////////////////////////////////////
  SEQ_LCD_CursorSet(0, 1);

  if( ui_selected_item == ITEM_GXTY && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(7);
  } else {
    SEQ_LCD_PrintGxTy(ui_selected_group, ui_selected_tracks);
    SEQ_LCD_PrintSpaces(3);
  }

  ///////////////////////////////////////////////////////////////////////////
  SEQ_LCD_PrintSpaces(8);
  if( ui_selected_item == ITEM_LENGTH && ui_cursor_flash ) {
  } else {
    SEQ_LCD_CursorSet(7, 1);
    u16 num_steps = SEQ_TRG_NumStepsGet(visible_track);
    u16 len = SEQ_CC_Get(visible_track, SEQ_CC_LENGTH)+1;

    if( len > num_steps )
      SEQ_LCD_PrintFormattedString("!!!/%d", num_steps);
    else
      SEQ_LCD_PrintFormattedString("%d/%d", len, num_steps);
  }
  // to allow variable string lengths...
  SEQ_LCD_CursorSet(15, 1);

  ///////////////////////////////////////////////////////////////////////////
  if( ui_selected_item == ITEM_LOOP && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(4);
  } else {
    u16 num_steps = SEQ_TRG_NumStepsGet(visible_track);
    u16 loop = SEQ_CC_Get(visible_track, SEQ_CC_LOOP)+1;

    if( loop > num_steps )
      SEQ_LCD_PrintString("!!! ");
    else
      SEQ_LCD_PrintFormattedString("%3d ", loop);
  }

  ///////////////////////////////////////////////////////////////////////////
  //SEQ_LCD_PrintSpaces(14);
	SEQ_LCD_CursorSet(11, 2);  
  // free for sale

  ///////////////////////////////////////////////////////////////////////////
  if( ui_selected_item == ITEM_QUICKSEL_MODE && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(7);
  } else {
    if( quicksel_mode == QUICKSEL_MODE_LENGTH ) {
      SEQ_LCD_PrintString("Length     ");
    } else {
      SEQ_LCD_PrintString("Loops      ");
    }
  }

  ///////////////////////////////////////////////////////////////////////////
  int i;
  for(i=0; i<8; ++i) {
   		switch( i ) {
			case 0:
				SEQ_LCD_CursorSet(0, 5);
				break;
			case 4:
				SEQ_LCD_CursorSet(0, 7);
				break;
		}
  
  
    if( quicksel_item == i && ui_cursor_flash ) {
      SEQ_LCD_PrintSpaces(5);
    } else {
      int length = (int)((quicksel_mode == QUICKSEL_MODE_LENGTH) ? ui_quicksel_length[i] : ui_quicksel_loop_length[i]) + 1;

      if( length > SEQ_TRG_NumStepsGet(visible_track) )
	SEQ_LCD_PrintString(" --- ");
      else {
	PrintLengthOrLoop(length);
      }
    }
  }

  return 0; // no error
}
示例#19
0
/////////////////////////////////////////////////////////////////////////////
// Local button callback function
// Should return:
//   1 if value has been changed
//   0 if value hasn't been changed
//  -1 if invalid or unsupported button
/////////////////////////////////////////////////////////////////////////////
static s32 Button_Handler(seq_ui_button_t button, s32 depressed)
{
  if( depressed ) return 0; // ignore when button depressed

#if 0
  // leads to: comparison is always true due to limited range of data type
  if( button >= SEQ_UI_BUTTON_GP1 && button <= SEQ_UI_BUTTON_GP16 ) {
#else
  if( button <= SEQ_UI_BUTTON_GP16 ) {
#endif
    // -> same handling like for encoders
    return Encoder_Handler(button, 0);
  }

  switch( button ) {
    case SEQ_UI_BUTTON_Select:
      return -1; // unsupported (yet)

    case SEQ_UI_BUTTON_Right:
    case SEQ_UI_BUTTON_Up:
      if( depressed ) return 0; // ignore when button depressed
      return Encoder_Handler(SEQ_UI_ENCODER_Datawheel, 1);

    case SEQ_UI_BUTTON_Left:
    case SEQ_UI_BUTTON_Down:
      if( depressed ) return 0; // ignore when button depressed
      return Encoder_Handler(SEQ_UI_ENCODER_Datawheel, -1);
  }

  return -1; // invalid or unsupported button
}


/////////////////////////////////////////////////////////////////////////////
// Local Display Handler function
// IN: <high_prio>: if set, a high-priority LCD update is requested
/////////////////////////////////////////////////////////////////////////////
static s32 LCD_Handler(u8 high_prio)
{
  // layout normal mode:
  // 00000000001111111111222222222233333333330000000000111111111122222222223333333333
  // 01234567890123456789012345678901234567890123456789012345678901234567890123456789
  // <--------------------------------------><-------------------------------------->
  // Gate Acc. Roll Glide Skip R.G  R.V No Fx                                        
  //   A    B    C    D    E    F    G    H                                          

  // layout drum mode (lower line shows drum labels):
  // 00000000001111111111222222222233333333330000000000111111111122222222223333333333
  // 01234567890123456789012345678901234567890123456789012345678901234567890123456789
  // <--------------------------------------><-------------------------------------->
  // Select Drum Instrument:                                                         
  //  BD   SD   LT   MT   HT   CP   MA   RS   CB   CY   OH   CH  Smp1 Smp2 Smp3 Smp4 
  // ...horizontal VU meters...

  u8 visible_track = SEQ_UI_VisibleTrackGet();
  u8 event_mode = SEQ_CC_Get(visible_track, SEQ_CC_MIDI_EVENT_MODE);

  if( high_prio && event_mode == SEQ_EVENT_MODE_Drum ) {
    ///////////////////////////////////////////////////////////////////////////
    // frequently update VU meters

    SEQ_LCD_CursorSet(0, 1);

    u8 drum;
    u8 num_instruments = SEQ_TRG_NumInstrumentsGet(visible_track);
    for(drum=0; drum<num_instruments; ++drum) {
      if( seq_core_trk[visible_track].layer_muted & (1 << drum) )
	SEQ_LCD_PrintString("Mute ");
      else
	SEQ_LCD_PrintHBar((seq_layer_vu_meter[drum] >> 3) & 0xf);
    }

    return 0; // no error
  }
/////////////////////////////////////////////////////////////////////////////
// Local encoder callback function
// Should return:
//   1 if value has been changed
//   0 if value hasn't been changed
//  -1 if invalid or unsupported encoder
/////////////////////////////////////////////////////////////////////////////
static s32 Encoder_Handler(seq_ui_encoder_t encoder, s32 incrementer)
{
  u8 visible_track = SEQ_UI_VisibleTrackGet();
  u16 num_steps = SEQ_TRG_NumStepsGet(visible_track);

  switch( encoder ) {
    case SEQ_UI_ENCODER_GP1:
      SEQ_UI_Var8_Inc(&ui_selected_item, 0, NUM_OF_ITEMS, incrementer);
	  
	  //ui_selected_item = ITEM_GXTY;
      break;

    case SEQ_UI_ENCODER_GP2:
    case SEQ_UI_ENCODER_GP3:
      ui_selected_item = ITEM_LENGTH;
      break;

    case SEQ_UI_ENCODER_GP4:
    case SEQ_UI_ENCODER_GP5:
      ui_selected_item = ITEM_LOOP;
      break;

    case SEQ_UI_ENCODER_GP6:
      return 0; // not mapped

    case SEQ_UI_ENCODER_GP7:
    case SEQ_UI_ENCODER_GP8:
      ui_selected_item = ITEM_QUICKSEL_MODE;
      break;

    case SEQ_UI_ENCODER_GP9:
    case SEQ_UI_ENCODER_GP10:
    case SEQ_UI_ENCODER_GP11:
    case SEQ_UI_ENCODER_GP12:
    case SEQ_UI_ENCODER_GP13:
    case SEQ_UI_ENCODER_GP14:
    case SEQ_UI_ENCODER_GP15:
    case SEQ_UI_ENCODER_GP16: {
      int quicksel = encoder - 8;
      int len = (quicksel_mode == QUICKSEL_MODE_LENGTH) ? ui_quicksel_length[quicksel] : ui_quicksel_loop_length[quicksel];

      if( (len+1) > num_steps ) {
	len = num_steps-1;

	char buffer[20];
	sprintf(buffer, "for %d steps", num_steps);

	SEQ_UI_Msg(SEQ_UI_MSG_USER_R, 1000, "Track only prepared", buffer);
      } else if( seq_cc_trk[visible_track].clkdiv.SYNCH_TO_MEASURE && ((int)len > (int)seq_core_steps_per_measure) ) {
	char buffer[20];
	sprintf(buffer, "active for %d steps", (int)seq_core_steps_per_measure+1);
	SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, "Synch-to-Measure is", buffer);
      }

      SEQ_UI_CC_Set(SEQ_CC_LENGTH, len);

      if( quicksel_mode == QUICKSEL_MODE_LOOP ) {
	SEQ_UI_CC_Set(SEQ_CC_LOOP, ui_quicksel_loop_loop[quicksel]);
      }

      return 1; // value has been changed
    } break;
  }

  // for GP encoders and Datawheel
  if (encoder == SEQ_UI_ENCODER_Datawheel) {
  switch( ui_selected_item ) {
    case ITEM_GXTY:          return SEQ_UI_GxTyInc(incrementer);
    case ITEM_LENGTH: {
      if( SEQ_UI_CC_Inc(SEQ_CC_LENGTH, 0, num_steps-1, incrementer) >= 1 ) {
	if( seq_cc_trk[visible_track].clkdiv.SYNCH_TO_MEASURE && 
	    (int)SEQ_CC_Get(visible_track, SEQ_CC_LENGTH) > (int)seq_core_steps_per_measure ) {
	  char buffer[20];
	  sprintf(buffer, "active for %d steps", (int)seq_core_steps_per_measure+1);
	  SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, "Synch-to-Measure is", buffer);
	}
	return 1;
      }
      return 0;
    }

    case ITEM_LOOP:
      return SEQ_UI_CC_Inc(SEQ_CC_LOOP, 0, num_steps-1, incrementer);

    case ITEM_QUICKSEL_MODE:
      return SEQ_UI_Var8_Inc(&quicksel_mode, 0, 1, incrementer);
  }
  }
  return -1; // invalid or unsupported encoder
}
示例#21
0
/////////////////////////////////////////////////////////////////////////////
// Called from SEQ_MIDI_IN_Receive() if MIDI event has been received on
// matching IN port and channel
/////////////////////////////////////////////////////////////////////////////
s32 SEQ_RECORD_Receive(mios32_midi_package_t midi_package, u8 track)
{
  // step recording mode?
  // Note: if sequencer is not running, "Live Recording" will be handled like "Step Recording"
  u8 step_record_mode = seq_record_options.STEP_RECORD || !SEQ_BPM_IsRunning();

#if MBSEQV4L
  // extra for MBSEQ V4L: seq_record_state.ARMED_TRACKS and auto-assignment
  if( !seq_record_state.ARMED_TRACKS )
    return 0; // no track armed

  track = 0;
  if( seq_record_state.ARMED_TRACKS & 0xff00)
    track = 8;

  // search for free track/layer
  if( (midi_package.event == NoteOn) || (midi_package.event == NoteOff) ) {
    // fine, we will record Note in selected track
  } else if( midi_package.event == PitchBend ) {
    track += 3; // G1T4 resp. G3T4
  } else if( midi_package.event == CC ) {
    const u8 track_layer_cc_table[19][2] = {
      { 4, 0 },
      { 5, 0 },
      { 6, 0 },
      { 7, 0 },
      { 7, 1 }, { 7, 2 }, { 7, 3 },
      { 6, 1 }, { 6, 2 }, { 6, 3 },
      { 5, 1 }, { 5, 2 }, { 5, 3 },
      { 4, 1 }, { 4, 2 }, { 4, 3 },
      { 3, 1 }, { 3, 2 }, { 3, 3 },
    };

    // search for same (or free) CC entry
    // new track/layer search algorithm since V4L.082
    u8 seq_track_offset = track; // depends on sequence
    int par_layer = 0;
    int i;
    u8 free_layer_found = 0;
    for(i=0; i<19 && !free_layer_found; ++i) {
      track = seq_track_offset + track_layer_cc_table[i][0];
      par_layer = track_layer_cc_table[i][1];
      seq_cc_trk_t *tcc = &seq_cc_trk[track];
      u8 *layer_type_ptr = (u8 *)&tcc->lay_const[0*16 + par_layer];
      u8 *layer_cc_ptr = (u8 *)&tcc->lay_const[1*16 + par_layer];

      if( *layer_type_ptr == SEQ_PAR_Type_CC &&
	  (*layer_cc_ptr >= 0x80 || *layer_cc_ptr == midi_package.cc_number) &&
	  (seq_record_state.ARMED_TRACKS & (1 << track)) ) {

	if( *layer_cc_ptr >= 0x80 ) {
	  *layer_cc_ptr = midi_package.cc_number; // assing CC number to free track

	  // initialize whole layer with invalid value 0xc0 (indicates: not recorded)
	  int num_p_steps = SEQ_PAR_NumStepsGet(track);
	  int instrument = 0;
	  int step;
	  for(step=0; step<num_p_steps; ++step)
	    SEQ_PAR_Set(track, step, par_layer, instrument, 0xc0);
#if DEBUG_VERBOSE_LEVEL >= 2
	  DEBUG_MSG("[SEQ_RECORD_Receive] free CC layer found for CC#%d in track #%d.%c\n", midi_package.cc_number, track+1, 'A'+par_layer);
#endif
	}

	free_layer_found = 1;
      }
    }

    if( !free_layer_found ) {
#if DEBUG_VERBOSE_LEVEL >= 2
      DEBUG_MSG("[SEQ_RECORD_Receive] no free CC layer found for CC#%d\n", midi_package.cc_number);
#endif
      return 0; // no free layer
    }
  } else {
    return 0; // event not relevant
  }

  // exit if track not armed
  if( !(seq_record_state.ARMED_TRACKS & (1 << track)) )
    return 0;
#else
  // MBSEQV4 (without L)
  if( midi_package.event == CC && track == SEQ_UI_VisibleTrackGet() ) {
    // search for same (or free) CC entry
    seq_cc_trk_t *tcc = &seq_cc_trk[track];
    u8 free_layer_found = 0;
    {
      u8 num_p_layers = SEQ_PAR_NumLayersGet(track);
      u8 *layer_type_ptr = (u8 *)&tcc->lay_const[0*16];
      u8 *layer_cc_ptr = (u8 *)&tcc->lay_const[1*16];
      int par_layer;
      for(par_layer=0; par_layer<num_p_layers && !free_layer_found; ++par_layer, ++layer_type_ptr, ++layer_cc_ptr) {
	if( *layer_type_ptr == SEQ_PAR_Type_CC &&
	    (*layer_cc_ptr >= 0x80 || *layer_cc_ptr == midi_package.cc_number) ) {

	  if( *layer_cc_ptr >= 0x80 ) {
	    *layer_cc_ptr = midi_package.cc_number; // assing CC number to free track

	    // initialize whole layer with invalid value 0xc0 (indicates: not recorded)
	    int num_p_steps = SEQ_PAR_NumStepsGet(track);
	    int instrument = 0;
	    int step;
	    for(step=0; step<num_p_steps; ++step)
	      SEQ_PAR_Set(track, step, par_layer, instrument, 0xc0);
#if DEBUG_VERBOSE_LEVEL >= 2
	    DEBUG_MSG("[SEQ_RECORD_Receive] free CC layer found for CC#%d in track #%d.%c\n", midi_package.cc_number, track+1, 'A'+par_layer);
#endif
	  }

	  free_layer_found = 1;
	  break;
	}
      }
    }

    if( !free_layer_found ) {
#if DEBUG_VERBOSE_LEVEL >= 2
      DEBUG_MSG("[SEQ_RECORD_Receive] no free CC layer found for CC#%d\n", midi_package.cc_number);
#endif
      return 0; // no free layer
    }
  }
#endif

#if DEBUG_VERBOSE_LEVEL >= 2
  DEBUG_MSG("[SEQ_RECORD_Receive] %02x %02x %02x -> track #%d\n", 
	    midi_package.evnt0, midi_package.evnt1, midi_package.evnt2, 
	    track+1);
#endif

  // exit if track number too high
  if( track >= SEQ_CORE_NUM_TRACKS )
    return -1; // unsupported track

  seq_core_trk_t *t = &seq_core_trk[track];
  seq_cc_trk_t *tcc = &seq_cc_trk[track];

  // branch depending on event
  u8 rec_event = 0;
  u8 send_note_off = 0;
  switch( midi_package.event ) {
    case NoteOff:
    case NoteOn: {
      midi_package.note &= 0x7f; // to avoid array overwrites
      u32 note_mask = 1 << (midi_package.note & 0x1f);

      // if Note Off and new note number matches with recorded note number
      if( midi_package.event == NoteOff || midi_package.velocity == 0 ) {
	if( seq_record_played_notes[midi_package.note>>5] & note_mask ) {
	  MIOS32_IRQ_Disable();
	  // note not active anymore
	  seq_record_played_notes[midi_package.note>>5] &= ~note_mask;

	  // determine duration in mS (for step recording function)
	  u16 duration_ms = MIOS32_TIMESTAMP_Get() - seq_record_note_timestamp_ms[midi_package.note];
	  // map to BPM
	  int duration = (int)((float)duration_ms / ((1000.0*60.0) / SEQ_BPM_EffectiveGet() / (float)SEQ_BPM_PPQN_Get()));
#if DEBUG_VERBOSE_LEVEL >= 3
	  DEBUG_MSG("[SEQ_RECORD_Receive] duration of note 0x%02x was %d mS (%d ticks)\n",
		    midi_package.note, duration_ms, duration);
#endif	  

	  // insert length into current step
	  u8 instrument = 0;
	  int len;
	  if( step_record_mode ) {
	    len = 71; // 75%
	    if( tcc->event_mode != SEQ_EVENT_MODE_Drum )
	      len = (duration <= 96) ? duration : 96; // for duration >= 96 the length will be stretched after record
	  } else {
	    len = SEQ_BPM_TickGet() - t->rec_timestamp;

	    if( len < 1 )
	      len = 1;
	    else if( len > 95 )
	      len = 95;
	  }

	  int len_step = step_record_mode ? ui_selected_step : t->step;
	  u8 num_p_layers = SEQ_PAR_NumLayersGet(track);

	  while( 1 ) {
	    if( tcc->event_mode == SEQ_EVENT_MODE_Combined ) {
	      // extra for MBSEQ V4L:
	      // search for note in track 1/8, insert length into track 3/10
	      int par_layer;
	      for(par_layer=0; par_layer<num_p_layers; ++par_layer) {
		if( SEQ_PAR_Get(track, len_step, par_layer, instrument) == midi_package.note ) {
		  SEQ_PAR_Set(track+2, len_step, par_layer, instrument, len);
		  break;
		}
	      }
	    } else {
	      if( tcc->link_par_layer_length >= 0 )
		SEQ_PAR_Set(track, len_step, tcc->link_par_layer_length, instrument, len);
	    }

	    if( !step_record_mode )
	      break;
	    if( tcc->event_mode == SEQ_EVENT_MODE_Drum )
	      break;
	    if( duration <= 0 )
	      break;
	    duration -= 96;

	    // insert length into all following steps until a gate is set
	    if( ++len_step > tcc->length ) // TODO: handle this correctly if track is played backwards
	      len_step = tcc->loop;

	    if( SEQ_TRG_GateGet(track, len_step, instrument) )
	      break;

	    len = (duration > 0) ? 96 : -duration;

	    // copy notes
	    u8 *layer_type_ptr = (u8 *)&tcc->lay_const[0*16];
	    int par_layer;
	    for(par_layer=0; par_layer<num_p_layers; ++par_layer, ++layer_type_ptr) {
	      if( *layer_type_ptr == SEQ_PAR_Type_Note || *layer_type_ptr == SEQ_PAR_Type_Chord ) {
		u8 note = SEQ_PAR_Get(track, ui_selected_step, par_layer, instrument);
		SEQ_PAR_Set(track, len_step, par_layer, instrument, note);
	      }
	    }
	  }

	  MIOS32_IRQ_Enable();
	}

	if( step_record_mode && seq_record_options.FWD_MIDI ) {
	  // send Note Off events of current track if no key is played anymore
	  u8 any_note_played = seq_record_played_notes[0] || seq_record_played_notes[1] || seq_record_played_notes[2] || seq_record_played_notes[3];
	  if( !any_note_played )
	    send_note_off = 1;     
	}
      } else {
	MIOS32_IRQ_Disable();

	if( step_record_mode && tcc->event_mode != SEQ_EVENT_MODE_Drum ) {
	  // check if another note is already played
	  u8 any_note_played = seq_record_played_notes[0] || seq_record_played_notes[1] || seq_record_played_notes[2] || seq_record_played_notes[3];
	  // if not: clear poly counter and all notes (so that new chord can be entered if all keys were released)
	  if( !any_note_played ) {
	    t->rec_poly_ctr = 0;

	    u8 num_p_layers = SEQ_PAR_NumLayersGet(track);
	    u8 *layer_type_ptr = (u8 *)&tcc->lay_const[0*16];
	    int par_layer;
	    u8 instrument = 0;
	    for(par_layer=0; par_layer<num_p_layers; ++par_layer, ++layer_type_ptr) {
	      if( *layer_type_ptr == SEQ_PAR_Type_Note || *layer_type_ptr == SEQ_PAR_Type_Chord )
		SEQ_PAR_Set(track, ui_selected_step, par_layer, instrument, 0x00);
	    }
	  }
	}

	// note is active
	seq_record_played_notes[midi_package.note>>5] |= note_mask;
	// start measuring length
	t->rec_timestamp = SEQ_BPM_TickGet();
	// for step record function: independent from BPM
	seq_record_note_timestamp_ms[midi_package.note & 0x7f] = MIOS32_TIMESTAMP_Get(); // note: 16bit only

	MIOS32_IRQ_Enable();

	// record event
	rec_event = 1;
      }
    } break;

    case CC:
    case PitchBend: {
      rec_event = 1;
    } break;

    default: {
#if DEBUG_VERBOSE_LEVEL >= 2
      DEBUG_MSG("[SEQ_RECORD_Receive] event %x not supported.\n", midi_package.event);
#endif
      return -2; // unsupported event
    }
  }
/////////////////////////////////////////////////////////////////////////////
// Local encoder callback function
// Should return:
//   1 if value has been changed
//   0 if value hasn't been changed
//  -1 if invalid or unsupported encoder
/////////////////////////////////////////////////////////////////////////////
static s32 Encoder_Handler(seq_ui_encoder_t encoder, s32 incrementer)
{
  u8 visible_track = SEQ_UI_VisibleTrackGet();

  switch( encoder ) {
    case SEQ_UI_ENCODER_GP1:
    case SEQ_UI_ENCODER_GP2:
      ui_selected_item = ITEM_GXTY;
      break;

    case SEQ_UI_ENCODER_GP3:
    case SEQ_UI_ENCODER_GP4:
      ui_selected_item = ITEM_REPEATS;
      break;

    case SEQ_UI_ENCODER_GP5:
    case SEQ_UI_ENCODER_GP6:
      ui_selected_item = ITEM_DELAY;
      break;

    case SEQ_UI_ENCODER_GP7:
    case SEQ_UI_ENCODER_GP8:
      ui_selected_item = ITEM_VELOCITY;
      break;

    case SEQ_UI_ENCODER_GP9:
    case SEQ_UI_ENCODER_GP10:
      ui_selected_item = ITEM_FB_VELOCITY;
      break;

    case SEQ_UI_ENCODER_GP11:
    case SEQ_UI_ENCODER_GP12:
      ui_selected_item = ITEM_FB_NOTE;
      break;

    case SEQ_UI_ENCODER_GP13:
    case SEQ_UI_ENCODER_GP14:
      ui_selected_item = ITEM_FB_GATELENGTH;
      break;

    case SEQ_UI_ENCODER_GP15:
    case SEQ_UI_ENCODER_GP16:
      ui_selected_item = ITEM_FB_TICKS;
      break;
  }

  // for GP encoders and Datawheel
  switch( ui_selected_item ) {
  case ITEM_GXTY:          return SEQ_UI_GxTyInc(incrementer);
  case ITEM_REPEATS:       return SEQ_UI_CC_Inc(SEQ_CC_ECHO_REPEATS, 0, 15, incrementer);
  case ITEM_DELAY: {
    // for compatibility with older patches pre Beta30
    u8 value = SEQ_CC_Get(visible_track, SEQ_CC_ECHO_DELAY);
    value = SEQ_CORE_Echo_MapInternalToUser(value);
    if( SEQ_UI_Var8_Inc(&value, 0, 21, incrementer) ) {
      value = SEQ_CORE_Echo_MapUserToInternal(value);
      SEQ_CC_Set(visible_track, SEQ_CC_ECHO_DELAY, value);
      return 1;
    }
    return 0;
  } break;

  case ITEM_VELOCITY:      return SEQ_UI_CC_Inc(SEQ_CC_ECHO_VELOCITY, 0, 40, incrementer);
  case ITEM_FB_VELOCITY:   return SEQ_UI_CC_Inc(SEQ_CC_ECHO_FB_VELOCITY, 0, 40, incrementer);
  case ITEM_FB_NOTE:       return SEQ_UI_CC_Inc(SEQ_CC_ECHO_FB_NOTE, 0, 49, incrementer);
  case ITEM_FB_GATELENGTH: return SEQ_UI_CC_Inc(SEQ_CC_ECHO_FB_GATELENGTH, 0, 40, incrementer);
  case ITEM_FB_TICKS:      return SEQ_UI_CC_Inc(SEQ_CC_ECHO_FB_TICKS, 0, 40, incrementer);
  }

  return -1; // invalid or unsupported encoder
}
示例#23
0
/////////////////////////////////////////////////////////////////////////////
// Local encoder callback function
// Should return:
//   1 if value has been changed
//   0 if value hasn't been changed
//  -1 if invalid or unsupported encoder
/////////////////////////////////////////////////////////////////////////////
static s32 Encoder_Handler(seq_ui_encoder_t encoder, s32 incrementer)
{
#if 0
  // leads to: comparison is always true due to limited range of data type
  if( (encoder >= SEQ_UI_ENCODER_GP1 && encoder <= SEQ_UI_ENCODER_GP16) ) {
#else
  if( encoder <= SEQ_UI_ENCODER_GP16 ) {
#endif
    if( seq_ui_button_state.SELECT_PRESSED ) {
      // select button pressed: indirect MUTED flag modification (taken over when select button depressed)
      u16 mask = 1 << encoder;
      if( incrementer < 0 || (incrementer == 0 && !(latched_mute & mask)) )
	latched_mute |= mask;
      else
	latched_mute &= ~mask;
    } else {
      // select button not pressed: direct MUTED flag modification
      // access to seq_core_trk[] must be atomic!
      portENTER_CRITICAL();

      u8 visible_track = SEQ_UI_VisibleTrackGet();
      u16 mask = 1 << encoder;
      u16 *muted = seq_ui_button_state.MUTE_PRESSED ? (u16 *)&seq_core_trk[visible_track].layer_muted : (u16 *)&seq_core_trk_muted;

      if( incrementer < 0 )
	*muted |= mask;
      else if( incrementer > 0 )
	*muted &= ~mask;
      else
	*muted ^= mask;

      portEXIT_CRITICAL();
    }

    return 1; // value changed
  }

  return -1; // invalid or unsupported encoder
}


/////////////////////////////////////////////////////////////////////////////
// Local button callback function
// Should return:
//   1 if value has been changed
//   0 if value hasn't been changed
//  -1 if invalid or unsupported button
/////////////////////////////////////////////////////////////////////////////
static s32 Button_Handler(seq_ui_button_t button, s32 depressed)
{
#if 0
  // leads to: comparison is always true due to limited range of data type
  if( button >= SEQ_UI_BUTTON_GP1 && button <= SEQ_UI_BUTTON_GP16 ) {
#else
  if( button <= SEQ_UI_BUTTON_GP16 ) {
#endif
    if( depressed ) return 0; // ignore when button depressed

    // re-using encoder routine
    return Encoder_Handler(button, 0);
  }

  switch( button ) {
    case SEQ_UI_BUTTON_Select:
      portENTER_CRITICAL();
      if( depressed ) {
	// select button released: take over latched mutes
	if( seq_ui_button_state.MUTE_PRESSED ) {
	  u8 visible_track = SEQ_UI_VisibleTrackGet();
	  seq_core_trk[visible_track].layer_muted = latched_mute;
	} else {
	  seq_core_trk_muted = latched_mute;
	}
      } else {
	// select pressed: init latched mutes which will be taken over once SELECT button released
	if( seq_ui_button_state.MUTE_PRESSED ) {
	  u8 visible_track = SEQ_UI_VisibleTrackGet();
	  latched_mute = seq_core_trk[visible_track].layer_muted;
	} else {
	  latched_mute = seq_core_trk_muted;
	}
      }

      portEXIT_CRITICAL();
      return 1;
  }

  return -1; // invalid or unsupported button
}


/////////////////////////////////////////////////////////////////////////////
// Local Display Handler function
// IN: <high_prio>: if set, a high-priority LCD update is requested
/////////////////////////////////////////////////////////////////////////////
static s32 LCD_Handler(u8 high_prio)
{
  // layout:
  // 00000000001111111111222222222233333333330000000000111111111122222222223333333333
  // 01234567890123456789012345678901234567890123456789012345678901234567890123456789
  // <--------------------------------------><-------------------------------------->
  //  > 1<   2    3    4    5    6    7    8    9   10   11   12   13   14   15   16 
  // ...horizontal VU meters...

  if( high_prio ) {
    ///////////////////////////////////////////////////////////////////////////
    // frequently update VU meters
    SEQ_LCD_CursorSet(0, 1);

    u8 track;
    u16 mute_flags = 0;

    if( !ui_cursor_flash && seq_ui_button_state.SELECT_PRESSED ) {
      mute_flags = latched_mute;
    } else {
      if( seq_ui_button_state.MUTE_PRESSED ) {
	u8 visible_track = SEQ_UI_VisibleTrackGet();
	mute_flags = seq_core_trk[visible_track].layer_muted;
      } else {
	mute_flags = seq_core_trk_muted;
      }
    }

    if( seq_ui_button_state.MUTE_PRESSED ) {
      u8 layer;
      for(layer=0; layer<16; ++layer)
	if( mute_flags & (1 << layer) )
	  SEQ_LCD_PrintString("Mute ");
	else
	  SEQ_LCD_PrintHBar((seq_layer_vu_meter[layer] >> 3) & 0xf);
    } else {
      seq_core_trk_t *t = &seq_core_trk[0];
      for(track=0; track<16; ++t, ++track)
	if( mute_flags & (1 << track) )
	  SEQ_LCD_PrintString("Mute ");
	else
	  SEQ_LCD_PrintHBar(t->vu_meter >> 3);
    }
  } else {
/////////////////////////////////////////////////////////////////////////////
// Local encoder callback function
// Should return:
//   1 if value has been changed
//   0 if value hasn't been changed
//  -1 if invalid or unsupported encoder
/////////////////////////////////////////////////////////////////////////////
static s32 Encoder_Handler(seq_ui_encoder_t encoder, s32 incrementer)
{
  // ensure that original record screen will be print immediately
  ui_hold_msg_ctr = 0;

  switch( encoder ) {
    case SEQ_UI_ENCODER_GP1:
      ui_selected_item = ITEM_GXTY;
      break;

    case SEQ_UI_ENCODER_GP2:
      ui_selected_item = ITEM_MUTE;
      break;

    case SEQ_UI_ENCODER_GP3:
      ui_selected_item = ITEM_OCT_TRANSPOSE;
      break;

    case SEQ_UI_ENCODER_GP4:
      ui_selected_item = ITEM_LIVE_VELOCITY;
      break;

    case SEQ_UI_ENCODER_GP5:
      ui_selected_item = ITEM_LIVE_FORCE_SCALE;
      break;

    case SEQ_UI_ENCODER_GP6:
      ui_selected_item = ITEM_LIVE_FX;
      break;

    case SEQ_UI_ENCODER_GP7:
    case SEQ_UI_ENCODER_GP8:
      return 0; // not mapped (yet)
      break;

    case SEQ_UI_ENCODER_GP9:
      ui_selected_item = ITEM_IN_BUS;
      break;

    case SEQ_UI_ENCODER_GP10:
      ui_selected_item = ITEM_IN_PORT;
      break;

    case SEQ_UI_ENCODER_GP11:
      ui_selected_item = ITEM_IN_CHN;
      break;

    case SEQ_UI_ENCODER_GP12:
      ui_selected_item = ITEM_IN_LOWER;
      break;

    case SEQ_UI_ENCODER_GP13:
      ui_selected_item = ITEM_IN_UPPER;
      break;

    case SEQ_UI_ENCODER_GP14:
      ui_selected_item = ITEM_IN_MODE;
      break;

    case SEQ_UI_ENCODER_GP15:
      return -1; // not mapped

    case SEQ_UI_ENCODER_GP16:
      ui_selected_item = ITEM_RESET_STACKS;
      break;
  }

  // for GP encoders and Datawheel
  switch( ui_selected_item ) {
    case ITEM_GXTY: {
      if( !seq_midi_in_options[selected_bus].MODE_PLAY )
	return -1;
      return SEQ_UI_GxTyInc(incrementer);
    }

    case ITEM_MUTE: {
      if( !seq_midi_in_options[selected_bus].MODE_PLAY )
	return -1;

      u8 visible_track = SEQ_UI_VisibleTrackGet();
      u16 mask = 1 << visible_track;

      if( incrementer < 0 )
	seq_core_trk_muted |= mask;
      else
	seq_core_trk_muted &= ~mask;
      return 1; // value changed
    } break;

    case ITEM_OCT_TRANSPOSE: {
      if( !seq_midi_in_options[selected_bus].MODE_PLAY )
	return -1;

      u8 tmp = seq_live_options.OCT_TRANSPOSE + 5;
      if( SEQ_UI_Var8_Inc(&tmp, 0, 10, incrementer) >= 0 ) {
	seq_live_options.OCT_TRANSPOSE = (s8)tmp - 5;
	store_file_required = 1;
	return 1; // value changed
      }
      return 0; // no change
    } break;

    case ITEM_LIVE_VELOCITY: {
      if( !seq_midi_in_options[selected_bus].MODE_PLAY )
	return -1;

      if( SEQ_UI_Var8_Inc(&seq_live_options.VELOCITY, 1, 127, incrementer) >= 0 ) {
	store_file_required = 1;
	return 1; // value changed
      }
      return 0; // no change
    }

    case ITEM_LIVE_FORCE_SCALE: {
      if( !seq_midi_in_options[selected_bus].MODE_PLAY )
	return -1;

      u8 tmp = seq_live_options.FORCE_SCALE;
      if( SEQ_UI_Var8_Inc(&tmp, 0, 1, incrementer) >= 0 ) {
	seq_live_options.FORCE_SCALE = tmp;
	store_file_required = 1;
	return 1; // value changed
      }
      return 0; // no change
    }

    case ITEM_LIVE_FX: {
      if( !seq_midi_in_options[selected_bus].MODE_PLAY )
	return -1;

      u8 tmp = seq_live_options.FX;
      if( SEQ_UI_Var8_Inc(&tmp, 0, 1, incrementer) >= 0 ) {
	seq_live_options.FX = tmp;
	store_file_required = 1;
	return 1; // value changed
      }
      return 0; // no change
    }

    case ITEM_IN_BUS: {
      if( SEQ_UI_Var8_Inc(&selected_bus, 0, SEQ_MIDI_IN_NUM_BUSSES-1, incrementer) >= 0 ) {
	return 1; // value changed
      }
      return 0; // no change
    } break;

    case ITEM_IN_PORT: {
      u8 port_ix = SEQ_MIDI_PORT_InIxGet(seq_midi_in_port[selected_bus]);
      if( SEQ_UI_Var8_Inc(&port_ix, 0, SEQ_MIDI_PORT_InNumGet()-1-4, incrementer) >= 0 ) { // don't allow selection of Bus1..Bus4
	seq_midi_in_port[selected_bus] = SEQ_MIDI_PORT_InPortGet(port_ix);
	store_file_required = 1;
	return 1; // value changed
      }
      return 0; // no change
    } break;

    case ITEM_IN_CHN:
      if( SEQ_UI_Var8_Inc(&seq_midi_in_channel[selected_bus], 0, 16, incrementer) >= 0 ) {
	store_file_required = 1;
	return 1; // value changed
      }
      return 0; // no change

    case ITEM_IN_LOWER:
      if( SEQ_UI_Var8_Inc(&seq_midi_in_lower[selected_bus], 0, 127, incrementer) >= 0 ) {
	store_file_required = 1;
	return 1; // value changed
      }
      return 0; // no change

    case ITEM_IN_UPPER:
      if( SEQ_UI_Var8_Inc(&seq_midi_in_upper[selected_bus], 0, 127, incrementer) >= 0 ) {
	store_file_required = 1;
	return 1; // value changed
      }
      return 0; // no change

    case ITEM_IN_MODE: {
      u8 fwd = seq_midi_in_options[selected_bus].MODE_PLAY;
      if( SEQ_UI_Var8_Inc(&fwd, 0, 1, incrementer) >= 0 ) {
	seq_midi_in_options[selected_bus].MODE_PLAY = fwd;
	store_file_required = 1;
	return 1; // value changed
      }
      return 0; // no change
    } break;

    case ITEM_RESET_STACKS: {
      SEQ_MIDI_IN_ResetTransArpStacks();
      SEQ_UI_Msg(SEQ_UI_MSG_USER_R, 2000, "Transposer/Arp.", "Stacks cleared!");
      return 1;
    } break;
  }

  return -1; // invalid or unsupported encoder
}
示例#25
0
/////////////////////////////////////////////////////////////////////////////
// This hook is called before the shift register chain is scanned
/////////////////////////////////////////////////////////////////////////////
void APP_SRIO_ServicePrepare(void)
{
  static u8 led_digit_ctr = 0;
  if( ++led_digit_ctr >= 7 )
    led_digit_ctr = 0;

#ifndef MBSEQV4L
  if( seq_hwcfg_blm.enabled ) {
    // prepare DOUT registers of BLM to drive the column
    BLM_PrepareCol();
  }
#else
  BLM_CHEAPO_PrepareCol();
#endif

  if( seq_hwcfg_blm8x8.enabled ) {
    // prepare DOUT registers of 8x8 BLM to drive the row
    BLM_X_PrepareRow();
  }

  // TK: using MIOS32_DOUT_SRSet/PinSet instead of SEQ_LED_SRSet/PinSet to ensure compatibility with MBSEQV4L
  if( seq_hwcfg_bpm_digits.enabled ) {
    // invert for common anodes
    u8 inversion_mask = (seq_hwcfg_bpm_digits.enabled == 2) ? 0xff : 0x00;
    u8 common_enable = (seq_hwcfg_bpm_digits.enabled == 2) ? 1 : 0;

    float bpm = SEQ_BPM_EffectiveGet();
    if( led_digit_ctr == 0 ) {
      u8 sr_value = SEQ_LED_DigitPatternGet(((int)(bpm*10)) % 10);
      MIOS32_DOUT_SRSet(seq_hwcfg_bpm_digits.segments_sr - 1, sr_value ^ inversion_mask);
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common1_pin, common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common2_pin, !common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common3_pin, !common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common4_pin, !common_enable);
    } else if( led_digit_ctr == 1 ) {
      u8 sr_value = SEQ_LED_DigitPatternGet((int)bpm % 10) | 0x80; // +dot
      MIOS32_DOUT_SRSet(seq_hwcfg_bpm_digits.segments_sr - 1, sr_value ^ inversion_mask);
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common1_pin, !common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common2_pin, common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common3_pin, !common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common4_pin, !common_enable);
    } else if( led_digit_ctr == 2 ) {
      u8 sr_value = SEQ_LED_DigitPatternGet(((int)bpm / 10) % 10);
      MIOS32_DOUT_SRSet(seq_hwcfg_bpm_digits.segments_sr - 1, sr_value ^ inversion_mask);
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common1_pin, !common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common2_pin, !common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common3_pin, common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common4_pin, !common_enable);
    } else if( led_digit_ctr == 3 ) {
      u8 sr_value = SEQ_LED_DigitPatternGet(((int)bpm / 100) % 10);
      MIOS32_DOUT_SRSet(seq_hwcfg_bpm_digits.segments_sr - 1, sr_value ^ inversion_mask);
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common1_pin, !common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common2_pin, !common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common3_pin, !common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common4_pin, common_enable);
    }
    else { // not displaying bpm digit in this cycle, disable common pins
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common1_pin, !common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common2_pin, !common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common3_pin, !common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_bpm_digits.common4_pin, !common_enable);
    }
  }

  if( seq_hwcfg_step_digits.enabled ) {
    // invert for common anodes
    u8 inversion_mask = (seq_hwcfg_step_digits.enabled == 2) ? 0xff : 0x00;
    u8 common_enable = (seq_hwcfg_step_digits.enabled == 2) ? 1 : 0;
    
    int step = (int)(SEQ_BPM_IsRunning() ? seq_core_trk[SEQ_UI_VisibleTrackGet()].step : ui_selected_step) + 1;
    if( led_digit_ctr == 4 ) {
      u8 sr_value = SEQ_LED_DigitPatternGet(step % 10);
      MIOS32_DOUT_SRSet(seq_hwcfg_step_digits.segments_sr - 1, sr_value ^ inversion_mask);
      MIOS32_DOUT_PinSet(seq_hwcfg_step_digits.common1_pin, common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_step_digits.common2_pin, !common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_step_digits.common3_pin, !common_enable);
    } else if( led_digit_ctr == 5 ) {
      u8 sr_value = SEQ_LED_DigitPatternGet((step / 10) % 10);
      MIOS32_DOUT_SRSet(seq_hwcfg_step_digits.segments_sr - 1, sr_value ^ inversion_mask);
      MIOS32_DOUT_PinSet(seq_hwcfg_step_digits.common1_pin, !common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_step_digits.common2_pin, common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_step_digits.common3_pin, !common_enable);
    } else if( led_digit_ctr == 6 ) {
      u8 sr_value = SEQ_LED_DigitPatternGet((step / 100) % 10);
      MIOS32_DOUT_SRSet(seq_hwcfg_step_digits.segments_sr - 1, sr_value ^ inversion_mask);
      MIOS32_DOUT_PinSet(seq_hwcfg_step_digits.common1_pin, !common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_step_digits.common2_pin, !common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_step_digits.common3_pin, common_enable);
    }
    else { // not displaying step digit in this cycle, disable common pins
      MIOS32_DOUT_PinSet(seq_hwcfg_step_digits.common1_pin, !common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_step_digits.common2_pin, !common_enable);
      MIOS32_DOUT_PinSet(seq_hwcfg_step_digits.common3_pin, !common_enable);
    }    
  }
  
  SEQ_TPD_LED_Update();     
}
示例#26
0
/////////////////////////////////////////////////////////////////////////////
// Local encoder callback function
// Should return:
//   1 if value has been changed
//   0 if value hasn't been changed
//  -1 if invalid or unsupported encoder
/////////////////////////////////////////////////////////////////////////////
static s32 Encoder_Handler(seq_ui_encoder_t encoder, s32 incrementer)
{
  u8 visible_track = SEQ_UI_VisibleTrackGet();

  switch( encoder ) {
    case SEQ_UI_ENCODER_GP1:
      ui_selected_item = ITEM_GXTY;
      break;

    case SEQ_UI_ENCODER_GP2:
    case SEQ_UI_ENCODER_GP3:
    case SEQ_UI_ENCODER_GP4:
      ui_selected_item = ITEM_GROOVE_STYLE;
      break;

    case SEQ_UI_ENCODER_GP5:
    case SEQ_UI_ENCODER_GP6:
      ui_selected_item = ITEM_GROOVE_VALUE;
      break;

    case SEQ_UI_ENCODER_GP7:
    case SEQ_UI_ENCODER_GP8:
      ui_selected_item = ITEM_GROOVE_VALUE_GLB;
      break;

    case SEQ_UI_ENCODER_GP9:
      ui_selected_item = ITEM_GROOVE_STEP;
      break;
      
    case SEQ_UI_ENCODER_GP10:
      ui_selected_item = ITEM_GROOVE_DELAY;
      break;
      
    case SEQ_UI_ENCODER_GP11:
      ui_selected_item = ITEM_GROOVE_LENGTH;
      break;
      
    case SEQ_UI_ENCODER_GP12:
      ui_selected_item = ITEM_GROOVE_VELOCITY;
      break;

    case SEQ_UI_ENCODER_GP13:
      ui_selected_item = ITEM_GROOVE_NUM_STEPS;
      break;

    case SEQ_UI_ENCODER_GP14:
    case SEQ_UI_ENCODER_GP15:
    case SEQ_UI_ENCODER_GP16:
      return -1; // not mapped yet
  }

  // for GP encoders and Datawheel
  u8 grooves_total = SEQ_GROOVE_NUM_PRESETS+SEQ_GROOVE_NUM_TEMPLATES;
  u8 selected_groove = SEQ_CC_Get(visible_track, SEQ_CC_GROOVE_STYLE);
  s32 groove_template = selected_groove - SEQ_GROOVE_NUM_PRESETS; // negative if not a custom template
  seq_groove_entry_t *g;
  if( selected_groove >= SEQ_GROOVE_NUM_PRESETS )
    g = (seq_groove_entry_t *)&seq_groove_templates[selected_groove-SEQ_GROOVE_NUM_PRESETS];
  else
    g = (seq_groove_entry_t *)&seq_groove_presets[selected_groove];

  switch( ui_selected_item ) {
    case ITEM_GXTY:              return SEQ_UI_GxTyInc(incrementer);
    case ITEM_GROOVE_STYLE:      return SEQ_UI_CC_Inc(SEQ_CC_GROOVE_STYLE, 0, grooves_total-1, incrementer);
    case ITEM_GROOVE_VALUE:      return SEQ_UI_CC_Inc(SEQ_CC_GROOVE_VALUE, 0, 127, incrementer);
    case ITEM_GROOVE_STEP:       return SEQ_UI_Var8_Inc(&edit_step, 0, g->num_steps-1, incrementer);

    case ITEM_GROOVE_VALUE_GLB: {
      if( SEQ_UI_CC_Inc(SEQ_CC_GROOVE_VALUE, 0, 127, incrementer) > 0 ) {
	// change value for all tracks
	u8 value = SEQ_CC_Get(visible_track, SEQ_CC_GROOVE_VALUE);
	u8 track;
	for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track) {
	  SEQ_CC_Set(track, SEQ_CC_GROOVE_VALUE, value);
	}
	return 1;
      }
      return 0;
    }

    case ITEM_GROOVE_DELAY: {
      if( groove_template < 0 || groove_template >= SEQ_GROOVE_NUM_TEMPLATES )
	return 0;
      u8 value = (u8)seq_groove_templates[groove_template].add_step_delay[edit_step] + 128;
      if( SEQ_UI_Var8_Inc(&value, 0, 255, incrementer) > 0 ) {
	seq_groove_templates[groove_template].add_step_delay[edit_step] = (s8)(value - 128);
	ui_store_file_required = 1;
	return 1;
      }
      return 0;
    }

    case ITEM_GROOVE_LENGTH: {
      if( groove_template < 0 || groove_template >= SEQ_GROOVE_NUM_TEMPLATES )
	return 0;
      u8 value = (u8)seq_groove_templates[groove_template].add_step_length[edit_step] + 128;
      if( SEQ_UI_Var8_Inc(&value, 0, 255, incrementer) > 0 ) {
	seq_groove_templates[groove_template].add_step_length[edit_step] = (s8)(value - 128);
	ui_store_file_required = 1;
	return 1;
      }
      return 0;
    }

    case ITEM_GROOVE_VELOCITY: {
      if( groove_template < 0 || groove_template >= SEQ_GROOVE_NUM_TEMPLATES )
	return 0;
      u8 value = (u8)seq_groove_templates[groove_template].add_step_velocity[edit_step] + 128;
      if( SEQ_UI_Var8_Inc(&value, 0, 255, incrementer) > 0 ) {
	seq_groove_templates[groove_template].add_step_velocity[edit_step] = (s8)(value - 128);
	ui_store_file_required = 1;
	return 1;
      }
      return 0;
    }

    case ITEM_GROOVE_NUM_STEPS: {
      if( groove_template < 0 || groove_template >= SEQ_GROOVE_NUM_TEMPLATES )
	return 0;
      u8 value = (u8)seq_groove_templates[groove_template].num_steps;
      if( SEQ_UI_Var8_Inc(&value, 1, 16, incrementer) > 0 ) {
	seq_groove_templates[groove_template].num_steps = value;
	ui_store_file_required = 1;
	return 1;
      }
      return 0;
    }

  }

  return -1; // invalid or unsupported encoder
}
/////////////////////////////////////////////////////////////////////////////
// Local Display Handler function
// IN: <high_prio>: if set, a high-priority LCD update is requested
/////////////////////////////////////////////////////////////////////////////
static s32 LCD_Handler(u8 high_prio)
{
    if( high_prio )
        return 0; // there are no high-priority updates

    // layout:
    // 00000000001111111111222222222233333333330000000000111111111122222222223333333333
    // 01234567890123456789012345678901234567890123456789012345678901234567890123456789
    // <--------------------------------------><-------------------------------------->
    // Trk. off     Transpose              Bus Hold Sort  Restart  ForceScale  Sustain
    // G1T1   >Normal<  Arpeggiator         1   on   on     on        on         on

    u8 visible_track = SEQ_UI_VisibleTrackGet();

    ///////////////////////////////////////////////////////////////////////////
    SEQ_LCD_CursorSet(0, 0);
    SEQ_LCD_PrintString("Trk.");

    SEQ_LCD_CursorSet(0, 1);
    if( ui_selected_item == ITEM_GXTY && ui_cursor_flash ) {
        SEQ_LCD_PrintSpaces(9);
    } else {
        SEQ_LCD_PrintGxTy(ui_selected_group, ui_selected_tracks);
        SEQ_LCD_PrintSpaces(5);
    }

    ///////////////////////////////////////////////////////////////////////////
    const char mode_names[7][14] = {
        ">off<        ",
        ">Normal<     ",
        ">Transpose<  ",
        ">Arpeggiator<"
    };
    int i;
    int selected_mode = SEQ_CC_Get(visible_track, SEQ_CC_MODE);
    for(i=0; i<4; ++i) {
        u8 x = 4 + 5*i;
        SEQ_LCD_CursorSet(x, i%2);

        // print unmodified name if item selected
        // replace '>' and '<' by space if item not selected
        // flash item (print only '>'/'<' and spaces) if cursor position == 1 and flash flag set by timer
        int j;
        for(j=0; j<13; ++j) {
            u8 c = mode_names[i][j];

            if( ++x > 35 ) // don't print more than 35 characters per line
                break;

            if( c == '>' || c == '<' ) {
                SEQ_LCD_PrintChar((i == selected_mode) ? c : ' ');
            } else {
                if( ui_selected_item == ITEM_MODE && i == selected_mode && ui_cursor_flash )
                    SEQ_LCD_PrintChar(' ');
                else
                    SEQ_LCD_PrintChar(c);
            }
        }
    }

    // additional spaces to fill LCD (avoids artefacts on page switches)
    SEQ_LCD_CursorSet(25, 0);
    SEQ_LCD_PrintSpaces(15);
    SEQ_LCD_CursorSet(32, 1);
    SEQ_LCD_PrintSpaces(8);

    ///////////////////////////////////////////////////////////////////////////
    SEQ_LCD_CursorSet(35, 0);
    SEQ_LCD_PrintString(" Bus Hold Sort  Restart  ForceScale  Sustain ");
    SEQ_LCD_CursorSet(35, 1);

    ///////////////////////////////////////////////////////////////////////////
    if( ui_selected_item == ITEM_BUS && ui_cursor_flash ) {
        SEQ_LCD_PrintSpaces(3);
    } else {
        SEQ_LCD_PrintFormattedString("  %d", SEQ_CC_Get(visible_track, SEQ_CC_BUSASG) + 1);
    }
    SEQ_LCD_PrintSpaces(3);

    ///////////////////////////////////////////////////////////////////////////
    if( ui_selected_item == ITEM_HOLD && ui_cursor_flash ) {
        SEQ_LCD_PrintSpaces(3);
    } else {
        SEQ_LCD_PrintString((SEQ_CC_Get(visible_track, SEQ_CC_MODE_FLAGS) & (1 << 1)) ? "on " : "off");
    }
    SEQ_LCD_PrintSpaces(2);

    ///////////////////////////////////////////////////////////////////////////
    if( ui_selected_item == ITEM_SORT && ui_cursor_flash ) {
        SEQ_LCD_PrintSpaces(3);
    } else {
        SEQ_LCD_PrintString((SEQ_CC_Get(visible_track, SEQ_CC_MODE_FLAGS) & (1 << 0)) ? "off" : "on "); // SORT is inverted!
    }
    SEQ_LCD_PrintSpaces(4);

    ///////////////////////////////////////////////////////////////////////////
    if( ui_selected_item == ITEM_RESTART && ui_cursor_flash ) {
        SEQ_LCD_PrintSpaces(3);
    } else {
        SEQ_LCD_PrintString((SEQ_CC_Get(visible_track, SEQ_CC_MODE_FLAGS) & (1 << 2)) ? "on " : "off");
    }
    SEQ_LCD_PrintSpaces(7);

    ///////////////////////////////////////////////////////////////////////////
    if( ui_selected_item == ITEM_FORCE_SCALE && ui_cursor_flash ) {
        SEQ_LCD_PrintSpaces(3);
    } else {
        SEQ_LCD_PrintString((SEQ_CC_Get(visible_track, SEQ_CC_MODE_FLAGS) & (1 << 3)) ? "on " : "off");
    }
    SEQ_LCD_PrintSpaces(8);

    ///////////////////////////////////////////////////////////////////////////
    if( ui_selected_item == ITEM_SUSTAIN && ui_cursor_flash ) {
        SEQ_LCD_PrintSpaces(3);
    } else {
        SEQ_LCD_PrintString((SEQ_CC_Get(visible_track, SEQ_CC_MODE_FLAGS) & (1 << 4)) ? "on " : "off");
    }
    SEQ_LCD_PrintSpaces(3);

    return 0; // no error
}
/////////////////////////////////////////////////////////////////////////////
// Local Display Handler function
// IN: <high_prio>: if set, a high-priority LCD update is requested
/////////////////////////////////////////////////////////////////////////////
static s32 LCD_Handler(u8 high_prio)
{
  u8 visible_track = SEQ_UI_VisibleTrackGet();

  if( high_prio )
    return 0; // there are no high-priority updates

  // layout:
  // 00000000001111111111222222222233333333330000000000111111111122222222223333333333
  // 01234567890123456789012345678901234567890123456789012345678901234567890123456789
  // <--------------------------------------><-------------------------------------->
  // Trk. Mute Oct. Vel. FTS   Fx             Bus Port Chn. Lower/Upper Mode   Reset 
  // G1T1       +0  100   on   on              1  IN1  #16   ---   ---  T&A    Stacks

  // The selected Bus1 is not configured      Bus Port Chn. Lower/Upper Mode   Reset 
  // for Play mode (but for Transposer&Arp.)   1  IN1  #16   ---   ---  T&A    Stacks

  ///////////////////////////////////////////////////////////////////////////
  SEQ_LCD_CursorSet(0, 0);
  if( !seq_midi_in_options[selected_bus].MODE_PLAY ) {
    SEQ_LCD_PrintFormattedString("The selected Bus%d is not configured     ", selected_bus+1);
  } else {
    SEQ_LCD_PrintString("Trk. Mute Oct. Vel. FTS   Fx            ");
  }

  SEQ_LCD_CursorSet(40, 0);
  SEQ_LCD_PrintString(" Bus Port Chn. Lower/Upper Mode   Reset ");


  ///////////////////////////////////////////////////////////////////////////
  SEQ_LCD_CursorSet(0, 1);
  if( !seq_midi_in_options[selected_bus].MODE_PLAY ) {
    SEQ_LCD_PrintString("for Play mode (but for Transposer&Arp.) ");
  } else {
    if( ui_selected_item == ITEM_GXTY && ui_cursor_flash ) {
      SEQ_LCD_PrintSpaces(4);
    } else {
      SEQ_LCD_PrintGxTy(ui_selected_group, ui_selected_tracks);
    }
    SEQ_LCD_PrintSpaces(1);

    ///////////////////////////////////////////////////////////////////////////
    if( ui_selected_item == ITEM_MUTE && ui_cursor_flash ) {
      SEQ_LCD_PrintSpaces(5);
    } else {
      SEQ_LCD_PrintSpaces(2);
      SEQ_LCD_PrintChar((seq_core_trk_muted & (1 << visible_track)) ? '*' : 'o');
      SEQ_LCD_PrintSpaces(2);
    }

    ///////////////////////////////////////////////////////////////////////////
    if( ui_selected_item == ITEM_OCT_TRANSPOSE && ui_cursor_flash ) {
      SEQ_LCD_PrintSpaces(4);
    } else {
      u8 event_mode = SEQ_CC_Get(visible_track, SEQ_CC_MIDI_EVENT_MODE);
      if( event_mode == SEQ_EVENT_MODE_Drum ) {
	SEQ_LCD_PrintString("Drum");
      } else {
	SEQ_LCD_PrintFormattedString(" %c%d ", (seq_live_options.OCT_TRANSPOSE < 0) ? '-' : '+', abs(seq_live_options.OCT_TRANSPOSE));
      }
    }
    SEQ_LCD_PrintSpaces(1);

    ///////////////////////////////////////////////////////////////////////////
    if( ui_selected_item == ITEM_LIVE_VELOCITY && ui_cursor_flash ) {
      SEQ_LCD_PrintSpaces(3);
    } else {
      SEQ_LCD_PrintFormattedString("%3d", seq_live_options.VELOCITY);
    }
    SEQ_LCD_PrintSpaces(2);

    ///////////////////////////////////////////////////////////////////////////
    if( ui_selected_item == ITEM_LIVE_FORCE_SCALE && ui_cursor_flash ) {
      SEQ_LCD_PrintSpaces(3);
    } else {
      SEQ_LCD_PrintString(seq_live_options.FORCE_SCALE ? " on" : "off");
    }
    SEQ_LCD_PrintSpaces(2);

    ///////////////////////////////////////////////////////////////////////////
    if( ui_selected_item == ITEM_LIVE_FX && ui_cursor_flash ) {
      SEQ_LCD_PrintSpaces(3);
    } else {
      SEQ_LCD_PrintString(seq_live_options.FX ? " on" : "off");
    }
    SEQ_LCD_PrintSpaces(2 + 10);
  }



  ///////////////////////////////////////////////////////////////////////
  if( ui_selected_item == ITEM_IN_BUS && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(5);
  } else {
    SEQ_LCD_PrintFormattedString("  %d  ", selected_bus+1);
  }

  ///////////////////////////////////////////////////////////////////////
  if( ui_selected_item == ITEM_IN_PORT && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(4);
  } else {
    if( seq_midi_in_port[selected_bus] )
      SEQ_LCD_PrintString(SEQ_MIDI_PORT_InNameGet(SEQ_MIDI_PORT_InIxGet(seq_midi_in_port[selected_bus])));
    else
      SEQ_LCD_PrintString(" All");
  }
  SEQ_LCD_PrintSpaces(1);


  ///////////////////////////////////////////////////////////////////////
  if( ui_selected_item == ITEM_IN_CHN && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(3);
  } else {
    if( seq_midi_in_channel[selected_bus] )
      SEQ_LCD_PrintFormattedString("#%2d", seq_midi_in_channel[selected_bus]);
    else
      SEQ_LCD_PrintString("---");
  }
  SEQ_LCD_PrintSpaces(3);


  ///////////////////////////////////////////////////////////////////////
  if( ui_selected_item == ITEM_IN_LOWER && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(3);
  } else {
    SEQ_LCD_PrintNote(seq_midi_in_lower[selected_bus]);
  }
  SEQ_LCD_PrintSpaces(3);


  ///////////////////////////////////////////////////////////////////////
  if( ui_selected_item == ITEM_IN_UPPER && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(3);
  } else {
    SEQ_LCD_PrintNote(seq_midi_in_upper[selected_bus]);
  }
  SEQ_LCD_PrintSpaces(2);


  ///////////////////////////////////////////////////////////////////////
  if( ui_selected_item == ITEM_IN_MODE && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(4);
  } else {
    SEQ_LCD_PrintString(seq_midi_in_options[selected_bus].MODE_PLAY ? "Play" : "T&A ");
  }
  SEQ_LCD_PrintSpaces(3);

  SEQ_LCD_PrintString("Stacks");

  return 0; // no error
}
/////////////////////////////////////////////////////////////////////////////
// Local encoder callback function
// Should return:
//   1 if value has been changed
//   0 if value hasn't been changed
//  -1 if invalid or unsupported encoder
/////////////////////////////////////////////////////////////////////////////
static s32 Encoder_Handler(seq_ui_encoder_t encoder, s32 incrementer)
{
    u8 visible_track = SEQ_UI_VisibleTrackGet();

    switch( encoder ) {
    case SEQ_UI_ENCODER_GP1:
        ui_selected_item = ITEM_GXTY;
        break;

    case SEQ_UI_ENCODER_GP2:
    case SEQ_UI_ENCODER_GP3:
    case SEQ_UI_ENCODER_GP4:
    case SEQ_UI_ENCODER_GP5:
        ui_selected_item = ITEM_MODE;
        SEQ_UI_CC_Set(SEQ_CC_MODE, encoder-1);
        return 1;

    case SEQ_UI_ENCODER_GP6:
    case SEQ_UI_ENCODER_GP7:
        return -1; // not mapped

    case SEQ_UI_ENCODER_GP8:
        ui_selected_item = ITEM_BUS;
        break;

    case SEQ_UI_ENCODER_GP9:
        ui_selected_item = ITEM_HOLD;
        break;

    case SEQ_UI_ENCODER_GP10:
        ui_selected_item = ITEM_SORT;
        break;

    case SEQ_UI_ENCODER_GP11:
    case SEQ_UI_ENCODER_GP12:
        ui_selected_item = ITEM_RESTART;
        break;

    case SEQ_UI_ENCODER_GP13:
    case SEQ_UI_ENCODER_GP14:
        ui_selected_item = ITEM_FORCE_SCALE;
        break;

    case SEQ_UI_ENCODER_GP15:
    case SEQ_UI_ENCODER_GP16:
        ui_selected_item = ITEM_SUSTAIN;
        break;
    }

    // for GP encoders and Datawheel
    switch( ui_selected_item ) {
    case ITEM_GXTY:
        return SEQ_UI_GxTyInc(incrementer);

    case ITEM_MODE:
        return SEQ_UI_CC_Inc(SEQ_CC_MODE, 0, 3, incrementer);

    case ITEM_BUS:
        return SEQ_UI_CC_Inc(SEQ_CC_BUSASG, 0, 3, incrementer);

    case ITEM_HOLD:
        if( !incrementer ) // toggle flag
            incrementer = (SEQ_CC_Get(visible_track, SEQ_CC_MODE_FLAGS) & (1<<1)) ? -1 : 1;
        return SEQ_UI_CC_SetFlags(SEQ_CC_MODE_FLAGS, (1<<1), (incrementer >= 0) ? (1<<1) : 0);

    case ITEM_SORT:
        if( !incrementer ) // toggle flag - SORT is inverted!
            incrementer = (SEQ_CC_Get(visible_track, SEQ_CC_MODE_FLAGS) & (1<<0)) ? 1 : -1;
        return SEQ_UI_CC_SetFlags(SEQ_CC_MODE_FLAGS, (1<<0), (incrementer >= 0) ? 0 : (1<<0)); // SORT is inverted!

    case ITEM_RESTART:
        if( !incrementer ) // toggle flag
            incrementer = (SEQ_CC_Get(visible_track, SEQ_CC_MODE_FLAGS) & (1<<2)) ? -1 : 1;
        return SEQ_UI_CC_SetFlags(SEQ_CC_MODE_FLAGS, (1<<2), (incrementer >= 0) ? (1<<2) : 0);

    case ITEM_FORCE_SCALE:
        if( !incrementer ) // toggle flag
            incrementer = (SEQ_CC_Get(visible_track, SEQ_CC_MODE_FLAGS) & (1<<3)) ? -1 : 1;
        return SEQ_UI_CC_SetFlags(SEQ_CC_MODE_FLAGS, (1<<3), (incrementer >= 0) ? (1<<3) : 0);

    case ITEM_SUSTAIN:
        if( !incrementer ) // toggle flag
            incrementer = (SEQ_CC_Get(visible_track, SEQ_CC_MODE_FLAGS) & (1<<4)) ? -1 : 1;
        return SEQ_UI_CC_SetFlags(SEQ_CC_MODE_FLAGS, (1<<4), (incrementer >= 0) ? (1<<4) : 0);
    }

    return -1; // invalid or unsupported encoder
}
示例#30
0
/////////////////////////////////////////////////////////////////////////////
// Frequently called to return the status of GP LEDs
/////////////////////////////////////////////////////////////////////////////
u16 SEQ_UI_PAGES_GP_LED_Handler(void)
{
  if( ui_controller_mode )
    return SEQ_UI_PAGES_GP_LED_Handler_Controller();

  static u16 check_100mS_ctr = 0;

  if( load_save_notifier_ctr )
    --load_save_notifier_ctr;

  u8 visible_track = SEQ_UI_VisibleTrackGet();

  // for periodic checks (e.g. of selections derived from patches)
  if( ++check_100mS_ctr >= 100 )
    check_100mS_ctr = 0;

  // clear button pressed: print track activity
  if( seq_ui_button_state.CLEAR ) {
    return ui_track_activity_state;
  }

  switch( ui_page ) {

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_LOAD:
  case SEQ_UI_PAGE_SAVE: {
    u8 group = 0;
    u16 leds = (1 << ui_selected_pattern[group].group) | (1 << (ui_selected_pattern[group].num+8));
    if( ui_selected_pattern_changing && ui_cursor_flash )
      leds &= 0x00ff;

    // invert LEDs each 50 mS if load/save notifier active
    if( load_save_notifier_ctr && (load_save_notifier_ctr % 100) >= 50 )
      leds ^= 0xffff;

    return leds;
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_TRIGGER: {
    u8 *trg_ptr = (u8 *)&seq_trg_layer_value[visible_track][2*ui_selected_step_view];
    u16 leds = *trg_ptr;
    ++trg_ptr;
    leds |= (*trg_ptr << 8);

    return leds;
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_REC_STEP:
  case SEQ_UI_PAGE_REC_LIVE: {
    u8 record_track = 8;
    if( seq_record_state.ARMED_TRACKS & (1 << 0) )
      record_track = 0;

    u8 *trg_ptr = (u8 *)&seq_trg_layer_value[record_track][2*ui_selected_step_view];
    u16 leds = *trg_ptr;
    ++trg_ptr;
    leds |= (*trg_ptr << 8);

    u16 record_step_mask = (1 << (seq_record_step % 16));
    if( ui_cursor_flash &&
	((seq_record_step >> 4) == ui_selected_step_view) ) {
      leds ^= record_step_mask;
    }

    // button of selected step always active as long as GP button is pressed
    if( ui_selected_gp_buttons & record_step_mask )
      leds |= record_step_mask;

    return leds;
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_LENGTH: {
    u16 leds = 0x0000;
    u8 length = SEQ_CC_Get(visible_track, SEQ_CC_LENGTH);
    u8 loop = SEQ_CC_Get(visible_track, SEQ_CC_LOOP);

    if( length >= 16*(ui_selected_step_view+1) )
      leds = 0xffff;
    else if( (length >> 4) == ui_selected_step_view )
      leds = (1 << ((length % 16)+1))-1;

    if( ui_cursor_flash ) {
      if( (loop/16) == ui_selected_step_view )
	leds &= ~(1 << loop % 16);

      if( (length/16) == ui_selected_step_view )
	leds &= ~(1 << length % 16);
    }

    return leds;
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_PROGRESSION: {
    // check if selection still valid
    if( check_100mS_ctr == 0 ) {
      seq_cc_trk_t *tcc = &seq_cc_trk[visible_track];
      seq_ui_pages_progression_presets_t *preset = (seq_ui_pages_progression_presets_t *)&seq_ui_pages_progression_presets[0];
      int i;
      for(i=0; i<16; ++i, ++preset) {
	if( ((u8)tcc->steps_forward+1) == preset->steps_forward &&
	    tcc->steps_jump_back == preset->steps_jump_back &&
	    tcc->steps_replay == preset->steps_replay &&
	    tcc->steps_repeat == preset->steps_repeat &&
	    tcc->steps_skip == preset->steps_skip &&
	    tcc->steps_rs_interval == preset->steps_rs_interval ) {
	  ui_selected_progression_preset = i;
	  break;
	}
      }
    }

    return (1 << ui_selected_progression_preset);
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_GROOVE: {
    u8 groove_style = SEQ_CC_Get(visible_track, SEQ_CC_GROOVE_STYLE);
    if( groove_style < 8 || groove_style > 22 )
      return 0x0001; // off resp. non-selectable value
    else // note: starting at second custom groove, the first groove is always "off"
      return (1 << (groove_style-8+1));
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_ECHO: {
    // check if selection still valid
    if( check_100mS_ctr == 0 ) {
      seq_cc_trk_t *tcc = &seq_cc_trk[visible_track];
      seq_ui_pages_echo_presets_t *preset = (seq_ui_pages_echo_presets_t *)&seq_ui_pages_echo_presets[0];
      int i;
      for(i=0; i<16; ++i, ++preset) {
	if( tcc->echo_repeats == preset->repeats &&
	    tcc->echo_delay == preset->delay &&
	    tcc->echo_velocity == preset->velocity &&
	    tcc->echo_fb_velocity == preset->fb_velocity &&
	    tcc->echo_fb_note == preset->fb_note &&
	    tcc->echo_fb_gatelength == preset->fb_gatelength &&
	    tcc->echo_fb_ticks == preset->fb_ticks ) {
	  ui_selected_echo_preset = i;
	  break;
	}
      }
    }

    return (1 << ui_selected_echo_preset);
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_HUMANIZER: {
    // check if selection still valid
    if( check_100mS_ctr == 0 ) {
      seq_cc_trk_t *tcc = &seq_cc_trk[visible_track];
      seq_ui_pages_humanizer_presets_t *preset = (seq_ui_pages_humanizer_presets_t *)&seq_ui_pages_humanizer_presets[0];
      int i;
      for(i=0; i<16; ++i, ++preset) {
	if( tcc->humanize_mode == preset->mode &&
	    tcc->humanize_value == preset->value ) {
	  ui_selected_humanizer_preset = i;
	  break;
	}
      }
    }

    return (1 << ui_selected_humanizer_preset);
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_LFO: {
    // check if selection still valid
    if( check_100mS_ctr == 0 ) {
      seq_cc_trk_t *tcc = &seq_cc_trk[visible_track];
      seq_ui_pages_lfo_presets_t *preset = (seq_ui_pages_lfo_presets_t *)&seq_ui_pages_lfo_presets[0];
      int i;
      for(i=0; i<16; ++i, ++preset) {
	if( tcc->lfo_waveform == preset->waveform &&
	    tcc->lfo_amplitude == preset->amplitude &&
	    tcc->lfo_phase == preset->phase &&
	    tcc->lfo_steps == preset->steps &&
	    tcc->lfo_steps_rst == preset->steps_rst &&
	    tcc->lfo_enable_flags.ALL == preset->enable_flags &&
	    tcc->lfo_cc == preset->cc &&
	    tcc->lfo_cc_offset == preset->cc_offset &&
	    tcc->lfo_cc_ppqn == preset->cc_ppqn ) {
	  ui_selected_lfo_preset = i;
	  break;
	}
      }
    }

    return (1 << ui_selected_lfo_preset);
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_SCALE: {
    // check if selection still valid
    if( check_100mS_ctr == 0 ) {
      u8 note_track = 8;
      if( ui_selected_tracks & (1 << 0) )
	note_track = 0;

      if( !seq_cc_trk[note_track].mode.FORCE_SCALE )
	ui_selected_scale = 0;
      else {
	u8 *preset = (u8 *)&seq_ui_pages_scale_presets[1];
	int i;
	for(i=1; i<16; ++i, ++preset)
	  if( seq_core_global_scale == *preset )
	    break;

	ui_selected_scale = (i > 15) ? 15 : i; // if no preset scale, show last LED
      }
    }

    if( seq_ui_button_state.SCALE_PRESSED )
      return (1 << ui_selected_scale);

    if( seq_core_global_scale_root_selection )
      return (1 << (seq_core_global_scale_root_selection-1)); // selected scale
    else
      return 0xf000 | (1 << seq_core_keyb_scale_root); // scale via keyboard
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_MUTE: {
    u16 muted = seq_core_trk_muted;
    if( ui_cursor_flash && seq_ui_button_state.SOLO ) {
      //muted |= !ui_selected_tracks; // doesn't work with gcc version 4.2.1 ?!?
      muted |= ui_selected_tracks ^ 0xffff;
    }
    return muted;
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_MIDICHN: {
    u8 chn = SEQ_CC_Get(visible_track, SEQ_CC_MIDI_CHANNEL);
    return (1 << chn);
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_REC_ARM: {
    return seq_record_state.ARMED_TRACKS;
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_TEMPO: {
    // check if selection still valid
    if( check_100mS_ctr == 0 ) {
      seq_cc_trk_t *tcc = &seq_cc_trk[visible_track];
      seq_ui_pages_tempo_presets_t *preset = (seq_ui_pages_tempo_presets_t *)&seq_ui_pages_tempo_presets[0];
      int i;
      for(i=0; i<16; ++i, ++preset) {
	if( tcc->clkdiv.value == preset->clkdiv &&
	    tcc->clkdiv.TRIPLETS == preset->triplets ) {
	  ui_selected_tempo_preset = i;
	  break;
	}
      }
    }

    return (1 << ui_selected_tempo_preset);
  } break;
  }

  return 0x0000;
}