Esempio n. 1
0
static void knobValueSet(u32 ix, u16 value)
{
  if( knobValue[ix] != value ) {
    knobValue[ix] = value;
    MIOS32_MIDI_SendCC(USB0,  knobChn[ix], knobCC[ix], knobValue[ix]);
    MIOS32_MIDI_SendCC(UART0, knobChn[ix], knobCC[ix], knobValue[ix]);
  }
}
Esempio n. 2
0
/////////////////////////////////////////////////////////////////////////////
// This hook is called when an AINSER pot has been moved
/////////////////////////////////////////////////////////////////////////////
static void APP_AINSER_NotifyChange(u32 module, u32 pin, u32 pin_value)
{
    // toggle Status LED on each AIN value change
    MIOS32_BOARD_LED_Set(0x0001, ~MIOS32_BOARD_LED_Get());

    // convert 12bit value to 7bit value
    u8 value_7bit = pin_value >> 5;

    // send MIDI event
    MIOS32_MIDI_SendCC(DEFAULT, Chn1, pin + 0x10, value_7bit);
}
Esempio n. 3
0
/////////////////////////////////////////////////////////////////////////////
// This hook is called when an encoder has been moved
// incrementer is positive when encoder has been turned clockwise, else
// it is negative
/////////////////////////////////////////////////////////////////////////////
void APP_ENC_NotifyChange(u32 encoder, s32 incrementer)
{
#if DEBUG_VERBOSE_LEVEL >= 2
  DEBUG_MSG("APP_ENC_NotifyChange(%d, %d)\n", encoder, incrementer);
#endif

  // remember last pin and direction
  last_enc = encoder;
  last_enc_dir = (incrementer > 0) ? 1 : 0;

  // send MIDI event
  MIOS32_MIDI_SendCC(DEFAULT, Chn1, encoder, incrementer & 0x7f);
}
Esempio n. 4
0
/////////////////////////////////////////////////////////////////////////////
// This hook is called when an encoder has been moved
// incrementer is positive when encoder has been turned clockwise, else
// it is negative
/////////////////////////////////////////////////////////////////////////////
void APP_ENC_NotifyChange(u32 encoder, s32 incrementer)
{
  // toggle Status LED on each AIN value change
  MIOS32_BOARD_LED_Set(0x0001, ~MIOS32_BOARD_LED_Get());

  // determine relative value: 64 +/- <incrementer>
  int value = 64 + incrementer;

  // ensure that value is in range of 0..127
  if( value < 0 )
    value = 0;
  else if( value > 127 )
    value = 127;

  // send event
  MIOS32_MIDI_SendCC(DEFAULT, Chn1, 0x10 + encoder, value);
}
Esempio n. 5
0
/////////////////////////////////////////////////////////////////////////////
// Sends a single mixer value
/////////////////////////////////////////////////////////////////////////////
s32 SEQ_MIXER_Send(u8 chn, seq_mixer_par_t par)
{
    mios32_midi_port_t midi_port = SEQ_MIXER_Get(chn, SEQ_MIXER_PAR_PORT);
    mios32_midi_chn_t  midi_chn = SEQ_MIXER_Get(chn, SEQ_MIXER_PAR_CHANNEL);

    s32 value;
    if( (value=SEQ_MIXER_Get(chn, par)) < 0 )
        return 0; // don't return error, as it could be misinterpreded as a MIDI interface issue

    switch( par ) {
    case SEQ_MIXER_PAR_PRG:
        return value == 0 ? 0 : MIOS32_MIDI_SendProgramChange(midi_port, midi_chn, value-1);
    case SEQ_MIXER_PAR_VOLUME:
        return value == 0 ? 0 : MIOS32_MIDI_SendCC(midi_port, midi_chn, 7, value-1);
    case SEQ_MIXER_PAR_PANORAMA:
        return value == 0 ? 0 : MIOS32_MIDI_SendCC(midi_port, midi_chn, 10, value-1);
    case SEQ_MIXER_PAR_REVERB:
        return value == 0 ? 0 : MIOS32_MIDI_SendCC(midi_port, midi_chn, 91, value-1);
    case SEQ_MIXER_PAR_CHORUS:
        return value == 0 ? 0 : MIOS32_MIDI_SendCC(midi_port, midi_chn, 93, value-1);
    case SEQ_MIXER_PAR_MODWHEEL:
        return value == 0 ? 0 : MIOS32_MIDI_SendCC(midi_port, midi_chn, 1, value-1);

    case SEQ_MIXER_PAR_CC1:
        return value == 0 ? 0 : MIOS32_MIDI_SendCC(midi_port, midi_chn, SEQ_MIXER_Get(chn, SEQ_MIXER_PAR_CC1_NUM), value-1);
    case SEQ_MIXER_PAR_CC2:
        return value == 0 ? 0 : MIOS32_MIDI_SendCC(midi_port, midi_chn, SEQ_MIXER_Get(chn, SEQ_MIXER_PAR_CC2_NUM), value-1);
    case SEQ_MIXER_PAR_CC3:
        return value == 0 ? 0 : MIOS32_MIDI_SendCC(midi_port, midi_chn, SEQ_MIXER_Get(chn, SEQ_MIXER_PAR_CC3_NUM), value-1);
    case SEQ_MIXER_PAR_CC4:
        return value == 0 ? 0 : MIOS32_MIDI_SendCC(midi_port, midi_chn, SEQ_MIXER_Get(chn, SEQ_MIXER_PAR_CC4_NUM), value-1);
    }

    // not supported
    // don't return error, as this could be misinterpreted as a MIDI interface issue
    return 0;
}
Esempio n. 6
0
/////////////////////////////////////////////////////////////////////////////
// This function should be called from ENC_NotifyChange() in main.c
// when the jogwheel has been moved
/////////////////////////////////////////////////////////////////////////////
s32 LC_VPOT_SendJogWheelEvent(s32 incrementer)
{
  if( lc_hwcfg_verbose_level >= 2 ) {
    MIOS32_MIDI_SendDebugMessage("  -> LC_VPOT_SendJogWheelEvent(%d)\n", incrementer);
  }

  if( lc_flags.GPC_SEL ) {
    // in GPC mode: select GPC offset
    LC_GPC_SendJogWheelEvent(incrementer);
  } else {
    // otherwise send relative event to host application
    u8 cc_number = 0x3c;
    u8 value = (incrementer < 0) ? ((-incrementer & 0x3f) | 0x40) : ((incrementer & 0x3f) | 0x00);
    MIOS32_MIDI_SendCC(DEFAULT, Chn1, cc_number, value);
  }

  return 0; // no error
}
Esempio n. 7
0
/////////////////////////////////////////////////////////////////////////////
// This function should be called from ENC_NotifyChange() in main.c
// when a V-Pot has been moved
/////////////////////////////////////////////////////////////////////////////
s32 LC_VPOT_SendENCEvent(u8 encoder, s32 incrementer)
{
  if( lc_hwcfg_verbose_level >= 2 ) {
    MIOS32_MIDI_SendDebugMessage("  -> LC_VPOT_SendEncEvent(%d, %d)\n", encoder, incrementer);
  }

  if( lc_flags.GPC_SEL ) {
    // in GPC mode: change GPC value
    LC_GPC_SendENCEvent(encoder, incrementer);
  } else {
    // otherwise send relative event to host application
    u8 cc_number = 0x10 | (encoder & 0x07);
    u8 value = (incrementer < 0) ? ((-incrementer & 0x3f) | 0x40) : ((incrementer & 0x3f) | 0x00);
    MIOS32_MIDI_SendCC(DEFAULT, Chn1, cc_number, value);
  }

  return 0; // no error
}
Esempio n. 8
0
/////////////////////////////////////////////////////////////////////////////
// This hook is called when an encoder has been moved
// incrementer is positive when encoder has been turned clockwise, else
// it is negative
/////////////////////////////////////////////////////////////////////////////
void APP_ENC_NotifyChange(u32 encoder, s32 incrementer)
{
  // toggle Status LED on each AIN value change
  MIOS32_BOARD_LED_Set(1, ~MIOS32_BOARD_LED_Get());

  // increment to virtual position and ensure that the value is in range 0..127
  int value = enc_virtual_pos[encoder] + incrementer;
  if( value < 0 )
    value = 0;
  else if( value > 127 )
    value = 127;

  // only send if value has changed
  if( enc_virtual_pos[encoder] != value ) {
    // store new value
    enc_virtual_pos[encoder] = value;

    // send event
    MIOS32_MIDI_SendCC(DEFAULT, Chn1, 0x10 + encoder, value);
  }
}
/////////////////////////////////////////////////////////////////////////////
// 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 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;

}