///////////////////////////////////////////////////////////////////////////// // Local button callback function // Should return: // 1 if value has been changed // 0 if value hasn't been changed // -1 if invalid or unsupported button ///////////////////////////////////////////////////////////////////////////// static s32 Button_Handler(seq_ui_button_t button, s32 depressed) { if( SEQ_FILE_FormattingRequired() ) return 0; // no button action as long as files not available u8 group; s32 status; switch( button ) { case SEQ_UI_BUTTON_Edit: { if ( depressed && (selected_page == PAGE_REMIX) ) { // we want to show vertical VU meters normal mode SEQ_LCD_InitSpecialChars(SEQ_LCD_CHARSET_VBars); selected_page = PAGE_MAIN; // // here we run the commands for remix states // u16 remix_map_tmp; // if we are in no preview_mode them call the demix procedment in case we got some request if ( (seq_pattern_remix_map != seq_pattern_demix_map) && ( remix_mode ) ) { remix_map_tmp = seq_pattern_remix_map; seq_pattern_remix_map = ~(seq_pattern_remix_map ^ seq_pattern_demix_map); if (ableton_api) { // TODO: implements a ableton remotescript to the clip control functionality u8 track; for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track) { // if we got the track bit setup inside our remix_map, them do not send mixer data for that track channel, let it be mixed down if ( ((1 << track) | seq_pattern_remix_map) == seq_pattern_remix_map ) { // do nothing... } else { // delay our task for ableton get a breath before change the pattern line vTaskDelay(50); // send slot play envet to ableton: cc (111 + track) with value 127 to channel 16 MIOS32_MIDI_SendCC(ableton_port, 15, (111 + track), 127); } } } // if we are in remix mode lets start the process if (remix_map_tmp == 0) { //pattern_name = pattern_name_remix; preview_mode = 0; remix_mode = 0; // set the pattern_remix_timer reference pattern_remix_timer = MIOS32_SYS_TimeGet(); } // Change Pattern u8 group; for(group=0; group<SEQ_CORE_NUM_GROUPS; ++group) { // change pattern SEQ_PATTERN_Change(group, seq_pattern[group], 0); } // copy the pattern name for future reference sprintf(pattern_name, seq_pattern_name[0]); // getting back seq_pattern_remix_map = remix_map_tmp; seq_pattern_demix_map = seq_pattern_remix_map; } } else if ( !depressed ) { // we want to show horizontal VU meters in remix mode SEQ_LCD_InitSpecialChars(SEQ_LCD_CHARSET_HBars); selected_page = PAGE_REMIX; } return 1; } break; case SEQ_UI_BUTTON_Select: { if(!depressed) { selected_page = PAGE_OPTION; return 1; } if( (depressed) && (selected_page == PAGE_OPTION) ) { selected_page = PAGE_MAIN; } } break; default: break; } if( depressed ) return 0; // ignore when button depressed if its not SEQ_UI_BUTTON_Select or SEQ_UI_BUTTON_Edit switch( selected_page ) { /////////////////////////////////////////////////////////////////////////// // REMIX PAGE case PAGE_REMIX: { if( button <= SEQ_UI_BUTTON_GP16 ) { // re-using encoder routine return Encoder_Handler(button, 0); } } break; /////////////////////////////////////////////////////////////////////////// // OPTION PAGE case PAGE_OPTION: { switch( button ) { case SEQ_UI_BUTTON_GP1: // Save Pattern(all 4 groups at once) for(group=0; group<SEQ_CORE_NUM_GROUPS; ++group) { if( (status=SEQ_PATTERN_Save(group, seq_pattern[group])) < 0 ) { SEQ_UI_SDCardErrMsg(2000, status); return 0; } } // Save the pattern mixer SEQ_MIXER_Save(SEQ_MIXER_NumGet()); break; case SEQ_UI_BUTTON_GP2: // Edit Pattern Name //SEQ_LCD_Clear(); selected_page = PAGE_NAME_EDIT; break; case SEQ_UI_BUTTON_GP3: // Copy Pattern // We are going to use the multicopy procedure SEQ_UI_PATTERN_Copy(); // coping mixer SEQ_UI_MIXER_Copy(); break; case SEQ_UI_BUTTON_GP4: // Paste Pattern // We are going to use the multicopy procedure SEQ_UI_PATTERN_Paste(); // paste mixer SEQ_UI_MIXER_Paste(); break; case SEQ_UI_BUTTON_GP5: case SEQ_UI_BUTTON_GP6: return -1; // not mapped case SEQ_UI_BUTTON_GP7: case SEQ_UI_BUTTON_GP8: // Track Delay Page //SEQ_LCD_Clear(); //selected_page = PAGE_TRK_DELAY; //break; return -1; // not mapped case SEQ_UI_BUTTON_GP9: case SEQ_UI_BUTTON_GP10: return -1; // not mapped case SEQ_UI_BUTTON_GP11: case SEQ_UI_BUTTON_GP12: return -1; // not mapped case SEQ_UI_BUTTON_GP13: case SEQ_UI_BUTTON_GP14: // Auto Save switch auto_save ^= 1; break; break; case SEQ_UI_BUTTON_GP15: case SEQ_UI_BUTTON_GP16: // Ableton API switch ableton_api ^= 1; return -1; // not mapped } return 0; } break; /////////////////////////////////////////////////////////////////////////// // PATTERN NAME EDIT PAGE case PAGE_NAME_EDIT: { return Encoder_Handler((seq_ui_encoder_t)button, 0); } break; /////////////////////////////////////////////////////////////////////////// // TRACK DELAY PAGE case PAGE_TRK_DELAY: { } break; /////////////////////////////////////////////////////////////////////////// // MAIN PAGE case PAGE_MAIN: { // Pattern Change Group Requests if( button <= SEQ_UI_BUTTON_GP8 ) { u8 group; for(group=0; group<SEQ_CORE_NUM_GROUPS; ++group) { if( selected_pattern[group].group == button ) { if( SEQ_FILE_B_NumPatterns(selected_pattern[group].bank) > 64 ) { selected_pattern[group].lower ^= 1; } else { selected_pattern[group].lower = 0; // toggling not required } } else { selected_pattern[group].group = button; preview_bank = button; //preview_mode = 0; } } SEQ_PATTERN_PeekName(selected_pattern[0], preview_name); preview_mode = 1; return 1; // value always changed } // Pattern Change Request if( button >= SEQ_UI_BUTTON_GP9 && button <= SEQ_UI_BUTTON_GP16 ) { //u8 group; s32 status = 0; // setting save patterns for later autosave procedure //for(group=0; group<SEQ_CORE_NUM_GROUPS; ++group) // save_pattern[group] = seq_pattern[group]; // change preview pattern selected_pattern[0].num = button-8; selected_pattern[1].num = button-8; selected_pattern[2].num = button-8; selected_pattern[3].num = button-8; if ( !preview_mode ) { preview_num = button-8; SEQ_PATTERN_PeekName(selected_pattern[0], preview_name); preview_mode = 1; // for security reasons in live environment, we can not accept rapid 2x press of pattern button. // if the buttons are not good quality they can send a 2x rapid signal os pressing in just one physical pressing // the time we need is bassicly the human time to read the name of patterns requested // start time in count pc_time_control = seq_core_timestamp_ms + 200; // vTaksDelay(200); } else { // if ( remix_mode == 0 ) { //char str[30]; //sprintf(str, "%d = %d %d = %d", selected_pattern[0].num, preview_num, selected_pattern[0].group, preview_bank); //SEQ_UI_Msg(SEQ_UI_MSG_USER, 2000, str, "debug"); // Check for remix state if ( (selected_pattern[0].num == preview_num) && (selected_pattern[0].group == preview_bank) ) { //if ( pc_time_control >= seq_core_timestamp_ms ) // return 0; // do nothing, just to be shure we are not handle acidental double clicks, it happens! // if we got some remix bit setup, enter in remix mode if (seq_pattern_remix_map != 0) { // set the remix mode remix_mode = 1; } } } // Change Pattern if ( (selected_pattern[0].num == preview_num) && (selected_pattern[0].group == preview_bank) ) { if ( pc_time_control >= seq_core_timestamp_ms ) return 0; // do nothing, just to be shure we are not handle acidental double clicks if (ableton_api) { u8 ableton_pattern_number = 0; // // ABLETON API PATTERN CHANGE HANDLE // // send ableton event to change the line clips if (selected_pattern[0].lower) { ableton_pattern_number = ((selected_pattern[0].group - 1) * 8) + button; } else { ableton_pattern_number = (((selected_pattern[0].group - 1) + 8) * 8) + button; } // midi_cc to send = 110 // midi_chn = 16 // midi_port = ableton_port // here we need to send a clip line change request MIOS32_MIDI_SendCC(ableton_port, 15, 110, ableton_pattern_number); // delay our task for ableton get a breath before change the pattern line vTaskDelay(50); // clip triggering u8 track; for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track) { // if we got the track bit setup inside our remix_map, them do not send mixer data for that track channel, let it be mixed down if ( ((1 << track) | seq_pattern_remix_map) == seq_pattern_remix_map ) { // do nothing... } else { // delay our task for ableton get a breath before change the pattern line vTaskDelay(50); // send clip slot play envet to ableton cc (111 + track) with value 127 to channel 16 MIOS32_MIDI_SendCC(ableton_port, 15, (111 + track), 127); } } // send a global clip change(all clips in the clip line) // send play envet to ableton cc 20 with value 127 to channel 16 //MIOS32_MIDI_SendCC(ableton_port, 15, 20, 127); } // // Autosave Pattern // if (auto_save) { // Autosave all 4 group of patterns for(group=0; group<SEQ_CORE_NUM_GROUPS; ++group) { // Save to SD Card if( (status=SEQ_PATTERN_Save(group, seq_pattern[group])) < 0 ) { SEQ_UI_SDCardErrMsg(2000, status); } } // Autosave Mixer Map SEQ_MIXER_Save(SEQ_MIXER_NumGet()); } // if we are not in remix mode if (seq_pattern_remix_map == 0) { // keep the name of old pattern(because we still got 1 or more tracks belongs to this pattern) //pattern_name = seq_pattern_name; // set timer for mixed pattern pattern_remix_timer = MIOS32_SYS_TimeGet(); } // // Pattern change request // for(group=0; group<SEQ_CORE_NUM_GROUPS; ++group) { // change pattern //selected_pattern[group].num = button-8; SEQ_PATTERN_Change(group, selected_pattern[group], 0); //if ( remix_mode ) { // keep the pattern name... //sprintf(seq_pattern_name[group], pattern_name); //} } if ( !remix_mode ) { // copy the pattern name for future reference //sprintf(pattern_name, seq_pattern_name[0]); SEQ_PATTERN_PeekName(selected_pattern[0], pattern_name); // TODO: sync this with the pattern change handled by SEQ_PATTERN_Handler() //pattern_timer.seconds = 0; preview_mode = 0; } // support for demix seq_pattern_demix_map = seq_pattern_remix_map; //preview_mode = 0; // Request a Pattern Preview } else { preview_num = button-8; SEQ_PATTERN_PeekName(selected_pattern[0], preview_name); // for security reasons in live environment, we can not accept 2x rapid press of pattern button. // if the buttons are not good quality they can send a 2x rapid signal os pressing in just one physical pressing // the time we need is bassicly the human time to read the name of patterns requested // start time in count pc_time_control = seq_core_timestamp_ms + 200; } } return 1; // value always changed } u8 visible_track = SEQ_UI_VisibleTrackGet(); switch( button ) { case SEQ_UI_BUTTON_Right: // switch to next track if( visible_track < (SEQ_CORE_NUM_TRACKS - 1) ) visible_track++; ui_selected_tracks = (1 << visible_track); ui_selected_group = visible_track / 4; return 1; // value always changed case SEQ_UI_BUTTON_Left: // switch to previous track if( visible_track >= 1 ) visible_track--; ui_selected_tracks = (1 << visible_track); ui_selected_group = visible_track / 4; return 1; // value always changed case SEQ_UI_BUTTON_Up: return Encoder_Handler(SEQ_UI_ENCODER_Datawheel, 1); case SEQ_UI_BUTTON_Down: return Encoder_Handler(SEQ_UI_ENCODER_Datawheel, -1); } return -1; // invalid or unsupported button } break; /////////////////////////////////////////////////////////////////////////// // Page do not exist default: break; } return 0; }
s32 SEQ_TERMINAL_PrintSdCardInfo(void *_output_function) { void (*out)(char *format, ...) = _output_function; FRESULT res; FILINFO fno; DIR dir; char *fn; char str_buffer[128]; MUTEX_MIDIOUT_TAKE; out("SD Card Informations\n"); out("====================\n"); #if !defined(MIOS32_FAMILY_EMULATION) // this yield ensures, that Debug Messages are sent before we continue the execution // Since MIOS Studio displays the time at which the messages arrived, this allows // us to measure the delay of following operations taskYIELD(); MUTEX_SDCARD_TAKE; SEQ_FILE_PrintSDCardInfos(); MUTEX_SDCARD_GIVE; #endif out("\n"); out("Reading Root Directory\n"); out("======================\n"); taskYIELD(); if( !SEQ_FILE_SDCardAvailable() ) { sprintf(str_buffer, "not connected"); } else if( !SEQ_FILE_VolumeAvailable() ) { sprintf(str_buffer, "Invalid FAT"); } else { out("Retrieving SD Card informations - please wait!\n"); MUTEX_MIDIOUT_GIVE; MUTEX_SDCARD_TAKE; SEQ_FILE_UpdateFreeBytes(); MUTEX_SDCARD_GIVE; MUTEX_MIDIOUT_TAKE; sprintf(str_buffer, "'%s': %u of %u MB free", SEQ_FILE_VolumeLabel(), (unsigned int)(SEQ_FILE_VolumeBytesFree()/1000000), (unsigned int)(SEQ_FILE_VolumeBytesTotal()/1000000)); } out("SD Card: %s\n", str_buffer); taskYIELD(); #if _USE_LFN static char lfn[_MAX_LFN * (_DF1S ? 2 : 1) + 1]; fno.lfname = lfn; fno.lfsize = sizeof(lfn); #endif MUTEX_SDCARD_TAKE; if( (res=f_opendir(&dir, "/")) != FR_OK ) { out("Failed to open root directory - error status: %d\n", res); } else { while( (f_readdir(&dir, &fno) == FR_OK) && fno.fname[0] ) { #if _USE_LFN fn = *fno.lfname ? fno.lfname : fno.fname; #else fn = fno.fname; #endif char date[10]; ShowFatDate(fno.fdate,(char*)&date); char time[12]; ShowFatTime(fno.ftime,(char*)&time); out("[%s%s%s%s%s%s%s] %s %s %s %u %s\n", (fno.fattrib & AM_RDO ) ? "r" : ".", (fno.fattrib & AM_HID ) ? "h" : ".", (fno.fattrib & AM_SYS ) ? "s" : ".", (fno.fattrib & AM_VOL ) ? "v" : ".", (fno.fattrib & AM_LFN ) ? "l" : ".", (fno.fattrib & AM_DIR ) ? "d" : ".", (fno.fattrib & AM_ARC ) ? "a" : ".", date,time, (fno.fattrib & AM_DIR) ? "<DIR>" : " ", fno.fsize,fn); } } MUTEX_SDCARD_GIVE; taskYIELD(); out("\n"); out("Checking SD Card at application layer\n"); out("=====================================\n"); out("Current session: /SESSIONS/%s\n", seq_file_session_name); { u8 bank; for(bank=0; bank<SEQ_FILE_B_NUM_BANKS; ++bank) { int num_patterns = SEQ_FILE_B_NumPatterns(bank); if( num_patterns ) out("File /SESSIONS/%s/MBSEQ_B%d.V4: valid (%d patterns)\n", seq_file_session_name, bank+1, num_patterns); else out("File /SESSIONS/%s/MBSEQ_B%d.V4: doesn't exist\n", seq_file_session_name, bank+1, num_patterns); } int num_maps = SEQ_FILE_M_NumMaps(); if( num_maps ) out("File /SESSIONS/%sMBSEQ_M.V4: valid (%d mixer maps)\n", seq_file_session_name, num_maps); else out("File /SESSIONS/%s/MBSEQ_M.V4: doesn't exist\n", seq_file_session_name); int num_songs = SEQ_FILE_S_NumSongs(); if( num_songs ) out("File /SESSIONS/%s/MBSEQ_S.V4: valid (%d songs)\n", seq_file_session_name, num_songs); else out("File /SESSIONS/%s/MBSEQ_S.V4: doesn't exist\n", seq_file_session_name); if( SEQ_FILE_G_Valid() ) out("File /SESSIONS/%s/MBSEQ_G.V4: valid\n", seq_file_session_name); else out("File /SESSIONS/%s/MBSEQ_G.V4: doesn't exist\n", seq_file_session_name); if( SEQ_FILE_C_Valid() ) out("File /SESSIONS/%s/MBSEQ_C.V4: valid\n", seq_file_session_name); else out("File /SESSIONS/%s/MBSEQ_C.V4: doesn't exist\n", seq_file_session_name); if( SEQ_FILE_HW_Valid() ) out("File /SESSIONS/%s/MBSEQ_HW.V4: valid\n", seq_file_session_name); else out("File /SESSIONS/%s/MBSEQ_HW.V4: doesn't exist or hasn't been re-loaded\n", seq_file_session_name); } out("done.\n"); MUTEX_MIDIOUT_GIVE; return 0; // no error }
///////////////////////////////////////////////////////////////////////////// // CC has been received over selected port and channel ///////////////////////////////////////////////////////////////////////////// static s32 SEQ_MIDI_IN_Receive_CC(u8 bus, u8 cc, u8 value) { static u8 nrpn_lsb = 0; static u8 nrpn_msb = 0; if( bus >= SEQ_MIDI_IN_NUM_BUSSES ) return -1; // MIDI Remote Function? if( seq_hwcfg_midi_remote.cc && seq_hwcfg_midi_remote.cc == cc ) { remote_active = value >= 0x40; return 1; } // Remaining functions switch( cc ) { case 0x01: // ModWheel -> Morph Value case 0x03: // Global Scale return SEQ_CC_MIDI_Set(0, cc, value); case 0x70: // Pattern Group #1 case 0x71: // Pattern Group #2 case 0x72: // Pattern Group #3 case 0x73: { // Pattern Group #4 u8 group = cc-0x70; seq_pattern_t pattern = seq_pattern[group]; if( value < SEQ_FILE_B_NumPatterns(pattern.bank) ) { pattern.pattern = value; pattern.DISABLED = 0; pattern.SYNCHED = 0; SEQ_PATTERN_Change(group, pattern, 0); } return 1; } break; case 0x74: // Bank Group #1 case 0x75: // Bank Group #2 case 0x76: // Bank Group #3 case 0x77: { // Bank Group #4 u8 group = cc-0x74; seq_pattern_t pattern = seq_pattern[group]; if( value < SEQ_FILE_B_NUM_BANKS ) { pattern.bank = value; pattern.DISABLED = 0; pattern.SYNCHED = 0; SEQ_PATTERN_Change(group, pattern, 0); } return 1; } break; case 0x62: // NRPN LSB (selects parameter) nrpn_lsb = value; return 1; case 0x63: // NRPN MSB (selects track) nrpn_msb = value; return 1; case 0x06: // NRPN Value LSB (sets parameter) if( nrpn_msb < SEQ_CORE_NUM_TRACKS) return SEQ_CC_MIDI_Set(nrpn_msb, nrpn_lsb, value); break; case 0x7b: // all notes off (transposer, arpeggiator, patch changer) if( value == 0 ) { SEQ_MIDI_IN_ResetAllStacks(); SEQ_CV_ResetAllChannels(); } break; } 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 }