diff --git a/UVR.py b/UVR.py index c51f407..c0b57db 100644 --- a/UVR.py +++ b/UVR.py @@ -38,6 +38,8 @@ import subprocess # Run python file import inference_MDX import inference_v5 import inference_v5_ensemble +import inference_demucs + from win32api import GetSystemMetrics @@ -68,6 +70,7 @@ help_path = os.path.join(base_path, 'img', 'help.png') gen_opt_path = os.path.join(base_path, 'img', 'gen_opt.png') mdx_opt_path = os.path.join(base_path, 'img', 'mdx_opt.png') vr_opt_path = os.path.join(base_path, 'img', 'vr_opt.png') +demucs_opt_path = os.path.join(base_path, 'img', 'demucs_opt.png') ense_opt_path = os.path.join(base_path, 'img', 'ense_opt.png') user_ens_opt_path = os.path.join(base_path, 'img', 'user_ens_opt.png') credits_path = os.path.join(base_path, 'img', 'credits.png') @@ -98,25 +101,32 @@ DEFAULT_DATA = { 'modelInstrumentalLabel': '', 'aiModel': 'MDX-Net', 'algo': 'Instrumentals (Min Spec)', - 'ensChoose': 'MDX-Net/VR Ensemble', + 'demucs_stems': 'All Stems', + 'ensChoose': 'Multi-AI Ensemble', 'useModel': 'instrumental', 'lastDir': None, 'break': False, #Advanced Options 'appendensem': False, 'demucs_only': False, + 'split_mode': True, #MDX-Net 'demucsmodel': True, 'non_red': False, 'noise_reduc': True, 'voc_only': False, 'inst_only': False, + 'voc_only_b': False, + 'inst_only_b': False, + 'audfile': True, 'chunks': 'Auto', 'n_fft_scale': 6144, 'dim_f': 2048, 'noise_pro_select': 'Auto Select', - 'overlap': 0.5, - 'shifts': 0, + 'overlap': 0.25, + 'shifts': 2, + 'overlap_b': 0.25, + 'shifts_b': 2, 'margin': 44100, 'channel': 64, 'compensate': 1.03597672895, @@ -124,7 +134,8 @@ DEFAULT_DATA = { 'noisereduc_s': '3', 'mixing': 'Default', 'mdxnetModel': 'UVR-MDX-NET 1', - 'DemucsModel': 'demucs_extra-3646af93_org.th', + 'DemucsModel': 'mdx_extra', + 'DemucsModel_MDX': 'UVR_Demucs_Model_1', 'ModelParams': 'Auto', } @@ -324,6 +335,8 @@ class MainWindow(TkinterDnD.Tk): size=(900, 826)) self.vr_opt_img = open_image(path=vr_opt_path, size=(900, 826)) + self.demucs_opt_img = open_image(path=demucs_opt_path, + size=(900, 826)) self.ense_opt_img = open_image(path=ense_opt_path, size=(900, 826)) self.user_ens_opt_img = open_image(path=user_ens_opt_path, @@ -337,6 +350,8 @@ class MainWindow(TkinterDnD.Tk): size=(740, 826)) self.vr_opt_img = open_image(path=vr_opt_path, size=(695, 826)) + self.demucs_opt_img = open_image(path=demucs_opt_path, + size=(695, 826)) self.ense_opt_img = open_image(path=ense_opt_path, size=(740, 826)) self.user_ens_opt_img = open_image(path=user_ens_opt_path, @@ -350,7 +365,9 @@ class MainWindow(TkinterDnD.Tk): size=(740, 826)) self.vr_opt_img = open_image(path=vr_opt_path, size=(730, 826)) - self.ense_opt_img = open_image(path=ense_opt_path, + self.demucs_opt_img = open_image(path=vr_opt_path, + size=(730, 826)) + self.ense_opt_img = open_image(path=demucs_opt_path, size=(740, 826)) self.user_ens_opt_img = open_image(path=user_ens_opt_path, size=(740, 826)) @@ -361,9 +378,12 @@ class MainWindow(TkinterDnD.Tk): self.lastInstrumentalModels = [] self.MDXLabel_to_path = defaultdict(lambda: '') self.lastMDXModels = [] - self.DemucsLabel_to_path = defaultdict(lambda: '') self.ModelParamsLabel_to_path = defaultdict(lambda: '') self.lastModelParams = [] + self.DemucsLabel_to_path = defaultdict(lambda: '') + self.lastDemucsModels = [] + self.DemucsLabel_to_path_MDX = defaultdict(lambda: '') + self.lastDemucsModels_MDX = [] # -Tkinter Value Holders- data = load_data() @@ -387,6 +407,7 @@ class MainWindow(TkinterDnD.Tk): #Advanced Options self.appendensem_var = tk.BooleanVar(value=data['appendensem']) self.demucs_only_var = tk.BooleanVar(value=data['demucs_only']) + self.split_mode_var = tk.BooleanVar(value=data['split_mode']) # Processing Options self.gpuConversion_var = tk.BooleanVar(value=data['gpu']) self.postprocessing_var = tk.BooleanVar(value=data['postprocess']) @@ -412,6 +433,9 @@ class MainWindow(TkinterDnD.Tk): self.noise_pro_select_var = tk.StringVar(value=data['noise_pro_select']) self.overlap_var = tk.StringVar(value=data['overlap']) self.shifts_var = tk.StringVar(value=data['shifts']) + self.overlap_b_var = tk.StringVar(value=data['overlap_b']) + self.shifts_b_var = tk.StringVar(value=data['shifts_b']) + self.channel_var = tk.StringVar(value=data['channel']) self.margin_var = tk.StringVar(value=data['margin']) self.compensate_var = tk.StringVar(value=data['compensate']) @@ -419,18 +443,23 @@ class MainWindow(TkinterDnD.Tk): # Instrumental or Vocal Only self.voc_only_var = tk.BooleanVar(value=data['voc_only']) self.inst_only_var = tk.BooleanVar(value=data['inst_only']) + self.voc_only_b_var = tk.BooleanVar(value=data['voc_only_b']) + self.inst_only_b_var = tk.BooleanVar(value=data['inst_only_b']) + self.audfile_var = tk.BooleanVar(value=data['audfile']) # Choose Conversion Method self.aiModel_var = tk.StringVar(value=data['aiModel']) self.last_aiModel = self.aiModel_var.get() # Choose Conversion Method self.algo_var = tk.StringVar(value=data['algo']) self.last_algo = self.aiModel_var.get() + self.demucs_stems_var = tk.StringVar(value=data['demucs_stems']) # Choose Ensemble self.ensChoose_var = tk.StringVar(value=data['ensChoose']) self.last_ensChoose = self.ensChoose_var.get() # Choose MDX-NET Model self.mdxnetModel_var = tk.StringVar(value=data['mdxnetModel']) self.DemucsModel_var = tk.StringVar(value=data['DemucsModel']) + self.DemucsModel_MDX_var = tk.StringVar(value=data['DemucsModel_MDX']) self.ModelParams_var = tk.StringVar(value=data['ModelParams']) self.last_mdxnetModel = self.mdxnetModel_var.get() # Other @@ -469,9 +498,9 @@ class MainWindow(TkinterDnD.Tk): self.stop_Button = ttk.Button(master=self, image=self.stop_img, command=self.restart) - self.help_Button = ttk.Button(master=self, + self.settings_Button = ttk.Button(master=self, image=self.help_img, - command=self.help) + command=self.settings) #ttk.Button(win, text= "Open", command= open_popup).pack() @@ -534,7 +563,7 @@ class MainWindow(TkinterDnD.Tk): self.stop_Button.place(x=-10 - 35, y=self.IMAGE_HEIGHT + self.FILEPATHS_HEIGHT + self.OPTIONS_HEIGHT + self.PADDING*2, width=35, height=self.CONVERSIONBUTTON_HEIGHT, relx=1, rely=0, relwidth=0, relheight=0) - self.help_Button.place(x=-10 - 600, y=self.IMAGE_HEIGHT + self.FILEPATHS_HEIGHT + self.OPTIONS_HEIGHT + self.PADDING*2, width=35, height=self.CONVERSIONBUTTON_HEIGHT, + self.settings_Button.place(x=-10 - 600, y=self.IMAGE_HEIGHT + self.FILEPATHS_HEIGHT + self.OPTIONS_HEIGHT + self.PADDING*2, width=35, height=self.CONVERSIONBUTTON_HEIGHT, relx=1, rely=0, relwidth=0, relheight=0) self.command_Text.place(x=25, y=self.IMAGE_HEIGHT + self.FILEPATHS_HEIGHT + self.OPTIONS_HEIGHT + self.CONVERSIONBUTTON_HEIGHT + self.PADDING*3, width=-30, height=self.COMMAND_HEIGHT, relx=0, rely=0, relwidth=1, relheight=0) @@ -615,7 +644,7 @@ class MainWindow(TkinterDnD.Tk): background='#0e0e0f', font=self.font, foreground='#13a4c9', borderwidth=0, command=self.open_appdir_filedialog) self.options_aiModel_Optionmenu = ttk.OptionMenu(self.options_Frame, self.aiModel_var, - None, 'VR Architecture', 'MDX-Net', 'Ensemble Mode') + None, 'VR Architecture', 'MDX-Net', 'Demucs v3', 'Ensemble Mode') # Choose Instrumental Model self.options_instrumentalModel_Label = tk.Button(master=self.options_Frame, @@ -623,6 +652,14 @@ class MainWindow(TkinterDnD.Tk): background='#0e0e0f', font=self.font, foreground='#13a4c9', borderwidth=0, command=self.open_Modelfolder_vr) self.options_instrumentalModel_Optionmenu = ttk.OptionMenu(self.options_Frame, self.instrumentalModel_var) + + # Choose Demucs Model + self.options_DemucsModel_Label = tk.Button(master=self.options_Frame, + text='Choose Demucs Model', + background='#0e0e0f', font=self.font, foreground='#13a4c9', borderwidth=0, command=self.open_Modelfolder_de) + self.options_DemucsModel_Optionmenu = ttk.OptionMenu(self.options_Frame, + self.DemucsModel_var) + # Choose MDX-Net Model self.options_mdxnetModel_Label = tk.Button(master=self.options_Frame, text='Choose MDX-Net Model', anchor=tk.CENTER, @@ -637,7 +674,7 @@ class MainWindow(TkinterDnD.Tk): background='#0e0e0f', font=self.font, foreground='#13a4c9', borderwidth=0, command=self.custom_ensemble) self.options_ensChoose_Optionmenu = ttk.OptionMenu(self.options_Frame, self.ensChoose_var, - None, 'MDX-Net/VR Ensemble', 'Basic Ensemble', 'HP2 Models', 'All HP/HP2 Models', 'Vocal Models', 'User Ensemble') + None, 'Multi-AI Ensemble', 'Basic VR Ensemble', 'Vocal Models', 'Manual Ensemble') # Choose Agorithim self.options_algo_Label = tk.Label(master=self.options_Frame, @@ -646,6 +683,14 @@ class MainWindow(TkinterDnD.Tk): self.options_algo_Optionmenu = ttk.OptionMenu(self.options_Frame, self.algo_var, None, 'Vocals (Max Spec)', 'Instrumentals (Min Spec)')#, 'Invert (Normal)', 'Invert (Spectral)') + + # Choose Demucs Stems + self.options_demucs_stems_Label = tk.Button(master=self.options_Frame, + text='Choose Stem(s)', anchor=tk.CENTER, + background='#0e0e0f', font=self.font, foreground='#13a4c9', borderwidth=0, command=self.advanced_demucs_options) + self.options_demucs_stems_Optionmenu = ttk.OptionMenu(self.options_Frame, + self.demucs_stems_var, + None, 'All Stems', 'Vocals', 'Other', 'Bass', 'Drums') # -Column 2- @@ -659,16 +704,35 @@ class MainWindow(TkinterDnD.Tk): self.winSize_var, None, '320', '512','1024') # MDX-chunks - self.options_chunks_Label = tk.Button(master=self.options_Frame, + self.options_chunks_Label = tk.Label(master=self.options_Frame, text='Chunks', - background='#0e0e0f', font=self.font, foreground='#13a4c9', - borderwidth=0, command=self.advanced_mdx_options) + background='#0e0e0f', font=self.font, foreground='#13a4c9') self.options_chunks_Optionmenu = ttk.OptionMenu(self.options_Frame, self.chunks_var, None, 'Auto', '1', '5', '10', '15', '20', '25', '30', '35', '40', '45', '50', '55', '60', '65', '70', '75', '80', '85', '90', '95', 'Full') + + + # Overlap + self.options_overlap_b_Label = tk.Label(master=self.options_Frame, + text='Overlap', anchor=tk.CENTER, + background='#0e0e0f', font=self.font, foreground='#13a4c9') + self.options_overlap_b_Optionmenu = ttk.OptionMenu(self.options_Frame, + self.overlap_b_var, + 0, 0.25, 0.50, 0.75, 0.99) + + # Shifts + self.options_shifts_b_Label = tk.Label(master=self.options_Frame, + text='Shifts', anchor=tk.CENTER, + background='#0e0e0f', font=self.font, foreground='#13a4c9') + self.options_shifts_b_Optionmenu = ttk.OptionMenu(self.options_Frame, + self.shifts_b_var, + 0, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, + 18, 19, 20) #Checkboxes # GPU Selection @@ -687,6 +751,18 @@ class MainWindow(TkinterDnD.Tk): text='Save Instrumental Only', variable=self.inst_only_var, ) + + # Vocal Only + self.options_voc_only_b_Checkbutton = ttk.Checkbutton(master=self.options_Frame, + text='Stem Only', + variable=self.voc_only_b_var, + ) + # Instrumental Only + self.options_inst_only_b_Checkbutton = ttk.Checkbutton(master=self.options_Frame, + text='Mix Without Stem Only', + variable=self.inst_only_b_var, + ) + # TTA self.options_tta_Checkbutton = ttk.Checkbutton(master=self.options_Frame, text='TTA', @@ -704,6 +780,12 @@ class MainWindow(TkinterDnD.Tk): text='Post-Process', variable=self.postprocessing_var, ) + + # Split Mode + self.options_split_Checkbutton = ttk.Checkbutton(master=self.options_Frame, + text='Split Mode', + variable=self.split_mode_var, + ) # -Column 3- @@ -784,6 +866,13 @@ class MainWindow(TkinterDnD.Tk): relx=0, rely=6/self.COL1_ROWS, relwidth=1/3, relheight=1/self.COL1_ROWS) self.options_instrumentalModel_Optionmenu.place(x=0, y=19, width=0, height=7, relx=0, rely=7/self.COL1_ROWS, relwidth=1/3, relheight=1/self.COL1_ROWS) + + # Choose Demucs Model + self.options_DemucsModel_Label.place(x=0, y=19, width=0, height=-10, + relx=0, rely=6/self.COL1_ROWS, relwidth=1/3, relheight=1/self.COL1_ROWS) + self.options_DemucsModel_Optionmenu.place(x=0, y=19, width=0, height=7, + relx=0, rely=7/self.COL1_ROWS, relwidth=1/3, relheight=1/self.COL1_ROWS) + # Choose MDX-Net Model self.options_mdxnetModel_Label.place(x=0, y=19, width=0, height=-10, relx=0, rely=6/self.COL1_ROWS, relwidth=1/3, relheight=1/self.COL1_ROWS) @@ -800,6 +889,12 @@ class MainWindow(TkinterDnD.Tk): relx=1/3, rely=2/self.COL1_ROWS, relwidth=1/3, relheight=1/self.COL1_ROWS) self.options_algo_Optionmenu.place(x=12, y=-2, width=0, height=7, relx=1/3, rely=3/self.COL1_ROWS, relwidth=1/3, relheight=1/self.COL1_ROWS) + + # Choose Demucs Stems + self.options_demucs_stems_Label.place(x=13, y=0, width=0, height=-10, + relx=1/3, rely=2/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + self.options_demucs_stems_Optionmenu.place(x=71, y=-2, width=-118, height=7, + relx=1/3, rely=3/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) # -Column 2- @@ -811,9 +906,23 @@ class MainWindow(TkinterDnD.Tk): #---MDX-Net Specific--- # MDX-chunks self.options_chunks_Label.place(x=12, y=0, width=0, height=-10, - relx=1/3, rely=2/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + relx=2/3, rely=2/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) self.options_chunks_Optionmenu.place(x=71, y=-2, width=-118, height=7, - relx=1/3, rely=3/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + relx=2/3, rely=3/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + + # Overlap + self.options_overlap_b_Label.place(x=13, y=0, width=0, height=-10, + relx=2/3, rely=4/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + self.options_overlap_b_Optionmenu.place(x=71, y=-2, width=-118, height=7, + relx=2/3, rely=5/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + + # Shifts + self.options_shifts_b_Label.place(x=12, y=0, width=0, height=-10, + relx=2/3, rely=6/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + self.options_shifts_b_Optionmenu.place(x=71, y=-2, width=-118, height=7, + relx=2/3, rely=7/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + + #Checkboxes #GPU Conversion @@ -826,6 +935,16 @@ class MainWindow(TkinterDnD.Tk): self.options_inst_only_Checkbutton.place(x=35, y=21, width=0, height=5, relx=1/3, rely=7/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + #Vocals Only + self.options_voc_only_b_Checkbutton.place(x=35, y=21, width=0, height=5, + relx=1/3, rely=6/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + #Instrumental Only + self.options_inst_only_b_Checkbutton.place(x=35, y=21, width=0, height=5, + relx=1/3, rely=7/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + #Split Mode + self.options_split_Checkbutton.place(x=35, y=21, width=0, height=5, + relx=1/3, rely=7/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + # TTA self.options_tta_Checkbutton.place(x=35, y=21, width=0, height=5, relx=2/3, rely=5/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) @@ -842,9 +961,9 @@ class MainWindow(TkinterDnD.Tk): relx=2/3, rely=3/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) # MDX-noisereduc_s self.options_noisereduc_s_Label.place(x=15, y=0, width=0, height=-10, - relx=2/3, rely=2/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + relx=1/3, rely=2/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) self.options_noisereduc_s_Optionmenu.place(x=71, y=-2, width=-118, height=7, - relx=2/3, rely=3/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + relx=1/3, rely=3/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) #Checkboxes #---MDX-Net Specific--- # MDX-demucs Model @@ -878,6 +997,16 @@ class MainWindow(TkinterDnD.Tk): self.voc_only_var.trace_add('write', lambda *args: self.update_states()) + + self.inst_only_b_var.trace_add('write', + lambda *args: self.update_states()) + + self.voc_only_b_var.trace_add('write', + lambda *args: self.update_states()) + + self.demucs_stems_var.trace_add('write', + lambda *args: self.update_states()) + self.noisereduc_s_var.trace_add('write', lambda *args: self.update_states()) self.non_red_var.trace_add('write', @@ -898,6 +1027,12 @@ class MainWindow(TkinterDnD.Tk): self.demucs_only_var.trace_add('write', lambda *args: self.update_states()) + self.split_mode_var.trace_add('write', + lambda *args: self.update_states()) + + self.chunks_var.trace_add('write', + lambda *args: self.update_states()) + # Opening filedialogs def open_file_filedialog(self): """Make user select music files""" @@ -1022,6 +1157,8 @@ class MainWindow(TkinterDnD.Tk): inference = inference_v5_ensemble elif self.aiModel_var.get() == 'MDX-Net': inference = inference_MDX + elif self.aiModel_var.get() == 'Demucs v3': + inference = inference_demucs else: raise TypeError('This error should not occur.') @@ -1050,10 +1187,12 @@ class MainWindow(TkinterDnD.Tk): 'postprocess': self.postprocessing_var.get(), 'appendensem': self.appendensem_var.get(), 'demucs_only': self.demucs_only_var.get(), + 'split_mode': self.split_mode_var.get(), 'tta': self.tta_var.get(), 'save': self.save_var.get(), 'output_image': self.outputImage_var.get(), 'algo': self.algo_var.get(), + 'demucs_stems': self.demucs_stems_var.get(), # Models 'instrumentalModel': instrumentalModel_path, 'vocalModel': '', # Always not needed @@ -1067,6 +1206,7 @@ class MainWindow(TkinterDnD.Tk): 'ensChoose': ensChoose, 'mdxnetModel': mdxnetModel, 'DemucsModel': self.DemucsModel_var.get(), + 'DemucsModel_MDX': self.DemucsModel_MDX_var.get(), 'ModelParams': self.ModelParams_var.get(), # Other Variables (Tkinter) 'window': self, @@ -1080,6 +1220,9 @@ class MainWindow(TkinterDnD.Tk): 'noise_reduc': self.noisereduc_var.get(), 'voc_only': self.voc_only_var.get(), 'inst_only': self.inst_only_var.get(), + 'voc_only_b': self.voc_only_b_var.get(), + 'inst_only_b': self.inst_only_b_var.get(), + 'audfile': self.audfile_var.get(), 'chunks': chunks, 'noisereduc_s': noisereduc_s, 'mixing': mixing, @@ -1088,6 +1231,8 @@ class MainWindow(TkinterDnD.Tk): 'noise_pro_select': self.noise_pro_select_var.get(), 'overlap': self.overlap_var.get(), 'shifts': self.shifts_var.get(), + 'overlap_b': self.overlap_b_var.get(), + 'shifts_b': self.shifts_b_var.get(), 'margin': self.margin_var.get(), 'channel': self.channel_var.get(), 'compensate': self.compensate_var.get(), @@ -1196,7 +1341,7 @@ class MainWindow(TkinterDnD.Tk): """ try: - temp_DemucsModels_dir = os.path.join(instrumentalModels_dir, 'Demucs_Model') # nopep8 + temp_DemucsModels_dir = os.path.join(instrumentalModels_dir, 'Demucs_Models') # nopep8 new_DemucsModels = os.listdir(temp_DemucsModels_dir) if new_DemucsModels != self.lastDemucsModels: @@ -1204,7 +1349,11 @@ class MainWindow(TkinterDnD.Tk): self.DemucsLabel_to_path.clear() self.options_DemucsModel_Optionmenu['menu'].delete(0, 'end') for file_name_2 in natsort.natsorted(new_DemucsModels): - if file_name_2.endswith(('.th', '.pth')): + if file_name_2.endswith(('.yaml')): + b = [".yaml"] + for char in b: + file_name_2 = file_name_2.replace(char, "") + self.options_DemucsModel_Optionmenu['menu'].add_radiobutton(label=file_name_2, command=tk._setit(self.DemucsModel_var, file_name_2)) @@ -1212,6 +1361,26 @@ class MainWindow(TkinterDnD.Tk): except: pass + try: + temp_DemucsModels_MDX_dir = os.path.join(instrumentalModels_dir, 'Demucs_Models') # nopep8 + new_DemucsModels_MDX = os.listdir(temp_DemucsModels_MDX_dir) + + if new_DemucsModels_MDX != self.lastDemucsModels_MDX: + #print(new_MDXModels) + self.DemucsLabel_MDX_to_path.clear() + self.options_DemucsModel_MDX_Optionmenu['menu'].delete(0, 'end') + for file_name_3 in natsort.natsorted(new_DemucsModels_MDX): + if file_name_3.endswith(('.yaml')): + b = [".yaml"] + for char in b: + file_name_3 = file_name_3.replace(char, "") + + self.options_DemucsModel_MDX_Optionmenu['menu'].add_radiobutton(label=file_name_3, + command=tk._setit(self.DemucsModel_MDX_var, file_name_3)) + self.lastDemucsModels_MDX = new_DemucsModels_MDX + except: + pass + """ Loop through every model param (.json) in the models directory @@ -1252,14 +1421,14 @@ class MainWindow(TkinterDnD.Tk): relx=0, rely=7/self.COL1_ROWS, relwidth=1/3, relheight=1/self.COL1_ROWS) # MDX-chunks self.options_chunks_Label.place(x=12, y=0, width=0, height=-10, - relx=1/3, rely=2/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + relx=2/3, rely=2/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) self.options_chunks_Optionmenu.place(x=71, y=-2, width=-118, height=7, - relx=1/3, rely=3/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + relx=2/3, rely=3/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) # MDX-noisereduc_s self.options_noisereduc_s_Label.place(x=15, y=0, width=0, height=-10, - relx=2/3, rely=2/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + relx=1/3, rely=2/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) self.options_noisereduc_s_Optionmenu.place(x=71, y=-2, width=-118, height=7, - relx=2/3, rely=3/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + relx=1/3, rely=3/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) #GPU Conversion self.options_gpu_Checkbutton.configure(state=tk.NORMAL) self.options_gpu_Checkbutton.place(x=35, y=21, width=0, height=5, @@ -1305,6 +1474,21 @@ class MainWindow(TkinterDnD.Tk): self.options_agg_Optionmenu.place_forget() self.options_algo_Label.place_forget() self.options_algo_Optionmenu.place_forget() + self.options_DemucsModel_Label.place_forget() + self.options_DemucsModel_Optionmenu.place_forget() + self.options_demucs_stems_Label.place_forget() + self.options_demucs_stems_Optionmenu.place_forget() + self.options_voc_only_b_Checkbutton.configure(state=tk.DISABLED) + self.options_voc_only_b_Checkbutton.place_forget() + self.options_inst_only_b_Checkbutton.configure(state=tk.DISABLED) + self.options_inst_only_b_Checkbutton.place_forget() + self.options_inst_only_b_Checkbutton.place_forget() + self.options_overlap_b_Label.place_forget() + self.options_overlap_b_Optionmenu.place_forget() + self.options_shifts_b_Label.place_forget() + self.options_shifts_b_Optionmenu.place_forget() + self.options_split_Checkbutton.configure(state=tk.DISABLED) + self.options_split_Checkbutton.place_forget() elif self.aiModel_var.get() == 'VR Architecture': @@ -1373,9 +1557,108 @@ class MainWindow(TkinterDnD.Tk): self.options_demucsmodel_Checkbutton.place_forget() self.options_non_red_Checkbutton.configure(state=tk.DISABLED) self.options_non_red_Checkbutton.place_forget() + self.options_DemucsModel_Label.place_forget() + self.options_DemucsModel_Optionmenu.place_forget() + self.options_demucs_stems_Label.place_forget() + self.options_demucs_stems_Optionmenu.place_forget() + self.options_voc_only_b_Checkbutton.configure(state=tk.DISABLED) + self.options_voc_only_b_Checkbutton.place_forget() + self.options_inst_only_b_Checkbutton.configure(state=tk.DISABLED) + self.options_inst_only_b_Checkbutton.place_forget() + self.options_overlap_b_Label.place_forget() + self.options_overlap_b_Optionmenu.place_forget() + self.options_shifts_b_Label.place_forget() + self.options_shifts_b_Optionmenu.place_forget() + self.options_split_Checkbutton.configure(state=tk.DISABLED) + self.options_split_Checkbutton.place_forget() + + elif self.aiModel_var.get() == 'Demucs v3': + #Keep for Ensemble & VR Architecture Mode + # Choose Main Model + self.options_DemucsModel_Label.place(x=0, y=19, width=0, height=-10, + relx=0, rely=6/self.COL1_ROWS, relwidth=1/3, relheight=1/self.COL1_ROWS) + self.options_DemucsModel_Optionmenu.place(x=0, y=19, width=0, height=7, + relx=0, rely=7/self.COL1_ROWS, relwidth=1/3, relheight=1/self.COL1_ROWS) + + # Choose Stems + self.options_demucs_stems_Label.place(x=13, y=0, width=0, height=-10, + relx=1/3, rely=2/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + self.options_demucs_stems_Optionmenu.place(x=55, y=-2, width=-85, height=7, + relx=1/3, rely=3/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + + # Chunks + self.options_chunks_Label.place(x=12, y=0, width=0, height=-10, + relx=2/3, rely=2/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + self.options_chunks_Optionmenu.place(x=55, y=-2, width=-85, height=7, + relx=2/3, rely=3/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + + # Shifts + self.options_shifts_b_Label.place(x=12, y=0, width=0, height=-10, + relx=2/3, rely=5/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + self.options_shifts_b_Optionmenu.place(x=55, y=-2, width=-85, height=7, + relx=2/3, rely=6/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + + # Overlap + self.options_overlap_b_Label.place(x=13, y=0, width=0, height=-10, + relx=2/3, rely=8/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + self.options_overlap_b_Optionmenu.place(x=55, y=-2, width=-85, height=7, + relx=2/3, rely=9/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + + #GPU Conversion + self.options_gpu_Checkbutton.configure(state=tk.NORMAL) + self.options_gpu_Checkbutton.place(x=35, y=21, width=0, height=5, + relx=1/3, rely=5/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + #Vocals Only + self.options_voc_only_b_Checkbutton.configure(state=tk.NORMAL) + self.options_voc_only_b_Checkbutton.place(x=35, y=21, width=0, height=5, + relx=1/3, rely=6/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + #Instrumental Only + self.options_inst_only_b_Checkbutton.configure(state=tk.NORMAL) + self.options_inst_only_b_Checkbutton.place(x=35, y=21, width=0, height=5, + relx=1/3, rely=7/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + + #Instrumental Only + self.options_split_Checkbutton.configure(state=tk.NORMAL) + self.options_split_Checkbutton.place(x=35, y=21, width=0, height=5, + relx=1/3, rely=8/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + + # Forget Widgets + self.options_save_Checkbutton.configure(state=tk.DISABLED) + self.options_save_Checkbutton.place_forget() + self.options_post_Checkbutton.configure(state=tk.DISABLED) + self.options_post_Checkbutton.place_forget() + self.options_tta_Checkbutton.configure(state=tk.DISABLED) + self.options_tta_Checkbutton.place_forget() + # self.options_image_Checkbutton.configure(state=tk.DISABLED) + # self.options_image_Checkbutton.place_forget() + self.options_demucsmodel_Checkbutton.configure(state=tk.DISABLED) + self.options_demucsmodel_Checkbutton.place_forget() + self.options_noisereduc_Checkbutton.configure(state=tk.DISABLED) + self.options_noisereduc_Checkbutton.place_forget() + self.options_non_red_Checkbutton.configure(state=tk.DISABLED) + self.options_non_red_Checkbutton.place_forget() + self.options_voc_only_Checkbutton.configure(state=tk.DISABLED) + self.options_voc_only_Checkbutton.place_forget() + self.options_inst_only_Checkbutton.configure(state=tk.DISABLED) + self.options_inst_only_Checkbutton.place_forget() + self.options_noisereduc_s_Label.place_forget() + self.options_noisereduc_s_Optionmenu.place_forget() + self.options_mdxnetModel_Label.place_forget() + self.options_mdxnetModel_Optionmenu.place_forget() + self.options_winSize_Label.place_forget() + self.options_winSize_Optionmenu.place_forget() + self.options_agg_Label.place_forget() + self.options_agg_Optionmenu.place_forget() + self.options_ensChoose_Label.place_forget() + self.options_ensChoose_Optionmenu.place_forget() + self.options_instrumentalModel_Label.place_forget() + self.options_instrumentalModel_Optionmenu.place_forget() + self.options_algo_Label.place_forget() + self.options_algo_Optionmenu.place_forget() + self.options_modelFolder_Checkbutton.place_forget() elif self.aiModel_var.get() == 'Ensemble Mode': - if self.ensChoose_var.get() == 'User Ensemble': + if self.ensChoose_var.get() == 'Manual Ensemble': # Choose Algorithm self.options_algo_Label.place(x=20, y=0, width=0, height=-10, relx=1/3, rely=2/self.COL1_ROWS, relwidth=1/3, relheight=1/self.COL1_ROWS) @@ -1419,8 +1702,24 @@ class MainWindow(TkinterDnD.Tk): self.options_winSize_Optionmenu.place_forget() self.options_agg_Label.place_forget() self.options_agg_Optionmenu.place_forget() + self.options_DemucsModel_Label.place_forget() + self.options_DemucsModel_Optionmenu.place_forget() + self.options_demucs_stems_Label.place_forget() + self.options_demucs_stems_Optionmenu.place_forget() + self.options_voc_only_b_Checkbutton.configure(state=tk.DISABLED) + self.options_voc_only_b_Checkbutton.place_forget() + self.options_inst_only_b_Checkbutton.configure(state=tk.DISABLED) + self.options_inst_only_b_Checkbutton.place_forget() + self.options_inst_only_b_Checkbutton.place_forget() + self.options_overlap_b_Label.place_forget() + self.options_overlap_b_Optionmenu.place_forget() + self.options_shifts_b_Label.place_forget() + self.options_shifts_b_Optionmenu.place_forget() + self.options_split_Checkbutton.configure(state=tk.DISABLED) + self.options_split_Checkbutton.place_forget() + - elif self.ensChoose_var.get() == 'MDX-Net/VR Ensemble': + elif self.ensChoose_var.get() == 'Multi-AI Ensemble': # Choose Ensemble self.options_ensChoose_Label.place(x=0, y=19, width=0, height=-10, relx=0, rely=6/self.COL1_ROWS, relwidth=1/3, relheight=1/self.COL1_ROWS) @@ -1428,14 +1727,14 @@ class MainWindow(TkinterDnD.Tk): relx=0, rely=7/self.COL1_ROWS, relwidth=1/3, relheight=1/self.COL1_ROWS) # MDX-chunks self.options_chunks_Label.place(x=12, y=0, width=0, height=-10, - relx=1/3, rely=2/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + relx=2/3, rely=2/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) self.options_chunks_Optionmenu.place(x=71, y=-2, width=-118, height=7, - relx=1/3, rely=3/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + relx=2/3, rely=3/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) # MDX-noisereduc_s self.options_noisereduc_s_Label.place(x=15, y=0, width=0, height=-10, - relx=2/3, rely=2/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + relx=1/3, rely=2/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) self.options_noisereduc_s_Optionmenu.place(x=71, y=-2, width=-118, height=7, - relx=2/3, rely=3/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) + relx=1/3, rely=3/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) # WINDOW self.options_winSize_Label.place(x=13, y=-7, width=0, height=-10, relx=1/3, rely=5/self.COL2_ROWS, relwidth=1/3, relheight=1/self.COL2_ROWS) @@ -1483,6 +1782,21 @@ class MainWindow(TkinterDnD.Tk): self.options_non_red_Checkbutton.place_forget() self.options_algo_Label.place_forget() self.options_algo_Optionmenu.place_forget() + self.options_DemucsModel_Label.place_forget() + self.options_DemucsModel_Optionmenu.place_forget() + self.options_demucs_stems_Label.place_forget() + self.options_demucs_stems_Optionmenu.place_forget() + self.options_voc_only_b_Checkbutton.configure(state=tk.DISABLED) + self.options_voc_only_b_Checkbutton.place_forget() + self.options_inst_only_b_Checkbutton.configure(state=tk.DISABLED) + self.options_inst_only_b_Checkbutton.place_forget() + self.options_inst_only_b_Checkbutton.place_forget() + self.options_overlap_b_Label.place_forget() + self.options_overlap_b_Optionmenu.place_forget() + self.options_shifts_b_Label.place_forget() + self.options_shifts_b_Optionmenu.place_forget() + self.options_split_Checkbutton.configure(state=tk.DISABLED) + self.options_split_Checkbutton.place_forget() else: # Choose Ensemble self.options_ensChoose_Label.place(x=0, y=19, width=0, height=-10, @@ -1546,6 +1860,21 @@ class MainWindow(TkinterDnD.Tk): self.options_demucsmodel_Checkbutton.configure(state=tk.DISABLED) self.options_non_red_Checkbutton.place_forget() self.options_non_red_Checkbutton.configure(state=tk.DISABLED) + self.options_DemucsModel_Label.place_forget() + self.options_DemucsModel_Optionmenu.place_forget() + self.options_demucs_stems_Label.place_forget() + self.options_demucs_stems_Optionmenu.place_forget() + self.options_voc_only_b_Checkbutton.configure(state=tk.DISABLED) + self.options_voc_only_b_Checkbutton.place_forget() + self.options_inst_only_b_Checkbutton.configure(state=tk.DISABLED) + self.options_inst_only_b_Checkbutton.place_forget() + self.options_inst_only_b_Checkbutton.place_forget() + self.options_overlap_b_Label.place_forget() + self.options_overlap_b_Optionmenu.place_forget() + self.options_shifts_b_Label.place_forget() + self.options_shifts_b_Optionmenu.place_forget() + self.options_split_Checkbutton.configure(state=tk.DISABLED) + self.options_split_Checkbutton.place_forget() if self.inst_only_var.get() == True: @@ -1562,6 +1891,60 @@ class MainWindow(TkinterDnD.Tk): elif self.voc_only_var.get() == False: self.options_inst_only_Checkbutton.configure(state=tk.NORMAL) + if self.demucs_stems_var.get() == 'All Stems': + self.voc_only_b_var.set(False) + self.inst_only_b_var.set(False) + self.options_voc_only_b_Checkbutton.configure(state=tk.DISABLED) + self.options_inst_only_b_Checkbutton.configure(state=tk.DISABLED) + elif self.demucs_stems_var.get() == 'Vocals': + if self.inst_only_b_var.get() == True: + self.options_voc_only_b_Checkbutton.configure(state=tk.DISABLED) + self.voc_only_b_var.set(False) + elif self.inst_only_b_var.get() == False: + self.options_voc_only_b_Checkbutton.configure(state=tk.NORMAL) + + if self.voc_only_b_var.get() == True: + self.options_inst_only_b_Checkbutton.configure(state=tk.DISABLED) + self.inst_only_b_var.set(False) + elif self.voc_only_b_var.get() == False: + self.options_inst_only_b_Checkbutton.configure(state=tk.NORMAL) + elif self.demucs_stems_var.get() == 'Other': + if self.inst_only_b_var.get() == True: + self.options_voc_only_b_Checkbutton.configure(state=tk.DISABLED) + self.voc_only_b_var.set(False) + elif self.inst_only_b_var.get() == False: + self.options_voc_only_b_Checkbutton.configure(state=tk.NORMAL) + + if self.voc_only_b_var.get() == True: + self.options_inst_only_b_Checkbutton.configure(state=tk.DISABLED) + self.inst_only_b_var.set(False) + elif self.voc_only_b_var.get() == False: + self.options_inst_only_b_Checkbutton.configure(state=tk.NORMAL) + elif self.demucs_stems_var.get() == 'Drums': + if self.inst_only_b_var.get() == True: + self.options_voc_only_b_Checkbutton.configure(state=tk.DISABLED) + self.voc_only_b_var.set(False) + elif self.inst_only_b_var.get() == False: + self.options_voc_only_b_Checkbutton.configure(state=tk.NORMAL) + if self.voc_only_b_var.get() == True: + self.options_inst_only_b_Checkbutton.configure(state=tk.DISABLED) + self.inst_only_b_var.set(False) + elif self.voc_only_b_var.get() == False: + self.options_inst_only_b_Checkbutton.configure(state=tk.NORMAL) + elif self.demucs_stems_var.get() == 'Bass': + if self.inst_only_b_var.get() == True: + self.options_voc_only_b_Checkbutton.configure(state=tk.DISABLED) + self.voc_only_b_var.set(False) + elif self.inst_only_b_var.get() == False: + self.options_voc_only_b_Checkbutton.configure(state=tk.NORMAL) + + if self.voc_only_b_var.get() == True: + self.options_inst_only_b_Checkbutton.configure(state=tk.DISABLED) + self.inst_only_b_var.set(False) + elif self.voc_only_b_var.get() == False: + self.options_inst_only_b_Checkbutton.configure(state=tk.NORMAL) + + if self.noisereduc_s_var.get() == 'None': self.options_non_red_Checkbutton.configure(state=tk.DISABLED) self.non_red_var.set(False) @@ -1651,6 +2034,10 @@ class MainWindow(TkinterDnD.Tk): if self.demucs_only_var.get() == True: self.demucsmodel_var.set(True) + self.options_demucsmodel_Checkbutton.configure(state=tk.DISABLED) + elif self.demucs_only_var.get() == False: + self.options_demucsmodel_Checkbutton.configure(state=tk.NORMAL) + self.update_inputPaths() @@ -1665,7 +2052,7 @@ class MainWindow(TkinterDnD.Tk): self.last_aiModel = self.aiModel_var.get() self.instrumentalModel_var.set('') - self.ensChoose_var.set('MDX-Net/VR Ensemble') + self.ensChoose_var.set('Multi-AI Ensemble') self.mdxnetModel_var.set('UVR-MDX-NET 1') self.winSize_var.set(DEFAULT_DATA['window_size']) @@ -1685,24 +2072,13 @@ class MainWindow(TkinterDnD.Tk): if confirm: self.save_values() - - subprocess.Popen(f'UVR_Launcher.exe') + try: + subprocess.Popen(f'UVR_Launcher.exe') + except: + subprocess.Popen(f'python "{__file__}"', shell=True) exit() else: pass - - def utagoe_start(self): - """ - Restart the application after asking for confirmation - """ - # confirm = tk.messagebox.askyesno(title='Restart Confirmation', - # message='This will restart the application and halt any running processes. Your current settings will be saved. \n\n Are you sure you wish to continue?') - - # if confirm: - try: - subprocess.Popen(f'Utagoe-en.exe') - except: - pass def open_newModel_filedialog(self): """Let user paste an MDX-Net model to use for the vocal seperation""" @@ -1717,9 +2093,9 @@ class MainWindow(TkinterDnD.Tk): def advanced_vr_options(self): """ - Open Help Guide + Open Advanced VR Options """ - top= Toplevel(self) + top=Toplevel(self) top.geometry("600x500") window_height = 600 @@ -1740,6 +2116,10 @@ class MainWindow(TkinterDnD.Tk): # change title bar icon top.iconbitmap('img\\UVR-Icon-v2.ico') + def close_win(): + top.destroy() + self.settings() + tabControl = ttk.Notebook(top) tab1 = ttk.Frame(tabControl) @@ -1754,6 +2134,9 @@ class MainWindow(TkinterDnD.Tk): frame0=Frame(tab1, highlightbackground='red',highlightthicknes=0) frame0.grid(row=0,column=0,padx=0,pady=30) + l0=Label(frame0,text="Advanced VR Options",font=("Century Gothic", "13", "bold", "underline"), justify="center", fg="#13a4c9") + l0.grid(row=0,column=0,padx=0,pady=10) + l0=tk.Label(frame0, text='Window Size (Set Manually)', font=("Century Gothic", "9"), foreground='#13a4c9') l0.grid(row=1,column=0,padx=0,pady=10) @@ -1777,19 +2160,124 @@ class MainWindow(TkinterDnD.Tk): l0=ttk.Checkbutton(frame0, text='Save Output Image(s) of Spectrogram(s)', variable=self.outputImage_var) l0.grid(row=8,column=0,padx=0,pady=10) + l0=ttk.Button(frame0,text='Open VR Models Folder', command=self.open_Modelfolder_vr) + l0.grid(row=9,column=0,padx=0,pady=0) + + l0=ttk.Button(frame0,text='Back to Main Menu', command=close_win) + l0.grid(row=10,column=0,padx=0,pady=10) + + def close_win_self(): + top.destroy() + + l0=ttk.Button(frame0,text='Close Window', command=close_win_self) + l0.grid(row=11,column=0,padx=0,pady=0) + self.ModelParamsLabel_to_path = defaultdict(lambda: '') self.lastModelParams = [] self.update_states() - - def advanced_mdx_options(self): + + + def advanced_demucs_options(self): """ - Open Help Guide + Open Advanced Demucs Options """ top= Toplevel(self) - top.geometry("600x550") - window_height = 600 + top.geometry("670x500") + window_height = 670 + window_width = 500 + + top.title("Advanced Demucs Options") + + top.resizable(False, False) # This code helps to disable windows from resizing + + screen_width = top.winfo_screenwidth() + screen_height = top.winfo_screenheight() + + x_cordinate = int((screen_width/2) - (window_width/2)) + y_cordinate = int((screen_height/2) - (window_height/2)) + + top.geometry("{}x{}+{}+{}".format(window_width, window_height, x_cordinate, y_cordinate)) + + # change title bar icon + top.iconbitmap('img\\UVR-Icon-v2.ico') + + def close_win(): + top.destroy() + self.settings() + + tabControl = ttk.Notebook(top) + + tab1 = ttk.Frame(tabControl) + + tabControl.add(tab1, text ='Advanced Settings') + + tabControl.pack(expand = 1, fill ="both") + + tab1.grid_rowconfigure(0, weight=1) + tab1.grid_columnconfigure(0, weight=1) + + frame0=Frame(tab1, highlightbackground='red',highlightthicknes=0) + frame0.grid(row=0,column=0,padx=0,pady=30) + + l0=Label(frame0,text="Advanced Demucs Options",font=("Century Gothic", "13", "bold", "underline"), justify="center", fg="#13a4c9") + l0.grid(row=0,column=0,padx=0,pady=10) + + l0=tk.Label(frame0, text='Chunks (Set Manually)', font=("Century Gothic", "9"), foreground='#13a4c9') + l0.grid(row=1,column=0,padx=0,pady=10) + + l0=ttk.Entry(frame0, textvariable=self.chunks_var, justify='center') + l0.grid(row=2,column=0,padx=0,pady=0) + + l0=tk.Label(frame0, text='Chunk Margin', font=("Century Gothic", "9"), foreground='#13a4c9') + l0.grid(row=3,column=0,padx=0,pady=10) + + l0=ttk.Entry(frame0, textvariable=self.margin_var, justify='center') + l0.grid(row=4,column=0,padx=0,pady=0) + + l0=tk.Label(frame0, text='Shifts\n(Higher values use more resources and increase processing times)', font=("Century Gothic", "9"), foreground='#13a4c9') + l0.grid(row=5,column=0,padx=0,pady=10) + + l0=ttk.Entry(frame0, textvariable=self.shifts_b_var, justify='center') + l0.grid(row=6,column=0,padx=0,pady=0) + + l0=tk.Label(frame0, text='Overlap', font=("Century Gothic", "9"), foreground='#13a4c9') + l0.grid(row=7,column=0,padx=0,pady=10) + + l0=ttk.Entry(frame0, textvariable=self.overlap_b_var, justify='center') + l0.grid(row=8,column=0,padx=0,pady=0) + + l0=ttk.Checkbutton(frame0, text='Save Stems to Model Name Directory', variable=self.audfile_var) + l0.grid(row=9,column=0,padx=0,pady=0) + + l0=ttk.Checkbutton(frame0, text='Settings Test Mode', variable=self.modelFolder_var) + l0.grid(row=10,column=0,padx=0,pady=0) + + # l0=ttk.Checkbutton(frame0, text='Basic Prediction', variable=self.audfile_var) + # l0.grid(row=10,column=0,padx=0,pady=0) + + l0=ttk.Button(frame0,text='Open Demucs Model Folder', command=self.open_Modelfolder_de) + l0.grid(row=11,column=0,padx=0,pady=0) + + l0=ttk.Button(frame0,text='Back to Main Menu', command=close_win) + l0.grid(row=12,column=0,padx=0,pady=10) + + def close_win_self(): + top.destroy() + + l0=ttk.Button(frame0,text='Close Window', command=close_win_self) + l0.grid(row=13,column=0,padx=0,pady=0) + + + def advanced_mdx_options(self): + """ + Open Advanced MDX Options + """ + top= Toplevel(self) + + top.geometry("670x550") + window_height = 670 window_width = 550 top.title("Advanced MDX-Net Options") @@ -1806,6 +2294,10 @@ class MainWindow(TkinterDnD.Tk): # change title bar icon top.iconbitmap('img\\UVR-Icon-v2.ico') + + def close_win(): + top.destroy() + self.settings() tabControl = ttk.Notebook(top) @@ -1829,35 +2321,50 @@ class MainWindow(TkinterDnD.Tk): frame0=Frame(tab1, highlightbackground='red',highlightthicknes=0) frame0.grid(row=0,column=0,padx=0,pady=30) - l0=tk.Label(frame0, text='Chunks (Set Manually)', font=("Century Gothic", "9"), foreground='#13a4c9') + l0=Label(frame0,text="Advanced MDX-Net Options",font=("Century Gothic", "13", "bold", "underline"), justify="center", fg="#13a4c9") l0.grid(row=0,column=0,padx=0,pady=10) + l0=tk.Label(frame0, text='Chunks (Set Manually)', font=("Century Gothic", "9"), foreground='#13a4c9') + l0.grid(row=1,column=0,padx=0,pady=10) + l0=ttk.Entry(frame0, textvariable=self.chunks_var, justify='center') - l0.grid(row=1,column=0,padx=0,pady=0) + l0.grid(row=2,column=0,padx=0,pady=0) l0=tk.Label(frame0, text='Noise Reduction (Set Manually)', font=("Century Gothic", "9"), foreground='#13a4c9') - l0.grid(row=2,column=0,padx=0,pady=10) + l0.grid(row=3,column=0,padx=0,pady=10) l0=ttk.Entry(frame0, textvariable=self.noisereduc_s_var, justify='center') - l0.grid(row=3,column=0,padx=0,pady=0) + l0.grid(row=4,column=0,padx=0,pady=0) l0=tk.Label(frame0, text='Chunk Margin', font=("Century Gothic", "9"), foreground='#13a4c9') - l0.grid(row=4,column=0,padx=0,pady=10) + l0.grid(row=5,column=0,padx=0,pady=10) l0=ttk.Entry(frame0, textvariable=self.margin_var, justify='center') - l0.grid(row=5,column=0,padx=0,pady=0) + l0.grid(row=6,column=0,padx=0,pady=0) l0=tk.Label(frame0, text='Volume Compensation', font=("Century Gothic", "9"), foreground='#13a4c9') - l0.grid(row=6,column=0,padx=0,pady=10) + l0.grid(row=7,column=0,padx=0,pady=10) l0=ttk.Entry(frame0, textvariable=self.compensate_var, justify='center') - l0.grid(row=7,column=0,padx=0,pady=0) + l0.grid(row=8,column=0,padx=0,pady=0) l0=tk.Label(frame0, text='Noise Profile', font=("Century Gothic", "9"), foreground='#13a4c9') - l0.grid(row=8,column=0,padx=0,pady=10) + l0.grid(row=9,column=0,padx=0,pady=10) l0=ttk.OptionMenu(frame0, self.noise_pro_select_var, None, 'Auto Select', 'MDX-NET_Noise_Profile_14_kHz', 'MDX-NET_Noise_Profile_17_kHz', 'MDX-NET_Noise_Profile_Full_Band') - l0.grid(row=9,column=0,padx=0,pady=0) + l0.grid(row=10,column=0,padx=0,pady=0) + + l0=ttk.Button(frame0,text='Open MDX-Net Models Folder', command=self.open_newModel_filedialog) + l0.grid(row=11,column=0,padx=0,pady=10) + + l0=ttk.Button(frame0,text='Back to Main Menu', command=close_win) + l0.grid(row=12,column=0,padx=0,pady=0) + + def close_win_self(): + top.destroy() + + l0=ttk.Button(frame0,text='Close Window', command=close_win_self) + l0.grid(row=13,column=0,padx=0,pady=10) frame0=Frame(tab2, highlightbackground='red',highlightthicknes=0) frame0.grid(row=0,column=0,padx=0,pady=30) @@ -1865,40 +2372,36 @@ class MainWindow(TkinterDnD.Tk): l0=tk.Label(frame0, text='Choose Demucs Model', font=("Century Gothic", "9"), foreground='#13a4c9') l0.grid(row=0,column=0,padx=0,pady=0) - self.options_DemucsModel_Optionmenu = l0=ttk.OptionMenu(frame0, self.DemucsModel_var) - - self.options_DemucsModel_Optionmenu - l0.grid(row=2,column=0,padx=0,pady=0) - l0=tk.Button(frame0, text='(Click here to add more Demucs models)', font=("Century Gothic", "8"), foreground='#13a4c9', borderwidth=0, command=self.open_Modelfolder_de) l0.grid(row=1,column=0,padx=0,pady=0) + self.options_DemucsModel_MDX_Optionmenu = l0=ttk.OptionMenu(frame0, self.DemucsModel_MDX_var) + + self.options_DemucsModel_MDX_Optionmenu + l0.grid(row=2,column=0,padx=0,pady=0) + l0=tk.Label(frame0, text='Mixing Algorithm', font=("Century Gothic", "9"), foreground='#13a4c9') l0.grid(row=3,column=0,padx=0,pady=10) l0=ttk.OptionMenu(frame0, self.mixing_var, None, 'Default', 'Min_Mag', 'Max_Mag', 'Invert_p') l0.grid(row=4,column=0,padx=0,pady=0) - l0=tk.Label(frame0, text='Channel', font=("Century Gothic", "9"), foreground='#13a4c9') + l0=tk.Label(frame0, text='Shifts\n(Higher values use more resources and increase processing times)', font=("Century Gothic", "9"), foreground='#13a4c9') l0.grid(row=5,column=0,padx=0,pady=10) - l0=ttk.Entry(frame0, textvariable=self.channel_var, justify='center') + l0=ttk.Entry(frame0, textvariable=self.shifts_var, justify='center') l0.grid(row=6,column=0,padx=0,pady=0) - l0=tk.Label(frame0, text='Shifts\n(Higher values use more resources and increase processing times)', font=("Century Gothic", "9"), foreground='#13a4c9') + l0=tk.Label(frame0, text='Overlap', font=("Century Gothic", "9"), foreground='#13a4c9') l0.grid(row=7,column=0,padx=0,pady=10) - l0=ttk.Entry(frame0, textvariable=self.shifts_var, justify='center') + l0=ttk.Entry(frame0, textvariable=self.overlap_var, justify='center') l0.grid(row=8,column=0,padx=0,pady=0) - l0=tk.Label(frame0, text='Overlap', font=("Century Gothic", "9"), foreground='#13a4c9') + l0=ttk.Checkbutton(frame0, text='Split Mode', variable=self.split_mode_var) l0.grid(row=9,column=0,padx=0,pady=10) - l0=ttk.Entry(frame0, textvariable=self.overlap_var, justify='center') - l0.grid(row=10,column=0,padx=0,pady=0) - - l0=ttk.Checkbutton(frame0, text='Run Demucs Model Only', variable=self.demucs_only_var) - l0.grid(row=12,column=0,padx=0,pady=10) + self.update_states() frame0=Frame(tab3, highlightbackground='red',highlightthicknes=0) frame0.grid(row=0,column=0,padx=0,pady=30) @@ -1940,21 +2443,21 @@ class MainWindow(TkinterDnD.Tk): self.options_dim_f_Entry l0.grid(row=6,column=1,padx=0,pady=0) - - self.DemucsLabel_to_path = defaultdict(lambda: '') - self.lastDemucsModels = [] + + self.DemucsLabel_MDX_to_path = defaultdict(lambda: '') + self.lastDemucsModels_MDX = [] self.update_states() def custom_ensemble(self): """ - Open Help Guide + Open Ensemble Custom """ top= Toplevel(self) - top.geometry("670x670") - window_height = 670 + top.geometry("800x680") + window_height = 680 window_width = 800 top.title("Customize Ensemble") @@ -1971,6 +2474,10 @@ class MainWindow(TkinterDnD.Tk): # change title bar icon top.iconbitmap('img\\UVR-Icon-v2.ico') + + def close_win(): + top.destroy() + self.settings() tabControl = ttk.Notebook(top) @@ -1986,67 +2493,67 @@ class MainWindow(TkinterDnD.Tk): frame0=Frame(tab1, highlightbackground='red',highlightthicknes=0) frame0.grid(row=0,column=0,padx=0,pady=30) - l0=Label(frame0,text="MDX-Net/VR Ensemble Options",font=("Century Gothic", "10", "bold", "underline"), justify="center", fg="#f4f4f4") + l0=Label(frame0,text="Multi-AI Ensemble Options",font=("Century Gothic", "10", "bold", "underline"), justify="center", fg="#f4f4f4") l0.grid(row=1,column=0,padx=20,pady=10) - l0=tk.Label(frame0,text='MDX-Net Model\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') + l0=tk.Label(frame0,text='MDX-Net or Demucs Model 1\n',font=("Century Gothic", "9"), justify="center", foreground='#13a4c9') l0.grid(row=2,column=0,padx=0,pady=0) l0=ttk.OptionMenu(frame0, self.mdxensemchoose_var, None, 'UVR-MDX-NET 1', 'UVR-MDX-NET 2', 'UVR-MDX-NET 3', - 'UVR-MDX-NET Karaoke') + 'UVR-MDX-NET Karaoke', 'Demucs UVR Model 1', 'Demucs UVR Model 2', 'Demucs mdx_extra', 'Demucs mdx_extra_q') l0.grid(row=3,column=0,padx=0,pady=0) - l0=tk.Label(frame0,text='\nVR Model 1\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') + l0=tk.Label(frame0,text='\nMDX-Net or Demucs Model 2\n',font=("Century Gothic", "9"), justify="center", foreground='#13a4c9') l0.grid(row=4,column=0,padx=0,pady=0) + l0=ttk.OptionMenu(frame0, self.mdxensemchoose_b_var, None, 'No Model', 'UVR-MDX-NET 1', 'UVR-MDX-NET 2', 'UVR-MDX-NET 3', + 'UVR-MDX-NET Karaoke', 'Demucs UVR Model 1', 'Demucs UVR Model 2', 'Demucs mdx_extra', 'Demucs mdx_extra_q') + l0.grid(row=5,column=0,padx=0,pady=0) + + l0=tk.Label(frame0,text='\nVR Model 1\n',font=("Century Gothic", "9"), justify="center", foreground='#13a4c9') + l0.grid(row=6,column=0,padx=0,pady=0) + l0=ttk.OptionMenu(frame0, self.vrensemchoose_var, None, 'No Model', '1_HP-UVR', '2_HP-UVR', '3_HP-Vocal-UVR', '4_HP-Vocal-UVR', '5_HP-Karaoke-UVR', '6_HP-Karaoke-UVR', '7_HP2-UVR', '8_HP2-UVR', '9_HP2-UVR', '10_SP-UVR-2B-32000-1', '11_SP-UVR-2B-32000-2', '12_SP-UVR-3B-44100', '13_SP-UVR-4B-44100-1', '14_SP-UVR-4B-44100-2', '15_SP-UVR-MID-44100-1', '16_SP-UVR-MID-44100-2', 'MGM_MAIN_v4', 'MGM_HIGHEND_v4', 'MGM_LOWEND_A_v4', 'MGM_LOWEND_B_v4') - l0.grid(row=5,column=0,padx=0,pady=0) + l0.grid(row=7,column=0,padx=0,pady=0) - l0=tk.Label(frame0,text='\nVR Model 2\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') - l0.grid(row=6,column=0,padx=0,pady=0) + l0=tk.Label(frame0,text='\nVR Model 2\n',font=("Century Gothic", "9"), justify="center", foreground='#13a4c9') + l0.grid(row=8,column=0,padx=0,pady=0) l0=ttk.OptionMenu(frame0, self.vrensemchoose_mdx_a_var, None, 'No Model', '1_HP-UVR', '2_HP-UVR', '3_HP-Vocal-UVR', '4_HP-Vocal-UVR', '5_HP-Karaoke-UVR', '6_HP-Karaoke-UVR', '7_HP2-UVR', '8_HP2-UVR', '9_HP2-UVR', '10_SP-UVR-2B-32000-1', '11_SP-UVR-2B-32000-2', '12_SP-UVR-3B-44100', '13_SP-UVR-4B-44100-1', '14_SP-UVR-4B-44100-2', '15_SP-UVR-MID-44100-1', '16_SP-UVR-MID-44100-2', 'MGM_MAIN_v4', 'MGM_HIGHEND_v4', 'MGM_LOWEND_A_v4', 'MGM_LOWEND_B_v4') - l0.grid(row=7,column=0,padx=0,pady=0) + l0.grid(row=9,column=0,padx=0,pady=0) - l0=tk.Label(frame0,text='\nVR Model 3\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') - l0.grid(row=8,column=0,padx=0,pady=0) + l0=tk.Label(frame0,text='\nVR Model 3\n',font=("Century Gothic", "9"), justify="center", foreground='#13a4c9') + l0.grid(row=10,column=0,padx=0,pady=0) l0=ttk.OptionMenu(frame0, self.vrensemchoose_mdx_b_var, None, 'No Model', '1_HP-UVR', '2_HP-UVR', '3_HP-Vocal-UVR', '4_HP-Vocal-UVR', '5_HP-Karaoke-UVR', '6_HP-Karaoke-UVR', '7_HP2-UVR', '8_HP2-UVR', '9_HP2-UVR', '10_SP-UVR-2B-32000-1', '11_SP-UVR-2B-32000-2', '12_SP-UVR-3B-44100', '13_SP-UVR-4B-44100-1', '14_SP-UVR-4B-44100-2', '15_SP-UVR-MID-44100-1', '16_SP-UVR-MID-44100-2', 'MGM_MAIN_v4', 'MGM_HIGHEND_v4', 'MGM_LOWEND_A_v4', 'MGM_LOWEND_B_v4') - l0.grid(row=9,column=0,padx=0,pady=0) + l0.grid(row=11,column=0,padx=0,pady=0) - l0=tk.Label(frame0,text='\nVR Model 4\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') - l0.grid(row=10,column=0,padx=0,pady=0) + l0=tk.Label(frame0,text='\nVR Model 4\n',font=("Century Gothic", "9"), justify="center", foreground='#13a4c9') + l0.grid(row=12,column=0,padx=0,pady=0) l0=ttk.OptionMenu(frame0, self.vrensemchoose_mdx_c_var, None, 'No Model', '1_HP-UVR', '2_HP-UVR', '3_HP-Vocal-UVR', '4_HP-Vocal-UVR', '5_HP-Karaoke-UVR', '6_HP-Karaoke-UVR', '7_HP2-UVR', '8_HP2-UVR', '9_HP2-UVR', '10_SP-UVR-2B-32000-1', '11_SP-UVR-2B-32000-2', '12_SP-UVR-3B-44100', '13_SP-UVR-4B-44100-1', '14_SP-UVR-4B-44100-2', '15_SP-UVR-MID-44100-1', '16_SP-UVR-MID-44100-2', 'MGM_MAIN_v4', 'MGM_HIGHEND_v4', 'MGM_LOWEND_A_v4', 'MGM_LOWEND_B_v4') - l0.grid(row=11,column=0,padx=0,pady=0) - - l0=tk.Label(frame0,text='\nMDX-Net Model 2\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') - l0.grid(row=12,column=0,padx=0,pady=0) - - l0=ttk.OptionMenu(frame0, self.mdxensemchoose_b_var, None, 'No Model', 'UVR-MDX-NET 1', 'UVR-MDX-NET 2', 'UVR-MDX-NET 3', - 'UVR-MDX-NET Karaoke') l0.grid(row=13,column=0,padx=0,pady=0) - l0=Label(frame0,text="Basic Ensemble Options",font=("Century Gothic", "10", "bold", "underline"), justify="center", fg="#f4f4f4") + l0=Label(frame0,text="Basic VR Ensemble Options",font=("Century Gothic", "10", "bold", "underline"), justify="center", fg="#f4f4f4") l0.grid(row=1,column=1,padx=20,pady=10) - l0=tk.Label(frame0,text='VR Model 1\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') + l0=tk.Label(frame0,text='VR Model 1\n',font=("Century Gothic", "9"), justify="center", foreground='#13a4c9') l0.grid(row=2,column=1,padx=0,pady=0) l0=ttk.OptionMenu(frame0, self.vrensemchoose_a_var, None, '1_HP-UVR', '2_HP-UVR', '3_HP-Vocal-UVR', @@ -2056,7 +2563,7 @@ class MainWindow(TkinterDnD.Tk): 'MGM_MAIN_v4', 'MGM_HIGHEND_v4', 'MGM_LOWEND_A_v4', 'MGM_LOWEND_B_v4') l0.grid(row=3,column=1,padx=0,pady=0) - l0=tk.Label(frame0,text='\nVR Model 2\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') + l0=tk.Label(frame0,text='\nVR Model 2\n',font=("Century Gothic", "9"), justify="center", foreground='#13a4c9') l0.grid(row=4,column=1,padx=0,pady=0) l0=ttk.OptionMenu(frame0, self.vrensemchoose_b_var, None, '1_HP-UVR', '2_HP-UVR', '3_HP-Vocal-UVR', @@ -2066,7 +2573,7 @@ class MainWindow(TkinterDnD.Tk): 'MGM_MAIN_v4', 'MGM_HIGHEND_v4', 'MGM_LOWEND_A_v4', 'MGM_LOWEND_B_v4') l0.grid(row=5,column=1,padx=0,pady=0) - l0=tk.Label(frame0,text='\nVR Model 3\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') + l0=tk.Label(frame0,text='\nVR Model 3\n',font=("Century Gothic", "9"), justify="center", foreground='#13a4c9') l0.grid(row=6,column=1,padx=0,pady=0) l0=ttk.OptionMenu(frame0, self.vrensemchoose_c_var, None, 'No Model', '1_HP-UVR', '2_HP-UVR', '3_HP-Vocal-UVR', @@ -2076,7 +2583,7 @@ class MainWindow(TkinterDnD.Tk): 'MGM_MAIN_v4', 'MGM_HIGHEND_v4', 'MGM_LOWEND_A_v4', 'MGM_LOWEND_B_v4') l0.grid(row=7,column=1,padx=0,pady=0) - l0=tk.Label(frame0,text='\nVR Model 4\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') + l0=tk.Label(frame0,text='\nVR Model 4\n',font=("Century Gothic", "9"), justify="center", foreground='#13a4c9') l0.grid(row=8,column=1,padx=0,pady=0) l0=ttk.OptionMenu(frame0, self.vrensemchoose_d_var, None, 'No Model', '1_HP-UVR', '2_HP-UVR', '3_HP-Vocal-UVR', @@ -2086,7 +2593,7 @@ class MainWindow(TkinterDnD.Tk): 'MGM_MAIN_v4', 'MGM_HIGHEND_v4', 'MGM_LOWEND_A_v4', 'MGM_LOWEND_B_v4') l0.grid(row=9,column=1,padx=0,pady=0) - l0=tk.Label(frame0,text='\nVR Model 5\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') + l0=tk.Label(frame0,text='\nVR Model 5\n',font=("Century Gothic", "9"), justify="center", foreground='#13a4c9') l0.grid(row=10,column=1,padx=0,pady=0) l0=ttk.OptionMenu(frame0, self.vrensemchoose_e_var, None, 'No Model', '1_HP-UVR', '2_HP-UVR', '3_HP-Vocal-UVR', @@ -2096,18 +2603,50 @@ class MainWindow(TkinterDnD.Tk): 'MGM_MAIN_v4', 'MGM_HIGHEND_v4', 'MGM_LOWEND_A_v4', 'MGM_LOWEND_B_v4') l0.grid(row=11,column=1,padx=0,pady=0) + def close_win_self(): + top.destroy() + + l0=ttk.Button(frame0,text='Close Window', command=close_win_self) + l0.grid(row=13,column=1,padx=20,pady=0) l0=Label(frame0,text="Additional Options",font=("Century Gothic", "10", "bold", "underline"), justify="center", fg="#f4f4f4") - l0.grid(row=1,column=2,padx=0,pady=0) + l0.grid(row=1,column=2,padx=0,pady=10) l0=ttk.Checkbutton(frame0, text='Append Ensemble Name to Final Output', variable=self.appendensem_var) l0.grid(row=2,column=2,padx=0,pady=0) - l0=ttk.Checkbutton(frame0, text='Post-Process (VR Architecture Only)', variable=self.postprocessing_var) + l0=ttk.Button(frame0,text='Open Models Directory', command=self.open_Modelfolder_filedialog) l0.grid(row=3,column=2,padx=0,pady=0) - l0=ttk.Button(frame0,text='Open Models Directory', command=self.open_Modelfolder_filedialog) - l0.grid(row=4,column=2,padx=0,pady=10) + l0=ttk.Button(frame0,text='Back to Main Menu', command=close_win) + l0.grid(row=4,column=2,padx=0,pady=0) + + l0=tk.Label(frame0,text='Additional VR Architecture Options',font=("Century Gothic", "10", "bold", "underline"), justify="center", fg="#f4f4f4") + l0.grid(row=5,column=2,padx=0,pady=0) + + l0=ttk.Checkbutton(frame0, text='Post-Process', variable=self.postprocessing_var) + l0.grid(row=6,column=2,padx=0,pady=0) + + l0=ttk.Checkbutton(frame0, text='Save Output Image(s) of Spectrogram(s)', variable=self.outputImage_var) + l0.grid(row=7,column=2,padx=0,pady=0) + + l0=tk.Label(frame0,text='Additional Demucs v3 Options',font=("Century Gothic", "10", "bold", "underline"), justify="center", fg="#f4f4f4") + l0.grid(row=8,column=2,padx=0,pady=0) + + l0=tk.Label(frame0, text='Shifts\n(Higher values use more resources)', font=("Century Gothic", "9"), foreground='#13a4c9') + l0.grid(row=9,column=2,padx=0,pady=0) + + l0=ttk.Entry(frame0, textvariable=self.shifts_var, justify='center') + l0.grid(row=10,column=2,padx=0,pady=0) + + l0=tk.Label(frame0, text='Overlap', font=("Century Gothic", "9"), foreground='#13a4c9') + l0.grid(row=11,column=2,padx=0,pady=0) + + l0=ttk.Entry(frame0, textvariable=self.overlap_var, justify='center') + l0.grid(row=12,column=2,padx=0,pady=0) + + l0=ttk.Checkbutton(frame0, text='Split Mode', variable=self.split_mode_var) + l0.grid(row=13,column=2,padx=0,pady=0) def help(self): """ @@ -2140,6 +2679,10 @@ class MainWindow(TkinterDnD.Tk): # change title bar icon top.iconbitmap('img\\UVR-Icon-v2.ico') + + def close_win(): + top.destroy() + self.settings() tabControl = ttk.Notebook(top) @@ -2152,24 +2695,20 @@ class MainWindow(TkinterDnD.Tk): tab7 = ttk.Frame(tabControl) tab8 = ttk.Frame(tabControl) tab9 = ttk.Frame(tabControl) - tab10 = ttk.Frame(tabControl) tabControl.add(tab1, text ='General') tabControl.add(tab2, text ='VR Architecture') tabControl.add(tab3, text ='MDX-Net') - tabControl.add(tab4, text ='Ensemble Mode') - tabControl.add(tab5, text ='User Ensemble') - tabControl.add(tab6, text ='More Info') - tabControl.add(tab7, text ='Credits') - tabControl.add(tab8, text ='Updates') - tabControl.add(tab9, text ='Advanced') - tabControl.add(tab10, text ='Error Log') + tabControl.add(tab4, text ='Demucs v3') + tabControl.add(tab5, text ='Ensemble Mode') + tabControl.add(tab6, text ='Manual Ensemble') + tabControl.add(tab7, text ='More Info') + tabControl.add(tab8, text ='Credits') + tabControl.add(tab9, text ='Updates') tabControl.pack(expand = 1, fill ="both") #Configure the row/col of our frame and root window to be resizable and fill all available space - tab6.grid_rowconfigure(0, weight=1) - tab6.grid_columnconfigure(0, weight=1) tab7.grid_rowconfigure(0, weight=1) tab7.grid_columnconfigure(0, weight=1) @@ -2180,36 +2719,38 @@ class MainWindow(TkinterDnD.Tk): tab9.grid_rowconfigure(0, weight=1) tab9.grid_columnconfigure(0, weight=1) - tab10.grid_rowconfigure(0, weight=1) - tab10.grid_columnconfigure(0, weight=1) + tk.Button(tab1, image=self.gen_opt_img, borderwidth=0, command=close_win).grid(column = 0, + row = 0, + padx = 87, + pady = 30) + + tk.Button(tab2, image=self.vr_opt_img, borderwidth=0, command=close_win).grid(column = 0, + row = 0, + padx = 87, + pady = 30) + + tk.Button(tab3, image=self.mdx_opt_img, borderwidth=0, command=close_win).grid(column = 0, + row = 0, + padx = 87, + pady = 30) - ttk.Label(tab1, image=self.gen_opt_img).grid(column = 0, + tk.Button(tab4, image=self.demucs_opt_img, borderwidth=0, command=close_win).grid(column = 0, row = 0, padx = 87, pady = 30) - ttk.Label(tab2, image=self.vr_opt_img).grid(column = 0, + tk.Button(tab5, image=self.ense_opt_img, borderwidth=0, command=close_win).grid(column = 0, row = 0, padx = 87, pady = 30) - ttk.Label(tab3, image=self.mdx_opt_img).grid(column = 0, - row = 0, - padx = 87, - pady = 30) - - ttk.Label(tab4, image=self.ense_opt_img).grid(column = 0, - row = 0, - padx = 87, - pady = 30) - - ttk.Label(tab5, image=self.user_ens_opt_img).grid(column = 0, + tk.Button(tab6, image=self.user_ens_opt_img, borderwidth=0, command=close_win).grid(column = 0, row = 0, padx = 87, pady = 30) #frame0 - frame0=Frame(tab6,highlightbackground='red',highlightthicknes=0) + frame0=Frame(tab7,highlightbackground='red',highlightthicknes=0) frame0.grid(row=0,column=0,padx=0,pady=30) if GetSystemMetrics(1) >= 900: @@ -2262,7 +2803,7 @@ class MainWindow(TkinterDnD.Tk): l0=Label(frame0,text="If you wish to support and donate to this project, click the link above and become a Patreon!",font=("Century Gothic", "13"), justify="center", fg="#F6F6F7") l0.grid(row=13,column=0,padx=10,pady=7) - frame0=Frame(tab7,highlightbackground='red',highlightthicknes=0) + frame0=Frame(tab8,highlightbackground='red',highlightthicknes=0) frame0.grid(row=0,column=0,padx=0,pady=30) #inside frame0 @@ -2327,7 +2868,7 @@ class MainWindow(TkinterDnD.Tk): l0=Label(frame0,text="Thank you for the support!",font=("Century Gothic", "12"), justify="center", fg="#F6F6F7") l0.grid(row=18,column=0,padx=0,pady=0) - frame0=Frame(tab8,highlightbackground='red',highlightthicknes=0) + frame0=Frame(tab9,highlightbackground='red',highlightthicknes=0) frame0.grid(row=0,column=0,padx=0,pady=30) l0=Label(frame0,text="Update Details",font=("Century Gothic", "16", "bold"), justify="center", fg="#f4f4f4") @@ -2368,72 +2909,7 @@ class MainWindow(TkinterDnD.Tk): callback("https://github.com/Anjok07/ultimatevocalremovergui/releases")) l0=ttk.Button(frame0,text='Open Application Directory', command=self.open_appdir_filedialog) - l0.grid(row=12,column=0,padx=0,pady=0) - - frame0=Frame(tab9,highlightbackground='red',highlightthicknes=0) - frame0.grid(row=0,column=0,padx=0,pady=0) - - l0=Label(frame0,text="Advanced Option Guide",font=("Century Gothic", "12", "bold", "underline"), fg="#f4f4f4") - l0.grid(row=0,column=0,padx=0,pady=0) - - l0=ttk.Button(frame0,text="Ensemble Customization Options", command=self.custom_ensemble) - l0.grid(row=1,column=0,padx=20,pady=10) - - l0=ttk.Button(frame0,text="Advanced MDX-Net Options", command=self.advanced_mdx_options) - l0.grid(row=2,column=0,padx=20,pady=10) - - l0=ttk.Button(frame0,text="Advanced VR Options", command=self.advanced_vr_options) - l0.grid(row=3,column=0,padx=20,pady=10) - - l0=ttk.Button(frame0,text='Open Utagoe', command=self.utagoe_start) - l0.grid(row=4,column=0,padx=20,pady=10) - - l0=Label(frame0,text="Set Dropdown Parameters Manually",font=("Century Gothic", "10", "bold", "underline"), fg="#f4f4f4") - l0.grid(row=5,column=0,padx=30,pady=20) - - l0=tk.Label(frame0, text='Chunks (Set Manually)', font=("Century Gothic", "9"), foreground='#13a4c9') - l0.grid(row=6,column=0,padx=0,pady=0) - - l0=ttk.Entry(frame0, textvariable=self.chunks_var, justify='center') - l0.grid(row=7,column=0,padx=20,pady=10) - - l0=tk.Label(frame0, text='Noise Reduction (Set Manually)', font=("Century Gothic", "9"), foreground='#13a4c9') - l0.grid(row=8,column=0,padx=0,pady=0) - - l0=ttk.Entry(frame0, textvariable=self.noisereduc_s_var, justify='center') - l0.grid(row=9,column=0,padx=20,pady=10) - - l0=tk.Label(frame0, text='Window Size (Set Manually)', font=("Century Gothic", "9"), foreground='#13a4c9') - l0.grid(row=10,column=0,padx=0,pady=0) - - l0=ttk.Entry(frame0, textvariable=self.winSize_var, justify="center") - l0.grid(row=11,column=0,padx=20,pady=10) - - l0=tk.Label(frame0, text='Aggression Setting (Set Manually)', font=("Century Gothic", "9"), foreground='#13a4c9') - l0.grid(row=12,column=0,padx=0,pady=0) - - l0=ttk.Entry(frame0, textvariable=self.agg_var, justify="center") - l0.grid(row=13,column=0,padx=20,pady=10) - - frame0=Frame(tab10,highlightbackground='red',highlightthicknes=0) - frame0.grid(row=0,column=0,padx=0,pady=30) - - l0=Label(frame0,text="Error Details",font=("Century Gothic", "16", "bold"), justify="center", fg="#f4f4f4") - l0.grid(row=1,column=0,padx=20,pady=10) - - l0=Label(frame0,text="This tab will show the raw details of the last error received.",font=("Century Gothic", "12"), justify="center", fg="#F6F6F7") - l0.grid(row=2,column=0,padx=0,pady=0) - - l0=Label(frame0,text="(Click the error console below to copy the error)\n",font=("Century Gothic", "10"), justify="center", fg="#F6F6F7") - l0.grid(row=3,column=0,padx=0,pady=0) - - with open("errorlog.txt", "r") as f: - l0=Button(frame0,text=f.read(),font=("Century Gothic", "8"), command=self.copy_clip, justify="left", wraplength=1000, fg="#FF0000", bg="black", relief="sunken") - l0.grid(row=4,column=0,padx=0,pady=0) - - l0=Label(frame0,text="",font=("Century Gothic", "10"), justify="center", fg="#F6F6F7") - l0.grid(row=5,column=0,padx=0,pady=0) - + l0.grid(row=12,column=0,padx=0,pady=0) else: l0=Label(frame0,text="Notes",font=("Century Gothic", "11", "bold"), justify="center", fg="#f4f4f4") l0.grid(row=1,column=0,padx=5,pady=5) @@ -2484,7 +2960,7 @@ class MainWindow(TkinterDnD.Tk): l0=Label(frame0,text="If you wish to support and donate to this project, click the link above and become a Patreon!",font=("Century Gothic", "10"), justify="center", fg="#F6F6F7") l0.grid(row=13,column=0,padx=5,pady=5) - frame0=Frame(tab7,highlightbackground='red',highlightthicknes=0) + frame0=Frame(tab8,highlightbackground='red',highlightthicknes=0) frame0.grid(row=0,column=0,padx=0,pady=30) #inside frame0 @@ -2543,7 +3019,7 @@ class MainWindow(TkinterDnD.Tk): l0=Label(frame0,text="Thank you for the support!",font=("Century Gothic", "10"), justify="center", fg="#F6F6F7") l0.grid(row=16,column=0,padx=0,pady=0) - frame0=Frame(tab8,highlightbackground='red',highlightthicknes=0) + frame0=Frame(tab9,highlightbackground='red',highlightthicknes=0) frame0.grid(row=0,column=0,padx=0,pady=30) l0=Label(frame0,text="Update Details",font=("Century Gothic", "12", "bold"), justify="center", fg="#f4f4f4") @@ -2586,204 +3062,176 @@ class MainWindow(TkinterDnD.Tk): l0=Button(frame0,text='Open Application Directory',font=("Century Gothic", "8"), command=self.open_appdir_filedialog, justify="left", wraplength=1000, bg="black", relief="ridge") l0.grid(row=12,column=0,padx=0,pady=0) - frame0=Frame(tab10,highlightbackground='red',highlightthicknes=0) - frame0.grid(row=0,column=0,padx=0,pady=30) - l0=Label(frame0,text="Error Details",font=("Century Gothic", "12", "bold"), justify="center", fg="#f4f4f4") - l0.grid(row=1,column=0,padx=20,pady=5) - - l0=Label(frame0,text="This tab will show the raw details of the last error received.",font=("Century Gothic", "10"), justify="center", fg="#F6F6F7") - l0.grid(row=2,column=0,padx=0,pady=0) - - l0=Label(frame0,text="(Click the error console below to copy the error)\n",font=("Century Gothic", "10"), justify="center", fg="#F6F6F7") - l0.grid(row=3,column=0,padx=0,pady=0) - - with open("errorlog.txt", "r") as f: - l0=Button(frame0,text=f.read(),font=("Century Gothic", "8"), command=self.copy_clip, justify="left", wraplength=1000, fg="#FF0000", bg="black", relief="sunken") - l0.grid(row=4,column=0,padx=0,pady=0) - - l0=Label(frame0,text="",font=("Century Gothic", "10"), justify="center", fg="#F6F6F7") - l0.grid(row=5,column=0,padx=0,pady=0) - - frame0=Frame(tab9,highlightbackground='red',highlightthicknes=0) - frame0.grid(row=0,column=0,padx=0,pady=0) - - l0=Label(frame0,text="MDX-Net/VR Ensemble Options",font=("Century Gothic", "10", "bold", "underline"), justify="center", fg="#f4f4f4") - l0.grid(row=1,column=0,padx=20,pady=10) - - l0=tk.Label(frame0,text='MDX-Net Model\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') - l0.grid(row=2,column=0,padx=0,pady=0) - - l0=ttk.OptionMenu(frame0, self.mdxensemchoose_var, None, 'UVR-MDX-NET 1', 'UVR-MDX-NET 2', 'UVR-MDX-NET 3', - 'UVR-MDX-NET Karaoke') - l0.grid(row=3,column=0,padx=0,pady=0) - - l0=tk.Label(frame0,text='\nVR Model 1\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') - l0.grid(row=4,column=0,padx=0,pady=0) - - l0=ttk.OptionMenu(frame0, self.vrensemchoose_var, None, 'No Model', '1_HP-UVR', '2_HP-UVR', '3_HP-Vocal-UVR', - '4_HP-Vocal-UVR', '5_HP-Karaoke-UVR', '6_HP-Karaoke-UVR', '7_HP2-UVR', '8_HP2-UVR', - '9_HP2-UVR', '10_SP-UVR-2B-32000-1', '11_SP-UVR-2B-32000-2', '12_SP-UVR-3B-44100', '13_SP-UVR-4B-44100-1', - '14_SP-UVR-4B-44100-2', '15_SP-UVR-MID-44100-1', '16_SP-UVR-MID-44100-2', - 'MGM_MAIN_v4', 'MGM_HIGHEND_v4', 'MGM_LOWEND_A_v4', 'MGM_LOWEND_B_v4') - l0.grid(row=5,column=0,padx=0,pady=0) - - l0=tk.Label(frame0,text='\nVR Model 2\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') - l0.grid(row=6,column=0,padx=0,pady=0) - - l0=ttk.OptionMenu(frame0, self.vrensemchoose_mdx_a_var, None, 'No Model', '1_HP-UVR', '2_HP-UVR', '3_HP-Vocal-UVR', - '4_HP-Vocal-UVR', '5_HP-Karaoke-UVR', '6_HP-Karaoke-UVR', '7_HP2-UVR', '8_HP2-UVR', - '9_HP2-UVR', '10_SP-UVR-2B-32000-1', '11_SP-UVR-2B-32000-2', '12_SP-UVR-3B-44100', '13_SP-UVR-4B-44100-1', - '14_SP-UVR-4B-44100-2', '15_SP-UVR-MID-44100-1', '16_SP-UVR-MID-44100-2', - 'MGM_MAIN_v4', 'MGM_HIGHEND_v4', 'MGM_LOWEND_A_v4', 'MGM_LOWEND_B_v4') - l0.grid(row=7,column=0,padx=0,pady=0) - - l0=tk.Label(frame0,text='\nVR Model 3\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') - l0.grid(row=8,column=0,padx=0,pady=0) - - l0=ttk.OptionMenu(frame0, self.vrensemchoose_mdx_b_var, None, 'No Model', '1_HP-UVR', '2_HP-UVR', '3_HP-Vocal-UVR', - '4_HP-Vocal-UVR', '5_HP-Karaoke-UVR', '6_HP-Karaoke-UVR', '7_HP2-UVR', '8_HP2-UVR', - '9_HP2-UVR', '10_SP-UVR-2B-32000-1', '11_SP-UVR-2B-32000-2', '12_SP-UVR-3B-44100', '13_SP-UVR-4B-44100-1', - '14_SP-UVR-4B-44100-2', '15_SP-UVR-MID-44100-1', '16_SP-UVR-MID-44100-2', - 'MGM_MAIN_v4', 'MGM_HIGHEND_v4', 'MGM_LOWEND_A_v4', 'MGM_LOWEND_B_v4') - l0.grid(row=9,column=0,padx=0,pady=0) - - l0=tk.Label(frame0,text='\nVR Model 4\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') - l0.grid(row=10,column=0,padx=0,pady=0) - - l0=ttk.OptionMenu(frame0, self.vrensemchoose_mdx_c_var, None, 'No Model', '1_HP-UVR', '2_HP-UVR', '3_HP-Vocal-UVR', - '4_HP-Vocal-UVR', '5_HP-Karaoke-UVR', '6_HP-Karaoke-UVR', '7_HP2-UVR', '8_HP2-UVR', - '9_HP2-UVR', '10_SP-UVR-2B-32000-1', '11_SP-UVR-2B-32000-2', '12_SP-UVR-3B-44100', '13_SP-UVR-4B-44100-1', - '14_SP-UVR-4B-44100-2', '15_SP-UVR-MID-44100-1', '16_SP-UVR-MID-44100-2', - 'MGM_MAIN_v4', 'MGM_HIGHEND_v4', 'MGM_LOWEND_A_v4', 'MGM_LOWEND_B_v4') - l0.grid(row=11,column=0,padx=0,pady=0) - - l0=tk.Label(frame0,text='\nMDX-Net Model 2\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') - l0.grid(row=12,column=0,padx=0,pady=0) - - l0=ttk.OptionMenu(frame0, self.mdxensemchoose_b_var, None, 'No Model', 'UVR-MDX-NET 1', 'UVR-MDX-NET 2', 'UVR-MDX-NET 3', - 'UVR-MDX-NET Karaoke') - l0.grid(row=13,column=0,padx=0,pady=0) - - l0=Label(frame0,text="Basic Ensemble Options",font=("Century Gothic", "10", "bold", "underline"), justify="center", fg="#f4f4f4") - l0.grid(row=1,column=1,padx=20,pady=10) - - l0=tk.Label(frame0,text='VR Model 1\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') - l0.grid(row=2,column=1,padx=0,pady=0) - - l0=ttk.OptionMenu(frame0, self.vrensemchoose_a_var, None, '1_HP-UVR', '2_HP-UVR', '3_HP-Vocal-UVR', - '4_HP-Vocal-UVR', '5_HP-Karaoke-UVR', '6_HP-Karaoke-UVR', '7_HP2-UVR', '8_HP2-UVR', - '9_HP2-UVR', '10_SP-UVR-2B-32000-1', '11_SP-UVR-2B-32000-2', '12_SP-UVR-3B-44100', '13_SP-UVR-4B-44100-1', - '14_SP-UVR-4B-44100-2', '15_SP-UVR-MID-44100-1', '16_SP-UVR-MID-44100-2', - 'MGM_MAIN_v4', 'MGM_HIGHEND_v4', 'MGM_LOWEND_A_v4', 'MGM_LOWEND_B_v4') - l0.grid(row=3,column=1,padx=0,pady=0) + def settings(self): + """ + Open Settings + """ + top= Toplevel(self) - l0=tk.Label(frame0,text='\nVR Model 2\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') - l0.grid(row=4,column=1,padx=0,pady=0) + top.geometry("600x500") + window_height = 600 + window_width = 500 + + top.title("Settings Guide") + + top.resizable(False, False) # This code helps to disable windows from resizing + + screen_width = top.winfo_screenwidth() + screen_height = top.winfo_screenheight() + + x_cordinate = int((screen_width/2) - (window_width/2)) + y_cordinate = int((screen_height/2) - (window_height/2)) + + top.geometry("{}x{}+{}+{}".format(window_width, window_height, x_cordinate, y_cordinate)) + + # change title bar icon + top.iconbitmap('img\\UVR-Icon-v2.ico') + + def close_win_custom_ensemble(): + top.destroy() + self.custom_ensemble() - l0=ttk.OptionMenu(frame0, self.vrensemchoose_b_var, None, '1_HP-UVR', '2_HP-UVR', '3_HP-Vocal-UVR', - '4_HP-Vocal-UVR', '5_HP-Karaoke-UVR', '6_HP-Karaoke-UVR', '7_HP2-UVR', '8_HP2-UVR', - '9_HP2-UVR', '10_SP-UVR-2B-32000-1', '11_SP-UVR-2B-32000-2', '12_SP-UVR-3B-44100', '13_SP-UVR-4B-44100-1', - '14_SP-UVR-4B-44100-2', '15_SP-UVR-MID-44100-1', '16_SP-UVR-MID-44100-2', - 'MGM_MAIN_v4', 'MGM_HIGHEND_v4', 'MGM_LOWEND_A_v4', 'MGM_LOWEND_B_v4') - l0.grid(row=5,column=1,padx=0,pady=0) + def close_win_advanced_mdx_options(): + top.destroy() + self.advanced_mdx_options() - l0=tk.Label(frame0,text='\nVR Model 3\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') - l0.grid(row=6,column=1,padx=0,pady=0) + def close_win_advanced_demucs_options(): + top.destroy() + self.advanced_demucs_options() - l0=ttk.OptionMenu(frame0, self.vrensemchoose_c_var, None, 'No Model', '1_HP-UVR', '2_HP-UVR', '3_HP-Vocal-UVR', - '4_HP-Vocal-UVR', '5_HP-Karaoke-UVR', '6_HP-Karaoke-UVR', '7_HP2-UVR', '8_HP2-UVR', - '9_HP2-UVR', '10_SP-UVR-2B-32000-1', '11_SP-UVR-2B-32000-2', '12_SP-UVR-3B-44100', '13_SP-UVR-4B-44100-1', - '14_SP-UVR-4B-44100-2', '15_SP-UVR-MID-44100-1', '16_SP-UVR-MID-44100-2', - 'MGM_MAIN_v4', 'MGM_HIGHEND_v4', 'MGM_LOWEND_A_v4', 'MGM_LOWEND_B_v4') - l0.grid(row=7,column=1,padx=0,pady=0) + def close_win_advanced_vr_options(): + top.destroy() + self.advanced_vr_options() - l0=tk.Label(frame0,text='\nVR Model 4\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') - l0.grid(row=8,column=1,padx=0,pady=0) + def close_win_error_log(): + top.destroy() + self.error_log() - l0=ttk.OptionMenu(frame0, self.vrensemchoose_d_var, None, 'No Model', '1_HP-UVR', '2_HP-UVR', '3_HP-Vocal-UVR', - '4_HP-Vocal-UVR', '5_HP-Karaoke-UVR', '6_HP-Karaoke-UVR', '7_HP2-UVR', '8_HP2-UVR', - '9_HP2-UVR', '10_SP-UVR-2B-32000-1', '11_SP-UVR-2B-32000-2', '12_SP-UVR-3B-44100', '13_SP-UVR-4B-44100-1', - '14_SP-UVR-4B-44100-2', '15_SP-UVR-MID-44100-1', '16_SP-UVR-MID-44100-2', - 'MGM_MAIN_v4', 'MGM_HIGHEND_v4', 'MGM_LOWEND_A_v4', 'MGM_LOWEND_B_v4') - l0.grid(row=9,column=1,padx=0,pady=0) + def close_win_help(): + top.destroy() + self.help() - l0=tk.Label(frame0,text='\nVR Model 5\n',font=("Century Gothic", "9", "bold"), justify="center", foreground='#13a4c9') - l0.grid(row=10,column=1,padx=0,pady=0) + def close_win(): + top.destroy() + + tabControl = ttk.Notebook(top) + + tab1 = ttk.Frame(tabControl) + + tabControl.add(tab1, text ='Settings Guide') + + tabControl.pack(expand = 1, fill ="both") + + tab1.grid_rowconfigure(0, weight=1) + tab1.grid_columnconfigure(0, weight=1) + + frame0=Frame(tab1,highlightbackground='red',highlightthicknes=0) + frame0.grid(row=0,column=0,padx=0,pady=0) + + l0=Label(frame0,text="Main Menu",font=("Century Gothic", "13", "bold", "underline"), justify="center", fg="#13a4c9") + l0.grid(row=0,column=0,padx=0,pady=10) + + l0=ttk.Button(frame0,text="Ensemble Customization Options", command=close_win_custom_ensemble) + l0.grid(row=1,column=0,padx=20,pady=5) + + l0=ttk.Button(frame0,text="Advanced MDX-Net Options", command=close_win_advanced_mdx_options) + l0.grid(row=2,column=0,padx=20,pady=5) + + l0=ttk.Button(frame0,text="Advanced Demucs Options", command=close_win_advanced_demucs_options) + l0.grid(row=3,column=0,padx=20,pady=5) + + l0=ttk.Button(frame0,text="Advanced VR Options", command=close_win_advanced_vr_options) + l0.grid(row=4,column=0,padx=20,pady=5) + + l0=ttk.Button(frame0,text="Open Help Guide", command=close_win_help) + l0.grid(row=5,column=0,padx=20,pady=5) + + l0=ttk.Button(frame0,text='Open Error Log', command=close_win_error_log) + l0.grid(row=6,column=0,padx=20,pady=5) + + l0=Label(frame0,text="Additional Options",font=("Century Gothic", "13", "bold", "underline"), justify="center", fg="#13a4c9") + l0.grid(row=7,column=0,padx=0,pady=10) + + l0=ttk.Button(frame0,text='Open Application Directory', command=self.open_appdir_filedialog) + l0.grid(row=8,column=0,padx=20,pady=5) + + l0=ttk.Button(frame0,text='Close Window', command=close_win) + l0.grid(row=9,column=0,padx=20,pady=5) + + + def error_log(self): + """ + Open Error Log + """ + top= Toplevel(self) + if GetSystemMetrics(1) >= 900: + top.geometry("1080x810") + window_height = 810 + window_width = 1080 + elif GetSystemMetrics(1) <= 720: + top.geometry("930x640") + window_height = 640 + window_width = 930 + else: + top.geometry("930x670") + window_height = 670 + window_width = 930 - l0=ttk.OptionMenu(frame0, self.vrensemchoose_e_var, None, 'No Model', '1_HP-UVR', '2_HP-UVR', '3_HP-Vocal-UVR', - '4_HP-Vocal-UVR', '5_HP-Karaoke-UVR', '6_HP-Karaoke-UVR', '7_HP2-UVR', '8_HP2-UVR', - '9_HP2-UVR', '10_SP-UVR-2B-32000-1', '11_SP-UVR-2B-32000-2', '12_SP-UVR-3B-44100', '13_SP-UVR-4B-44100-1', - '14_SP-UVR-4B-44100-2', '15_SP-UVR-MID-44100-1', '16_SP-UVR-MID-44100-2', - 'MGM_MAIN_v4', 'MGM_HIGHEND_v4', 'MGM_LOWEND_A_v4', 'MGM_LOWEND_B_v4') - l0.grid(row=11,column=1,padx=0,pady=0) - - l0=Label(frame0,text="Additional Options",font=("Century Gothic", "10", "bold", "underline"), justify="center", fg="#f4f4f4") - l0.grid(row=1,column=2,padx=0,pady=0) - - l0=ttk.Checkbutton(frame0, text='Append Ensemble Name to Final Output', variable=self.appendensem_var) - l0.grid(row=2,column=2,padx=0,pady=0) - - l0=ttk.Checkbutton(frame0, text='Save Output Image Spectrogram (VR Architecture Only)', variable=self.outputImage_var) - l0.grid(row=3,column=2,padx=0,pady=0) - - l0=Label(frame0,text="Set Outside Parameters",font=("Century Gothic", "10", "bold", "underline"), fg="#f4f4f4") - l0.grid(row=4,column=2,padx=0,pady=0) - - l0=tk.Label(frame0, text='Window Size (VR Architecture)', font=("Century Gothic", "9", "bold"), foreground='#13a4c9') - l0.grid(row=5,column=2,padx=0,pady=0) - - l0=ttk.Entry(frame0, textvariable=self.winSize_var) - l0.grid(row=6,column=2,padx=0,pady=0) - - l0=tk.Label(frame0, text='Aggression Setting (VR Architecture)', font=("Century Gothic", "9", "bold"), foreground='#13a4c9') - l0.grid(row=7,column=2,padx=0,pady=0) - - l0=ttk.Entry(frame0, textvariable=self.agg_var) - l0.grid(row=8,column=2,padx=0,pady=0) - - l0=tk.Label(frame0, text='Chunks (MDX-Net)', font=("Century Gothic", "9", "bold"), foreground='#13a4c9') - l0.grid(row=9,column=2,padx=0,pady=0) - - l0=ttk.Entry(frame0, textvariable=self.chunks_var) - l0.grid(row=10,column=2,padx=0,pady=0) - - - - l0=tk.Label(frame0, text='N_FFT Scale (MDX-Net)', font=("Century Gothic", "9", "bold"), foreground='#13a4c9') - l0.grid(row=11,column=2,padx=0,pady=0) - - l0=ttk.Entry(frame0, textvariable=self.n_fft_scale_var) - l0.grid(row=12,column=2,padx=0,pady=0) - - l0=tk.Label(frame0, text='Dim_f (MDX-Net)', font=("Century Gothic", "9", "bold"), foreground='#13a4c9') - l0.grid(row=13,column=2,padx=0,pady=0) - - l0=ttk.Entry(frame0, textvariable=self.dim_f_var) - l0.grid(row=14,column=2,padx=0,pady=0) - - l0=ttk.Button(frame0,text='Open Utagoe', command=self.utagoe_start) - - - frame0=Frame(tab10,highlightbackground='red',highlightthicknes=0) - frame0.grid(row=0,column=0,padx=0,pady=30) - - l0=Label(frame0,text="Error Details",font=("Century Gothic", "16", "bold"), justify="center", fg="#f4f4f4") - l0.grid(row=1,column=0,padx=20,pady=10) - - l0=Label(frame0,text="This tab will show the raw details of the last error received.",font=("Century Gothic", "12"), justify="center", fg="#F6F6F7") - l0.grid(row=2,column=0,padx=0,pady=0) - - l0=Label(frame0,text="(Click the error console below to copy the error)\n",font=("Century Gothic", "10"), justify="center", fg="#F6F6F7") - l0.grid(row=3,column=0,padx=0,pady=0) - - with open("errorlog.txt", "r") as f: - l0=Button(frame0,text=f.read(),font=("Century Gothic", "8"), command=self.copy_clip, justify="left", wraplength=1000, fg="#FF0000", bg="black", relief="sunken") - l0.grid(row=4,column=0,padx=0,pady=0) - - l0=Label(frame0,text="",font=("Century Gothic", "10"), justify="center", fg="#F6F6F7") - l0.grid(row=5,column=0,padx=0,pady=0) + top.title("UVR Help Guide") + + top.resizable(False, False) # This code helps to disable windows from resizing + + screen_width = top.winfo_screenwidth() + screen_height = top.winfo_screenheight() + + x_cordinate = int((screen_width/2) - (window_width/2)) + y_cordinate = int((screen_height/2) - (window_height/2)) + + top.geometry("{}x{}+{}+{}".format(window_width, window_height, x_cordinate, y_cordinate)) + + # change title bar icon + top.iconbitmap('img\\UVR-Icon-v2.ico') + + def close_win(): + top.destroy() + self.settings() + def close_win_self(): + top.destroy() + + tabControl = ttk.Notebook(top) + + tab1 = ttk.Frame(tabControl) + + tabControl.add(tab1, text ='Error Log') + + tabControl.pack(expand = 1, fill ="both") + + tab1.grid_rowconfigure(0, weight=1) + tab1.grid_columnconfigure(0, weight=1) + + frame0=Frame(tab1,highlightbackground='red',highlightthicknes=0) + frame0.grid(row=0,column=0,padx=0,pady=0) + + l0=Label(frame0,text="Error Details",font=("Century Gothic", "16", "bold"), justify="center", fg="#f4f4f4") + l0.grid(row=1,column=0,padx=20,pady=10) + + l0=Label(frame0,text="This tab will show the raw details of the last error received.",font=("Century Gothic", "12"), justify="center", fg="#F6F6F7") + l0.grid(row=2,column=0,padx=0,pady=0) + + l0=Label(frame0,text="(Click the error console below to copy the error)\n",font=("Century Gothic", "10"), justify="center", fg="#F6F6F7") + l0.grid(row=3,column=0,padx=0,pady=0) + + with open("errorlog.txt", "r") as f: + l0=Button(frame0,text=f.read(),font=("Century Gothic", "7"), command=self.copy_clip, justify="left", wraplength=1000, fg="#FF0000", bg="black", relief="sunken") + l0.grid(row=4,column=0,padx=0,pady=0) + + l0=ttk.Button(frame0,text="Back to Main Menu", command=close_win) + l0.grid(row=5,column=0,padx=20,pady=10) + + l0=ttk.Button(frame0,text='Close Window', command=close_win_self) + l0.grid(row=6,column=0,padx=20,pady=0) def copy_clip(self): copy_t = open("errorlog.txt", "r").read() @@ -2811,7 +3259,7 @@ class MainWindow(TkinterDnD.Tk): def open_Modelfolder_de(self): """Let user paste a ".pth" model to use for the vocal seperation""" - filename = 'models\Demucs_Model' + filename = 'models\Demucs_Models' if sys.platform == "win32": os.startfile(filename) @@ -2869,6 +3317,7 @@ class MainWindow(TkinterDnD.Tk): 'gpu': self.gpuConversion_var.get(), 'appendensem': self.appendensem_var.get(), 'demucs_only': self.demucs_only_var.get(), + 'split_mode': self.split_mode_var.get(), 'postprocess': self.postprocessing_var.get(), 'tta': self.tta_var.get(), 'save': self.save_var.get(), @@ -2881,9 +3330,11 @@ class MainWindow(TkinterDnD.Tk): 'modelInstrumentalLabel': self.instrumentalModel_var.get(), 'aiModel': self.aiModel_var.get(), 'algo': self.algo_var.get(), + 'demucs_stems': self.demucs_stems_var.get(), 'ensChoose': self.ensChoose_var.get(), 'mdxnetModel': self.mdxnetModel_var.get(), 'DemucsModel': self.DemucsModel_var.get(), + 'DemucsModel_MDX': self.DemucsModel_MDX_var.get(), 'ModelParams': self.ModelParams_var.get(), #MDX-Net 'demucsmodel': self.demucsmodel_var.get(), @@ -2891,12 +3342,17 @@ class MainWindow(TkinterDnD.Tk): 'noise_reduc': self.noisereduc_var.get(), 'voc_only': self.voc_only_var.get(), 'inst_only': self.inst_only_var.get(), + 'voc_only_b': self.voc_only_b_var.get(), + 'inst_only_b': self.inst_only_b_var.get(), + 'audfile': self.audfile_var.get(), 'chunks': chunks, 'n_fft_scale': self.n_fft_scale_var.get(), 'dim_f': self.dim_f_var.get(), 'noise_pro_select': self.noise_pro_select_var.get(), 'overlap': self.overlap_var.get(), 'shifts': self.shifts_var.get(), + 'overlap_b': self.overlap_b_var.get(), + 'shifts_b': self.shifts_b_var.get(), 'margin': self.margin_var.get(), 'channel': self.channel_var.get(), 'compensate': self.compensate_var.get(), diff --git a/inference_MDX.py b/inference_MDX.py index ecf188b..dde6a60 100644 --- a/inference_MDX.py +++ b/inference_MDX.py @@ -1,7 +1,4 @@ import os -from pickle import STOP -from tracemalloc import stop -from turtle import update import subprocess from unittest import skip from pathlib import Path @@ -11,14 +8,18 @@ import pydub import shutil import hashlib -import gc #MDX-Net #---------------------------------------- import soundfile as sf import torch import numpy as np -from demucs.model import Demucs -from demucs.utils import apply_model + +from demucs.pretrained import get_model as _gm +from demucs.hdemucs import HDemucs +from demucs.apply import BagOfModels, apply_model +from demucs.audio import AudioFile +import pathlib + from models import get_models, spec_effects import onnxruntime as ort import time @@ -37,38 +38,43 @@ import torch import tkinter as tk import traceback # Error Message Recent Calls import time # Timer + +from typing import Literal class Predictor(): def __init__(self): pass - def prediction_setup(self, demucs_name, - channels=64): + def prediction_setup(self): global device print('Print the gpu setting: ', data['gpu']) if data['gpu'] >= 0: - device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') + device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') if data['gpu'] == -1: device = torch.device('cpu') if data['demucsmodel']: - self.demucs = Demucs(sources=["drums", "bass", "other", "vocals"], channels=channels) - widget_text.write(base_text + 'Loading Demucs model... ') + if 'UVR' in demucs_model_set: + self.demucs = HDemucs(sources=["other", "vocals"]) + else: + self.demucs = HDemucs(sources=["drums", "bass", "other", "vocals"]) + widget_text.write(base_text + 'Loading Demucs model...') update_progress(**progress_kwargs, step=0.05) + path_d = Path('models/Demucs_Models') + self.demucs = _gm(name=demucs_model_set, repo=path_d) self.demucs.to(device) - self.demucs.load_state_dict(torch.load(demucs_name)) - widget_text.write('Done!\n') self.demucs.eval() + widget_text.write('Done!\n') + if isinstance(self.demucs, BagOfModels): + widget_text.write(base_text + f"Selected Demucs model is a bag of {len(self.demucs.models)} model(s).\n") self.onnx_models = {} c = 0 - print('stemtype: ', modeltype) - self.models = get_models('tdf_extra', load=False, device=cpu, stems=modeltype, n_fft_scale=n_fft_scale_set, dim_f=dim_f_set) if not data['demucs_only']: widget_text.write(base_text + 'Loading ONNX model... ') @@ -87,19 +93,17 @@ class Predictor(): elif data['gpu'] == -1: run_type = ['CPUExecutionProvider'] - print(run_type) - print(str(device)) - + print('Selected Model: ', model_set) self.onnx_models[c] = ort.InferenceSession(os.path.join('models/MDX_Net_Models', str(model_set) + '.onnx'), providers=run_type) if not data['demucs_only']: widget_text.write('Done!\n') def prediction(self, m): - #mix, rate = sf.read(m) - mix, rate = librosa.load(m, mono=False, sr=44100) + mix, samplerate = librosa.load(m, mono=False, sr=44100) if mix.ndim == 1: - mix = np.asfortranarray([mix,mix]) + mix = np.asfortranarray([mix,mix]) + samplerate = samplerate mix = mix.T sources = self.demix(mix.T) widget_text.write(base_text + 'Inferences complete!\n') @@ -226,13 +230,12 @@ class Predictor(): c += 1 if not data['demucsmodel']: - if data['inst_only']: widget_text.write(base_text + 'Preparing to save Instrumental...') else: widget_text.write(base_text + 'Saving vocals... ') - sf.write(non_reduced_vocal_path, sources[c].T, rate) + sf.write(non_reduced_vocal_path, sources[c].T, samplerate) update_progress(**progress_kwargs, step=(0.9)) widget_text.write('Done!\n') @@ -240,7 +243,7 @@ class Predictor(): reduction_sen = float(int(data['noisereduc_s'])/10) subprocess.call("lib_v5\\sox\\sox.exe" + ' "' + f"{str(non_reduced_vocal_path)}" + '" "' + f"{str(vocal_path)}" + '" ' + - "noisered lib_v5\\sox\\mdxnetnoisereduc.prof " + f"{reduction_sen}", + "noisered lib_v5\\sox\\" + noise_pro_set + ".prof " + f"{reduction_sen}", shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) widget_text.write('Done!\n') @@ -252,7 +255,11 @@ class Predictor(): else: widget_text.write(base_text + 'Saving Vocals... ') - sf.write(non_reduced_vocal_path, sources[3].T, rate) + if data['demucs_only']: + if 'UVR' in demucs_model_set: + sf.write(non_reduced_vocal_path, sources[1].T, samplerate) + else: + sf.write(non_reduced_vocal_path, sources[source_val].T, samplerate) update_progress(**progress_kwargs, step=(0.9)) widget_text.write('Done!\n') @@ -275,7 +282,7 @@ class Predictor(): widget_text.write(base_text + 'Preparing Instrumental...') else: widget_text.write(base_text + 'Saving Vocals... ') - sf.write(vocal_path, sources[c].T, rate) + sf.write(vocal_path, sources[c].T, samplerate) update_progress(**progress_kwargs, step=(0.9)) widget_text.write('Done!\n') @@ -284,7 +291,15 @@ class Predictor(): widget_text.write(base_text + 'Preparing Instrumental...') else: widget_text.write(base_text + 'Saving Vocals... ') - sf.write(vocal_path, sources[3].T, rate) + + if data['demucs_only']: + if 'UVR' in demucs_model_set: + sf.write(vocal_path, sources[1].T, samplerate) + else: + sf.write(vocal_path, sources[source_val].T, samplerate) + else: + sf.write(vocal_path, sources[source_val].T, samplerate) + update_progress(**progress_kwargs, step=(0.9)) widget_text.write('Done!\n') @@ -470,13 +485,6 @@ class Predictor(): errmessage + f'\nError Time Stamp: [{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]\n') except: pass - - - try: - print('Is there already a voc file there? ', file_exists_v) - print('Is there already a non_voc file there? ', file_exists_n) - except: - pass if data['noisereduc_s'] == 'None': pass @@ -567,23 +575,37 @@ class Predictor(): segmented_mix[skip] = mix[:,start:end].copy() if end == samples: break + if not data['demucsmodel']: sources = self.demix_base(segmented_mix, margin_size=margin) elif data['demucs_only']: - sources = self.demix_demucs(segmented_mix, margin_size=margin) + if split_mode == True: + sources = self.demix_demucs_split(mix) + if split_mode == False: + sources = self.demix_demucs(segmented_mix, margin_size=margin) else: # both, apply spec effects base_out = self.demix_base(segmented_mix, margin_size=margin) - demucs_out = self.demix_demucs(segmented_mix, margin_size=margin) + print(split_mode) + if split_mode == True: + demucs_out = self.demix_demucs_split(mix) + if split_mode == False: + demucs_out = self.demix_demucs(segmented_mix, margin_size=margin) nan_count = np.count_nonzero(np.isnan(demucs_out)) + np.count_nonzero(np.isnan(base_out)) if nan_count > 0: print('Warning: there are {} nan values in the array(s).'.format(nan_count)) demucs_out, base_out = np.nan_to_num(demucs_out), np.nan_to_num(base_out) sources = {} print(data['mixing']) - sources[3] = (spec_effects(wave=[demucs_out[source_val],base_out[0]], - algorithm=data['mixing'], - value=b[3])*float(data['compensate'])) # compensation + + if 'UVR' in demucs_model_set: + sources[source_val] = (spec_effects(wave=[demucs_out[1],base_out[0]], + algorithm=data['mixing'], + value=b[source_val])*float(data['compensate'])) # compensation + else: + sources[source_val] = (spec_effects(wave=[demucs_out[source_val],base_out[0]], + algorithm=data['mixing'], + value=b[source_val])*float(data['compensate'])) # compensation return sources def demix_base(self, mixes, margin_size): @@ -594,6 +616,7 @@ class Predictor(): widget_text.write(base_text + "Running ONNX Inference...\n") widget_text.write(base_text + "Processing "f"{onnxitera} slices... ") print(' Running ONNX Inference...') + for mix in mixes: gui_progress_bar_onnx += 1 if data['demucsmodel']: @@ -602,6 +625,7 @@ class Predictor(): else: update_progress(**progress_kwargs, step=(0.1 + (0.9/onnxitera * gui_progress_bar_onnx))) + cmix = mixes[mix] sources = [] n_sample = cmix.shape[1] @@ -634,7 +658,6 @@ class Predictor(): end = None sources.append(tar_signal[:,start:end]) - chunked_sources.append(sources) _sources = np.concatenate(chunked_sources, axis=-1) del self.onnx_models @@ -647,6 +670,7 @@ class Predictor(): demucsitera = len(mix) demucsitera_calc = demucsitera * 2 gui_progress_bar_demucs = 0 + widget_text.write(base_text + "Split Mode is off. (Chunks enabled for Demucs Model)\n") widget_text.write(base_text + "Running Demucs Inference...\n") widget_text.write(base_text + "Processing "f"{len(mix)} slices... ") print(' Running Demucs Inference...') @@ -659,7 +683,8 @@ class Predictor(): ref = cmix.mean(0) cmix = (cmix - ref.mean()) / ref.std() with torch.no_grad(): - sources = apply_model(self.demucs, cmix.to(device), split=True, overlap=overlap_set, shifts=shift_set) + print(split_mode) + sources = apply_model(self.demucs, cmix[None], split=split_mode, device=device, overlap=overlap_set, shifts=shift_set, progress=False)[0] sources = (sources * ref.std() + ref.mean()).cpu().numpy() sources[[0,1]] = sources[[1,0]] @@ -673,6 +698,27 @@ class Predictor(): sources = np.concatenate(sources, axis=-1) widget_text.write('Done!\n') return sources + + def demix_demucs_split(self, mix): + + print('shift_set ', shift_set) + widget_text.write(base_text + "Split Mode is on. (Chunks disabled for Demucs Model)\n") + widget_text.write(base_text + "Running Demucs Inference...\n") + widget_text.write(base_text + "Processing "f"{len(mix)} slices... ") + print(' Running Demucs Inference...') + + mix = torch.tensor(mix, dtype=torch.float32) + ref = mix.mean(0) + mix = (mix - ref.mean()) / ref.std() + + with torch.no_grad(): + sources = apply_model(self.demucs, mix[None], split=split_mode, device=device, overlap=overlap_set, shifts=shift_set, progress=False)[0] + + widget_text.write('Done!\n') + + sources = (sources * ref.std() + ref.mean()).cpu().numpy() + sources[[0,1]] = sources[[1,0]] + return sources data = { # Paths @@ -694,11 +740,11 @@ data = { 'overlap': 0.5, 'shifts': 0, 'margin': 44100, - 'channel': 64, + 'split_mode': False, 'compensate': 1.03597672895, 'demucs_only': False, 'mixing': 'Default', - 'DemucsModel': 'demucs_extra-3646af93_org.th', + 'DemucsModel_MDX': 'UVR_Demucs_Model_1', # Choose Model 'mdxnetModel': 'UVR-MDX-NET 1', 'mdxnetModeltype': 'Vocals (Custom)', @@ -751,6 +797,7 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress global model_set_name global stemset_n global noise_pro_set + global demucs_model_set global mdx_model_hash @@ -759,6 +806,9 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress global overlap_set global shift_set global source_val + global split_mode + + global demucs_switch # Update default settings default_chunks = data['chunks'] @@ -823,161 +873,90 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress source_val_set = 0 stem_name = '(Bass)' - - try: - if data['mdxnetModel'] == 'UVR-MDX-NET 1': + if data['mdxnetModel'] == 'UVR-MDX-NET 1': + if os.path.isfile('models/MDX_Net_Models/UVR_MDXNET_1_9703.onnx'): model_set = 'UVR_MDXNET_1_9703' model_set_name = 'UVR_MDXNET_1_9703' - modeltype = 'v' - noise_pro = 'MDX-NET_Noise_Profile_14_kHz' - stemset_n = '(Vocals)' - source_val = 3 - n_fft_scale_set=6144 - dim_f_set=2048 - elif data['mdxnetModel'] == 'UVR-MDX-NET 2': - model_set = 'UVR_MDXNET_2_9682' - model_set_name = 'UVR_MDXNET_2_9682' - modeltype = 'v' - noise_pro = 'MDX-NET_Noise_Profile_14_kHz' - stemset_n = '(Vocals)' - source_val = 3 - n_fft_scale_set=6144 - dim_f_set=2048 - elif data['mdxnetModel'] == 'UVR-MDX-NET 3': - model_set = 'UVR_MDXNET_3_9662' - model_set_name = 'UVR_MDXNET_3_9662' - modeltype = 'v' - noise_pro = 'MDX-NET_Noise_Profile_14_kHz' - stemset_n = '(Vocals)' - source_val = 3 - n_fft_scale_set=6144 - dim_f_set=2048 - elif data['mdxnetModel'] == 'UVR-MDX-NET Karaoke': - model_set = 'UVR_MDXNET_KARA' - model_set_name = 'UVR_MDXNET_Karaoke' - modeltype = 'v' - noise_pro = 'MDX-NET_Noise_Profile_14_kHz' - stemset_n = '(Vocals)' - source_val = 3 - n_fft_scale_set=6144 - dim_f_set=2048 - elif data['mdxnetModel'] == 'other': - model_set = 'other' - model_set_name = 'other' - modeltype = 'o' - noise_pro = 'MDX-NET_Noise_Profile_Full_Band' - stemset_n = '(Other)' - source_val = 2 - n_fft_scale_set=8192 - dim_f_set=2048 - elif data['mdxnetModel'] == 'drums': - model_set = 'drums' - model_set_name = 'drums' - modeltype = 'd' - noise_pro = 'MDX-NET_Noise_Profile_Full_Band' - stemset_n = '(Drums)' - source_val = 1 - n_fft_scale_set=4096 - dim_f_set=2048 - elif data['mdxnetModel'] == 'bass': - model_set = 'bass' - model_set_name = 'bass' - modeltype = 'b' - noise_pro = 'MDX-NET_Noise_Profile_Full_Band' - stemset_n = '(Bass)' - source_val = 0 - n_fft_scale_set=16384 - dim_f_set=2048 else: - model_set = data['mdxnetModel'] - model_set_name = data['mdxnetModel'] - modeltype = stemset - noise_pro = 'MDX-NET_Noise_Profile_Full_Band' - stemset_n = stem_name - source_val = source_val_set - n_fft_scale_set=int(data['n_fft_scale']) - dim_f_set=int(data['dim_f']) - - MDXModelName=('models/MDX_Net_Models/' + model_set + '.onnx') - mdx_model_hash = hashlib.md5(open(MDXModelName, 'rb').read()).hexdigest() - print(mdx_model_hash) - except: - if data['mdxnetModel'] == 'UVR-MDX-NET 1': model_set = 'UVR_MDXNET_9703' model_set_name = 'UVR_MDXNET_9703' - modeltype = 'v' - noise_pro = 'MDX-NET_Noise_Profile_14_kHz' - stemset_n = '(Vocals)' - source_val = 3 - n_fft_scale_set=6144 - dim_f_set=2048 - elif data['mdxnetModel'] == 'UVR-MDX-NET 2': + modeltype = 'v' + noise_pro = 'MDX-NET_Noise_Profile_14_kHz' + stemset_n = '(Vocals)' + source_val = 3 + n_fft_scale_set=6144 + dim_f_set=2048 + elif data['mdxnetModel'] == 'UVR-MDX-NET 2': + if os.path.isfile('models/MDX_Net_Models/UVR_MDXNET_2_9682.onnx'): + model_set = 'UVR_MDXNET_2_9682' + model_set_name = 'UVR_MDXNET_2_9682' + else: model_set = 'UVR_MDXNET_9682' model_set_name = 'UVR_MDXNET_9682' - modeltype = 'v' - noise_pro = 'MDX-NET_Noise_Profile_14_kHz' - stemset_n = '(Vocals)' - source_val = 3 - n_fft_scale_set=6144 - dim_f_set=2048 - elif data['mdxnetModel'] == 'UVR-MDX-NET 3': + modeltype = 'v' + noise_pro = 'MDX-NET_Noise_Profile_14_kHz' + stemset_n = '(Vocals)' + source_val = 3 + n_fft_scale_set=6144 + dim_f_set=2048 + elif data['mdxnetModel'] == 'UVR-MDX-NET 3': + if os.path.isfile('models/MDX_Net_Models/UVR_MDXNET_3_9662.onnx'): + model_set = 'UVR_MDXNET_3_9662' + model_set_name = 'UVR_MDXNET_3_9662' + else: model_set = 'UVR_MDXNET_9662' model_set_name = 'UVR_MDXNET_9662' - modeltype = 'v' - noise_pro = 'MDX-NET_Noise_Profile_14_kHz' - stemset_n = '(Vocals)' - source_val = 3 - n_fft_scale_set=6144 - dim_f_set=2048 - elif data['mdxnetModel'] == 'UVR-MDX-NET Karaoke': - model_set = 'UVR_MDXNET_KARA' - model_set_name = 'UVR_MDXNET_Karaoke' - modeltype = 'v' - noise_pro = 'MDX-NET_Noise_Profile_14_kHz' - stemset_n = '(Vocals)' - source_val = 3 - n_fft_scale_set=6144 - dim_f_set=2048 - elif data['mdxnetModel'] == 'other': - model_set = 'other' - model_set_name = 'other' - modeltype = 'o' - noise_pro = 'MDX-NET_Noise_Profile_Full_Band' - stemset_n = '(Other)' - source_val = 2 - n_fft_scale_set=8192 - dim_f_set=2048 - elif data['mdxnetModel'] == 'drums': - model_set = 'drums' - model_set_name = 'drums' - modeltype = 'd' - noise_pro = 'MDX-NET_Noise_Profile_Full_Band' - stemset_n = '(Drums)' - source_val = 1 - n_fft_scale_set=4096 - dim_f_set=2048 - elif data['mdxnetModel'] == 'bass': - model_set = 'bass' - model_set_name = 'bass' - modeltype = 'b' - noise_pro = 'MDX-NET_Noise_Profile_Full_Band' - stemset_n = '(Bass)' - source_val = 0 - n_fft_scale_set=16384 - dim_f_set=2048 - else: - model_set = data['mdxnetModel'] - model_set_name = data['mdxnetModel'] - modeltype = stemset - noise_pro = 'MDX-NET_Noise_Profile_Full_Band' - stemset_n = stem_name - source_val = source_val_set - n_fft_scale_set=int(data['n_fft_scale']) - dim_f_set=int(data['dim_f']) - - MDXModelName=('models/MDX_Net_Models/' + model_set_name + '.onnx') - mdx_model_hash = hashlib.md5(open(MDXModelName, 'rb').read()).hexdigest() - print(mdx_model_hash) + modeltype = 'v' + noise_pro = 'MDX-NET_Noise_Profile_14_kHz' + stemset_n = '(Vocals)' + source_val = 3 + n_fft_scale_set=6144 + dim_f_set=2048 + elif data['mdxnetModel'] == 'UVR-MDX-NET Karaoke': + model_set = 'UVR_MDXNET_KARA' + model_set_name = 'UVR_MDXNET_Karaoke' + modeltype = 'v' + noise_pro = 'MDX-NET_Noise_Profile_14_kHz' + stemset_n = '(Vocals)' + source_val = 3 + n_fft_scale_set=6144 + dim_f_set=2048 + elif 'other' in data['mdxnetModel']: + model_set = 'other' + model_set_name = 'other' + modeltype = 'o' + noise_pro = 'MDX-NET_Noise_Profile_Full_Band' + stemset_n = '(Other)' + source_val = 2 + n_fft_scale_set=8192 + dim_f_set=2048 + elif 'drums' in data['mdxnetModel']: + model_set = 'drums' + model_set_name = 'drums' + modeltype = 'd' + noise_pro = 'MDX-NET_Noise_Profile_Full_Band' + stemset_n = '(Drums)' + source_val = 1 + n_fft_scale_set=4096 + dim_f_set=2048 + elif 'bass' in data['mdxnetModel']: + model_set = 'bass' + model_set_name = 'bass' + modeltype = 'b' + noise_pro = 'MDX-NET_Noise_Profile_Full_Band' + stemset_n = '(Bass)' + source_val = 0 + n_fft_scale_set=16384 + dim_f_set=2048 + else: + model_set = data['mdxnetModel'] + model_set_name = data['mdxnetModel'] + modeltype = stemset + noise_pro = 'MDX-NET_Noise_Profile_Full_Band' + stemset_n = stem_name + source_val = source_val_set + n_fft_scale_set=int(data['n_fft_scale']) + dim_f_set=int(data['dim_f']) if data['noise_pro_select'] == 'Auto Select': @@ -988,12 +967,8 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress print(n_fft_scale_set) print(dim_f_set) - print(data['DemucsModel']) + print(data['DemucsModel_MDX']) - overlap_set = float(data['overlap']) - channel_set = int(data['channel']) - margin_set = int(data['margin']) - shift_set = int(data['shifts']) stime = time.perf_counter() progress_var.set(0) @@ -1002,7 +977,46 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress try: #Load File(s) for file_num, music_file in tqdm(enumerate(data['input_paths'], start=1)): - + + overlap_set = float(data['overlap']) + channel_set = int(data['channel']) + margin_set = int(data['margin']) + shift_set = int(data['shifts']) + demucs_model_set = data['DemucsModel_MDX'] + split_mode = data['split_mode'] + demucs_switch = data['demucsmodel'] + + if stemset_n == '(Bass)': + if 'UVR' in demucs_model_set: + text_widget.write('The selected Demucs model can only be used with vocal stems.\n') + text_widget.write('Please select a 4 stem Demucs model and try again.\n\n') + text_widget.write(f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}') + progress_var.set(0) + button_widget.configure(state=tk.NORMAL) # Enable Button + return + else: + pass + if stemset_n == '(Drums)': + if 'UVR' in demucs_model_set: + text_widget.write('The selected Demucs model can only be used with vocal stems.\n') + text_widget.write('Please select a 4 stem Demucs model and try again.\n\n') + text_widget.write(f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}') + progress_var.set(0) + button_widget.configure(state=tk.NORMAL) # Enable Button + return + else: + pass + if stemset_n == '(Other)': + if 'UVR' in demucs_model_set: + text_widget.write('The selected Demucs model can only be used with vocal stems.\n') + text_widget.write('Please select a 4 stem Demucs model and try again.\n\n') + text_widget.write(f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}') + progress_var.set(0) + button_widget.configure(state=tk.NORMAL) # Enable Button + return + else: + pass + _mixture = f'{data["input_paths"]}' _basename = f'{data["export_path"]}/{file_num}_{os.path.splitext(os.path.basename(music_file))[0]}' @@ -1063,11 +1077,10 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress e = os.path.join(data["export_path"]) - demucsmodel = 'models/Demucs_Model/' + str(data['DemucsModel']) + demucsmodel = 'models/Demucs_Models/' + str(data['DemucsModel_MDX']) pred = Predictor() - pred.prediction_setup(demucs_name=demucsmodel, - channels=channel_set) + pred.prediction_setup() print(demucsmodel) @@ -1373,7 +1386,10 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress text_widget.write("\n" + f'Please address the error and try again.' + "\n") text_widget.write(f'If this error persists, please contact the developers with the error details.\n\n') text_widget.write(f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}') - torch.cuda.empty_cache() + try: + torch.cuda.empty_cache() + except: + pass button_widget.configure(state=tk.NORMAL) # Enable Button return diff --git a/inference_demucs.py b/inference_demucs.py new file mode 100644 index 0000000..32419e2 --- /dev/null +++ b/inference_demucs.py @@ -0,0 +1,1225 @@ +import os +from pathlib import Path +import os.path +from datetime import datetime +import pydub +import shutil +from random import randrange +#MDX-Net +#---------------------------------------- +import soundfile as sf +import torch +import numpy as np + +from demucs.pretrained import get_model as _gm +from demucs.hdemucs import HDemucs +from demucs.apply import BagOfModels, apply_model +from demucs.audio import AudioFile + +import time +import os +from tqdm import tqdm +import warnings +import sys +import librosa +import psutil +#---------------------------------------- +from lib_v5 import spec_utils +from lib_v5.model_param_init import ModelParameters +import torch + +# Command line text parsing and widget manipulation +import tkinter as tk +import traceback # Error Message Recent Calls +import time # Timer + +class Predictor(): + def __init__(self): + pass + + def prediction_setup(self): + + global device + + if data['gpu'] >= 0: + device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') + if data['gpu'] == -1: + device = torch.device('cpu') + + if data['demucsmodel']: + self.demucs = HDemucs(sources=["drums", "bass", "other", "vocals"]) + widget_text.write(base_text + 'Loading Demucs model... ') + update_progress(**progress_kwargs, + step=0.05) + path_d = Path('models/Demucs_Models') + print('What Demucs model was chosen? ', data['DemucsModel']) + self.demucs = _gm(name=data['DemucsModel'], repo=path_d) + widget_text.write('Done!\n') + if 'UVR' in data['DemucsModel']: + widget_text.write(base_text + "2 stem model selected.\n") + if isinstance(self.demucs, BagOfModels): + widget_text.write(base_text + f"Selected model is a bag of {len(self.demucs.models)} models.\n") + self.demucs.to(device) + self.demucs.eval() + + + update_progress(**progress_kwargs, + step=0.1) + + def prediction(self, m): + + mix, samplerate = librosa.load(m, mono=False, sr=44100) + if mix.ndim == 1: + mix = np.asfortranarray([mix,mix]) + + samplerate = self.demucs.samplerate + + mix = mix.T + sources = self.demix(mix.T) + widget_text.write(base_text + 'Inferences complete!\n') + + #Main Save Path + save_path = os.path.dirname(_basename) + + vocals_name = '(Vocals)' + other_name = '(Other)' + drums_name = '(Drums)' + bass_name = '(Bass)' + + vocals_path = '{save_path}/{file_name}.wav'.format( + save_path=save_path, + file_name = f'{os.path.basename(_basename)}_{vocals_name}',) + vocals_path_mp3 = '{save_path}/{file_name}.mp3'.format( + save_path=save_path, + file_name = f'{os.path.basename(_basename)}_{vocals_name}',) + vocals_path_flac = '{save_path}/{file_name}.flac'.format( + save_path=save_path, + file_name = f'{os.path.basename(_basename)}_{vocals_name}',) + + #Other + + other_path = '{save_path}/{file_name}.wav'.format( + save_path=save_path, + file_name = f'{os.path.basename(_basename)}_{other_name}',) + other_path_mp3 = '{save_path}/{file_name}.mp3'.format( + save_path=save_path, + file_name = f'{os.path.basename(_basename)}_{other_name}',) + other_path_flac = '{save_path}/{file_name}.flac'.format( + save_path=save_path, + file_name = f'{os.path.basename(_basename)}_{other_name}',) + + #Drums + + drums_path = '{save_path}/{file_name}.wav'.format( + save_path=save_path, + file_name = f'{os.path.basename(_basename)}_{drums_name}',) + drums_path_mp3 = '{save_path}/{file_name}.mp3'.format( + save_path=save_path, + file_name = f'{os.path.basename(_basename)}_{drums_name}',) + drums_path_flac = '{save_path}/{file_name}.flac'.format( + save_path=save_path, + file_name = f'{os.path.basename(_basename)}_{drums_name}',) + + #Bass + + + bass_path = '{save_path}/{file_name}.wav'.format( + save_path=save_path, + file_name = f'{os.path.basename(_basename)}_{bass_name}',) + bass_path_mp3 = '{save_path}/{file_name}.mp3'.format( + save_path=save_path, + file_name = f'{os.path.basename(_basename)}_{bass_name}',) + bass_path_flac = '{save_path}/{file_name}.flac'.format( + save_path=save_path, + file_name = f'{os.path.basename(_basename)}_{bass_name}',) + + + + #If not 'All Stems' + + if stemset_n == '(Vocals)': + vocal_name = '(Vocals)' + elif stemset_n == '(Other)': + vocal_name = '(Other)' + elif stemset_n == '(Drums)': + vocal_name = '(Drums)' + elif stemset_n == '(Bass)': + vocal_name = '(Bass)' + elif stemset_n == '(Instrumental)': + vocal_name = '(Instrumental)' + + vocal_path = '{save_path}/{file_name}.wav'.format( + save_path=save_path, + file_name = f'{os.path.basename(_basename)}_{vocal_name}',) + vocal_path_mp3 = '{save_path}/{file_name}.mp3'.format( + save_path=save_path, + file_name = f'{os.path.basename(_basename)}_{vocal_name}',) + vocal_path_flac = '{save_path}/{file_name}.flac'.format( + save_path=save_path, + file_name = f'{os.path.basename(_basename)}_{vocal_name}',) + + #Instrumental Path + + if stemset_n == '(Vocals)': + Instrumental_name = '(Instrumental)' + elif stemset_n == '(Other)': + Instrumental_name = '(No_Other)' + elif stemset_n == '(Drums)': + Instrumental_name = '(No_Drums)' + elif stemset_n == '(Bass)': + Instrumental_name = '(No_Bass)' + elif stemset_n == '(Instrumental)': + if data['demucs_stems'] == 'All Stems': + Instrumental_name = '(Instrumental)' + else: + Instrumental_name = '(Vocals)' + + + Instrumental_path = '{save_path}/{file_name}.wav'.format( + save_path=save_path, + file_name = f'{os.path.basename(_basename)}_{Instrumental_name}',) + Instrumental_path_mp3 = '{save_path}/{file_name}.mp3'.format( + save_path=save_path, + file_name = f'{os.path.basename(_basename)}_{Instrumental_name}',) + Instrumental_path_flac = '{save_path}/{file_name}.flac'.format( + save_path=save_path, + file_name = f'{os.path.basename(_basename)}_{Instrumental_name}',) + + + if os.path.isfile(vocal_path): + file_exists_n = 'there' + else: + file_exists_n = 'not_there' + + if os.path.isfile(vocal_path): + file_exists_v = 'there' + else: + file_exists_v = 'not_there' + + if os.path.isfile(Instrumental_path): + file_exists_i = 'there' + else: + file_exists_i = 'not_there' + + + if not data['demucs_stems'] == 'All Stems': + if data['inst_only_b']: + widget_text.write(base_text + 'Preparing mixture without selected stem...') + else: + widget_text.write(base_text + 'Saving Stem(s)... ') + else: + pass + + if data['demucs_stems'] == 'All Stems': + + if data['saveFormat'] == 'Wav': + widget_text.write(base_text + 'Saving Stem(s)... ') + else: + pass + + if 'UVR' in model_set_name: + sf.write(Instrumental_path, sources[0].T, samplerate) + sf.write(vocals_path, sources[1].T, samplerate) + else: + sf.write(bass_path, sources[0].T, samplerate) + sf.write(drums_path, sources[1].T, samplerate) + sf.write(other_path, sources[2].T, samplerate) + sf.write(vocals_path, sources[3].T, samplerate) + + if data['saveFormat'] == 'Mp3': + try: + if 'UVR' in model_set_name: + widget_text.write(base_text + 'Saving Stem(s) as Mp3(s)... ') + musfile = pydub.AudioSegment.from_wav(vocals_path) + musfile.export(vocals_path_mp3, format="mp3", bitrate="320k") + musfile = pydub.AudioSegment.from_wav(Instrumental_path) + musfile.export(Instrumental_path_mp3, format="mp3", bitrate="320k") + try: + os.remove(Instrumental_path) + os.remove(vocals_path) + except: + pass + else: + widget_text.write(base_text + 'Saving Stem(s) as Mp3(s)... ') + musfile = pydub.AudioSegment.from_wav(drums_path) + musfile.export(drums_path_mp3, format="mp3", bitrate="320k") + musfile = pydub.AudioSegment.from_wav(bass_path) + musfile.export(bass_path_mp3, format="mp3", bitrate="320k") + musfile = pydub.AudioSegment.from_wav(other_path) + musfile.export(other_path_mp3, format="mp3", bitrate="320k") + musfile = pydub.AudioSegment.from_wav(vocals_path) + musfile.export(vocals_path_mp3, format="mp3", bitrate="320k") + try: + os.remove(drums_path) + os.remove(bass_path) + os.remove(other_path) + os.remove(vocals_path) + except: + pass + except Exception as e: + traceback_text = ''.join(traceback.format_tb(e.__traceback__)) + errmessage = f'Traceback Error: "{traceback_text}"\n{type(e).__name__}: "{e}"\n' + if "ffmpeg" in errmessage: + widget_text.write('\n' + base_text + 'Failed to save output(s) as Mp3(s).\n') + widget_text.write(base_text + 'FFmpeg might be missing or corrupted, please check error log.\n') + widget_text.write(base_text + 'Moving on...\n') + else: + widget_text.write(base_text + 'Failed to save output(s) as Mp3(s).\n') + widget_text.write(base_text + 'Please check error log.\n') + widget_text.write(base_text + 'Moving on...\n') + try: + with open('errorlog.txt', 'w') as f: + f.write(f'Last Error Received:\n\n' + + f'Error Received while attempting to save file as mp3 "{os.path.basename(music_file)}":\n\n' + + f'Process Method: Demucs v3\n\n' + + f'FFmpeg might be missing or corrupted.\n\n' + + f'If this error persists, please contact the developers.\n\n' + + f'Raw error details:\n\n' + + errmessage + f'\nError Time Stamp: [{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]\n') + except: + pass + elif data['saveFormat'] == 'Flac': + try: + if 'UVR' in model_set_name: + widget_text.write(base_text + 'Saving Stem(s) as flac(s)... ') + musfile = pydub.AudioSegment.from_wav(vocals_path) + musfile.export(vocals_path_flac, format="flac") + musfile = pydub.AudioSegment.from_wav(Instrumental_path) + musfile.export(Instrumental_path_flac, format="flac") + try: + os.remove(Instrumental_path) + os.remove(vocals_path) + except: + pass + else: + widget_text.write(base_text + 'Saving Stem(s) as Flac(s)... ') + musfile = pydub.AudioSegment.from_wav(drums_path) + musfile.export(drums_path_flac, format="flac") + musfile = pydub.AudioSegment.from_wav(bass_path) + musfile.export(bass_path_flac, format="flac") + musfile = pydub.AudioSegment.from_wav(other_path) + musfile.export(other_path_flac, format="flac") + musfile = pydub.AudioSegment.from_wav(vocals_path) + musfile.export(vocals_path_flac, format="flac") + try: + os.remove(drums_path) + os.remove(bass_path) + os.remove(other_path) + os.remove(vocals_path) + except: + pass + except Exception as e: + traceback_text = ''.join(traceback.format_tb(e.__traceback__)) + errmessage = f'Traceback Error: "{traceback_text}"\n{type(e).__name__}: "{e}"\n' + if "ffmpeg" in errmessage: + widget_text.write('\n' + base_text + 'Failed to save output(s) as Flac(s).\n') + widget_text.write(base_text + 'FFmpeg might be missing or corrupted, please check error log.\n') + widget_text.write(base_text + 'Moving on...\n') + else: + widget_text.write(base_text + 'Failed to save output(s) as flac(s).\n') + widget_text.write(base_text + 'Please check error log.\n') + widget_text.write(base_text + 'Moving on...\n') + try: + with open('errorlog.txt', 'w') as f: + f.write(f'Last Error Received:\n\n' + + f'Error Received while attempting to save file as flac "{os.path.basename(music_file)}":\n\n' + + f'Process Method: Demucs v3\n\n' + + f'FFmpeg might be missing or corrupted.\n\n' + + f'If this error persists, please contact the developers.\n\n' + + f'Raw error details:\n\n' + + errmessage + f'\nError Time Stamp: [{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]\n') + except: + pass + elif data['saveFormat'] == 'Wav': + pass + + widget_text.write('Done!\n') + else: + if 'UVR' in model_set_name: + if stemset_n == '(Vocals)': + sf.write(vocal_path, sources[1].T, samplerate) + else: + sf.write(vocal_path, sources[source_val].T, samplerate) + else: + sf.write(vocal_path, sources[source_val].T, samplerate) + + widget_text.write('Done!\n') + + update_progress(**progress_kwargs, + step=(0.9)) + + if data['demucs_stems'] == 'All Stems': + pass + else: + if data['voc_only_b'] and not data['inst_only_b']: + pass + + else: + finalfiles = [ + { + 'model_params':'lib_v5/modelparams/1band_sr44100_hl512.json', + 'files':[str(music_file), vocal_path], + } + ] + widget_text.write(base_text + 'Saving Instrumental... ') + for i, e in tqdm(enumerate(finalfiles)): + + wave, specs = {}, {} + + mp = ModelParameters(e['model_params']) + + for i in range(len(e['files'])): + spec = {} + + for d in range(len(mp.param['band']), 0, -1): + bp = mp.param['band'][d] + + if d == len(mp.param['band']): # high-end band + wave[d], _ = librosa.load( + e['files'][i], bp['sr'], False, dtype=np.float32, res_type=bp['res_type']) + + if len(wave[d].shape) == 1: # mono to stereo + wave[d] = np.array([wave[d], wave[d]]) + else: # lower bands + wave[d] = librosa.resample(wave[d+1], mp.param['band'][d+1]['sr'], bp['sr'], res_type=bp['res_type']) + + spec[d] = spec_utils.wave_to_spectrogram(wave[d], bp['hl'], bp['n_fft'], mp.param['mid_side'], mp.param['mid_side_b2'], mp.param['reverse']) + + specs[i] = spec_utils.combine_spectrograms(spec, mp) + + del wave + + ln = min([specs[0].shape[2], specs[1].shape[2]]) + specs[0] = specs[0][:,:,:ln] + specs[1] = specs[1][:,:,:ln] + X_mag = np.abs(specs[0]) + y_mag = np.abs(specs[1]) + max_mag = np.where(X_mag >= y_mag, X_mag, y_mag) + v_spec = specs[1] - max_mag * np.exp(1.j * np.angle(specs[0])) + update_progress(**progress_kwargs, + step=(1)) + + sf.write(Instrumental_path, spec_utils.cmb_spectrogram_to_wave(-v_spec, mp), mp.param['sr']) + + + if data['inst_only_b']: + if file_exists_v == 'there': + pass + else: + try: + os.remove(vocal_path) + except: + pass + + widget_text.write('Done!\n') + + + if not data['demucs_stems'] == 'All Stems': + + if data['saveFormat'] == 'Mp3': + try: + if data['inst_only_b'] == True: + pass + else: + musfile = pydub.AudioSegment.from_wav(vocal_path) + musfile.export(vocal_path_mp3, format="mp3", bitrate="320k") + if file_exists_v == 'there': + pass + else: + try: + os.remove(vocal_path) + except: + pass + if data['voc_only_b'] == True: + pass + else: + musfile = pydub.AudioSegment.from_wav(Instrumental_path) + musfile.export(Instrumental_path_mp3, format="mp3", bitrate="320k") + if file_exists_i == 'there': + pass + else: + try: + os.remove(Instrumental_path) + except: + pass + + + except Exception as e: + traceback_text = ''.join(traceback.format_tb(e.__traceback__)) + errmessage = f'Traceback Error: "{traceback_text}"\n{type(e).__name__}: "{e}"\n' + if "ffmpeg" in errmessage: + widget_text.write(base_text + 'Failed to save output(s) as Mp3(s).\n') + widget_text.write(base_text + 'FFmpeg might be missing or corrupted, please check error log.\n') + widget_text.write(base_text + 'Moving on...\n') + else: + widget_text.write(base_text + 'Failed to save output(s) as Mp3(s).\n') + widget_text.write(base_text + 'Please check error log.\n') + widget_text.write(base_text + 'Moving on...\n') + try: + with open('errorlog.txt', 'w') as f: + f.write(f'Last Error Received:\n\n' + + f'Error Received while attempting to save file as mp3 "{os.path.basename(music_file)}":\n\n' + + f'Process Method: Demucs v3\n\n' + + f'FFmpeg might be missing or corrupted.\n\n' + + f'If this error persists, please contact the developers.\n\n' + + f'Raw error details:\n\n' + + errmessage + f'\nError Time Stamp: [{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]\n') + except: + pass + + if data['saveFormat'] == 'Flac': + try: + if data['inst_only_b'] == True: + pass + else: + musfile = pydub.AudioSegment.from_wav(vocal_path) + musfile.export(vocal_path_flac, format="flac") + if file_exists_v == 'there': + pass + else: + try: + os.remove(vocal_path) + except: + pass + if data['voc_only_b'] == True: + pass + else: + musfile = pydub.AudioSegment.from_wav(Instrumental_path) + musfile.export(Instrumental_path_flac, format="flac") + if file_exists_i == 'there': + pass + else: + try: + os.remove(Instrumental_path) + except: + pass + + except Exception as e: + traceback_text = ''.join(traceback.format_tb(e.__traceback__)) + errmessage = f'Traceback Error: "{traceback_text}"\n{type(e).__name__}: "{e}"\n' + if "ffmpeg" in errmessage: + widget_text.write(base_text + 'Failed to save output(s) as Flac(s).\n') + widget_text.write(base_text + 'FFmpeg might be missing or corrupted, please check error log.\n') + widget_text.write(base_text + 'Moving on...\n') + else: + widget_text.write(base_text + 'Failed to save output(s) as Flac(s).\n') + widget_text.write(base_text + 'Please check error log.\n') + widget_text.write(base_text + 'Moving on...\n') + try: + with open('errorlog.txt', 'w') as f: + f.write(f'Last Error Received:\n\n' + + f'Error Received while attempting to save file as flac "{os.path.basename(music_file)}":\n\n' + + f'Process Method: Demucs v3\n\n' + + f'FFmpeg might be missing or corrupted.\n\n' + + f'If this error persists, please contact the developers.\n\n' + + f'Raw error details:\n\n' + + errmessage + f'\nError Time Stamp: [{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]\n') + except: + pass + + + if data['inst_only_b']: + if file_exists_n == 'there': + pass + else: + try: + os.remove(vocal_path) + except: + pass + else: + try: + os.remove(vocal_path) + except: + pass + + widget_text.write(base_text + 'Completed Seperation!\n') + + def demix(self, mix): + + # 1 = demucs only + # 0 = onnx only + if data['chunks'] == 'Full': + chunk_set = 0 + else: + chunk_set = data['chunks'] + + if data['chunks'] == 'Auto': + if split_mode == True: + widget_text.write(base_text + "Split Mode is on (Chunks disabled).\n") + chunk_set = 0 + else: + widget_text.write(base_text + "Split Mode is off (Chunks enabled).\n") + if data['gpu'] == 0: + try: + gpu_mem = round(torch.cuda.get_device_properties(0).total_memory/1.074e+9) + except: + widget_text.write(base_text + 'NVIDIA GPU Required for conversion!\n') + if int(gpu_mem) <= int(6): + chunk_set = int(10) + widget_text.write(base_text + 'Chunk size auto-set to 10... \n') + if gpu_mem in [7, 8, 9]: + chunk_set = int(30) + widget_text.write(base_text + 'Chunk size auto-set to 30... \n') + if gpu_mem in [10, 11, 12, 13, 14, 15]: + chunk_set = int(50) + widget_text.write(base_text + 'Chunk size auto-set to 50... \n') + if int(gpu_mem) >= int(16): + chunk_set = int(0) + widget_text.write(base_text + 'Chunk size auto-set to Full... \n') + if data['gpu'] == -1: + sys_mem = psutil.virtual_memory().total >> 30 + if int(sys_mem) <= int(4): + chunk_set = int(5) + widget_text.write(base_text + 'Chunk size auto-set to 5... \n') + if sys_mem in [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]: + chunk_set = int(10) + widget_text.write(base_text + 'Chunk size auto-set to 10... \n') + if sys_mem in [17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32]: + chunk_set = int(40) + widget_text.write(base_text + 'Chunk size auto-set to 40... \n') + if int(sys_mem) >= int(33): + chunk_set = int(0) + widget_text.write(base_text + 'Chunk size auto-set to Full... \n') + elif data['chunks'] == 'Full': + chunk_set = 0 + widget_text.write(base_text + "Chunk size set to full... \n") + else: + if split_mode == True: + widget_text.write(base_text + "Split Mode is on (Chunks disabled).\n") + chunk_set = 0 + else: + widget_text.write(base_text + "Split Mode is off (Chunks enabled).\n") + chunk_set = int(data['chunks']) + widget_text.write(base_text + "Chunk size user-set to "f"{chunk_set}... \n") + + samples = mix.shape[-1] + margin = margin_set + chunk_size = chunk_set*44100 + assert not margin == 0, 'margin cannot be zero!' + if margin > chunk_size: + margin = chunk_size + + + segmented_mix = {} + + if chunk_set == 0 or samples < chunk_size: + chunk_size = samples + + counter = -1 + for skip in range(0, samples, chunk_size): + counter+=1 + + s_margin = 0 if counter == 0 else margin + end = min(skip+chunk_size+margin, samples) + + start = skip-s_margin + + segmented_mix[skip] = mix[:,start:end].copy() + if end == samples: + break + + sources = self.demix_demucs(segmented_mix, margin_size=margin) + + return sources + + def demix_demucs(self, mix, margin_size): + + processed = {} + demucsitera = len(mix) + demucsitera_calc = demucsitera * 2 + gui_progress_bar_demucs = 0 + + widget_text.write(base_text + "Running Demucs Inference...\n") + widget_text.write(base_text + "Processing "f"{len(mix)} slices... ") + print(' Running Demucs Inference...') + for nmix in mix: + gui_progress_bar_demucs += 1 + update_progress(**progress_kwargs, + step=(0.1 + (1.7/demucsitera_calc * gui_progress_bar_demucs))) + cmix = mix[nmix] + cmix = torch.tensor(cmix, dtype=torch.float32) + ref = cmix.mean(0) + cmix = (cmix - ref.mean()) / ref.std() + with torch.no_grad(): + sources = apply_model(self.demucs, cmix[None], split=split_mode, device=device, overlap=overlap_set, shifts=shift_set, progress=False)[0] + sources = (sources * ref.std() + ref.mean()).cpu().numpy() + sources[[0,1]] = sources[[1,0]] + + start = 0 if nmix == 0 else margin_size + end = None if nmix == list(mix.keys())[::-1][0] else -margin_size + if margin_size == 0: + end = None + processed[nmix] = sources[:,:,start:end].copy() + + sources = list(processed.values()) + sources = np.concatenate(sources, axis=-1) + widget_text.write('Done!\n') + return sources + +data = { + # Paths + 'input_paths': None, + 'export_path': None, + 'saveFormat': 'Wav', + # Processing Options + 'demucsmodel': True, + 'gpu': -1, + 'chunks': 'Full', + 'modelFolder': False, + 'voc_only_b': False, + 'inst_only_b': False, + 'overlap_b': 0.25, + 'shifts_b': 2, + 'margin': 44100, + 'split_mode': False, + 'compensate': 1.03597672895, + 'demucs_stems': 'All Stems', + 'DemucsModel': 'mdx_extra', + 'audfile': True, +} +default_chunks = data['chunks'] + +def update_progress(progress_var, total_files, file_num, step: float = 1): + """Calculate the progress for the progress widget in the GUI""" + base = (100 / total_files) + progress = base * (file_num - 1) + progress += base * step + + progress_var.set(progress) + +def get_baseText(total_files, file_num): + """Create the base text for the command widget""" + text = 'File {file_num}/{total_files} '.format(file_num=file_num, + total_files=total_files) + return text + +warnings.filterwarnings("ignore") +cpu = torch.device('cpu') + +def hide_opt(): + with open(os.devnull, "w") as devnull: + old_stdout = sys.stdout + sys.stdout = devnull + try: + yield + finally: + sys.stdout = old_stdout + +def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress_var: tk.Variable, + **kwargs: dict): + + global widget_text + global gui_progress_bar + global music_file + global default_chunks + global _basename + global _mixture + global progress_kwargs + global base_text + global model_set_name + global stemset_n + global channel_set + global margin_set + global overlap_set + global shift_set + global source_val + global split_mode + + # Update default settings + default_chunks = data['chunks'] + + widget_text = text_widget + gui_progress_bar = progress_var + + #Error Handling + + onnxmissing = "[ONNXRuntimeError] : 3 : NO_SUCHFILE" + onnxmemerror = "onnxruntime::CudaCall CUDA failure 2: out of memory" + onnxmemerror2 = "onnxruntime::BFCArena::AllocateRawInternal" + systemmemerr = "DefaultCPUAllocator: not enough memory" + runtimeerr = "CUDNN error executing cudnnSetTensorNdDescriptor" + cuda_err = "CUDA out of memory" + mod_err = "ModuleNotFoundError" + file_err = "FileNotFoundError" + ffmp_err = """audioread\__init__.py", line 116, in audio_open""" + sf_write_err = "sf.write" + model_adv_set_err = "Got invalid dimensions for input" + + try: + with open('errorlog.txt', 'w') as f: + f.write(f'No errors to report at this time.' + f'\n\nLast Process Method Used: MDX-Net' + + f'\nLast Conversion Time Stamp: [{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]\n') + except: + pass + + timestampnum = round(datetime.utcnow().timestamp()) + randomnum = randrange(100000, 1000000) + + data.update(kwargs) + + stime = time.perf_counter() + progress_var.set(0) + text_widget.clear() + button_widget.configure(state=tk.DISABLED) # Disable Button + + try: #Load File(s) + for file_num, music_file in tqdm(enumerate(data['input_paths'], start=1)): + + model_set_name = data['DemucsModel'] + + if data['demucs_stems'] == 'Vocals': + source_val = 3 + stemset_n = '(Vocals)' + if data['demucs_stems'] == 'Other': + if 'UVR' in model_set_name: + source_val = 0 + stemset_n = '(Instrumental)' + else: + source_val = 2 + stemset_n = '(Other)' + if data['demucs_stems'] == 'Drums': + if 'UVR' in model_set_name: + text_widget.write('You can only choose "Vocals" or "Other" stems when using this model.\n') + text_widget.write('Please select one of the stock Demucs models and try again.\n\n') + text_widget.write(f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}') + progress_var.set(0) + button_widget.configure(state=tk.NORMAL) # Enable Button + return + else: + source_val = 1 + stemset_n = '(Drums)' + if data['demucs_stems'] == 'Bass': + if 'UVR' in model_set_name: + text_widget.write('You can only choose "Vocals" or "Other" stems when using this model.\n') + text_widget.write('Please select one of the stock Demucs models and try again.\n\n') + text_widget.write(f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}') + progress_var.set(0) + button_widget.configure(state=tk.NORMAL) # Enable Button + return + else: + source_val = 0 + stemset_n = '(Bass)' + if data['demucs_stems'] == 'All Stems': + source_val = 3 + stemset_n = '(Instrumental)' + + + overlap_set = float(data['overlap_b']) + channel_set = int(data['channel']) + margin_set = int(data['margin']) + shift_set = int(data['shifts_b']) + split_mode = data['split_mode'] + + def determinemodelFolderName(): + """ + Determine the name that is used for the folder and appended + to the back of the music files + """ + modelFolderName = '' + + if str(model_set_name): + modelFolderName += os.path.splitext(os.path.basename(model_set_name))[0] + + if modelFolderName: + + modelFolderName = '/' + modelFolderName + + + return modelFolderName + + + if data['audfile'] == True: + modelFolderName = determinemodelFolderName() + + if modelFolderName: + folder_path = f'{data["export_path"]}{modelFolderName}' + if not os.path.isdir(folder_path): + os.mkdir(folder_path) + + _mixture = f'{data["input_paths"]}' + if data['modelFolder']: + try: + _basename = f'{data["export_path"]}{modelFolderName}/{file_num}_{str(timestampnum)}_{os.path.splitext(os.path.basename(music_file))[0]}' + except: + _basename = f'{data["export_path"]}{modelFolderName}/{file_num}_{str(randomnum)}_{os.path.splitext(os.path.basename(music_file))[0]}' + else: + _basename = f'{data["export_path"]}{modelFolderName}/{file_num}_{os.path.splitext(os.path.basename(music_file))[0]}' + else: + _mixture = f'{data["input_paths"]}' + if data['modelFolder']: + try: + _basename = f'{data["export_path"]}/{file_num}_{str(timestampnum)}_{model_set_name}_{os.path.splitext(os.path.basename(music_file))[0]}' + except: + _basename = f'{data["export_path"]}/{file_num}_{str(randomnum)}_{model_set_name}_{os.path.splitext(os.path.basename(music_file))[0]}' + else: + _basename = f'{data["export_path"]}/{file_num}_{os.path.splitext(os.path.basename(music_file))[0]}' + + #if ('models/MDX_Net_Models/' + model_set + '.onnx') + + + # -Get text and update progress- + base_text = get_baseText(total_files=len(data['input_paths']), + file_num=file_num) + progress_kwargs = {'progress_var': progress_var, + 'total_files': len(data['input_paths']), + 'file_num': file_num} + + try: + + total, used, free = shutil.disk_usage("/") + + + total_space = int(total/1.074e+9) + used_space = int(used/1.074e+9) + free_space = int(free/1.074e+9) + + + if int(free/1.074e+9) <= int(2): + text_widget.write('Error: Not enough storage on main drive to continue. Your main drive must have \nat least 3 GB\'s of storage in order for this application function properly. \n\nPlease ensure your main drive has at least 3 GB\'s of storage and try again.\n\n') + text_widget.write('Detected Total Space: ' + str(total_space) + ' GB' + '\n') + text_widget.write('Detected Used Space: ' + str(used_space) + ' GB' + '\n') + text_widget.write('Detected Free Space: ' + str(free_space) + ' GB' + '\n') + progress_var.set(0) + button_widget.configure(state=tk.NORMAL) # Enable Button + return + + if int(free/1.074e+9) in [3, 4, 5, 6, 7, 8]: + text_widget.write('Warning: Your main drive is running low on storage. Your main drive must have \nat least 3 GB\'s of storage in order for this application function properly.\n\n') + text_widget.write('Detected Total Space: ' + str(total_space) + ' GB' + '\n') + text_widget.write('Detected Used Space: ' + str(used_space) + ' GB' + '\n') + text_widget.write('Detected Free Space: ' + str(free_space) + ' GB' + '\n\n') + except: + pass + + update_progress(**progress_kwargs, + step=0) + + e = os.path.join(data["export_path"]) + + demucsmodel = 'models/Demucs_Models/' + str(data['DemucsModel']) + + pred = Predictor() + pred.prediction_setup() + + # split + pred.prediction( + m=music_file, + ) + + except Exception as e: + traceback_text = ''.join(traceback.format_tb(e.__traceback__)) + message = f'Traceback Error: "{traceback_text}"\n{type(e).__name__}: "{e}"\n' + if runtimeerr in message: + text_widget.write("\n" + base_text + f'Separation failed for the following audio file:\n') + text_widget.write(base_text + f'"{os.path.basename(music_file)}"\n') + text_widget.write(f'\nError Received:\n\n') + text_widget.write(f'Your PC cannot process this audio file with the chunk size selected.\nPlease lower the chunk size and try again.\n\n') + text_widget.write(f'If this error persists, please contact the developers.\n\n') + text_widget.write(f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}') + try: + with open('errorlog.txt', 'w') as f: + f.write(f'Last Error Received:\n\n' + + f'Error Received while processing "{os.path.basename(music_file)}":\n' + + f'Process Method: Demucs v3\n\n' + + f'Your PC cannot process this audio file with the chunk size selected.\nPlease lower the chunk size and try again.\n\n' + + f'If this error persists, please contact the developers.\n\n' + + f'Raw error details:\n\n' + + message + f'\nError Time Stamp: [{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]\n') + except: + pass + torch.cuda.empty_cache() + progress_var.set(0) + button_widget.configure(state=tk.NORMAL) # Enable Button + return + + if cuda_err in message: + text_widget.write("\n" + base_text + f'Separation failed for the following audio file:\n') + text_widget.write(base_text + f'"{os.path.basename(music_file)}"\n') + text_widget.write(f'\nError Received:\n\n') + text_widget.write(f'The application was unable to allocate enough GPU memory to use this model.\n') + text_widget.write(f'Please close any GPU intensive applications and try again.\n') + text_widget.write(f'If the error persists, your GPU might not be supported.\n\n') + text_widget.write(f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}') + try: + with open('errorlog.txt', 'w') as f: + f.write(f'Last Error Received:\n\n' + + f'Error Received while processing "{os.path.basename(music_file)}":\n' + + f'Process Method: Demucs v3\n\n' + + f'The application was unable to allocate enough GPU memory to use this model.\n' + + f'Please close any GPU intensive applications and try again.\n' + + f'If the error persists, your GPU might not be supported.\n\n' + + f'Raw error details:\n\n' + + message + f'\nError Time Stamp [{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]\n') + except: + pass + torch.cuda.empty_cache() + progress_var.set(0) + button_widget.configure(state=tk.NORMAL) # Enable Button + return + + if mod_err in message: + text_widget.write("\n" + base_text + f'Separation failed for the following audio file:\n') + text_widget.write(base_text + f'"{os.path.basename(music_file)}"\n') + text_widget.write(f'\nError Received:\n\n') + text_widget.write(f'Application files(s) are missing.\n') + text_widget.write("\n" + f'{type(e).__name__} - "{e}"' + "\n\n") + text_widget.write(f'Please check for missing files/scripts in the app directory and try again.\n') + text_widget.write(f'If the error persists, please reinstall application or contact the developers.\n\n') + text_widget.write(f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}') + try: + with open('errorlog.txt', 'w') as f: + f.write(f'Last Error Received:\n\n' + + f'Error Received while processing "{os.path.basename(music_file)}":\n' + + f'Process Method: Demucs v3\n\n' + + f'Application files(s) are missing.\n' + + f'Please check for missing files/scripts in the app directory and try again.\n' + + f'If the error persists, please reinstall application or contact the developers.\n\n' + + message + f'\nError Time Stamp [{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]\n') + except: + pass + torch.cuda.empty_cache() + progress_var.set(0) + button_widget.configure(state=tk.NORMAL) # Enable Button + return + + if file_err in message: + text_widget.write("\n" + base_text + f'Separation failed for the following audio file:\n') + text_widget.write(base_text + f'"{os.path.basename(music_file)}"\n') + text_widget.write(f'\nError Received:\n\n') + text_widget.write(f'Missing file error raised.\n') + text_widget.write("\n" + f'{type(e).__name__} - "{e}"' + "\n\n") + text_widget.write("\n" + f'Please address the error and try again.' + "\n") + text_widget.write(f'If this error persists, please contact the developers.\n\n') + text_widget.write(f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}') + torch.cuda.empty_cache() + try: + with open('errorlog.txt', 'w') as f: + f.write(f'Last Error Received:\n\n' + + f'Error Received while processing "{os.path.basename(music_file)}":\n' + + f'Process Method: Demucs v3\n\n' + + f'Missing file error raised.\n' + + "\n" + f'Please address the error and try again.' + "\n" + + f'If this error persists, please contact the developers.\n\n' + + message + f'\nError Time Stamp [{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]\n') + except: + pass + progress_var.set(0) + button_widget.configure(state=tk.NORMAL) # Enable Button + return + + if ffmp_err in message: + text_widget.write("\n" + base_text + f'Separation failed for the following audio file:\n') + text_widget.write(base_text + f'"{os.path.basename(music_file)}"\n') + text_widget.write(f'\nError Received:\n\n') + text_widget.write(f'The input file type is not supported or FFmpeg is missing.\n') + text_widget.write(f'Please select a file type supported by FFmpeg and try again.\n\n') + text_widget.write(f'If FFmpeg is missing or not installed, you will only be able to process \".wav\" files \nuntil it is available on this system.\n\n') + text_widget.write(f'See the \"More Info\" tab in the Help Guide.\n\n') + text_widget.write(f'If this error persists, please contact the developers.\n\n') + text_widget.write(f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}') + torch.cuda.empty_cache() + try: + with open('errorlog.txt', 'w') as f: + f.write(f'Last Error Received:\n\n' + + f'Error Received while processing "{os.path.basename(music_file)}":\n' + + f'Process Method: Demucs v3\n\n' + + f'The input file type is not supported or FFmpeg is missing.\nPlease select a file type supported by FFmpeg and try again.\n\n' + + f'If FFmpeg is missing or not installed, you will only be able to process \".wav\" files until it is available on this system.\n\n' + + f'See the \"More Info\" tab in the Help Guide.\n\n' + + f'If this error persists, please contact the developers.\n\n' + + message + f'\nError Time Stamp [{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]\n') + except: + pass + progress_var.set(0) + button_widget.configure(state=tk.NORMAL) # Enable Button + return + + if onnxmissing in message: + text_widget.write("\n" + base_text + f'Separation failed for the following audio file:\n') + text_widget.write(base_text + f'"{os.path.basename(music_file)}"\n') + text_widget.write(f'\nError Received:\n\n') + text_widget.write(f'The application could not detect this MDX-Net model on your system.\n') + text_widget.write(f'Please make sure all the models are present in the correct directory.\n') + text_widget.write(f'If the error persists, please reinstall application or contact the developers.\n\n') + text_widget.write(f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}') + try: + with open('errorlog.txt', 'w') as f: + f.write(f'Last Error Received:\n\n' + + f'Error Received while processing "{os.path.basename(music_file)}":\n' + + f'Process Method: Demucs v3\n\n' + + f'The application could not detect this MDX-Net model on your system.\n' + + f'Please make sure all the models are present in the correct directory.\n' + + f'If the error persists, please reinstall application or contact the developers.\n\n' + + message + f'\nError Time Stamp [{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]\n') + except: + pass + torch.cuda.empty_cache() + progress_var.set(0) + button_widget.configure(state=tk.NORMAL) # Enable Button + return + + if onnxmemerror in message: + text_widget.write("\n" + base_text + f'Separation failed for the following audio file:\n') + text_widget.write(base_text + f'"{os.path.basename(music_file)}"\n') + text_widget.write(f'\nError Received:\n\n') + text_widget.write(f'The application was unable to allocate enough GPU memory to use this model.\n') + text_widget.write(f'Please do the following:\n\n1. Close any GPU intensive applications.\n2. Lower the set chunk size.\n3. Then try again.\n\n') + text_widget.write(f'If the error persists, your GPU might not be supported.\n\n') + text_widget.write(f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}') + try: + with open('errorlog.txt', 'w') as f: + f.write(f'Last Error Received:\n\n' + + f'Error Received while processing "{os.path.basename(music_file)}":\n' + + f'Process Method: Demucs v3\n\n' + + f'The application was unable to allocate enough GPU memory to use this model.\n' + + f'Please do the following:\n\n1. Close any GPU intensive applications.\n2. Lower the set chunk size.\n3. Then try again.\n\n' + + f'If the error persists, your GPU might not be supported.\n\n' + + message + f'\nError Time Stamp [{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]\n') + except: + pass + torch.cuda.empty_cache() + progress_var.set(0) + button_widget.configure(state=tk.NORMAL) # Enable Button + return + + if onnxmemerror2 in message: + text_widget.write("\n" + base_text + f'Separation failed for the following audio file:\n') + text_widget.write(base_text + f'"{os.path.basename(music_file)}"\n') + text_widget.write(f'\nError Received:\n\n') + text_widget.write(f'The application was unable to allocate enough GPU memory to use this model.\n') + text_widget.write(f'Please do the following:\n\n1. Close any GPU intensive applications.\n2. Lower the set chunk size.\n3. Then try again.\n\n') + text_widget.write(f'If the error persists, your GPU might not be supported.\n\n') + text_widget.write(f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}') + try: + with open('errorlog.txt', 'w') as f: + f.write(f'Last Error Received:\n\n' + + f'Error Received while processing "{os.path.basename(music_file)}":\n' + + f'Process Method: Demucs v3\n\n' + + f'The application was unable to allocate enough GPU memory to use this model.\n' + + f'Please do the following:\n\n1. Close any GPU intensive applications.\n2. Lower the set chunk size.\n3. Then try again.\n\n' + + f'If the error persists, your GPU might not be supported.\n\n' + + message + f'\nError Time Stamp [{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]\n') + except: + pass + torch.cuda.empty_cache() + progress_var.set(0) + button_widget.configure(state=tk.NORMAL) # Enable Button + return + + if sf_write_err in message: + text_widget.write("\n" + base_text + f'Separation failed for the following audio file:\n') + text_widget.write(base_text + f'"{os.path.basename(music_file)}"\n') + text_widget.write(f'\nError Received:\n\n') + text_widget.write(f'Could not write audio file.\n') + text_widget.write(f'This could be due to low storage on target device or a system permissions issue.\n') + text_widget.write(f"\nFor raw error details, go to the Error Log tab in the Help Guide.\n") + text_widget.write(f'\nIf the error persists, please contact the developers.\n\n') + text_widget.write(f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}') + try: + with open('errorlog.txt', 'w') as f: + f.write(f'Last Error Received:\n\n' + + f'Error Received while processing "{os.path.basename(music_file)}":\n' + + f'Process Method: Demucs v3\n\n' + + f'Could not write audio file.\n' + + f'This could be due to low storage on target device or a system permissions issue.\n' + + f'If the error persists, please contact the developers.\n\n' + + message + f'\nError Time Stamp [{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]\n') + except: + pass + torch.cuda.empty_cache() + progress_var.set(0) + button_widget.configure(state=tk.NORMAL) # Enable Button + return + + if systemmemerr in message: + text_widget.write("\n" + base_text + f'Separation failed for the following audio file:\n') + text_widget.write(base_text + f'"{os.path.basename(music_file)}"\n') + text_widget.write(f'\nError Received:\n\n') + text_widget.write(f'The application was unable to allocate enough system memory to use this \nmodel.\n\n') + text_widget.write(f'Please do the following:\n\n1. Restart this application.\n2. Ensure any CPU intensive applications are closed.\n3. Then try again.\n\n') + text_widget.write(f'Please Note: Intel Pentium and Intel Celeron processors do not work well with \nthis application.\n\n') + text_widget.write(f'If the error persists, the system may not have enough RAM, or your CPU might \nnot be supported.\n\n') + text_widget.write(f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}') + try: + with open('errorlog.txt', 'w') as f: + f.write(f'Last Error Received:\n\n' + + f'Error Received while processing "{os.path.basename(music_file)}":\n' + + f'Process Method: Demucs v3\n\n' + + f'The application was unable to allocate enough system memory to use this model.\n' + + f'Please do the following:\n\n1. Restart this application.\n2. Ensure any CPU intensive applications are closed.\n3. Then try again.\n\n' + + f'Please Note: Intel Pentium and Intel Celeron processors do not work well with this application.\n\n' + + f'If the error persists, the system may not have enough RAM, or your CPU might \nnot be supported.\n\n' + + message + f'\nError Time Stamp [{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]\n') + except: + pass + torch.cuda.empty_cache() + progress_var.set(0) + button_widget.configure(state=tk.NORMAL) # Enable Button + return + + if model_adv_set_err in message: + text_widget.write("\n" + base_text + f'Separation failed for the following audio file:\n') + text_widget.write(base_text + f'"{os.path.basename(music_file)}"\n') + text_widget.write(f'\nError Received:\n\n') + text_widget.write(f'The current ONNX model settings are not compatible with the selected \nmodel.\n\n') + text_widget.write(f'Please re-configure the advanced ONNX model settings accordingly and try \nagain.\n\n') + text_widget.write(f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}') + try: + with open('errorlog.txt', 'w') as f: + f.write(f'Last Error Received:\n\n' + + f'Error Received while processing "{os.path.basename(music_file)}":\n' + + f'Process Method: Demucs v3\n\n' + + f'The current ONNX model settings are not compatible with the selected model.\n\n' + + f'Please re-configure the advanced ONNX model settings accordingly and try again.\n\n' + + message + f'\nError Time Stamp [{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]\n') + except: + pass + torch.cuda.empty_cache() + progress_var.set(0) + button_widget.configure(state=tk.NORMAL) # Enable Button + return + + + print(traceback_text) + print(type(e).__name__, e) + print(message) + + try: + with open('errorlog.txt', 'w') as f: + f.write(f'Last Error Received:\n\n' + + f'Error Received while processing "{os.path.basename(music_file)}":\n' + + f'Process Method: Demucs v3\n\n' + + f'If this error persists, please contact the developers with the error details.\n\n' + + message + f'\nError Time Stamp [{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]\n') + except: + tk.messagebox.showerror(master=window, + title='Error Details', + message=message) + progress_var.set(0) + text_widget.write("\n" + base_text + f'Separation failed for the following audio file:\n') + text_widget.write(base_text + f'"{os.path.basename(music_file)}"\n') + text_widget.write(f'\nError Received:\n') + text_widget.write("\nFor raw error details, go to the Error Log tab in the Help Guide.\n") + text_widget.write("\n" + f'Please address the error and try again.' + "\n") + text_widget.write(f'If this error persists, please contact the developers with the error details.\n\n') + text_widget.write(f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}') + try: + torch.cuda.empty_cache() + except: + pass + button_widget.configure(state=tk.NORMAL) # Enable Button + return + + progress_var.set(0) + + text_widget.write(f'\nConversion(s) Completed!\n') + + text_widget.write(f'Time Elapsed: {time.strftime("%H:%M:%S", time.gmtime(int(time.perf_counter() - stime)))}') # nopep8 + torch.cuda.empty_cache() + button_widget.configure(state=tk.NORMAL) # Enable Button + +if __name__ == '__main__': + start_time = time.time() + main() + print("Successfully completed music demixing.");print('Total time: {0:.{1}f}s'.format(time.time() - start_time, 1)) + diff --git a/inference_v5.py b/inference_v5.py index e112490..338060d 100644 --- a/inference_v5.py +++ b/inference_v5.py @@ -1,7 +1,5 @@ -from functools import total_ordering import os import importlib -from statistics import mode import pydub import shutil import hashlib @@ -1006,7 +1004,7 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress with open('errorlog.txt', 'w') as f: f.write(f'Last Error Received:\n\n' + f'Error Received while processing "{os.path.basename(music_file)}":\n' + - f'Process Method: Ensemble Mode\n\n' + + f'Process Method: VR Architecture\n\n' + f'Could not write audio file.\n' + f'This could be due to low storage on target device or a system permissions issue.\n' + f'If the error persists, please contact the developers.\n\n' + @@ -1031,7 +1029,7 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress with open('errorlog.txt', 'w') as f: f.write(f'Last Error Received:\n\n' + f'Error Received while processing "{os.path.basename(music_file)}":\n' + - f'Process Method: Ensemble Mode\n\n' + + f'Process Method: VR Architecture\n\n' + f'The application was unable to allocate enough system memory to use this model.\n' + f'Please do the following:\n\n1. Restart this application.\n2. Ensure any CPU intensive applications are closed.\n3. Then try again.\n\n' + f'Please Note: Intel Pentium and Intel Celeron processors do not work well with this application.\n\n' + diff --git a/inference_v5_ensemble.py b/inference_v5_ensemble.py index 529d9f2..60a882c 100644 --- a/inference_v5_ensemble.py +++ b/inference_v5_ensemble.py @@ -11,8 +11,10 @@ import subprocess import soundfile as sf import torch import numpy as np -from demucs.model import Demucs -from demucs.utils import apply_model +from demucs.pretrained import get_model as _gm +from demucs.hdemucs import HDemucs +from demucs.apply import BagOfModels, apply_model +import pathlib from models import get_models, spec_effects import onnxruntime as ort import time @@ -47,32 +49,36 @@ class Predictor(): def __init__(self): pass - def prediction_setup(self, demucs_name, - channels=64): + def prediction_setup(self): global device - print('Print the gpu setting: ', data['gpu']) - if data['gpu'] >= 0: - device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') + device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') if data['gpu'] == -1: device = torch.device('cpu') - if data['demucsmodel']: - self.demucs = Demucs(sources=["drums", "bass", "other", "vocals"], channels=channels) + if demucs_switch == 'on': + if 'UVR' in demucs_model_set: + self.demucs = HDemucs(sources=["other", "vocals"]) + else: + self.demucs = HDemucs(sources=["drums", "bass", "other", "vocals"]) widget_text.write(base_text + 'Loading Demucs model... ') update_progress(**progress_kwargs, step=0.05) + path_d = Path('models/Demucs_Models') + self.demucs = _gm(name=demucs_model_set, repo=path_d) self.demucs.to(device) - self.demucs.load_state_dict(torch.load(demucs_name)) - widget_text.write('Done!\n') self.demucs.eval() + widget_text.write('Done!\n') + if isinstance(self.demucs, BagOfModels): + widget_text.write(base_text + f"Selected Demucs model is a bag of {len(self.demucs.models)} model(s).\n") + self.onnx_models = {} c = 0 self.models = get_models('tdf_extra', load=False, device=cpu, stems=modeltype, n_fft_scale=n_fft_scale_set, dim_f=dim_f_set) - if not data['demucs_only']: + if demucs_only == 'off': widget_text.write(base_text + 'Loading ONNX model... ') update_progress(**progress_kwargs, @@ -88,24 +94,26 @@ class Predictor(): run_type = ['CPUExecutionProvider'] elif data['gpu'] == -1: run_type = ['CPUExecutionProvider'] - - print(run_type) - print(str(device)) - print('model_set: ', model_set) - self.onnx_models[c] = ort.InferenceSession(os.path.join('models/MDX_Net_Models', model_set), providers=run_type) - - if not data['demucs_only']: + if demucs_only == 'off': + self.onnx_models[c] = ort.InferenceSession(os.path.join('models/MDX_Net_Models', model_set), providers=run_type) + print(demucs_model_set) widget_text.write('Done!\n') + elif demucs_only == 'on': + print(demucs_model_set) + pass def prediction(self, m): - #mix, rate = sf.read(m) - mix, rate = librosa.load(m, mono=False, sr=44100) + + mix, samplerate = librosa.load(m, mono=False, sr=44100) if mix.ndim == 1: mix = np.asfortranarray([mix,mix]) + samplerate = samplerate + mix = mix.T sources = self.demix(mix.T) widget_text.write(base_text + 'Inferences complete!\n') + c = -1 #Main Save Path @@ -154,20 +162,22 @@ class Predictor(): else: file_exists = 'not_there' + if demucs_only == 'on': + data['noisereduc_s'] == 'None' + if not data['noisereduc_s'] == 'None': c += 1 - if not data['demucsmodel']: + if demucs_switch == 'off': if data['inst_only'] and not data['voc_only']: widget_text.write(base_text + 'Preparing to save Instrumental...') else: widget_text.write(base_text + 'Saving vocals... ') - sf.write(non_reduced_vocal_path, sources[c].T, rate) + sf.write(non_reduced_vocal_path, sources[c].T, samplerate) update_progress(**progress_kwargs, step=(0.9)) widget_text.write('Done!\n') widget_text.write(base_text + 'Performing Noise Reduction... ') reduction_sen = float(int(data['noisereduc_s'])/10) - print(noise_pro_set) subprocess.call("lib_v5\\sox\\sox.exe" + ' "' + f"{str(non_reduced_vocal_path)}" + '" "' + f"{str(vocal_path)}" + '" ' + "noisered lib_v5\\sox\\" + noise_pro_set + ".prof " + f"{reduction_sen}", @@ -181,31 +191,49 @@ class Predictor(): widget_text.write(base_text + 'Preparing Instrumental...') else: widget_text.write(base_text + 'Saving Vocals... ') - sf.write(non_reduced_vocal_path, sources[3].T, rate) - update_progress(**progress_kwargs, - step=(0.9)) - widget_text.write('Done!\n') - widget_text.write(base_text + 'Performing Noise Reduction... ') - reduction_sen = float(data['noisereduc_s'])/10 - subprocess.call("lib_v5\\sox\\sox.exe" + ' "' + - f"{str(non_reduced_vocal_path)}" + '" "' + f"{str(vocal_path)}" + '" ' + - "noisered lib_v5\\sox\\" + noise_pro_set + ".prof " + f"{reduction_sen}", - shell=True, stdout=subprocess.PIPE, - stdin=subprocess.PIPE, stderr=subprocess.PIPE) - update_progress(**progress_kwargs, - step=(0.95)) - widget_text.write('Done!\n') + if demucs_only == 'on': + if 'UVR' in model_set_name: + sf.write(vocal_path, sources[1].T, samplerate) + update_progress(**progress_kwargs, + step=(0.95)) + widget_text.write('Done!\n') + if 'extra' in model_set_name: + sf.write(vocal_path, sources[3].T, samplerate) + update_progress(**progress_kwargs, + step=(0.95)) + widget_text.write('Done!\n') + else: + sf.write(non_reduced_vocal_path, sources[3].T, samplerate) + update_progress(**progress_kwargs, + step=(0.9)) + widget_text.write('Done!\n') + widget_text.write(base_text + 'Performing Noise Reduction... ') + reduction_sen = float(data['noisereduc_s'])/10 + subprocess.call("lib_v5\\sox\\sox.exe" + ' "' + + f"{str(non_reduced_vocal_path)}" + '" "' + f"{str(vocal_path)}" + '" ' + + "noisered lib_v5\\sox\\" + noise_pro_set + ".prof " + f"{reduction_sen}", + shell=True, stdout=subprocess.PIPE, + stdin=subprocess.PIPE, stderr=subprocess.PIPE) + update_progress(**progress_kwargs, + step=(0.95)) + widget_text.write('Done!\n') else: c += 1 - if not data['demucsmodel']: + if demucs_switch == 'off': widget_text.write(base_text + 'Saving Vocals..') - sf.write(vocal_path, sources[c].T, rate) + sf.write(vocal_path, sources[c].T, samplerate) update_progress(**progress_kwargs, step=(0.9)) widget_text.write('Done!\n') else: widget_text.write(base_text + 'Saving Vocals... ') - sf.write(vocal_path, sources[3].T, rate) + if demucs_only == 'on': + if 'UVR' in model_set_name: + sf.write(vocal_path, sources[1].T, samplerate) + if 'extra' in model_set_name: + sf.write(vocal_path, sources[3].T, samplerate) + else: + sf.write(vocal_path, sources[3].T, samplerate) update_progress(**progress_kwargs, step=(0.9)) widget_text.write('Done!\n') @@ -355,23 +383,36 @@ class Predictor(): segmented_mix[skip] = mix[:,start:end].copy() if end == samples: break + - if not data['demucsmodel']: + if demucs_switch == 'off': sources = self.demix_base(segmented_mix, margin_size=margin) - elif data['demucs_only']: - sources = self.demix_demucs(segmented_mix, margin_size=margin) + elif demucs_only == 'on': + if split_mode == True: + sources = self.demix_demucs_split(mix) + if split_mode == False: + sources = self.demix_demucs(segmented_mix, margin_size=margin) else: # both, apply spec effects base_out = self.demix_base(segmented_mix, margin_size=margin) - demucs_out = self.demix_demucs(segmented_mix, margin_size=margin) + if split_mode == True: + demucs_out = self.demix_demucs_split(mix) + if split_mode == False: + demucs_out = self.demix_demucs(segmented_mix, margin_size=margin) nan_count = np.count_nonzero(np.isnan(demucs_out)) + np.count_nonzero(np.isnan(base_out)) if nan_count > 0: print('Warning: there are {} nan values in the array(s).'.format(nan_count)) demucs_out, base_out = np.nan_to_num(demucs_out), np.nan_to_num(base_out) sources = {} - sources[3] = (spec_effects(wave=[demucs_out[3],base_out[0]], - algorithm=data['mixing'], - value=b[3])*float(data['compensate'])) # compensation + if 'UVR' in demucs_model_set: + sources[3] = (spec_effects(wave=[demucs_out[1],base_out[0]], + algorithm=data['mixing'], + value=b[3])*float(data['compensate'])) # compensation + else: + sources[3] = (spec_effects(wave=[demucs_out[3],base_out[0]], + algorithm=data['mixing'], + value=b[3])*float(data['compensate'])) # compensation + return sources def demix_base(self, mixes, margin_size): @@ -384,7 +425,7 @@ class Predictor(): print(' Running ONNX Inference...') for mix in mixes: gui_progress_bar_onnx += 1 - if data['demucsmodel']: + if demucs_switch == 'on': update_progress(**progress_kwargs, step=(0.1 + (0.5/onnxitera_calc * gui_progress_bar_onnx))) else: @@ -430,13 +471,18 @@ class Predictor(): return _sources def demix_demucs(self, mix, margin_size): + print('shift_set ', shift_set) processed = {} demucsitera = len(mix) demucsitera_calc = demucsitera * 2 gui_progress_bar_demucs = 0 + + widget_text.write(base_text + "Split Mode is off. (Chunks enabled for Demucs Model)\n") + widget_text.write(base_text + "Running Demucs Inference...\n") widget_text.write(base_text + "Processing "f"{len(mix)} slices... ") - print(' Running Demucs Inference...') + print('Running Demucs Inference...') + for nmix in mix: gui_progress_bar_demucs += 1 update_progress(**progress_kwargs, @@ -446,7 +492,7 @@ class Predictor(): ref = cmix.mean(0) cmix = (cmix - ref.mean()) / ref.std() with torch.no_grad(): - sources = apply_model(self.demucs, cmix.to(device), split=True, overlap=overlap_set, shifts=shift_set) + sources = apply_model(self.demucs, cmix[None], split=split_mode, device=device, overlap=overlap_set, shifts=shift_set, progress=False)[0] sources = (sources * ref.std() + ref.mean()).cpu().numpy() sources[[0,1]] = sources[[1,0]] @@ -461,6 +507,26 @@ class Predictor(): widget_text.write('Done!\n') return sources + def demix_demucs_split(self, mix): + + print('shift_set ', shift_set) + widget_text.write(base_text + "Split Mode is on. (Chunks disabled for Demucs Model)\n") + widget_text.write(base_text + "Running Demucs Inference...\n") + widget_text.write(base_text + "Processing "f"{len(mix)} slices... ") + print(' Running Demucs Inference...') + + mix = torch.tensor(mix, dtype=torch.float32) + ref = mix.mean(0) + mix = (mix - ref.mean()) / ref.std() + + with torch.no_grad(): + sources = apply_model(self.demucs, mix[None], split=split_mode, device=device, overlap=overlap_set, shifts=shift_set, progress=False)[0] + + widget_text.write('Done!\n') + + sources = (sources * ref.std() + ref.mean()).cpu().numpy() + sources[[0,1]] = sources[[1,0]] + return sources def update_progress(progress_var, total_files, file_num, step: float = 1): """Calculate the progress for the progress widget in the GUI""" @@ -567,7 +633,7 @@ data = { 'chunks': 'auto', 'non_red': False, 'noisereduc_s': 3, - 'ensChoose': 'Basic Ensemble', + 'ensChoose': 'Basic VR Ensemble', 'algo': 'Instrumentals (Min Spec)', #Advanced Options 'appendensem': False, @@ -575,11 +641,11 @@ data = { 'overlap': 0.5, 'shifts': 0, 'margin': 44100, - 'channel': 64, + 'split_mode': False, 'compensate': 1.03597672895, 'demucs_only': False, 'mixing': 'Default', - 'DemucsModel': 'demucs_extra-3646af93_org.th', + 'DemucsModel_MDX': 'UVR_Demucs_Model_1', # Models 'instrumentalModel': None, @@ -627,17 +693,21 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress global ModelName_2 global mdx_model_hash + global demucs_model_set + global channel_set global margin_set global overlap_set global shift_set global noise_pro_set - - global n_fft_scale_set global dim_f_set + global split_mode + global demucs_switch + global demucs_only + # Update default settings default_chunks = data['chunks'] default_noisereduc_s = data['noisereduc_s'] @@ -665,12 +735,6 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress f'\nLast Conversion Time Stamp: [{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]\n') except: pass - - - overlap_set = float(data['overlap']) - channel_set = int(data['channel']) - margin_set = int(data['margin']) - shift_set = int(data['shifts']) n_fft_scale_set=6144 dim_f_set=2048 @@ -770,7 +834,26 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress # Separation Preperation try: #Ensemble Dictionary - if not data['ensChoose'] == 'User Ensemble': + overlap_set = float(data['overlap']) + channel_set = int(data['channel']) + margin_set = int(data['margin']) + shift_set = int(data['shifts']) + demucs_model_set = data['DemucsModel_MDX'] + split_mode = data['split_mode'] + demucs_switch = data['demucsmodel'] + + if data['demucsmodel']: + demucs_switch = 'on' + else: + demucs_switch = 'off' + + if data['demucs_only']: + demucs_only = 'on' + else: + demucs_only = 'off' + + + if not data['ensChoose'] == 'Manual Ensemble': #1st Model @@ -1219,40 +1302,35 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress else: vr_ensem_mdx_c_name = data['vr_ensem_mdx_c'] vr_ensem_mdx_c = f'models/Main_Models/{vr_ensem_mdx_c_name}.pth' - - - - + #MDX-Net Model - try: - if data['mdx_ensem'] == 'UVR-MDX-NET 1': - mdx_ensem = 'UVR_MDXNET_1_9703' - if data['mdx_ensem'] == 'UVR-MDX-NET 2': - mdx_ensem = 'UVR_MDXNET_2_9682' - if data['mdx_ensem'] == 'UVR-MDX-NET 3': - mdx_ensem = 'UVR_MDXNET_3_9662' - if data['mdx_ensem'] == 'UVR-MDX-NET Karaoke': - mdx_ensem = 'UVR_MDXNET_KARA' - - MDXModelName=('models/MDX_Net_Models/' + mdx_ensem + '.onnx') - mdx_model_hash = hashlib.md5(open(MDXModelName, 'rb').read()).hexdigest() - print(mdx_ensem) - except: - if data['mdx_ensem'] == 'UVR-MDX-NET 1': - mdx_ensem = 'UVR_MDXNET_9703' - if data['mdx_ensem'] == 'UVR-MDX-NET 2': - mdx_ensem = 'UVR_MDXNET_9682' - if data['mdx_ensem'] == 'UVR-MDX-NET 3': - mdx_ensem = 'UVR_MDXNET_9662' - if data['mdx_ensem'] == 'UVR-MDX-NET Karaoke': - mdx_ensem = 'UVR_MDXNET_KARA' - - MDXModelName=('models/MDX_Net_Models/' + mdx_ensem + '.onnx') - mdx_model_hash = hashlib.md5(open(MDXModelName, 'rb').read()).hexdigest() - print(mdx_model_hash) - print(mdx_ensem) - + if data['mdx_ensem'] == 'UVR-MDX-NET 1': + if os.path.isfile('models/MDX_Net_Models/UVR_MDXNET_1_9703.onnx'): + mdx_ensem = 'UVR_MDXNET_1_9703' + else: + mdx_ensem = 'UVR_MDXNET_9703' + if data['mdx_ensem'] == 'UVR-MDX-NET 2': + if os.path.isfile('models/MDX_Net_Models/UVR_MDXNET_2_9682.onnx'): + mdx_ensem = 'UVR_MDXNET_2_9682' + else: + mdx_ensem = 'UVR_MDXNET_9682' + if data['mdx_ensem'] == 'UVR-MDX-NET 3': + if os.path.isfile('models/MDX_Net_Models/UVR_MDXNET_3_9662.onnx'): + mdx_ensem = 'UVR_MDXNET_3_9662' + else: + mdx_ensem = 'UVR_MDXNET_9662' + if data['mdx_ensem'] == 'UVR-MDX-NET Karaoke': + mdx_ensem = 'UVR_MDXNET_KARA' + if data['mdx_ensem'] == 'Demucs UVR Model 1': + mdx_ensem = 'UVR_Demucs_Model_1' + if data['mdx_ensem'] == 'Demucs UVR Model 2': + mdx_ensem = 'UVR_Demucs_Model_2' + if data['mdx_ensem'] == 'Demucs mdx_extra': + mdx_ensem = 'mdx_extra' + if data['mdx_ensem'] == 'Demucs mdx_extra_q': + mdx_ensem = 'mdx_extra_q' + #MDX-Net Model 2 if data['mdx_ensem_b'] == 'UVR-MDX-NET 1': @@ -1263,6 +1341,14 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress mdx_ensem_b = 'UVR_MDXNET_3_9662' if data['mdx_ensem_b'] == 'UVR-MDX-NET Karaoke': mdx_ensem_b = 'UVR_MDXNET_KARA' + if data['mdx_ensem_b'] == 'Demucs UVR Model 1': + mdx_ensem_b = 'UVR_Demucs_Model_1' + if data['mdx_ensem_b'] == 'Demucs UVR Model 2': + mdx_ensem_b = 'UVR_Demucs_Model_2' + if data['mdx_ensem_b'] == 'Demucs mdx_extra': + mdx_ensem_b = 'mdx_extra' + if data['mdx_ensem_b'] == 'Demucs mdx_extra_q': + mdx_ensem_b = 'mdx_extra_q' if data['mdx_ensem_b'] == 'No Model': mdx_ensem_b = 'pass' @@ -1456,7 +1542,7 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress } ] - if data['ensChoose'] == 'Basic Ensemble': + if data['ensChoose'] == 'Basic VR Ensemble': loops = Basic_Ensem ensefolder = 'Basic_Ensemble_Outputs' if data['vr_ensem_c'] == 'No Model' and data['vr_ensem_d'] == 'No Model' and data['vr_ensem_e'] == 'No Model': @@ -1487,7 +1573,7 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress loops = Vocal_Models ensefolder = 'Vocal_Models_Ensemble_Outputs' ensemode = 'Vocal_Models' - if data['ensChoose'] == 'MDX-Net/VR Ensemble': + if data['ensChoose'] == 'Multi-AI Ensemble': loops = mdx_vr ensefolder = 'MDX_VR_Ensemble_Outputs' if data['vr_ensem'] == 'No Model' and data['vr_ensem_mdx_a'] == 'No Model' and data['vr_ensem_mdx_b'] == 'No Model' and data['vr_ensem_mdx_c'] == 'No Model': @@ -1511,7 +1597,6 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress #Prepare Audiofile(s) for file_num, music_file in enumerate(data['input_paths'], start=1): - print(data['input_paths']) # -Get text and update progress- base_text = get_baseText(total_files=len(data['input_paths']), file_num=file_num) @@ -1609,9 +1694,9 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress presentmodel = Path(c['model_location']) if presentmodel.is_file(): - print(f'The file {presentmodel} exist') + print(f'The file {presentmodel} exists') else: - if data['ensChoose'] == 'MDX-Net/VR Ensemble': + if data['ensChoose'] == 'Multi-AI Ensemble': text_widget.write(base_text + 'Model "' + c['model_name'] + '.pth" is missing.\n') text_widget.write(base_text + 'Installation of v5 Model Expansion Pack required to use this model.\n') text_widget.write(base_text + f'If the error persists, please verify all models are present.\n\n') @@ -1963,7 +2048,7 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress text_widget.write(base_text + 'Completed Seperation!\n\n') - if data['ensChoose'] == 'MDX-Net/VR Ensemble': + if data['ensChoose'] == 'Multi-AI Ensemble': mdx_name = c['mdx_model_name'] @@ -1973,46 +2058,77 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress text_widget.write('Ensemble Mode - Running Model - ' + mdx_name + '\n\n') if mdx_name == 'UVR_MDXNET_1_9703': + demucs_only = 'off' model_set = 'UVR_MDXNET_1_9703.onnx' model_set_name = 'UVR_MDXNET_1_9703' modeltype = 'v' + demucs_model_set = data['DemucsModel_MDX'] noise_pro = 'MDX-NET_Noise_Profile_14_kHz' if mdx_name == 'UVR_MDXNET_2_9682': + demucs_only = 'off' model_set = 'UVR_MDXNET_2_9682.onnx' model_set_name = 'UVR_MDXNET_2_9682' modeltype = 'v' noise_pro = 'MDX-NET_Noise_Profile_14_kHz' if mdx_name == 'UVR_MDXNET_3_9662': + demucs_only = 'off' model_set = 'UVR_MDXNET_3_9662.onnx' model_set_name = 'UVR_MDXNET_3_9662' modeltype = 'v' + demucs_model_set = data['DemucsModel_MDX'] noise_pro = 'MDX-NET_Noise_Profile_14_kHz' if mdx_name == 'UVR_MDXNET_KARA': + demucs_only = 'off' model_set = 'UVR_MDXNET_KARA.onnx' model_set_name = 'UVR_MDXNET_KARA' modeltype = 'v' noise_pro = 'MDX-NET_Noise_Profile_14_kHz' if mdx_name == 'UVR_MDXNET_9703': + demucs_only = 'off' model_set = 'UVR_MDXNET_9703.onnx' model_set_name = 'UVR_MDXNET_9703' modeltype = 'v' + demucs_model_set = data['DemucsModel_MDX'] noise_pro = 'MDX-NET_Noise_Profile_14_kHz' if mdx_name == 'UVR_MDXNET_9682': + demucs_only = 'off' model_set = 'UVR_MDXNET_9682.onnx' model_set_name = 'UVR_MDXNET_9682' modeltype = 'v' + demucs_model_set = data['DemucsModel_MDX'] noise_pro = 'MDX-NET_Noise_Profile_14_kHz' if mdx_name == 'UVR_MDXNET_9662': + demucs_only = 'off' model_set = 'UVR_MDXNET_9662.onnx' model_set_name = 'UVR_MDXNET_9662' modeltype = 'v' + demucs_model_set = data['DemucsModel_MDX'] noise_pro = 'MDX-NET_Noise_Profile_14_kHz' if mdx_name == 'UVR_MDXNET_KARA': + demucs_only = 'off' model_set = 'UVR_MDXNET_KARA.onnx' model_set_name = 'UVR_MDXNET_KARA' modeltype = 'v' + demucs_model_set = data['DemucsModel_MDX'] + noise_pro = 'MDX-NET_Noise_Profile_14_kHz' + if 'Demucs' in mdx_name: + demucs_only = 'on' + demucs_switch = 'on' + demucs_model_set = mdx_name + model_set = '' + model_set_name = 'UVR' + modeltype = 'v' + noise_pro = 'MDX-NET_Noise_Profile_14_kHz' + if 'extra' in mdx_name: + demucs_only = 'on' + demucs_switch = 'on' + demucs_model_set = mdx_name + model_set = '' + model_set_name = 'extra' + modeltype = 'v' noise_pro = 'MDX-NET_Noise_Profile_14_kHz' + print('demucs_only? ', demucs_only) if data['noise_pro_select'] == 'Auto Select': noise_pro_set = noise_pro @@ -2033,12 +2149,9 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress widget_text.write(base_text + 'Noise Reduction will be disabled until SoX is available.\n\n') e = os.path.join(data["export_path"]) - - demucsmodel = 'models/Demucs_Model/' + str(data['DemucsModel']) pred = Predictor() - pred.prediction_setup(demucs_name=demucsmodel, - channels=channel_set) + pred.prediction_setup() # split pred.prediction( @@ -2502,7 +2615,7 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress try: with open('errorlog.txt', 'w') as f: f.write(f'Last Error Received:\n\n' + - f'Error Received while attempting to run user ensemble:\n' + + f'Error Received while attempting to run Manual Ensemble:\n' + f'Process Method: Ensemble Mode\n\n' + f'FFmpeg might be missing or corrupted.\n\n' + f'If this error persists, please contact the developers.\n\n' + @@ -2530,7 +2643,7 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress try: with open('errorlog.txt', 'w') as f: f.write(f'Last Error Received:\n\n' + - f'Error Received while attempting to run user ensemble:\n' + + f'Error Received while attempting to run Manual Ensemble:\n' + f'Process Method: Ensemble Mode\n\n' + f'FFmpeg might be missing or corrupted.\n\n' + f'If this error persists, please contact the developers.\n\n' + @@ -2899,11 +3012,10 @@ def main(window: tk.Wm, text_widget: tk.Text, button_widget: tk.Button, progress update_progress(**progress_kwargs, step=1) - print('Done!') progress_var.set(0) - if not data['ensChoose'] == 'User Ensemble': + if not data['ensChoose'] == 'Manual Ensemble': text_widget.write(base_text + f'Conversions Completed!\n') elif data['algo'] == 'Instrumentals (Min Spec)' and len(data['input_paths']) <= 1 or data['algo'] == 'Vocals (Max Spec)' and len(data['input_paths']) <= 1: text_widget.write(base_text + f'Please select 2 or more files to use this feature and try again.\n')