diff --git a/UVR.py b/UVR.py index 65ef926e..35bc2321 100644 --- a/UVR.py +++ b/UVR.py @@ -1421,6 +1421,7 @@ def __init__(self): self.is_menu_settings_open = False self.is_root_defined_var = tk.BooleanVar(value=False) self.is_check_splash = False + self.stime = None self.is_open_menu_advanced_vr_options = tk.BooleanVar(value=False) self.is_open_menu_advanced_demucs_options = tk.BooleanVar(value=False) @@ -3319,6 +3320,14 @@ def set_vars_for_sample_mode(event): is_create_model_folder_Option = ttk.Checkbutton(settings_menu_format_Frame, text=GENERATE_MODEL_FOLDER_TEXT, width=GEN_SETTINGS_WIDTH, variable=self.is_create_model_folder_var) is_create_model_folder_Option.grid() self.help_hints(is_create_model_folder_Option, text=IS_CREATE_MODEL_FOLDER_HELP) + + is_create_parent_folder_Option = ttk.Checkbutton(settings_menu_format_Frame, text=GENERATE_PARENT_FOLDER_TEXT, width=GEN_SETTINGS_WIDTH, variable=self.is_create_parent_folder_var) + is_create_parent_folder_Option.grid() + self.help_hints(is_create_parent_folder_Option, text=IS_CREATE_PARENT_FOLDER_HELP) + + is_files_numbered_Option = ttk.Checkbutton(settings_menu_format_Frame, text=GENERATE_FILES_NUMBERED_TEXT, width=GEN_SETTINGS_WIDTH, variable=self.is_files_numbered_var) + is_files_numbered_Option.grid() + self.help_hints(is_files_numbered_Option, text=IS_FILES_NUMBERED_HELP) is_accept_any_input_Option = ttk.Checkbutton(settings_menu_format_Frame, text=ACCEPT_ANY_INPUT_TEXT, width=GEN_SETTINGS_WIDTH, variable=self.is_accept_any_input_var) is_accept_any_input_Option.grid() @@ -6241,8 +6250,17 @@ def process_update_progress(self, total_files, step: float = 1): progress += base * step self.progress_bar_main_var.set(progress) - - self.conversion_Button_Text_var.set(f'Process Progress: {int(progress)}%') + + elapsed_time = time.perf_counter() - self.stime + total_time = elapsed_time / (progress / 100) + remaining_time = int(total_time - elapsed_time) + eta_minutes, eta_seconds = divmod(remaining_time, 60) + eta_hours, eta_minutes = divmod(eta_minutes, 60) + eta_h = f"{eta_hours}h " if eta_hours else "" + eta_m = f"{eta_minutes}m " if eta_minutes else "" + eta_s = f"{eta_seconds}s" + + self.conversion_Button_Text_var.set(f'Process Progress: {int(progress)}% (ETA {eta_h}{eta_m}{eta_s})') def confirm_stop_process(self): """Asks for confirmation before halting active process""" @@ -6290,7 +6308,7 @@ def process_tool_start(self): """Start the conversion for all the given mp3 and wav files""" def time_elapsed(): - return f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}' + return f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - self.stime)))}' def get_audio_file_base(audio_file): if audio_tool.audio_tool == MANUAL_ENSEMBLE: @@ -6325,7 +6343,7 @@ def handle_pitch_time_shift(audio_file, audio_file_base): self.command_Text.write(DONE) multiple_files = False - stime = time.perf_counter() + self.stime = time.perf_counter() self.process_button_init() inputPaths = self.inputPaths is_verified_audio = True @@ -6546,8 +6564,8 @@ def determine_voc_split(self, models): def process_start(self): """Start the conversion for all the given mp3 and wav files""" - stime = time.perf_counter() - time_elapsed = lambda:f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}' + self.stime = time.perf_counter() + time_elapsed = lambda:f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - self.stime)))}' export_path = self.export_path_var.get() is_ensemble = False self.true_model_count = 0 @@ -6604,12 +6622,17 @@ def process_start(self): set_progress_bar = lambda step, inference_iterations=0:self.process_update_progress(total_files=inputPath_total_len, step=(step + (inference_iterations))) write_to_console = lambda progress_text, base_text=base_text:self.command_Text.write(base_text + progress_text) - audio_file_base = f"{file_num}_{os.path.splitext(os.path.basename(audio_file))[0]}" + audio_file_base = os.path.splitext(os.path.basename(audio_file))[0] + audio_file_base = f"{file_num}_{audio_file_base}" if self.is_files_numbered_var.get() else audio_file_base audio_file_base = audio_file_base if not self.is_testing_audio_var.get() or is_ensemble else f"{round(time.time())}_{audio_file_base}" audio_file_base = audio_file_base if not is_ensemble else f"{audio_file_base}_{current_model.model_basename}" if not is_ensemble: audio_file_base = audio_file_base if not self.is_add_model_name_var.get() else f"{audio_file_base}_{current_model.model_basename}" + if self.is_create_parent_folder_var.get(): + export_path = os.path.join(Path(self.export_path_var.get()), os.path.basename(os.path.dirname(audio_file))) + if not os.path.isdir(export_path):os.makedirs(export_path) + if self.is_create_model_folder_var.get() and not is_ensemble: export_path = os.path.join(Path(self.export_path_var.get()), current_model.model_basename, os.path.splitext(os.path.basename(audio_file))[0]) if not os.path.isdir(export_path):os.makedirs(export_path) @@ -6837,6 +6860,8 @@ def load_saved_vars(self, data): self.is_use_opencl_var = tk.BooleanVar(value=False)#True if is_opencl_only else data['is_use_opencl'])# self.is_wav_ensemble_var = tk.BooleanVar(value=data['is_wav_ensemble'])# self.is_create_model_folder_var = tk.BooleanVar(value=data['is_create_model_folder']) + self.is_create_parent_folder_var = tk.BooleanVar(value=data['is_create_parent_folder']) + self.is_files_numbered_var = tk.BooleanVar(value=data['is_files_numbered']) self.help_hints_var = tk.BooleanVar(value=data['help_hints_var']) self.model_sample_mode_var = tk.BooleanVar(value=data['model_sample_mode']) self.model_sample_mode_duration_var = tk.StringVar(value=data['model_sample_mode_duration']) @@ -6962,6 +6987,8 @@ def load_saved_settings(self, loaded_setting: dict, process_method=None, is_defa self.is_accept_any_input_var.set(loaded_setting["is_accept_any_input"]) self.is_task_complete_var.set(loaded_setting['is_task_complete']) self.is_create_model_folder_var.set(loaded_setting['is_create_model_folder']) + self.is_create_parent_folder_var.set(loaded_setting['is_create_parent_folder']) + self.is_files_numbered_var.set(loaded_setting['is_files_numbered']) self.mp3_bit_set_var.set(loaded_setting['mp3_bit_set']) self.semitone_shift_var.set(loaded_setting['semitone_shift'])# self.save_format_var.set(loaded_setting['save_format']) @@ -7098,6 +7125,8 @@ def save_values(self, app_close=True, is_restart=False, is_auto_save=False): 'is_use_opencl': self.is_use_opencl_var.get(),# 'is_wav_ensemble': self.is_wav_ensemble_var.get(),# 'is_create_model_folder': self.is_create_model_folder_var.get(), + 'is_create_parent_folder': self.is_create_parent_folder_var.get(), + 'is_files_numbered': self.is_files_numbered_var.get(), 'mp3_bit_set': self.mp3_bit_set_var.get(), 'semitone_shift': self.semitone_shift_var.get(),# 'save_format': self.save_format_var.get(), diff --git a/gui_data/constants.py b/gui_data/constants.py index 22c59186..764ef3eb 100644 --- a/gui_data/constants.py +++ b/gui_data/constants.py @@ -648,6 +648,8 @@ 'is_use_opencl': False, 'is_wav_ensemble': False, 'is_create_model_folder': False, + 'is_create_parent_folder': False, + 'is_files_numbered': True, 'mp3_bit_set': '320k',# 'semitone_shift': '0',# 'save_format': WAV, @@ -759,6 +761,8 @@ "is_accept_any_input", 'is_task_complete', 'is_create_model_folder', + 'is_create_parent_folder', + 'is_files_numbered', 'mp3_bit_set',# 'semitone_shift',# 'save_format', @@ -1098,6 +1102,32 @@ ' └── First Directory (Named after the model)\n' ' └── Second Directory (Named after the track)\n' ' └── Output File(s)') +IS_CREATE_PARENT_FOLDER_HELP = ('Output files will have the same parent folder as their input file.\n\n' + '• Example: \n' + 'Input Files:\n' + ' └── Album_A\n' + ' └── Audio_A.mp3\n' + ' └── Album_B\n' + ' └── Audio_B.mp3\n\n' + 'Export Directory:\n' + ' └── Exports\n\n' + 'Output Files:\n' + ' └── Exports\n' + ' └── Album_A\n' + ' └── Audio_A_(Vocals).wav\n' + ' └── Audio_A_(Instrumental).wav\n' + ' └── Album_B\n' + ' └── Audio_B_(Vocals).wav\n' + ' └── Audio_B_(Instrumental).wav') +IS_FILES_NUMBERED_HELP = ('Prepends a number to the saved files based on processing order.\n\n' + '• Example:\n\n' + '─ Export Directory\n' + ' └── 1_Audio_X_(Vocals).wav\n' + ' └── 1_Audio_X_(Instrumental).wav\n' + ' └── 2_Audio_Y_(Vocals).wav\n' + ' └── 2_Audio_Y_(Instrumental).wav\n' + ' └── 3_Audio_Z_(Vocals).wav\n' + ' └── 3_Audio_Z_(Instrumental).wav') MDX_DIM_T_SET_HELP = INTERNAL_MODEL_ATT MDX_DIM_F_SET_HELP = INTERNAL_MODEL_ATT @@ -1432,6 +1462,8 @@ GENERAL_MENU_TEXT = 'General Menu' GENERAL_PROCESS_SETTINGS_TEXT = 'General Process Settings' GENERATE_MODEL_FOLDER_TEXT = 'Generate Model Folder' +GENERATE_PARENT_FOLDER_TEXT = 'Generate Parent Folder' +GENERATE_FILES_NUMBERED_TEXT = 'Prepend File Numbers' HIGHEND_PROCESS_TEXT = 'High-End Process' INPUT_CODE_TEXT = 'Input Code' INPUT_STEM_NAME_TEXT = 'Input Stem Name'