コード例 #1
0
ファイル: seq_midi_in.c プロジェクト: gillspice/mios32
static s32 SEQ_MIDI_IN_Receive_NotePC(u8 note, u8 velocity)
{
  int octave = note / 12;
  int octave_taken = 0;

  int group;
  for(group=0; group<4; ++group) {
    if( octave == (seq_midi_in_sect_note[group] / 12) ) {
      octave_taken = 1;
      notestack_t *n = &patch_changer_notestack[group];

      int patch = -1;
      if( velocity ) { // Note On
	NOTESTACK_Push(n, note, velocity);
	patch = n->note_items[0].note % 12;
      } else { // Note Off
	if( NOTESTACK_Pop(n, note) > 0 && n->len ) {
	  patch = n->note_items[0].note % 12;
	}
      }

      // switch to new patch if required
      if( patch >= 0 && patch < 8 ) {
	seq_pattern_t pattern = seq_pattern[group];
	if( pattern.num != patch ) {
	  pattern.num = patch;
	  pattern.DISABLED = 0;
	  pattern.SYNCHED = 0;
	  SEQ_PATTERN_Change(group, pattern);
	}
      }

#if DEBUG_VERBOSE_LEVEL >= 0
      DEBUG_MSG("NOTESTACK_PATCH_CHANGER_G%d:\n", group+1);
      NOTESTACK_SendDebugMessage(n);
#endif
    }
  }

  return octave_taken; // return 1 if octave has been taken, otherwise 0
}
コード例 #2
0
ファイル: seq_song.c プロジェクト: glocklueng/stm32-mios32
/////////////////////////////////////////////////////////////////////////////
// Help function for pattern switching
/////////////////////////////////////////////////////////////////////////////
static s32 SEQ_SONG_FetchHlp_PatternChange(u8 group, u8 pattern, u8 bank, u8 force_immediate_change)
{
  if( pattern < 0x80 ) {
    if( force_immediate_change || pattern != seq_pattern[group].pattern ) {
      seq_pattern_t p;
      p.ALL = 0;
      p.pattern = pattern;
      p.bank = bank;
      SEQ_PATTERN_Change(group, p, force_immediate_change);
    } else {
      // pattern not reloaded... we have to consider the RATOPC flag which is normally done in SEQ_PATTERN_Handler()
      if( seq_core_options.RATOPC ) {
	MIOS32_IRQ_Disable(); // must be atomic
	seq_core_state.reset_trkpos_req |= (0xf << (4*group));
	MIOS32_IRQ_Enable();
      }
    }
  }

  return 0; // no error
}
コード例 #3
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( 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;

}
コード例 #4
0
ファイル: seq_midi_in.c プロジェクト: gillspice/mios32
/////////////////////////////////////////////////////////////////////////////
// CC has been received over selected port and channel
/////////////////////////////////////////////////////////////////////////////
static s32 SEQ_MIDI_IN_Receive_CC(u8 bus, u8 cc, u8 value)
{
  static u8 nrpn_lsb = 0;
  static u8 nrpn_msb = 0;

  if( bus >= SEQ_MIDI_IN_NUM_BUSSES )
    return -1;

  // MIDI Remote Function?
  if( seq_hwcfg_midi_remote.cc && seq_hwcfg_midi_remote.cc == cc ) {
    remote_active = value >= 0x40;
    return 1;
  }

  // Remaining functions
  switch( cc ) {
    case 0x01: // ModWheel -> Morph Value
    case 0x03: // Global Scale
      return SEQ_CC_MIDI_Set(0, cc, value);

    case 0x70: // Pattern Group #1
    case 0x71: // Pattern Group #2
    case 0x72: // Pattern Group #3
    case 0x73: { // Pattern Group #4
      u8 group = cc-0x70;
      seq_pattern_t pattern = seq_pattern[group];
      if( value < SEQ_FILE_B_NumPatterns(pattern.bank) ) {
	pattern.pattern = value;
	pattern.DISABLED = 0;
	pattern.SYNCHED = 0;
	SEQ_PATTERN_Change(group, pattern, 0);
      }
      return 1;
    } break;
      
    case 0x74: // Bank Group #1
    case 0x75: // Bank Group #2
    case 0x76: // Bank Group #3
    case 0x77: { // Bank Group #4
      u8 group = cc-0x74;
      seq_pattern_t pattern = seq_pattern[group];
      if( value < SEQ_FILE_B_NUM_BANKS ) {
	pattern.bank = value;
	pattern.DISABLED = 0;
	pattern.SYNCHED = 0;
	SEQ_PATTERN_Change(group, pattern, 0);
      }
      return 1;
    } break;
      
    case 0x62: // NRPN LSB (selects parameter)
      nrpn_lsb = value;
      return 1;

    case 0x63: // NRPN MSB (selects track)
      nrpn_msb = value;
      return 1;

    case 0x06: // NRPN Value LSB (sets parameter)
      if( nrpn_msb < SEQ_CORE_NUM_TRACKS)
	return SEQ_CC_MIDI_Set(nrpn_msb, nrpn_lsb, value);
      break;

    case 0x7b: // all notes off (transposer, arpeggiator, patch changer)
      if( value == 0 ) {
	SEQ_MIDI_IN_ResetAllStacks();
	SEQ_CV_ResetAllChannels();
      }
      break;
  }

  return 0; // no error
}
コード例 #5
0
ファイル: seq_ui_pages.c プロジェクト: eranrund/mutebox
/////////////////////////////////////////////////////////////////////////////
// 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;
コード例 #6
0
/////////////////////////////////////////////////////////////////////////////
// fetches the pos entries of a song
// returns -1 if recursion counter reached max position
/////////////////////////////////////////////////////////////////////////////
s32 SEQ_SONG_FetchPos(u8 force_immediate_change)
{
  int recursion_ctr = 0;
	DEBUG_MSG("SEQ_SONG_FetchPos gestart");
  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);
	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;

	  seq_pattern_t p;

	  // TODO: implement prefetching until end of step!

	  if( s->pattern_g1 < 0x80 ) {
	    p.ALL = 0;
	    p.pattern = s->pattern_g1;
	    p.bank = s->bank_g1;
		if (seq_hwcfg_mb909.enabled && seq_hwcfg_mb909.multimachine==0){
			seq_core_trk_muted = ~((1<< s->bank_g2) & 0x0f);
		}
	    SEQ_PATTERN_Change(0, p, force_immediate_change);
	  }

	  if( s->pattern_g2 < 0x80 ) {
	    p.ALL = 0;
	    p.pattern = s->pattern_g2;
	    p.bank = s->bank_g2;
	    SEQ_PATTERN_Change(1, p, force_immediate_change);
	  }
	/*
	  if( s->pattern_g3 < 0x80 ) {
	    p.ALL = 0;
	    p.pattern = s->pattern_g3;
	    p.bank = s->bank_g3;
	    SEQ_PATTERN_Change(2, p, force_immediate_change);
	  }

	  if( s->pattern_g4 < 0x80 ) {
	    p.ALL = 0;
	    p.pattern = s->pattern_g4;
	    p.bank = s->bank_g4;
	    SEQ_PATTERN_Change(3, p, force_immediate_change);
	  }
	 */ 
	}
    }

  } while( again );

  return 0; // no error
}