///////////////////////////////////////////////////////////////////////////// // Initialisation ///////////////////////////////////////////////////////////////////////////// s32 SEQ_Init(u32 mode) { // initialize the Notestack #if 0 NOTESTACK_Init(¬estack, NOTESTACK_MODE_PUSH_TOP, ¬estack_items[0], NOTESTACK_SIZE); #else // for an arpeggiator we prefer sorted mode // activate hold mode as well. Stack will be cleared whenever no note is played anymore NOTESTACK_Init(¬estack, NOTESTACK_MODE_SORT_HOLD, ¬estack_items[0], NOTESTACK_SIZE); #endif // and the arp counter arp_counter = 0; // reset sequencer SEQ_Reset(); // init BPM generator SEQ_BPM_Init(0); SEQ_BPM_PPQN_Set(384); SEQ_BPM_Set(120.0); 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) { // Note On received? if( midi_package.type == NoteOn && midi_package.chn == Chn1 && midi_package.velocity > 0 ) { // determine base key number (0=C, 1=C#, 2=D, ...) u8 base_key = midi_package.note % 12; // branch depending on note switch( base_key ) { case 0: // "C" starts the sequencer MIOS32_MIDI_SendDebugMessage("Start\n"); // if in auto mode and BPM generator is clocked in slave mode: // change to master mode SEQ_BPM_CheckAutoMaster(); // start sequencer SEQ_BPM_Start(); break; case 2: // "D" stops the sequencer. If pressed twice, the sequencer will be reset MIOS32_MIDI_SendDebugMessage("Stop\n"); if( SEQ_BPM_IsRunning() ) SEQ_BPM_Stop(); // stop sequencer else SEQ_Reset(1); // reset sequencer break; case 4: // "E" pauses the sequencer // if in auto mode and BPM generator is clocked in slave mode: // change to master mode SEQ_BPM_CheckAutoMaster(); // toggle pause mode seq_pause ^= 1; MIOS32_MIDI_SendDebugMessage("Pause %s\n", seq_pause ? "on" : "off"); // execute stop/continue depending on new mode if( seq_pause ) SEQ_BPM_Stop(); // stop sequencer else SEQ_BPM_Cont(); // continue sequencer break; case 5: // "F" switches to next file MIOS32_MIDI_SendDebugMessage("Next File\n"); SEQ_PlayFileReq(1); break; } } }
///////////////////////////////////////////////////////////////////////////// // this sequencer handler is called periodically to check for new requests // from BPM generator ///////////////////////////////////////////////////////////////////////////// s32 SEQ_Handler(void) { // a lower priority task requested to play the next file if( next_file_req ) { SEQ_PlayFile(next_file_req-1); next_file_req = 0; }; // handle BPM requests u8 num_loops = 0; u8 again = 0; do { ++num_loops; // note: don't remove any request check - clocks won't be propagated // so long any Stop/Cont/Start/SongPos event hasn't been flagged to the sequencer if( SEQ_BPM_ChkReqStop() ) { SEQ_PlayOffEvents(); } if( SEQ_BPM_ChkReqCont() ) { // release pause mode seq_pause = 0; } if( SEQ_BPM_ChkReqStart() ) { SEQ_Reset(1); SEQ_SongPos(0); } u16 new_song_pos; if( SEQ_BPM_ChkReqSongPos(&new_song_pos) ) { SEQ_SongPos(new_song_pos); } u32 bpm_tick; if( SEQ_BPM_ChkReqClk(&bpm_tick) > 0 ) { again = 1; // check all requests again after execution of this part SEQ_Tick(bpm_tick); } } while( again && num_loops < 10 ); return 0; // no error }
///////////////////////////////////////////////////////////////////////////// // Initialisation ///////////////////////////////////////////////////////////////////////////// s32 SEQ_Init(u32 mode) { // init MIDI file handler MID_FILE_Init(0); // init MIDI parser module MID_PARSER_Init(0); // install callback functions MID_PARSER_InstallFileCallbacks(&MID_FILE_read, &MID_FILE_eof, &MID_FILE_seek); MID_PARSER_InstallEventCallbacks(&SEQ_PlayEvent, &SEQ_PlayMeta); // reset sequencer SEQ_Reset(0); // init BPM generator SEQ_BPM_Init(0); return 0; // no error }
///////////////////////////////////////////////////////////////////////////// // This task is called periodically each mS to handle sequencer requests ///////////////////////////////////////////////////////////////////////////// static void TASK_SEQ(void *pvParameters) { portTickType xLastExecutionTime; u16 sdcard_check_ctr = 0; // Initialise the xLastExecutionTime variable on task entry xLastExecutionTime = xTaskGetTickCount(); while( 1 ) { vTaskDelayUntil(&xLastExecutionTime, 1 / portTICK_RATE_MS); // execute sequencer handler SEQ_Handler(); // send timestamped MIDI events SEQ_MIDI_OUT_Handler(); // each second: check if SD Card (still) available if( ++sdcard_check_ctr >= 1000 ) { sdcard_check_ctr = 0; // use a mutex if multiple tasks access the SD Card! MUTEX_SDCARD_TAKE; s32 status = FILE_CheckSDCard(); if( status == 1 ) { MIOS32_MIDI_SendDebugMessage("SD Card connected: %s\n", FILE_VolumeLabel()); } else if( status == 2 ) { MIOS32_MIDI_SendDebugMessage("SD Card disconnected\n"); // stop sequencer SEQ_BPM_Stop(); // change filename sprintf(MID_FILE_UI_NameGet(), "No SD Card"); } else if( status == 3 ) { if( !FILE_SDCardAvailable() ) { MIOS32_MIDI_SendDebugMessage("SD Card not found\n"); // change filename sprintf(MID_FILE_UI_NameGet(), "No SD Card"); } else if( !FILE_VolumeAvailable() ) { MIOS32_MIDI_SendDebugMessage("ERROR: SD Card contains invalid FAT!\n"); MIOS32_BOARD_LED_Set(0x1, 0x0); // turn off LED // change filename sprintf(MID_FILE_UI_NameGet(), "No FAT"); // stop sequencer SEQ_BPM_Stop(); } else { // change filename sprintf(MID_FILE_UI_NameGet(), "SDCard found"); // if in auto mode and BPM generator is clocked in slave mode: // change to master mode SEQ_BPM_CheckAutoMaster(); // reset sequencer SEQ_Reset(1); // request to play the first file SEQ_PlayFileReq(0); // start sequencer SEQ_BPM_Start(); } } MUTEX_SDCARD_GIVE; } } }