/////////////////////////////////////////////////////////////////////////////
// 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

  // GP button selects preset
  if( button <= SEQ_UI_BUTTON_GP16 ) {
    // set preset
    seq_core_bpm_preset_num = button;
    // change Tempo
    SEQ_CORE_BPM_Update(seq_core_bpm_preset_tempo[seq_core_bpm_preset_num], seq_core_bpm_preset_ramp[seq_core_bpm_preset_num]);
#if 0
    // and enter BPM page again
    SEQ_UI_PageSet(SEQ_UI_PAGE_BPM);
#endif
    // (NO!)
    return 1;
  }

  // TODO
  // too bad, that the menu handling concept doesn't allow to react on exit button here
  // this would allow to exit preset selection mode w/o exiting BPM page

  return -1; // ignore remaining buttons
}
Exemple #2
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

  // reset tap tempo if any button != GP16 has been pressed
  if( button != SEQ_UI_BUTTON_GP16 )
    resetTapTempo();

#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
    switch( button ) {
      case SEQ_UI_BUTTON_GP6:
      case SEQ_UI_BUTTON_GP7:
	// fire preset
	SEQ_CORE_BPM_Update(seq_core_bpm_preset_tempo[seq_core_bpm_preset_num], seq_core_bpm_preset_ramp[seq_core_bpm_preset_num]);
	return 1;

      case SEQ_UI_BUTTON_GP8:
	// enter preset selection page
	SEQ_UI_PageSet(SEQ_UI_PAGE_BPM_PRESETS);
	return 1;
    }

    // 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
  // <--------------------------------------><-------------------------------------->
  //  Mode Preset Tempo  Ramp    Fire  Preset  MClk In/Out              Ext.    Tap 
  // Master   1   140.0   1s    Preset  Page USB1 I:on O:off           Restart Tempo

  ///////////////////////////////////////////////////////////////////////////
  SEQ_LCD_CursorSet(0, 0);
  SEQ_LCD_PrintString(" Mode Preset Tempo  Ramp    Fire  Preset  MClk In/Out               ");
  SEQ_LCD_PrintString(seq_core_state.EXT_RESTART_REQ ? "Ongoing" : " Ext.  ");
  SEQ_LCD_PrintString(" Tap ");


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

  if( ui_selected_item == ITEM_MODE && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(6);
  } else {
    const char mode_str[3][7] = { " Auto ", "Master", "Slave "};
    SEQ_LCD_PrintString((char *)mode_str[SEQ_BPM_ModeGet()]);
  }
  SEQ_LCD_PrintSpaces(2);

  ///////////////////////////////////////////////////////////////////////////
  if( ui_selected_item == ITEM_PRESET && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(2);
  } else {
    SEQ_LCD_PrintFormattedString("%2d", seq_core_bpm_preset_num+1);
  }
  SEQ_LCD_PrintSpaces(3);

  ///////////////////////////////////////////////////////////////////////////
  if( ui_selected_item == ITEM_BPM && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(5);
  } else {
    float bpm = seq_core_bpm_preset_tempo[seq_core_bpm_preset_num];
    SEQ_LCD_PrintFormattedString("%3d.%d", (int)bpm, (int)(10*bpm)%10);
  }
  SEQ_LCD_PrintSpaces(2);

  ///////////////////////////////////////////////////////////////////////////
  if( ui_selected_item == ITEM_RAMP && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(3);
  } else {
    float ramp = seq_core_bpm_preset_ramp[seq_core_bpm_preset_num];
    SEQ_LCD_PrintFormattedString("%2ds", (int)ramp);
  }

  ///////////////////////////////////////////////////////////////////////////
  SEQ_LCD_PrintString("    Preset  Page  ");

  ///////////////////////////////////////////////////////////////////////////
  if( ui_selected_item == ITEM_MCLK_PORT && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(4);
  } else {
    SEQ_LCD_PrintString(SEQ_MIDI_PORT_ClkNameGet(SEQ_MIDI_PORT_ClkIxGet(selected_mclk_port)));
  }
  SEQ_LCD_PrintSpaces(1);

  ///////////////////////////////////////////////////////////////////////////
  SEQ_LCD_PrintString("I:");
  if( ui_selected_item == ITEM_MCLK_IN && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(3);
  } else {
    s32 status = SEQ_MIDI_ROUTER_MIDIClockInGet(selected_mclk_port);

    if( !SEQ_MIDI_PORT_ClkCheckAvailable(selected_mclk_port) )
      status = -1; // MIDI In port not available

    switch( status ) {
      case 0:  SEQ_LCD_PrintString("off"); break;
      case 1:  SEQ_LCD_PrintString("on "); break;
      default: SEQ_LCD_PrintString("---");
    }
  }
  SEQ_LCD_PrintSpaces(1);

  ///////////////////////////////////////////////////////////////////////////
  SEQ_LCD_PrintString("O:");
  if( ui_selected_item == ITEM_MCLK_OUT && ui_cursor_flash ) {
    SEQ_LCD_PrintSpaces(3);
  } else {
    s32 status = SEQ_MIDI_ROUTER_MIDIClockOutGet(selected_mclk_port);

    if( !SEQ_MIDI_PORT_ClkCheckAvailable(selected_mclk_port) )
      status = -1; // MIDI Out port not available

    switch( status ) {
      case 0:  SEQ_LCD_PrintString("off"); break;
      case 1:  SEQ_LCD_PrintString("on "); break;
      default: SEQ_LCD_PrintString("---");
    }
  }
  SEQ_LCD_PrintSpaces(3);

  // DIN Sync moved to CV configuration
  SEQ_LCD_PrintSpaces(3+4);

  ///////////////////////////////////////////////////////////////////////////
  SEQ_LCD_PrintString("Restart Tempo");


  return 0; // no error
}


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

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

    store_file_required = 0;
  }

  return status;
}
Exemple #3
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)
{
  // reset tap tempo if any encoder != GP16 has been pressed
  if( encoder != SEQ_UI_ENCODER_GP16 )
    resetTapTempo();


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

    case SEQ_UI_ENCODER_GP2:
      ui_selected_item = ITEM_PRESET;
      break;

    case SEQ_UI_ENCODER_GP3:
      ui_selected_item = ITEM_BPM;
      // special feature: these two encoders increment *10
      incrementer *= 10;
      break;

    case SEQ_UI_ENCODER_GP4:
      ui_selected_item = ITEM_BPM;
      break;

    case SEQ_UI_ENCODER_GP5:
      ui_selected_item = ITEM_RAMP;
      break;

    case SEQ_UI_ENCODER_GP6:
    case SEQ_UI_ENCODER_GP7:
    case SEQ_UI_ENCODER_GP8:
      return -1; // not mapped to encoder

    case SEQ_UI_ENCODER_GP9:
      ui_selected_item = ITEM_MCLK_PORT;
      break;

    case SEQ_UI_ENCODER_GP10:
      ui_selected_item = ITEM_MCLK_IN;
      break;

    case SEQ_UI_ENCODER_GP11:
      ui_selected_item = ITEM_MCLK_OUT;
      break;

    case SEQ_UI_ENCODER_GP12:
    case SEQ_UI_ENCODER_GP13:
      return -1; // not used (yet)

    case SEQ_UI_ENCODER_GP14:
    case SEQ_UI_ENCODER_GP15:
      // external restart request should be atomic
      portENTER_CRITICAL();
      seq_core_state.EXT_RESTART_REQ = 1;
      portEXIT_CRITICAL();
      return 1;

    case SEQ_UI_ENCODER_GP16:
      SEQ_UI_BPM_TapTempo();
      return 1;
  }

  // for GP encoders and Datawheel
  switch( ui_selected_item ) {
    case ITEM_MODE: {
      u8 value = SEQ_BPM_ModeGet();
      if( SEQ_UI_Var8_Inc(&value, 0, 2, incrementer) ) {
	SEQ_BPM_ModeSet(value);
	store_file_required = 1;
	return 1; // value has been changed
      } else
	return 0; // value hasn't been changed
    } break;

    case ITEM_PRESET: {
      return SEQ_UI_Var8_Inc(&seq_core_bpm_preset_num, 0, SEQ_CORE_NUM_BPM_PRESETS-1, incrementer);
    } break;

    case ITEM_BPM: {
      u16 value = (u16)(seq_core_bpm_preset_tempo[seq_core_bpm_preset_num]*10);
      if( SEQ_UI_Var16_Inc(&value, 25, 3000, incrementer) ) { // at 384ppqn, the minimum BPM rate is ca. 2.5
	// set new BPM
      	seq_core_bpm_preset_tempo[seq_core_bpm_preset_num] = (float)value/10.0;
	SEQ_CORE_BPM_Update(seq_core_bpm_preset_tempo[seq_core_bpm_preset_num], seq_core_bpm_preset_ramp[seq_core_bpm_preset_num]);
	store_file_required = 1;
	return 1; // value has been changed
      } else
	return 0; // value hasn't been changed
    } break;

    case ITEM_RAMP: {
      u16 value = (u16)seq_core_bpm_preset_ramp[seq_core_bpm_preset_num];
      if( SEQ_UI_Var16_Inc(&value, 0, 99, incrementer) ) {
	seq_core_bpm_preset_ramp[seq_core_bpm_preset_num] = (float)value;
	store_file_required = 1;
	return 1; // value has been changed
      } else
	return 0; // value hasn't been changed
    } break;

    case ITEM_MCLK_PORT: {
      u8 port_ix = SEQ_MIDI_PORT_ClkIxGet(selected_mclk_port);
      if( SEQ_UI_Var8_Inc(&port_ix, 0, SEQ_MIDI_PORT_ClkNumGet()-1, incrementer) >= 0 ) {
	selected_mclk_port = SEQ_MIDI_PORT_ClkPortGet(port_ix);
	return 1; // value changed
      }
      return 0; // no change
    } break;

    case ITEM_MCLK_IN: {
      s32 status = SEQ_MIDI_ROUTER_MIDIClockInGet(selected_mclk_port);
      if( status < 0 )
	return 0; // no change
      u8 enable = status;
      if( SEQ_UI_Var8_Inc(&enable, 0, 1, incrementer) >= 0 ) {
	SEQ_MIDI_ROUTER_MIDIClockInSet(selected_mclk_port, enable);
	store_file_required = 1;
	return 1; // value changed
      }
      return 0; // no change
    } break;

    case ITEM_MCLK_OUT: {
      s32 status = SEQ_MIDI_ROUTER_MIDIClockOutGet(selected_mclk_port);
      if( status < 0 )
	return 0; // no change
      u8 enable = status;
      if( SEQ_UI_Var8_Inc(&enable, 0, 1, incrementer) >= 0 ) {
	SEQ_MIDI_ROUTER_MIDIClockOutSet(selected_mclk_port, enable);
	store_file_required = 1;
	return 1; // value changed
      }
      return 0; // no change
    } break;
  }

  return -1; // invalid or unsupported encoder
}
/////////////////////////////////////////////////////////////////////////////
// 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( SEQ_FILE_FormattingRequired() )
    return 0; // no encoder action as long as files not available

  switch( selected_page ) {

    ///////////////////////////////////////////////////////////////////////////
    // REMIX PAGE
    case PAGE_REMIX: {
			
      // TODO: finish the incrementer helper for gp encoders
      if( encoder <= SEQ_UI_ENCODER_GP16 ) {
		
				if ( preview_mode ) { // the remix state
						
					if( ((1 << encoder) | seq_pattern_remix_map) == seq_pattern_remix_map ) { // if we already got the requested bit setup
						// unset him inside remix map
						seq_pattern_remix_map &= ~(1 << encoder);
					} else { // else setup it!
						// set him inside remix map
						seq_pattern_remix_map |= (1 << encoder);
					}
						
				} else { // the demix state
					
					// in this state we can not mix, just turn mixed states track into demixed state
					if( ((1 << encoder) | seq_pattern_remix_map) == seq_pattern_remix_map ) { // if we already got the requested bit setup inside remix map
						// unset him inside remix map
						seq_pattern_remix_map &= ~(1 << encoder);
					} else if ( ((1 << encoder) | seq_pattern_demix_map) == seq_pattern_demix_map ) { // if we already got the requested bit setup demix map
						// set him inside remix map
						seq_pattern_remix_map |= (1 << encoder);
					}
						
			  }
				
				if ( !preview_mode && ableton_api) {
					// send slot play envet to ableton cc (111 + track) with value 127 to channel 16
					MIOS32_MIDI_SendCC(ableton_port, 15, (111 + encoder), 127);	
				}
				
      }			
			
    } break;

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

    } break;

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

      u8 group;
      s32 status;

      // if we got a OK button pressed
      if (encoder==SEQ_UI_ENCODER_GP16) {
        // Get back to main page
        selected_page = PAGE_MAIN;
        return 1;
      }

      if( (status=SEQ_UI_KeyPad_Handler(encoder, incrementer, (char *)&seq_pattern_name[0], 20)) < 0 ) {
        // error
        return 0;
      } else {
        // copy the name of group 1 pattern to all other pattern groups
        for(group=1; group<SEQ_CORE_NUM_GROUPS; ++group) {
					//SEQ_LABEL_CopyPresetCategory(seq_pattern[0].num, (char *)&seq_pattern_name[group][0]);
					sprintf(seq_pattern_name[group], seq_pattern_name[0]);
        }
				
				// copy the pattern name
				sprintf(pattern_name, seq_pattern_name[0]);
				
      }

      return 1;

    } break;

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

    } break;

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

      switch( encoder ) {

        case SEQ_UI_ENCODER_Datawheel:
          incrementer = incrementer;

          u16 value = (u16)(seq_core_bpm_preset_tempo[seq_core_bpm_preset_num]*10);
          if( SEQ_UI_Var16_Inc(&value, 25, 3000, incrementer) ) { // at 384ppqn, the minimum BPM rate is ca. 2.5
            // set new BPM
            seq_core_bpm_preset_tempo[seq_core_bpm_preset_num] = (float)value/10.0;
            SEQ_CORE_BPM_Update(seq_core_bpm_preset_tempo[seq_core_bpm_preset_num], seq_core_bpm_preset_ramp[seq_core_bpm_preset_num]);
            return 1; // value has been changed
          } else {
            return 0; // value hasn't been changed
          }

        default:
          return -1; // invalid or unsupported encoder
      }

    } break;

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

  }
	
	return 0;

}
Exemple #5
0
/////////////////////////////////////////////////////////////////////////////
// fetches the pos entries of a song
// returns -1 if recursion counter reached max position
/////////////////////////////////////////////////////////////////////////////
s32 SEQ_SONG_FetchPos(u8 force_immediate_change, u8 dont_dump_mixer_map)
{
  int recursion_ctr = 0;

  u8 again;
  do {
    again = 0;

    // stop song once recursion counter reached 64 loops
    if( ++recursion_ctr >= 64 ) {
      SEQ_BPM_Stop();
      return -1; // recursion detected
    }

    // reset song position if we reached the end (loop over 128 steps)
    if( song_pos >= SEQ_SONG_NUM_STEPS )
      song_pos = 0;

    // get step entry
    seq_song_step_t *s = (seq_song_step_t *)&seq_song_steps[song_pos];

    // branch depending on action
    switch( s->action ) {
      case SEQ_SONG_ACTION_End:
#if 0
	if( song_active ) // not in phrase mode
	  SEQ_BPM_Stop();
#else
	song_finished = 1; // deactivate song incrementer
#endif
	break;

      case SEQ_SONG_ACTION_JmpPos:
	song_pos = s->action_value % SEQ_SONG_NUM_STEPS;
	again = 1;
	break;

      case SEQ_SONG_ACTION_JmpSong: {
	if( song_active ) { // not in phrase mode
	  u32 new_song_num = s->action_value % SEQ_SONG_NUM;

	  SEQ_SONG_Save(song_num);
	  SEQ_SONG_Load(new_song_num);
	  song_pos = 0;
	  again = 1;
	}
      } break;

      case SEQ_SONG_ACTION_SelMixerMap:
	SEQ_MIXER_Load(s->action_value);
	SEQ_MIDI_IN_ExtCtrlSend(SEQ_MIDI_IN_EXT_CTRL_MIXER_MAP, s->action_value, 0);
	if( !dont_dump_mixer_map )
	  SEQ_MIXER_SendAll();
	++song_pos;
	again = 1;
	break;

      case SEQ_SONG_ACTION_Tempo: {
	float bpm = (float)s->action_value;
	if( bpm < 25.0 )
	  bpm = 25.0;
	float ramp = (float)s->pattern_g1;
	SEQ_CORE_BPM_Update(bpm, ramp);
	++song_pos;
	again = 1;
      } break;

      case SEQ_SONG_ACTION_Mutes: {
	// access to seq_core_trk[] must be atomic!
	portENTER_CRITICAL();

	seq_core_trk_muted =
	  ((s->pattern_g1 & 0x0f) <<  0) |
	  ((s->pattern_g2 & 0x0f) <<  4) |
	  ((s->pattern_g3 & 0x0f) <<  8) |
	  ((s->pattern_g4 & 0x0f) << 12);

	portEXIT_CRITICAL();

	++song_pos;
	again = 1;
      } break;

      case SEQ_SONG_ACTION_GuideTrack: {
	if( s->action_value <= 16 )
	  seq_song_guide_track = s->action_value;
	++song_pos;
	again = 1;
      } break;

      default:
	if( s->action >= SEQ_SONG_ACTION_Loop1 && s->action <= SEQ_SONG_ACTION_Loop16 ) {
	  song_loop_ctr = 0;
	  song_loop_ctr_max = s->action - SEQ_SONG_ACTION_Loop1;

	  // TODO: implement prefetching until end of step!
	  
	  SEQ_SONG_FetchHlp_PatternChange(0, s->pattern_g1, s->bank_g1, force_immediate_change);
	  SEQ_SONG_FetchHlp_PatternChange(1, s->pattern_g2, s->bank_g2, force_immediate_change);
	  SEQ_SONG_FetchHlp_PatternChange(2, s->pattern_g3, s->bank_g3, force_immediate_change);
	  SEQ_SONG_FetchHlp_PatternChange(3, s->pattern_g4, s->bank_g4, force_immediate_change);
	}
    }

  } while( again );

  return 0; // no error
}