示例#1
0
文件: seq.c 项目: gillspice/mios32
/////////////////////////////////////////////////////////////////////////////
// Should be called whenever a Note event has been received.
// We expect, that velocity is 0 on a Note Off event
/////////////////////////////////////////////////////////////////////////////
s32 SEQ_NotifyNoteOn(u8 note, u8 velocity)
{
  u8 clear_stack = 0;

  if( velocity )
    // push note into note stack
    NOTESTACK_Push(&notestack, note, velocity);
  else {
    // remove note from note stack
    // function returns 2 if no note played anymore (all keys depressed)
    if( NOTESTACK_Pop(&notestack, note) == 2 )
      clear_stack = 1;
  }

  // At least one note played?
  if( !clear_stack && notestack.len > 0 ) {
    // start sequencer if it isn't already running
    if( !SEQ_BPM_IsRunning() )
      SEQ_BPM_Start();
  } else {
    // clear stack
    NOTESTACK_Clear(&notestack);

    // no key is pressed anymore: stop sequencer
    SEQ_BPM_Stop();
  }


#if 1
  // optional debug messages
  NOTESTACK_SendDebugMessage(&notestack);
#endif

  return 0; // no error
}
示例#2
0
/////////////////////////////////////////////////////////////////////////////
// This hook is called when a MIDI package has been received
/////////////////////////////////////////////////////////////////////////////
void APP_MIDI_NotifyPackage(mios32_midi_port_t port, mios32_midi_package_t midi_package)
{
  // if note event over MIDI channel #1 controls note of both oscillators
  // Note On received?
  if( midi_package.chn == Chn1 && 
      (midi_package.type == NoteOn || midi_package.type == NoteOff) ) {

    // branch depending on Note On/Off event
    if( midi_package.event == NoteOn && midi_package.velocity > 0 ) {
      // push note into note stack
      NOTESTACK_Push(&notestack, midi_package.note, midi_package.velocity);
    } else {
      // remove note from note stack
      NOTESTACK_Pop(&notestack, midi_package.note);
    }


    // still a note in stack?
    if( notestack.len ) {
      // take first note of stack
      u8 note = notestack_items[0].note;
      u8 velocity = notestack_items[0].tag;

      // set frequency for both oscillators
      int chn;
      for(chn=0; chn<2; ++chn) {
	SYNTH_FrequencySet(chn, frqtab[note]);
	SYNTH_VelocitySet(chn, velocity);
      }

      // set board LED
      MIOS32_BOARD_LED_Set(1, 1);
    } else {
      // turn off LED (can also be used as a gate output!)
      MIOS32_BOARD_LED_Set(1, 0);

      // set velocity to 0 for all oscillators
      int chn;
      for(chn=0; chn<2; ++chn)
	SYNTH_VelocitySet(chn, 0x00);
    }

#if 0
    // optional debug messages
    NOTESTACK_SendDebugMessage(&notestack);
#endif

  // CC#1 over MIDI channel #1 controls waveform
  } else if( midi_package.event == CC && midi_package.chn == Chn1 ) {
    int chn;
    for(chn=0; chn<2; ++chn)
      SYNTH_WaveformSet(chn, midi_package.value >> 5);
    // print selection
    print_msg = PRINT_MSG_SELECTIONS;
  }
示例#3
0
/////////////////////////////////////////////////////////////////////////////
// For Section Changes
// If velocity == 0, Note Off event has been received, otherwise Note On event
/////////////////////////////////////////////////////////////////////////////
static s32 SEQ_MIDI_IN_Receive_NoteSC(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 = &section_changer_notestack[group];

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

      // switch to new section if required
      if( section >= 0 && section < 12 ) {
#if DEBUG_VERBOSE_LEVEL >= 1
	DEBUG_MSG("Group %d Section %d\n", group, section);
#endif

	// following operation should be atomic!
	u8 track;
	seq_core_trk_t *t = &seq_core_trk[group*SEQ_CORE_NUM_TRACKS_PER_GROUP];
	MIOS32_IRQ_Disable();
	for(track=0; track<SEQ_CORE_NUM_TRACKS_PER_GROUP; ++track, ++t)
	  t->play_section = section;
	MIOS32_IRQ_Enable();
      }

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

  return octave_taken; // return 1 if octave has been taken, otherwise 0
}
示例#4
0
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
}
示例#5
0
/////////////////////////////////////////////////////////////////////////////
// Arpeggiator Notestack Handling
// Note On
/////////////////////////////////////////////////////////////////////////////
void MbSidArp::noteOn(MbSidVoice *v, u8 note, u8 velocity)
{
    MbSidMidiVoice *mv = (MbSidMidiVoice *)v->midiVoicePtr;

    // store current notestack mode
    notestack_mode_t saved_mode = mv->midivoiceNotestack.mode;

    if( arpEasyChordMode && !arpHoldMode ) {
        // easy chord entry:
        // even when HOLD mode not active, a note off doesn't remove notes in stack
        // the notes of released keys will be removed from stack once a *new* note is played
        NOTESTACK_RemoveNonActiveNotes(&mv->midivoiceNotestack);
    }

    // if no note is played anymore, clear stack again (so that new notes can be added in HOLD mode)
    if( NOTESTACK_CountActiveNotes(&mv->midivoiceNotestack) == 0 ) {
        // clear stack
        NOTESTACK_Clear(&mv->midivoiceNotestack);
        // synchronize the arpeggiator
        restartReq = 1;
    }

    // push note into stack - select mode depending on sort/hold mode
    if( arpHoldMode )
        mv->midivoiceNotestack.mode = arpSortedNotes ? NOTESTACK_MODE_SORT_HOLD : NOTESTACK_MODE_PUSH_TOP_HOLD;
    else
        mv->midivoiceNotestack.mode = arpSortedNotes ? NOTESTACK_MODE_SORT : NOTESTACK_MODE_PUSH_TOP;
    NOTESTACK_Push(&mv->midivoiceNotestack, note, velocity);

    // activate note
    v->voiceActive = 1;

    // remember note
    v->voicePlayedNote = note;

    // restore notestack mode
    mv->midivoiceNotestack.mode = saved_mode;
}
示例#6
0
/////////////////////////////////////////////////////////////////////////////
// If velocity == 0, Note Off event has been received, otherwise Note On event
/////////////////////////////////////////////////////////////////////////////
static s32 SEQ_MIDI_IN_Receive_Note(u8 bus, u8 note, u8 velocity)
{
  notestack_t *n;

  if( bus >= SEQ_MIDI_IN_NUM_BUSSES )
    return -1;

  ///////////////////////////////////////////////////////////////////////////
  // Transposer
  ///////////////////////////////////////////////////////////////////////////

  n = &bus_notestack[bus][BUS_NOTESTACK_TRANSPOSER];
  if( velocity ) { // Note On
    NOTESTACK_Push(n, note, velocity);
    transposer_hold_note[bus] = n->note_items[0].note;

    // will only be used for Bus1 and if enabled in OPT menu
    if( bus == 0 )
      seq_core_keyb_scale_root = note % 12;
  } else { // Note Off
    if( NOTESTACK_Pop(n, note) > 0 && n->len ) {
      transposer_hold_note[bus] = n->note_items[0].note;
    }
  }
#if DEBUG_VERBOSE_LEVEL >= 1
  DEBUG_MSG("NOTESTACK_TRANSPOSER[%d]:\n", bus);
  NOTESTACK_SendDebugMessage(&bus_notestack[bus][BUS_NOTESTACK_TRANSPOSER]);
#endif


  ///////////////////////////////////////////////////////////////////////////
  // Arpeggiator
  ///////////////////////////////////////////////////////////////////////////

  if( velocity ) { // Note On
    // if no note in note stack anymore, reset position of all tracks with RESTART flag set
    if( !bus_notestack[bus][BUS_NOTESTACK_ARP_UNSORTED].len ) {
      u8 track;
      for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track)
	if( seq_cc_trk[track].mode.RESTART ) {
	  portENTER_CRITICAL();
	  seq_core_trk[track].state.POS_RESET = 1;
	  portEXIT_CRITICAL();
	}

      // and invalidate hold stacks
      int i;
      for(i=0; i<4; ++i)
	arp_sorted_hold[bus][i].ALL = arp_unsorted_hold[bus][i].ALL = 0;
    }

    // add to stacks
    NOTESTACK_Push(&bus_notestack[bus][BUS_NOTESTACK_ARP_SORTED], note, velocity);
    NOTESTACK_Push(&bus_notestack[bus][BUS_NOTESTACK_ARP_UNSORTED], note, velocity);

    // copy to hold stack
    int i;
    for(i=0; i<4; ++i) {
      arp_unsorted_hold[bus][i].ALL = (i < bus_notestack[bus][BUS_NOTESTACK_ARP_UNSORTED].len) ? bus_notestack[bus][BUS_NOTESTACK_ARP_UNSORTED].note_items[i].ALL : 0;
      arp_sorted_hold[bus][i].ALL = (i < bus_notestack[bus][BUS_NOTESTACK_ARP_SORTED].len) ? bus_notestack[bus][BUS_NOTESTACK_ARP_SORTED].note_items[i].ALL : 0;
    }

  } else { // Note Off
    // remove note from sorted/unsorted stack (not hold stacks)
    NOTESTACK_Pop(&bus_notestack[bus][BUS_NOTESTACK_ARP_SORTED], note);
    NOTESTACK_Pop(&bus_notestack[bus][BUS_NOTESTACK_ARP_UNSORTED], note);
  }

