コード例 #1
0
ファイル: seq_song.c プロジェクト: glocklueng/stm32-mios32
/////////////////////////////////////////////////////////////////////////////
// called by the UI to handle the "Fwd" button
/////////////////////////////////////////////////////////////////////////////
s32 SEQ_SONG_Fwd(void)
{
  if( ui_page == SEQ_UI_PAGE_SONG ) {
    song_pos = ui_song_edit_pos;
    song_loop_ctr = 0;
    SEQ_SONG_NextPos();
    if( ui_song_edit_pos != song_pos )
      ui_song_edit_pos = song_pos;
    else {
      // increment if possible
      if( song_pos < SEQ_SONG_NUM_STEPS ) {
	++song_pos;
	SEQ_SONG_FetchPos(0, 0);
	ui_song_edit_pos = song_pos;

	// update display immediately
	seq_ui_display_update_req = 1;
      }
    }
  } else {
    u32 bpm_tick = SEQ_BPM_TickGet();
    u32 ticks_per_pattern = ((u32)seq_core_steps_per_pattern+1) * (SEQ_BPM_PPQN_Get()/4);
    u32 measure = bpm_tick / ticks_per_pattern;
    u32 next_bpm_tick = (measure+1) * ticks_per_pattern;

    SEQ_CORE_Reset(next_bpm_tick);
    SEQ_SONG_NextPos();
    SEQ_BPM_TickSet(next_bpm_tick);
  }

  return 0; // no error
}
コード例 #2
0
ファイル: seq.c プロジェクト: JKcompute/395_midi_controller
/////////////////////////////////////////////////////////////////////////////
// Sets new song position (new_song_pos resolution: 16th notes)
/////////////////////////////////////////////////////////////////////////////
static s32 SEQ_SongPos(u16 new_song_pos)
{
  u16 new_tick = new_song_pos * (SEQ_BPM_PPQN_Get() / 4);

  // set new tick value
  SEQ_BPM_TickSet(new_tick);

#if DEBUG_VERBOSE_LEVEL >= 2
  DEBUG_MSG("[SEQ] Setting new song position %u (-> %u ticks)\n", new_song_pos, new_tick);
#endif

  // since timebase has been changed, ensure that Off-Events are played 
  // (otherwise they will be played much later...)
  SEQ_PlayOffEvents();

  // restart song
  MID_PARSER_RestartSong();

  // release pause
  seq_pause = 0;

  if( new_song_pos > 1 ) {
    // (silently) fast forward to requested position
    ffwd_silent_mode = 1;
    MID_PARSER_FetchEvents(0, new_tick-1);
    ffwd_silent_mode = 0;
  }

  // when do we expect the next prefetch:
  next_prefetch = new_tick;
  prefetch_offset = new_tick;

  return 0; // no error
}
コード例 #3
0
/////////////////////////////////////////////////////////////////////////////
//! Sets new song position (new_song_pos resolution: 16th notes)
/////////////////////////////////////////////////////////////////////////////
static s32 MBNG_SEQ_SongPos(u16 new_song_pos)
{
  u32 new_tick = new_song_pos * (SEQ_BPM_PPQN_Get() / 4);

  // set new tick value
  SEQ_BPM_TickSet(new_tick);

  return 0; // no error
}
コード例 #4
0
/////////////////////////////////////////////////////////////////////////////
//! performs a single bpm tick
/////////////////////////////////////////////////////////////////////////////
static s32 MBNG_SEQ_Tick(u32 bpm_tick)
{
  // send MIDI clock depending on ppqn
  if( (bpm_tick % (SEQ_BPM_PPQN_Get()/24)) == 0 ) {
    MIDI_ROUTER_SendMIDIClockEvent(0xf8, bpm_tick);
  }

  return 0; // no error
}
コード例 #5
0
ファイル: mclock.c プロジェクト: eranrund/mutebox
void Clocks_Init(void) {
    
    SEQ_BPM_TickSet(0);                                                         // reset sequencer
    
    SEQ_BPM_Init(0);                                                            // initialize SEQ module sequencer
    
    SEQ_BPM_PPQN_Set(VXPPQN);                                                   // set internal clock resolution as per the define (usually 384)
    MClock_SetBPM(100.0);                                                       // Master BPM
    
    
    mClock.status.all = 0;                                                      // bit 7 is run/stop
    mClock.ticked = 0;                                                          // we haven't gotten that far yet
    mClock.timesigu = 4;                                                        // Upper value of the Master Time Signature, min 2
    mClock.timesigl = 4;                                                        // Lower value of the Master Time Signature, min 2
    mClock.res = SEQ_BPM_PPQN_Get();                                            // fill this from the SEQ_BPM module to be safe
    mClock.rt_latency = VXLATENCY;                                              // initialise from define
    
    MClock_Init();                                                              // init the vX master clock
    MClock_Reset();
}
コード例 #6
0
ファイル: seq_song.c プロジェクト: glocklueng/stm32-mios32
/////////////////////////////////////////////////////////////////////////////
// called by the UI to handle the "Rew" button
/////////////////////////////////////////////////////////////////////////////
s32 SEQ_SONG_Rew(void)
{
  if( ui_page == SEQ_UI_PAGE_SONG ) {
    song_pos = ui_song_edit_pos;
    song_loop_ctr = 0;
    SEQ_SONG_PrevPos();
    ui_song_edit_pos = song_pos;
  } else {
    u32 bpm_tick = SEQ_BPM_TickGet();
    u32 ticks_per_pattern = ((u32)seq_core_steps_per_pattern+1) * (SEQ_BPM_PPQN_Get()/4);
    u32 measure = bpm_tick / ticks_per_pattern;
    u32 next_bpm_tick = measure ? ((measure-1) * ticks_per_pattern) : 0;

    SEQ_CORE_Reset(next_bpm_tick);
    SEQ_SONG_PrevPos();
    SEQ_BPM_TickSet(next_bpm_tick);
  }

  return 0; // no error
}
コード例 #7
0
ファイル: seq.c プロジェクト: gillspice/mios32
/////////////////////////////////////////////////////////////////////////////
// performs a single bpm tick
/////////////////////////////////////////////////////////////////////////////
static s32 SEQ_Tick(u32 bpm_tick)
{
  // whenever we reach a new 16th note (96 ticks @384 ppqn):
  if( (bpm_tick % (SEQ_BPM_PPQN_Get()/4)) == 0 ) {
    // ensure that arp is reseted on first bpm_tick
    if( bpm_tick == 0 )
      arp_counter = 0;
    else {
      // increment arpeggiator counter
      ++arp_counter;

      // reset once we reached length of notestack
      if( arp_counter >= notestack.len )
	arp_counter = 0;
    }

    if( notestack.len > 0 ) {
      // get note/velocity/length from notestack
      u8 note      = notestack_items[arp_counter].note;
      u8 velocity  = notestack_items[arp_counter].tag;
      u8 length    = 72; // always the same, could be varied, e.g. via CC

      // put note into queue if all values are != 0
      if( note && velocity && length ) {
	mios32_midi_package_t midi_package;
	midi_package.type     = NoteOn; // package type must match with event!
	midi_package.event    = NoteOn;
	midi_package.chn      = Chn1;
	midi_package.note     = note;
	midi_package.velocity = velocity;
	
	SEQ_MIDI_OUT_Send(DEFAULT, midi_package, SEQ_MIDI_OUT_OnOffEvent, bpm_tick, length);
      }
    }
  }

  return 0; // no error
}
コード例 #8
0
ファイル: mclock.c プロジェクト: eranrund/mutebox
void MClock_Init(void) {
    mClock.cyclelen = (unsigned int) 
    (((SEQ_BPM_PPQN_Get() * 4) * mClock.timesigu) / mClock.timesigl);           // Length of master track measured in ticks.

    midiclockdivider = (SEQ_BPM_PPQN_Get())/24;                                 // Set up the divider for 24ppqn output
}
コード例 #9
0
ファイル: seq_record.c プロジェクト: glocklueng/mios32-org
/////////////////////////////////////////////////////////////////////////////
// Called from SEQ_MIDI_IN_Receive() if MIDI event has been received on
// matching IN port and channel
/////////////////////////////////////////////////////////////////////////////
s32 SEQ_RECORD_Receive(mios32_midi_package_t midi_package, u8 track)
{
  // step recording mode?
  // Note: if sequencer is not running, "Live Recording" will be handled like "Step Recording"
  u8 step_record_mode = seq_record_options.STEP_RECORD || !SEQ_BPM_IsRunning();

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

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

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

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

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

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

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

	free_layer_found = 1;
      }
    }

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

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

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

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

	  free_layer_found = 1;
	  break;
	}
      }
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	  MIOS32_IRQ_Enable();
	}

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

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

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

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

	MIOS32_IRQ_Enable();

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

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

    default: {
#if DEBUG_VERBOSE_LEVEL >= 2
      DEBUG_MSG("[SEQ_RECORD_Receive] event %x not supported.\n", midi_package.event);
#endif
      return -2; // unsupported event
    }
  }