Exemple #1
0
/////////////////////////////////////////////////////////////////////////////
// Called when a GP button has been toggled
/////////////////////////////////////////////////////////////////////////////
s32 SEQ_UI_PAGES_GP_Button_Handler(u8 button, u8 depressed)
{
  if( ui_controller_mode )
    return SEQ_UI_PAGES_GP_Button_Handler_Controller(button, depressed);

  // no page reacts on depressed buttons
  if( depressed )
    return 0;

  // clear button pressed: clear track
  if( seq_ui_button_state.CLEAR ) {
    u8 seq = (button >= 8) ? 1 : 0;
    u8 track_offset = seq ? 8 : 0;
    ui_selected_tracks = seq ? 0xff00 : 0x00ff;
    seq_record_state.ARMED_TRACKS = seq ? 0xff00 : 0x00ff;

    u8 seq_button = button % 8;
    switch( seq_button ) {
    case 0: { // clear note triggers (values are kept but not played)
      u8 track = track_offset;
      int num_t_steps = SEQ_TRG_NumStepsGet(track);
      int step8;
      u8 instrument = 0;
      u8 layer = 0;
      for(step8=0; step8<(num_t_steps/8); ++step8)
	SEQ_TRG_Set8(track, step8, layer, instrument, 0x00);
    } break;

    case 1: { // reset velocity values to 64
      u8 track = track_offset + 1;
      int num_p_layers = SEQ_PAR_NumLayersGet(track);
      int par_layer;
      for(par_layer=0; par_layer<num_p_layers; ++par_layer) {
	int num_p_instruments = SEQ_PAR_NumInstrumentsGet(track);
	int num_p_steps  = SEQ_PAR_NumStepsGet(track);;
	u8 init_value = 64;

	int step;
	int instrument;
	for(instrument=0; instrument<num_p_instruments; ++instrument)
	  for(step=0; step<num_p_steps; ++step)
	    SEQ_PAR_Set(track, step, par_layer, instrument, init_value);
      }
    } break;

    case 2: { // reset note length values to half step
      u8 track = track_offset + 2;
      int num_p_layers = SEQ_PAR_NumLayersGet(track);
      int par_layer;
      for(par_layer=0; par_layer<num_p_layers; ++par_layer) {
	int num_p_instruments = SEQ_PAR_NumInstrumentsGet(track);
	int num_p_steps  = SEQ_PAR_NumStepsGet(track);;
	u8 init_value = 51; // half length

	int step;
	int instrument;
	for(instrument=0; instrument<num_p_instruments; ++instrument)
	  for(step=0; step<num_p_steps; ++step)
	    SEQ_PAR_Set(track, step, par_layer, instrument, init_value);
      }
    } break;

    default: {
      u8 track = track_offset + seq_button;

      if( seq_button == 3 ) { // special treatmend for pitchbend
	int par_layer = 0;
	{
	  int num_p_instruments = SEQ_PAR_NumInstrumentsGet(track);
	  int num_p_steps  = SEQ_PAR_NumStepsGet(track);;
	  u8 init_value = 64;

	  int step;
	  int instrument;
	  for(instrument=0; instrument<num_p_instruments; ++instrument)
	    for(step=0; step<num_p_steps; ++step)
	      SEQ_PAR_Set(track, step, par_layer, instrument, init_value);
	}
	// send pitchbend 0 for proper reset of MIDI device
	SEQ_LAYER_DirectSendEvent(track, par_layer);
      }

      // clear CCs
      {
	int num_p_layers = SEQ_PAR_NumLayersGet(track);
	int par_layer;
	for(par_layer=(track == 3) ? 1 : 0; par_layer<num_p_layers; ++par_layer) { // don't touch pitchbender
	  int num_p_instruments = SEQ_PAR_NumInstrumentsGet(track);
	  int num_p_steps  = SEQ_PAR_NumStepsGet(track);;
	  u8 init_value = 64;

	  int step;
	  int instrument;
	  for(instrument=0; instrument<num_p_instruments; ++instrument)
	    for(step=0; step<num_p_steps; ++step)
	      SEQ_PAR_Set(track, step, par_layer, instrument, init_value);

	  // disable CC assignment
	  SEQ_CC_Set(track, SEQ_CC_LAY_CONST_B1+par_layer, 0x80);
	}
      }
    }
    }

    return 0;
  }

  switch( ui_page ) {

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_LOAD:
  case SEQ_UI_PAGE_SAVE: {
    // not atomic so that files can be stored in background
    //portENTER_CRITICAL();

    u8 group;
    for(group=0; group<SEQ_CORE_NUM_GROUPS; ++group) {
      seq_pattern_t *pattern = &ui_selected_pattern[group];

      pattern->bank = group; // always same as group
      if( button < 8 ) {
	pattern->group = button;
	ui_selected_pattern_changing = 1;
      } else {
	pattern->num = button-8;
	ui_selected_pattern_changing = 0;

	if( ui_page == SEQ_UI_PAGE_SAVE ) {
	  //DEBUG_MSG("BEGIN Save %d:%c%d\n", pattern->bank+1, 'A'+pattern->group, pattern->num+1);
	  s32 status = 0;
	  if( (status=SEQ_PATTERN_Save(group, *pattern)) < 0 )
	    SEQ_UI_SDCardErrMsg(2000, status);
	  else
	    load_save_notifier_ctr = 300; // notify about save operation for 300 mS
	  //DEBUG_MSG("END   Save %d:%c%d\n", pattern->bank+1, 'A'+pattern->group, pattern->num+1);
	} else {
	  //DEBUG_MSG("BEGIN Load %d:%c%d\n", pattern->bank+1, 'A'+pattern->group, pattern->num+1);
	  SEQ_PATTERN_Change(group, *pattern, 0);
	  load_save_notifier_ctr = 300; // notify about load operation for 300 mS
	  //DEBUG_MSG("END   Load %d:%c%d\n", pattern->bank+1, 'A'+pattern->group, pattern->num+1);
	}
      }
    }

    //portEXIT_CRITICAL();
    return 0;
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_TRIGGER: {
    // should be atomic
    portENTER_CRITICAL();

    ui_selected_step = button;

    u8 track; // only change triggers if track 0 and 8
    for(track=0; track<SEQ_CORE_NUM_TRACKS; track+=8)
      if( ui_selected_tracks & (1 << track) ) {
	u8 *trg_ptr = (u8 *)&seq_trg_layer_value[track][2*ui_selected_step_view + (button>>3)];
	*trg_ptr ^= (1 << (button&7));
      }

    portEXIT_CRITICAL();
    return 0;
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_LENGTH: {
    // should be atomic
    portENTER_CRITICAL();

    u8 track;
    for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track) {
      if( ui_selected_tracks & (1 << track) ) {
	if( seq_ui_button_state.LENGTH_PRESSED ) {
	  if( (track >= 0 && track <= 2) || (track >= 8 && track <= 10) )
	    SEQ_CC_Set(track, SEQ_CC_LOOP, 16*ui_selected_step_view + button);
	  else
	    SEQ_CC_Set(track, SEQ_CC_LOOP, 64*ui_selected_step_view + 4*button + 3); // 4x resolution
	} else {
	  if( (track >= 0 && track <= 2) || (track >= 8 && track <= 10) )
	    SEQ_CC_Set(track, SEQ_CC_LENGTH, 16*ui_selected_step_view + button);
	  else
	    SEQ_CC_Set(track, SEQ_CC_LENGTH, 64*ui_selected_step_view + 4*button + 3); // 4x resolution
	}
      }
    }

    portEXIT_CRITICAL();
    return 0;
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_PROGRESSION: {
    // should be atomic
    portENTER_CRITICAL();

    ui_selected_progression_preset = button;
    seq_ui_pages_progression_presets_t *preset = (seq_ui_pages_progression_presets_t *)&seq_ui_pages_progression_presets[ui_selected_progression_preset];
    u8 track;
    for(track=0; track<SEQ_CORE_NUM_TRACKS; track+=8) {
      if( ui_selected_tracks & (1 << track) ) {
	SEQ_CC_Set(track, SEQ_CC_STEPS_FORWARD, (preset->steps_forward > 0) ? (preset->steps_forward-1) : 0);
	SEQ_CC_Set(track, SEQ_CC_STEPS_JMPBCK, preset->steps_jump_back);
	SEQ_CC_Set(track, SEQ_CC_STEPS_REPLAY, preset->steps_replay);
	SEQ_CC_Set(track, SEQ_CC_STEPS_REPEAT, preset->steps_repeat);
	SEQ_CC_Set(track, SEQ_CC_STEPS_SKIP, preset->steps_skip);
	SEQ_CC_Set(track, SEQ_CC_STEPS_RS_INTERVAL, preset->steps_rs_interval);
      }
    }

    // GP1 also requests synch to measure
    // it's a good idea to do this for all tracks so that both sequences are in synch again
    if( button == 0 )
      SEQ_CORE_ManualSynchToMeasure(0xffff);

    portEXIT_CRITICAL();
    return 0;
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_GROOVE: {
    // should be atomic
    portENTER_CRITICAL();

    // first button turns off groove function
    // remaining buttons select custom groove #1..15
    u8 groove_style = 0;
    if( button > 0 ) // note: starting at second custom groove, the first groove is always "off"
      groove_style = button+8-1;
    SEQ_UI_CC_Set(SEQ_CC_GROOVE_STYLE, groove_style);
    portEXIT_CRITICAL();
    return 0;
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_ECHO: {
    // should be atomic
    portENTER_CRITICAL();

    ui_selected_echo_preset = button;
    seq_ui_pages_echo_presets_t *preset = (seq_ui_pages_echo_presets_t *)&seq_ui_pages_echo_presets[ui_selected_echo_preset];
    u8 track;
    for(track=0; track<SEQ_CORE_NUM_TRACKS; track+=8) {
      if( ui_selected_tracks & (1 << track) ) {
	SEQ_CC_Set(track, SEQ_CC_ECHO_REPEATS, preset->repeats);
	SEQ_CC_Set(track, SEQ_CC_ECHO_DELAY, preset->delay);
	SEQ_CC_Set(track, SEQ_CC_ECHO_VELOCITY, preset->velocity);
	SEQ_CC_Set(track, SEQ_CC_ECHO_FB_VELOCITY, preset->fb_velocity);
	SEQ_CC_Set(track, SEQ_CC_ECHO_FB_NOTE, preset->fb_note);
	SEQ_CC_Set(track, SEQ_CC_ECHO_FB_GATELENGTH, preset->fb_gatelength);
	SEQ_CC_Set(track, SEQ_CC_ECHO_FB_TICKS, preset->fb_ticks);
      }
    }

    portEXIT_CRITICAL();
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_HUMANIZER: {
    // should be atomic
    portENTER_CRITICAL();

    ui_selected_humanizer_preset = button;
    seq_ui_pages_humanizer_presets_t *preset = (seq_ui_pages_humanizer_presets_t *)&seq_ui_pages_humanizer_presets[ui_selected_humanizer_preset];
    u8 track;
    for(track=0; track<SEQ_CORE_NUM_TRACKS; track+=8) {
      if( ui_selected_tracks & (1 << track) ) {
	SEQ_CC_Set(track, SEQ_CC_HUMANIZE_MODE, preset->mode);
	SEQ_CC_Set(track, SEQ_CC_HUMANIZE_VALUE, preset->value);
      }
    }

    portEXIT_CRITICAL();
    return 0;
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_LFO: {
    // should be atomic
    portENTER_CRITICAL();

    ui_selected_lfo_preset = button;
    seq_ui_pages_lfo_presets_t *preset = (seq_ui_pages_lfo_presets_t *)&seq_ui_pages_lfo_presets[ui_selected_lfo_preset];
    u8 track;
    for(track=0; track<SEQ_CORE_NUM_TRACKS; track+=8) {
      if( ui_selected_tracks & (1 << track) ) {
	SEQ_CC_Set(track, SEQ_CC_LFO_WAVEFORM, preset->waveform);
	SEQ_CC_Set(track, SEQ_CC_LFO_AMPLITUDE, preset->amplitude);
	SEQ_CC_Set(track, SEQ_CC_LFO_PHASE, preset->phase);
	SEQ_CC_Set(track, SEQ_CC_LFO_STEPS, preset->steps);
	SEQ_CC_Set(track, SEQ_CC_LFO_STEPS_RST, preset->steps_rst);
	SEQ_CC_Set(track, SEQ_CC_LFO_ENABLE_FLAGS, preset->enable_flags);
	SEQ_CC_Set(track, SEQ_CC_LFO_CC, preset->cc);
	SEQ_CC_Set(track, SEQ_CC_LFO_CC_OFFSET, preset->cc_offset);
	SEQ_CC_Set(track, SEQ_CC_LFO_CC_PPQN, preset->cc_ppqn);
      }
    }

    portEXIT_CRITICAL();
    return 0;
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_SCALE: {
    // should be atomic
    portENTER_CRITICAL();

    // if SCALE button not pressed: select root key
    if( !seq_ui_button_state.SCALE_PRESSED ) {
      if( button < 12 ) {
	seq_core_global_scale_root_selection = button + 1;
      } else {
	seq_core_global_scale_root_selection = 0; // via keyboard
      }
    } else {
      // if pressed: select scale

      ui_selected_scale = button;

      if( ui_selected_scale == 0 ) {
	// disable force-to-scale for both note tracks (makes sense, since the scale itself is global as well)
	u8 track;
	for(track=0; track<SEQ_CORE_NUM_TRACKS; track+=8)
	  seq_cc_trk[track].mode.FORCE_SCALE = 0;
      } else {
	// select scale
	seq_core_global_scale = seq_ui_pages_scale_presets[ui_selected_scale];

	// enable force-to-scale for both note tracks (makes sense, since the scale itself is global as well)
	u8 track;
	for(track=0; track<SEQ_CORE_NUM_TRACKS; track+=8)
	  seq_cc_trk[track].mode.FORCE_SCALE = 1;
      }
    }

    portEXIT_CRITICAL();
    return 0;
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_MUTE: {
    // should be atomic
    portENTER_CRITICAL();

    seq_core_trk_muted ^= (1 << button);

    portEXIT_CRITICAL();
    return 0;
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_MIDICHN: {
    // should be atomic
    portENTER_CRITICAL();

    u8 track;
    for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track)
      if( ui_selected_tracks & (1 << track) )
	SEQ_CC_Set(track, SEQ_CC_MIDI_CHANNEL, button);

    portEXIT_CRITICAL();
    return 0;
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_REC_ARM: {
    // should be atomic
    portENTER_CRITICAL();

    // allow to select an unplayed track
    if( button >= 8 && (seq_record_state.ARMED_TRACKS & 0x00ff) )
      seq_record_state.ARMED_TRACKS = 0xff00;
    else if( button < 8 && (seq_record_state.ARMED_TRACKS & 0xff00) )
      seq_record_state.ARMED_TRACKS = 0x00ff;
    else {
      seq_record_state.ARMED_TRACKS ^= (1 << button);
    }

    portEXIT_CRITICAL();
    return 0;
  } break;

  ///////////////////////////////////////////////////////////////////////////
  case SEQ_UI_PAGE_REC_STEP: {
  case SEQ_UI_PAGE_REC_LIVE:
    // should be atomic
    portENTER_CRITICAL();

    seq_record_step = 16*ui_selected_step_view + button;

    // we will always clear the current step for more comfortable handling
    // (no need to select the Trigger page for doing this)
    u8 track; // only change triggers if track 0 and 8
    for(track=0; track<SEQ_CORE_NUM_TRACKS; track+=8)
      if( seq_record_state.ARMED_TRACKS & (1 << track) ) {
	u8 *trg_ptr = (u8 *)&seq_trg_layer_value[track][2*ui_selected_step_view + (button>>3)];
	*trg_ptr &= ~(1 << (button&7));

	SEQ_RECORD_Reset(track);
      }

    portEXIT_CRITICAL();
    return 0;
  } break;
Exemple #2
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)
{
  // ensure that original screen will be print immediately
  ui_hold_msg_ctr = 0;

#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
    // select step within view
    ui_selected_step = (ui_selected_step_view << 4) | (u8)encoder;

    // show edit page for 2 seconds
    ui_hold_msg_ctr = 2000;

    // forward manual trigger to SEQ_CORE
    SEQ_CORE_ManualTrigger(ui_selected_step);

    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( depressed ) return 0; // ignore when button depressed

  // ensure that original screen will be print immediately
  ui_hold_msg_ctr = 0;

#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: {
      // Request synch to measure for all selected tracks
      SEQ_CORE_ManualSynchToMeasure();
      return 1;
    } break;

    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)
{
  // branch to edit page if requested
  if( ui_hold_msg_ctr )
    return SEQ_UI_EDIT_LCD_Handler(high_prio, SEQ_UI_EDIT_MODE_MANUAL);


  // layout:
  // 00000000001111111111222222222233333333330000000000111111111122222222223333333333
  // 01234567890123456789012345678901234567890123456789012345678901234567890123456789
  // <--------------------------------------><-------------------------------------->
  //   Selected Tracks: 1234 1234 1234 1234     Press SELECT to Synch to Measure!    
  // lower line: print step 1..16/17..32/...

  ///////////////////////////////////////////////////////////////////////////
  SEQ_LCD_CursorSet(0, 0);
  SEQ_LCD_PrintString("  Selected Tracks: ");

  u8 track;
  for(track=0; track<16; ++track) {
    if( seq_core_trk[track].state.SYNC_MEASURE )
      SEQ_LCD_PrintChar('S');
    else if( SEQ_UI_IsSelectedTrack(track) )
      SEQ_LCD_PrintChar('*');
    else
      SEQ_LCD_PrintChar('1' + (track&3));

    if( (track&3) == 3 )
      SEQ_LCD_PrintChar(' ');
  }
  SEQ_LCD_PrintSpaces(1);

  SEQ_LCD_PrintString("   Press SELECT to Synch to Measure!    ");


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

  u8 step;
  for(step=0; step<16; ++step)
    SEQ_LCD_PrintFormattedString(" %2d  ", 16*ui_selected_step_view + step + 1);

  return 0; // no error
}


/////////////////////////////////////////////////////////////////////////////
// Initialisation
/////////////////////////////////////////////////////////////////////////////
s32 SEQ_UI_MANUAL_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
}