///////////////////////////////////////////////////////////////////////////// // 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 }
///////////////////////////////////////////////////////////////////////////// // Resets song position of sequencer ///////////////////////////////////////////////////////////////////////////// s32 SEQ_Reset(u8 play_off_events) { // since timebase has been changed, ensure that Off-Events are played // (otherwise they will be played much later...) if( play_off_events ) SEQ_PlayOffEvents(); // release pause and FFWD mode seq_pause = 0; ffwd_silent_mode = 0; next_prefetch = 0; prefetch_offset = 0; // restart song MID_PARSER_RestartSong(); // set initial BPM (according to MIDI file spec) SEQ_BPM_PPQN_Set(384); // not specified SEQ_BPM_Set(120.0); // reset BPM tick SEQ_BPM_TickSet(0); return 0; // no error }
///////////////////////////////////////////////////////////////////////////// // this sequencer handler is called periodically to check for new requests // from BPM generator ///////////////////////////////////////////////////////////////////////////// s32 SEQ_Handler(void) { // handle 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(); } u16 new_song_pos; if( SEQ_BPM_ChkReqSongPos(&new_song_pos) ) { SEQ_PlayOffEvents(); } 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 }
///////////////////////////////////////////////////////////////////////////// // Resets song position of sequencer ///////////////////////////////////////////////////////////////////////////// s32 SEQ_Reset(void) { // since timebase has been changed, ensure that Off-Events are played // (otherwise they will be played much later...) SEQ_PlayOffEvents(); // release pause mode seq_pause = 0; // reset BPM tick SEQ_BPM_TickSet(0); return 0; // no error }
///////////////////////////////////////////////////////////////////////////// // Plays the first .mid file if next == 0, the next file if next != 0 ///////////////////////////////////////////////////////////////////////////// static s32 SEQ_PlayFile(u32 next) { // play off events before loading new file SEQ_PlayOffEvents(); char next_file[13]; if( MID_FILE_FindNext(next ? MID_FILE_UI_NameGet() : NULL, next_file) == 1 || MID_FILE_FindNext(NULL, next_file) == 1 ) { // if next file not found, try first file #if DEBUG_VERBOSE_LEVEL >= 1 DEBUG_MSG("[SEQ] next file found '%s'\n", next_file); #endif SEQ_BPM_Stop(); // stop BPM generator if( MID_FILE_open(next_file) ) { // try to open next file #if DEBUG_VERBOSE_LEVEL >= 1 DEBUG_MSG("[SEQ] file %s cannot be opened (wrong directory?)\n", next_file); #endif return -1; // file cannot be opened } if( MID_PARSER_Read() < 0 ) { // read file, stop on failure #if DEBUG_VERBOSE_LEVEL >= 1 DEBUG_MSG("[SEQ] file %s is invalid!\n", next_file); #endif return -2; // file is invalid } SEQ_BPM_Start(); // start BPM generator } else { SEQ_BPM_Stop(); // stop BPM generator #if DEBUG_VERBOSE_LEVEL >= 1 DEBUG_MSG("[SEQ] no file found\n"); #endif return -1; // file not found } return 0; // no error }