#if DEBUG_VERBOSE_LEVEL >= 1
  DEBUG_MSG("NOTESTACK_ARP_SORTED[%d]:\n", bus);
  NOTESTACK_SendDebugMessage(&bus_notestack[bus][BUS_NOTESTACK_ARP_SORTED]);
  DEBUG_MSG("NOTESTACK_ARP_UNSORTED[%d]:\n", bus);
  NOTESTACK_SendDebugMessage(&bus_notestack[bus][BUS_NOTESTACK_ARP_UNSORTED]);
#endif

  return 0; // no error
}
示例#7
0
/////////////////////////////////////////////////////////////////////////////
// This hook is called when a MIDI package has been received
/////////////////////////////////////////////////////////////////////////////
void APP_MIDI_NotifyPackage(mios32_midi_port_t port, mios32_midi_package_t midi_package)
{
  // if note event over MIDI channel #1 controls note of both oscillators
  // Note On received?
  if( midi_package.chn == Chn1 && 
      (midi_package.type == NoteOn || midi_package.type == NoteOff) ) {

    // branch depending on Note On/Off event
    if( midi_package.event == NoteOn && midi_package.velocity > 0 ) {
      // push note into note stack
      NOTESTACK_Push(&notestack, midi_package.note, midi_package.velocity);
    } else {
      // remove note from note stack
      NOTESTACK_Pop(&notestack, midi_package.note);
    }


    // still a note in stack?
    if( notestack.len ) {
      // take first note of stack
      u8 note = notestack_items[0].note;
      u8 velocity = notestack_items[0].tag;

#if 0
      // set frequency for both oscillators
      int chn;
      for(chn=0; chn<2; ++chn) {
	SYNTH_FrequencySet(chn, frqtab[note]);
	SYNTH_VelocitySet(chn, velocity);
      }
#endif

      // play note
      int phrase_num = note - PHRASE_NOTE_OFFSET;
      while( phrase_num < 0)
	phrase_num += SYNTH_NUM_PHRASES;
      while( phrase_num > SYNTH_NUM_PHRASES )
	phrase_num -= SYNTH_NUM_PHRASES;

      // legato...
      if( notestack.len == 1 )
	SYNTH_PhraseStop(phrase_num);

      SYNTH_PhrasePlay(phrase_num, velocity);
      
      // set board LED
      MIOS32_BOARD_LED_Set(1, 1);
    } else {
      // turn off LED (can also be used as a gate output!)
      MIOS32_BOARD_LED_Set(1, 0);

#if 0
      // set velocity to 0 for all oscillators
      int chn;
      for(chn=0; chn<2; ++chn)
	SYNTH_VelocitySet(chn, 0x00);
#endif
    }

#if 0
    // optional debug messages
    NOTESTACK_SendDebugMessage(&notestack);
#endif
  } else if( midi_package.type == CC ) {
    u8 phrase_num = 0;
    u8 phoneme_ix = midi_package.chn;
    u32 value = midi_package.value;

    if( midi_package.cc_number < 16 ) {
    } else if( midi_package.cc_number < 32 ) {
      u8 phoneme_par = midi_package.cc_number - 16;
      SYNTH_PhonemeParSet(phrase_num, phoneme_ix, phoneme_par, value);
    } else if( midi_package.cc_number < 48 ) {
      u8 phrase_par = midi_package.cc_number - 32;
      SYNTH_PhraseParSet(phrase_num, phrase_par, value);
    } else if( midi_package.cc_number < 64 ) {
      u8 global_par = midi_package.cc_number - 48;
      SYNTH_GlobalParSet(global_par, value);
    }
  }

}
void MbCvMidiVoice::notestackPush(u8 note, u8 velocity)
{
    NOTESTACK_Push(&midivoiceNotestack, note, velocity);
}
示例#9
0
/////////////////////////////////////////////////////////////////////////////
//! This function is called by MBNG_EVENT_ItemReceive when a matching value
//! has been received
/////////////////////////////////////////////////////////////////////////////
s32 MBNG_CV_NotifyReceivedValue(mbng_event_item_t *item)
{
  u16 hw_id = item->hw_id;

  if( debug_verbose_level >= DEBUG_VERBOSE_LEVEL_INFO ) {
    DEBUG_MSG("MBNG_CV_NotifyReceivedValue(%d, %d)\n", hw_id & 0xfff, item->value);
  }

  // forward to CV channel
  u16 hw_id_ix = hw_id & 0xfff;
  if( hw_id_ix && hw_id_ix <= MBNG_PATCH_NUM_CV_CHANNELS ) {
    u8 cv_ix = hw_id_ix - 1;
    u16 value = item->value;
    u8 set_value = 1;
    u8 gate_value = 0;

    if( item->flags.type == MBNG_EVENT_TYPE_NOTE_ON ) {
      if( item->flags.use_key_or_cc ) {
	if( item->secondary_value > 0 ) {
	  // push note into note stack
	  NOTESTACK_Push(&cv_notestack[cv_ix], value, item->secondary_value);
	} else {
	  // remove note from note stack
	  NOTESTACK_Pop(&cv_notestack[cv_ix], value);
	}

	// still a note in stack?
	if( cv_notestack[cv_ix].len ) {
	  // take first note of stack
	  value = cv_notestack_items[cv_ix][0].note;
	  u8 velocity = cv_notestack_items[cv_ix][0].tag;
	  // TODO: should we provide an option to forward the notestack based velocity to the appr. EVENT_CV item?

	  gate_value = 1;

	  if( debug_verbose_level >= DEBUG_VERBOSE_LEVEL_INFO ) {
	    DEBUG_MSG("-> Note %3d with velocity %3d\n", value, velocity);
	  }
	} else {
	  gate_value = 0;

	  if( debug_verbose_level >= DEBUG_VERBOSE_LEVEL_INFO ) {
	    DEBUG_MSG("-> Note %3d released the gate\n", value);
	  }
	}
      } else {
	if( item->value == 0 ) {
	  if( debug_verbose_level >= DEBUG_VERBOSE_LEVEL_INFO ) {
	    DEBUG_MSG("-> Velocity 0 won't change this channel!\n");
	  }
	  set_value = 0;
	} else {
	  if( debug_verbose_level >= DEBUG_VERBOSE_LEVEL_INFO ) {
	    DEBUG_MSG("-> Velocity set to %3d\n", item->value);
	  }
	}
      }
    }

    if( set_value ) {
      // scale value to 16bit
      u16 value16 = value;
      s32 mapped_value;
      if( (mapped_value=MBNG_EVENT_MapValue(item->map, value16, 65535, 0)) >= 0 ) {
	value16 = mapped_value;
      } else if( item->min <= item->max ) {
	int range = item->max - item->min + 1;
	value16 = (value - item->min) * (65536 / range);
      } else {
	int range = item->min - item->max + 1;
	value16 = (value - item->max)* (65536 / range);
      }

      if( value16 < 0 )
	value16 = 0;
      else if( value16 > 65535 )
	value16 = 65535;

      // change output curve
      AOUT_ConfigChannelInvertedSet(cv_ix, item->custom_flags.CV.cv_inverted);
      AOUT_ConfigChannelHzVSet(cv_ix, item->custom_flags.CV.cv_hz_v);

      // set CV value
      MBNG_CV_PinSet(cv_ix, value16);

      // gate inverted?
      if( item->custom_flags.CV.cv_gate_inverted ) {
	gate_value ^= 1;
      }

      // set gates
      AOUT_DigitalPinSet(cv_ix, gate_value);

      if( item->custom_flags.CV.fwd_gate_to_dout_pin ) {
	if( debug_verbose_level >= DEBUG_VERBOSE_LEVEL_INFO ) {
	  DEBUG_MSG("-> Setting DOUT Pin #%d=%d\n", item->custom_flags.CV.fwd_gate_to_dout_pin-1, gate_value);
	}	
	MIOS32_DOUT_PinSet(item->custom_flags.CV.fwd_gate_to_dout_pin-1, gate_value);
      }
    }
  }

  return 0; // no error
}