///////////////////////////////////////////////////////////////////////////// // fetches the pos entries of a song // returns -1 if recursion counter reached max position ///////////////////////////////////////////////////////////////////////////// s32 SEQ_SONG_FetchPos(u8 force_immediate_change, u8 dont_dump_mixer_map) { int recursion_ctr = 0; u8 again; do { again = 0; // stop song once recursion counter reached 64 loops if( ++recursion_ctr >= 64 ) { SEQ_BPM_Stop(); return -1; // recursion detected } // reset song position if we reached the end (loop over 128 steps) if( song_pos >= SEQ_SONG_NUM_STEPS ) song_pos = 0; // get step entry seq_song_step_t *s = (seq_song_step_t *)&seq_song_steps[song_pos]; // branch depending on action switch( s->action ) { case SEQ_SONG_ACTION_End: #if 0 if( song_active ) // not in phrase mode SEQ_BPM_Stop(); #else song_finished = 1; // deactivate song incrementer #endif break; case SEQ_SONG_ACTION_JmpPos: song_pos = s->action_value % SEQ_SONG_NUM_STEPS; again = 1; break; case SEQ_SONG_ACTION_JmpSong: { if( song_active ) { // not in phrase mode u32 new_song_num = s->action_value % SEQ_SONG_NUM; SEQ_SONG_Save(song_num); SEQ_SONG_Load(new_song_num); song_pos = 0; again = 1; } } break; case SEQ_SONG_ACTION_SelMixerMap: SEQ_MIXER_Load(s->action_value); SEQ_MIDI_IN_ExtCtrlSend(SEQ_MIDI_IN_EXT_CTRL_MIXER_MAP, s->action_value, 0); if( !dont_dump_mixer_map ) SEQ_MIXER_SendAll(); ++song_pos; again = 1; break; case SEQ_SONG_ACTION_Tempo: { float bpm = (float)s->action_value; if( bpm < 25.0 ) bpm = 25.0; float ramp = (float)s->pattern_g1; SEQ_CORE_BPM_Update(bpm, ramp); ++song_pos; again = 1; } break; case SEQ_SONG_ACTION_Mutes: { // access to seq_core_trk[] must be atomic! portENTER_CRITICAL(); seq_core_trk_muted = ((s->pattern_g1 & 0x0f) << 0) | ((s->pattern_g2 & 0x0f) << 4) | ((s->pattern_g3 & 0x0f) << 8) | ((s->pattern_g4 & 0x0f) << 12); portEXIT_CRITICAL(); ++song_pos; again = 1; } break; case SEQ_SONG_ACTION_GuideTrack: { if( s->action_value <= 16 ) seq_song_guide_track = s->action_value; ++song_pos; again = 1; } break; default: if( s->action >= SEQ_SONG_ACTION_Loop1 && s->action <= SEQ_SONG_ACTION_Loop16 ) { song_loop_ctr = 0; song_loop_ctr_max = s->action - SEQ_SONG_ACTION_Loop1; // TODO: implement prefetching until end of step! SEQ_SONG_FetchHlp_PatternChange(0, s->pattern_g1, s->bank_g1, force_immediate_change); SEQ_SONG_FetchHlp_PatternChange(1, s->pattern_g2, s->bank_g2, force_immediate_change); SEQ_SONG_FetchHlp_PatternChange(2, s->pattern_g3, s->bank_g3, force_immediate_change); SEQ_SONG_FetchHlp_PatternChange(3, s->pattern_g4, s->bank_g4, force_immediate_change); } } } while( again ); return 0; // no error }
///////////////////////////////////////////////////////////////////////////// // This task is called periodically each second ///////////////////////////////////////////////////////////////////////////// void SEQ_TASK_Period1S(void) { static s8 wait_boot_ctr = 3; // wait 3 seconds before loading from SD Card - this is to increase the time where the boot screen is print! u8 load_sd_content = 0; // poll for IIC modules as long as HW config hasn't been locked (read from SD card) // TODO: use proper mutex handling here #ifndef MIOS32_FAMILY_EMULATION if( !SEQ_FILE_HW_ConfigLocked() ) { MIOS32_IIC_MIDI_ScanInterfaces(); } #endif // boot phase of 2 seconds finished? if( wait_boot_ctr > 0 ) { --wait_boot_ctr; if( wait_boot_ctr ) return; } // BLM timeout counter MIOS32_IRQ_Disable(); if( seq_blm_timeout_ctr ) --seq_blm_timeout_ctr; MIOS32_IRQ_Enable(); // check if SD Card connected MUTEX_SDCARD_TAKE; s32 status = FILE_CheckSDCard(); if( status == 1 ) { if( wait_boot_ctr != 0 ) { // don't print message if we just booted char str[21]; sprintf(str, "Label: %s", FILE_VolumeLabel()); #ifndef MBSEQV4L SEQ_UI_Msg(SEQ_UI_MSG_SDCARD, 2000, " SD Card connected", " :-D"); #endif DEBUG_MSG("SD Card connected: %s\n", FILE_VolumeLabel()); } SEQ_FILE_LoadSessionName(); DEBUG_MSG("Loading session %s\n", seq_file_session_name); SEQ_FILE_LoadAllFiles(1); } else if( status == 2 ) { #ifndef MBSEQV4L SEQ_UI_Msg(SEQ_UI_MSG_SDCARD, 2000, "SD Card disconnected", " :-/"); #endif DEBUG_MSG("SD Card disconnected\n"); SEQ_FILE_UnloadAllFiles(); wait_boot_ctr = -1; } else if( status == 3 ) { if( !FILE_SDCardAvailable() ) { #ifndef MBSEQV4L SEQ_UI_Msg(SEQ_UI_MSG_SDCARD, 2000, " No SD Card found ", " :-("); #endif DEBUG_MSG("SD Card not found\n"); SEQ_FILE_HW_LockConfig(); // lock configuration wait_boot_ctr = -1; } else if( !FILE_VolumeAvailable() ) { #ifndef MBSEQV4L SEQ_UI_Msg(SEQ_UI_MSG_SDCARD, 2000, "!! SD Card Error !!!", "!! Invalid FAT !!!!!"); #endif DEBUG_MSG("ERROR: SD Card contains invalid FAT!\n"); SEQ_FILE_HW_LockConfig(); // lock configuration wait_boot_ctr = -1; } else { #ifndef MBSEQV4L if( wait_boot_ctr != 0 ) { // don't print message if we just booted char str1[30]; sprintf(str1, "Banks: ...."); u8 bank; for(bank=0; bank<4; ++bank) str1[7+bank] = SEQ_FILE_B_NumPatterns(bank) ? ('1'+bank) : '-'; char str2[30]; sprintf(str2, "M:%c S:%c G:%c C:%c%c HW:%c", SEQ_FILE_M_NumMaps() ? '*':'-', SEQ_FILE_S_NumSongs() ? '*':'-', SEQ_FILE_G_Valid() ? '*':'-', SEQ_FILE_C_Valid() ? 'S':'-', SEQ_FILE_GC_Valid() ? 'G':'-', SEQ_FILE_HW_Valid() ? '*':'-'); SEQ_UI_Msg(SEQ_UI_MSG_SDCARD, 2000, str1, str2); } #endif #if MBSEQV4L // auto-format // check if formatting is required if( SEQ_FILE_FormattingRequired() ) { strcpy(seq_file_new_session_name, "DEF_V4L"); DEBUG_MSG("Creating initial session '%s'... this can take some seconds!\n", seq_file_new_session_name); if( (status=SEQ_FILE_Format()) < 0 ) { DEBUG_MSG("Failed to create session! (status: %d)\n", status); } else { SEQ_FILE_StoreSessionName(); DEBUG_MSG("Done!\n"); } } #endif // request to load content of SD card load_sd_content = 1; // notify that boot finished wait_boot_ctr = -1; } } else if( status < 0 ) { wait_boot_ctr = -1; #ifndef MBSEQV4L SEQ_UI_SDCardErrMsg(2000, status); #endif DEBUG_MSG("ERROR: SD Card Error %d (FatFs: D%3d)\n", status, file_dfs_errno); } // check for format request // this is running with low priority, so that LCD is updated in parallel! if( seq_ui_format_req ) { // note: request should be cleared at the end of this process to avoid double-triggers! if( (status = SEQ_FILE_Format()) < 0 ) { #ifndef MBSEQV4L SEQ_UI_SDCardErrMsg(2000, status); #endif DEBUG_MSG("ERROR: SD Card Error %d (FatFs: D%3d)\n", status, file_dfs_errno); } else { #ifndef MBSEQV4L SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, "Files created", "successfully!"); #endif DEBUG_MSG("Files created successfully!\n"); // store session name status |= SEQ_FILE_StoreSessionName(); } // request to load content of SD card load_sd_content = 1; // finally clear request seq_ui_format_req = 0; } // check for backup request // this is running with low priority, so that LCD is updated in parallel! if( seq_ui_backup_req ) { // note: request should be cleared at the end of this process to avoid double-triggers! status = SEQ_FILE_CreateBackup(); if( status < 0 ) { if( status == FILE_ERR_COPY ) { #ifndef MBSEQV4L SEQ_UI_Msg(SEQ_UI_MSG_USER, 2000, "COPY FAILED!", "ERROR :-("); #endif DEBUG_MSG("ERROR: copy failed!\n"); } else { #ifndef MBSEQV4L SEQ_UI_SDCardErrMsg(2000, status); #endif DEBUG_MSG("ERROR: SD Card Error %d (FatFs: D%3d)\n", status, file_dfs_errno); } } else { #ifndef MBSEQV4L SEQ_UI_Msg(SEQ_UI_MSG_USER, 1000, "Files copied", "successfully!"); #endif DEBUG_MSG("Files copied successfully!\n"); // store session name status |= SEQ_FILE_StoreSessionName(); } // finally clear request seq_ui_backup_req = 0; } // check for save all request // this is running with low priority, so that LCD is updated in parallel! if( seq_ui_saveall_req ) { s32 status = 0; // store all patterns int group; for(group=0; group<SEQ_CORE_NUM_GROUPS; ++group) status |= SEQ_FILE_B_PatternWrite(seq_file_session_name, seq_pattern[group].bank, seq_pattern[group].pattern, group, 1); // store config (e.g. to store current song/mixermap/pattern numbers SEQ_FILE_C_Write(seq_file_session_name); // store global config SEQ_FILE_GC_Write(); // store mixer map SEQ_MIXER_Save(SEQ_MIXER_NumGet()); // store session name if( status >= 0 ) status |= SEQ_FILE_StoreSessionName(); if( status < 0 ) { #ifndef MBSEQV4L SEQ_UI_SDCardErrMsg(2000, status); #endif DEBUG_MSG("ERROR: SD Card Error %d (FatFs: D%3d)\n", status, file_dfs_errno); } // finally clear request seq_ui_saveall_req = 0; } MUTEX_SDCARD_GIVE; // load content of SD card if requested ((re-)connection detected) if( load_sd_content && !SEQ_FILE_FormattingRequired() ) { // send layout request to MBHP_BLM_SCALAR MUTEX_MIDIOUT_TAKE; SEQ_BLM_SYSEX_SendRequest(0x00); MUTEX_MIDIOUT_GIVE; // TODO: should we load the patterns when SD Card has been detected? // disadvantage: current edit patterns are destroyed - this could be fatal during a live session if there is a bad contact! SEQ_MIXER_Load(SEQ_MIXER_NumGet()); SEQ_SONG_Load(SEQ_SONG_NumGet()); } #ifndef MBSEQV4L SEQ_LCD_LOGO_ScreenSaver_Period1S(); #endif }