///////////////////////////////////////////////////////////////////////////// // 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(¬estack, note, velocity); else { // remove note from note stack // function returns 2 if no note played anymore (all keys depressed) if( NOTESTACK_Pop(¬estack, 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(¬estack); // no key is pressed anymore: stop sequencer SEQ_BPM_Stop(); } #if 1 // optional debug messages NOTESTACK_SendDebugMessage(¬estack); #endif return 0; // no error }
///////////////////////////////////////////////////////////////////////////// // 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(¬estack, midi_package.note, midi_package.velocity); } else { // remove note from note stack NOTESTACK_Pop(¬estack, 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(¬estack); #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; }
///////////////////////////////////////////////////////////////////////////// // 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 = §ion_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 }
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 }
///////////////////////////////////////////////////////////////////////////// // 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 }
///////////////////////////////////////////////////////////////////////////// // 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(¬estack, midi_package.note, midi_package.velocity); } else { // remove note from note stack NOTESTACK_Pop(¬estack, 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(¬estack); #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); } } }