2022-04-07 09:36:29 +02:00
# GUI modules
import tkinter as tk
import tkinter . ttk as ttk
import tkinter . messagebox
import tkinter . filedialog
import tkinter . font
from tkinterdnd2 import TkinterDnD , DND_FILES # Enable Drag & Drop
from datetime import datetime
# Images
from PIL import Image
from PIL import ImageTk
import pickle # Save Data
# Other Modules
import subprocess # Run python file
# Pathfinding
import pathlib
import sys
import os
import subprocess
from collections import defaultdict
# Used for live text displaying
import queue
import threading # Run the algorithm inside a thread
2022-04-15 06:41:57 +02:00
from pathlib import Path
2022-04-07 09:36:29 +02:00
import inference_v5
2022-04-15 06:41:57 +02:00
import inference_v5_ensemble
# import win32gui, win32con
2022-04-12 10:21:57 +02:00
2022-04-15 06:41:57 +02:00
# the_program_to_hide = win32gui.GetForegroundWindow()
# win32gui.ShowWindow(the_program_to_hide , win32con.SW_HIDE)
2022-04-07 09:36:29 +02:00
# Change the current working directory to the directory
# this file sits in
if getattr ( sys , ' frozen ' , False ) :
# If the application is run as a bundle, the PyInstaller bootloader
# extends the sys module by a flag frozen=True and sets the app
# path into variable _MEIPASS'.
base_path = sys . _MEIPASS
else :
base_path = os . path . dirname ( os . path . abspath ( __file__ ) )
os . chdir ( base_path ) # Change the current working directory to the base path
instrumentalModels_dir = os . path . join ( base_path , ' models ' )
banner_path = os . path . join ( base_path , ' img ' , ' UVR-banner.png ' )
2022-04-15 06:41:57 +02:00
efile_path = os . path . join ( base_path , ' img ' , ' file.png ' )
2022-04-07 09:36:29 +02:00
DEFAULT_DATA = {
' exportPath ' : ' ' ,
' inputPaths ' : [ ] ,
' gpu ' : False ,
' postprocess ' : False ,
' tta ' : False ,
2022-04-15 06:41:57 +02:00
' save ' : True ,
2022-04-07 09:36:29 +02:00
' output_image ' : False ,
' window_size ' : ' 512 ' ,
' agg ' : 10 ,
' modelFolder ' : False ,
' modelInstrumentalLabel ' : ' ' ,
2022-04-15 06:41:57 +02:00
' aiModel ' : ' Single Model ' ,
' ensChoose ' : ' HP1 Models ' ,
2022-04-07 09:36:29 +02:00
' useModel ' : ' instrumental ' ,
' lastDir ' : None ,
}
def open_image ( path : str , size : tuple = None , keep_aspect : bool = True , rotate : int = 0 ) - > ImageTk . PhotoImage :
"""
Open the image on the path and apply given settings \n
Paramaters :
path ( str ) :
Absolute path of the image
size ( tuple ) :
first value - width
second value - height
keep_aspect ( bool ) :
keep aspect ratio of image and resize
to maximum possible width and height
( maxima are given by size )
rotate ( int ) :
clockwise rotation of image
Returns ( ImageTk . PhotoImage ) :
Image of path
"""
img = Image . open ( path ) . convert ( mode = ' RGBA ' )
ratio = img . height / img . width
img = img . rotate ( angle = - rotate )
if size is not None :
size = ( int ( size [ 0 ] ) , int ( size [ 1 ] ) )
if keep_aspect :
img = img . resize ( ( size [ 0 ] , int ( size [ 0 ] * ratio ) ) , Image . ANTIALIAS )
else :
img = img . resize ( size , Image . ANTIALIAS )
return ImageTk . PhotoImage ( img )
def save_data ( data ) :
"""
Saves given data as a . pkl ( pickle ) file
Paramters :
data ( dict ) :
Dictionary containing all the necessary data to save
"""
# Open data file, create it if it does not exist
with open ( ' data.pkl ' , ' wb ' ) as data_file :
pickle . dump ( data , data_file )
def load_data ( ) - > dict :
"""
Loads saved pkl file and returns the stored data
Returns ( dict ) :
Dictionary containing all the saved data
"""
try :
with open ( ' data.pkl ' , ' rb ' ) as data_file : # Open data file
data = pickle . load ( data_file )
return data
except ( ValueError , FileNotFoundError ) :
# Data File is corrupted or not found so recreate it
save_data ( data = DEFAULT_DATA )
return load_data ( )
def drop ( event , accept_mode : str = ' files ' ) :
"""
Drag & Drop verification process
"""
path = event . data
if accept_mode == ' folder ' :
path = path . replace ( ' { ' , ' ' ) . replace ( ' } ' , ' ' )
if not os . path . isdir ( path ) :
tk . messagebox . showerror ( title = ' Invalid Folder ' ,
message = ' Your given export path is not a valid folder! ' )
return
# Set Variables
root . exportPath_var . set ( path )
elif accept_mode == ' files ' :
# Clean path text and set path to the list of paths
path = path . replace ( ' { ' , ' ' )
path = path . split ( ' } ' )
path [ - 1 ] = path [ - 1 ] . replace ( ' } ' , ' ' )
# Set Variables
root . inputPaths = path
root . update_inputPaths ( )
else :
# Invalid accept mode
return
class ThreadSafeConsole ( tk . Text ) :
"""
Text Widget which is thread safe for tkinter
"""
def __init__ ( self , master , * * options ) :
tk . Text . __init__ ( self , master , * * options )
self . queue = queue . Queue ( )
self . update_me ( )
def write ( self , line ) :
self . queue . put ( line )
def clear ( self ) :
self . queue . put ( None )
def update_me ( self ) :
self . configure ( state = tk . NORMAL )
try :
while 1 :
line = self . queue . get_nowait ( )
if line is None :
self . delete ( 1.0 , tk . END )
else :
self . insert ( tk . END , str ( line ) )
self . see ( tk . END )
self . update_idletasks ( )
except queue . Empty :
pass
self . configure ( state = tk . DISABLED )
self . after ( 100 , self . update_me )
class MainWindow ( TkinterDnD . Tk ) :
# --Constants--
# Layout
IMAGE_HEIGHT = 140
FILEPATHS_HEIGHT = 80
OPTIONS_HEIGHT = 190
CONVERSIONBUTTON_HEIGHT = 35
COMMAND_HEIGHT = 200
PROGRESS_HEIGHT = 26
PADDING = 10
COL1_ROWS = 6
2022-04-15 06:41:57 +02:00
COL2_ROWS = 6
2022-04-07 09:36:29 +02:00
COL3_ROWS = 6
def __init__ ( self ) :
# Run the __init__ method on the tk.Tk class
super ( ) . __init__ ( )
# Calculate window height
height = self . IMAGE_HEIGHT + self . FILEPATHS_HEIGHT + self . OPTIONS_HEIGHT
height + = self . CONVERSIONBUTTON_HEIGHT + self . COMMAND_HEIGHT + self . PROGRESS_HEIGHT
height + = self . PADDING * 5 # Padding
# --Window Settings--
self . title ( ' Vocal Remover ' )
# Set Geometry and Center Window
self . geometry ( ' {width} x {height} + {xpad} + {ypad} ' . format (
width = 620 ,
height = height ,
xpad = int ( self . winfo_screenwidth ( ) / 2 - 550 / 2 ) ,
ypad = int ( self . winfo_screenheight ( ) / 2 - height / 2 - 30 ) ) )
self . configure ( bg = ' #000000 ' ) # Set background color to black
self . protocol ( " WM_DELETE_WINDOW " , self . save_values )
self . resizable ( False , False )
self . update ( )
# --Variables--
self . logo_img = open_image ( path = banner_path ,
size = ( self . winfo_width ( ) , 9999 ) )
2022-04-15 06:41:57 +02:00
self . efile_img = open_image ( path = efile_path ,
2022-04-07 09:36:29 +02:00
size = ( 20 , 20 ) )
self . instrumentalLabel_to_path = defaultdict ( lambda : ' ' )
self . lastInstrumentalModels = [ ]
# -Tkinter Value Holders-
data = load_data ( )
# Paths
self . exportPath_var = tk . StringVar ( value = data [ ' exportPath ' ] )
self . inputPaths = data [ ' inputPaths ' ]
# Processing Options
self . gpuConversion_var = tk . BooleanVar ( value = data [ ' gpu ' ] )
self . postprocessing_var = tk . BooleanVar ( value = data [ ' postprocess ' ] )
self . tta_var = tk . BooleanVar ( value = data [ ' tta ' ] )
2022-04-15 06:41:57 +02:00
self . save_var = tk . BooleanVar ( value = data [ ' save ' ] )
2022-04-07 09:36:29 +02:00
self . outputImage_var = tk . BooleanVar ( value = data [ ' output_image ' ] )
# Models
self . instrumentalModel_var = tk . StringVar ( value = data [ ' modelInstrumentalLabel ' ] )
# Model Test Mode
self . modelFolder_var = tk . BooleanVar ( value = data [ ' modelFolder ' ] )
# Constants
self . winSize_var = tk . StringVar ( value = data [ ' window_size ' ] )
self . agg_var = tk . StringVar ( value = data [ ' agg ' ] )
# AI model
2022-04-15 06:41:57 +02:00
self . aiModel_var = tk . StringVar ( value = data [ ' aiModel ' ] )
self . last_aiModel = self . aiModel_var . get ( )
self . ensChoose_var = tk . StringVar ( value = data [ ' ensChoose ' ] )
self . last_ensChoose = self . ensChoose_var . get ( )
2022-04-07 09:36:29 +02:00
# Other
self . inputPathsEntry_var = tk . StringVar ( value = ' ' )
self . lastDir = data [ ' lastDir ' ] # nopep8
self . progress_var = tk . IntVar ( value = 0 )
# Font
self . font = tk . font . Font ( family = ' Microsoft JhengHei ' , size = 9 , weight = ' bold ' )
# --Widgets--
self . create_widgets ( )
self . configure_widgets ( )
self . bind_widgets ( )
self . place_widgets ( )
self . update_available_models ( )
self . update_states ( )
self . update_loop ( )
# -Widget Methods-
def create_widgets ( self ) :
""" Create window widgets """
self . title_Label = tk . Label ( master = self , bg = ' black ' ,
image = self . logo_img , compound = tk . TOP )
self . filePaths_Frame = tk . Frame ( master = self , bg = ' black ' )
self . fill_filePaths_Frame ( )
self . options_Frame = tk . Frame ( master = self , bg = ' black ' )
self . fill_options_Frame ( )
self . conversion_Button = ttk . Button ( master = self ,
text = ' Start Conversion ' ,
command = self . start_conversion )
2022-04-15 06:41:57 +02:00
self . efile_Button = ttk . Button ( master = self ,
image = self . efile_img ,
command = self . open_newModel_filedialog )
2022-04-07 09:36:29 +02:00
self . progressbar = ttk . Progressbar ( master = self ,
variable = self . progress_var )
self . command_Text = ThreadSafeConsole ( master = self ,
background = ' #a0a0a0 ' ,
borderwidth = 0 , )
self . command_Text . write ( f ' COMMAND LINE [ { datetime . now ( ) . strftime ( " % Y- % m- %d % H: % M: % S " ) } ] ' ) # nopep8
2022-04-15 06:41:57 +02:00
2022-04-07 09:36:29 +02:00
def configure_widgets ( self ) :
""" Change widget styling and appearance """
ttk . Style ( ) . configure ( ' TCheckbutton ' , background = ' black ' ,
font = self . font , foreground = ' white ' )
ttk . Style ( ) . configure ( ' TRadiobutton ' , background = ' black ' ,
font = self . font , foreground = ' white ' )
ttk . Style ( ) . configure ( ' T ' , font = self . font , foreground = ' white ' )
def bind_widgets ( self ) :
""" Bind widgets to the drag & drop mechanic """
self . filePaths_saveTo_Button . drop_target_register ( DND_FILES )
self . filePaths_saveTo_Entry . drop_target_register ( DND_FILES )
self . filePaths_musicFile_Button . drop_target_register ( DND_FILES )
self . filePaths_musicFile_Entry . drop_target_register ( DND_FILES )
self . filePaths_saveTo_Button . dnd_bind ( ' <<Drop>> ' ,
lambda e : drop ( e , accept_mode = ' folder ' ) )
self . filePaths_saveTo_Entry . dnd_bind ( ' <<Drop>> ' ,
lambda e : drop ( e , accept_mode = ' folder ' ) )
self . filePaths_musicFile_Button . dnd_bind ( ' <<Drop>> ' ,
lambda e : drop ( e , accept_mode = ' files ' ) )
self . filePaths_musicFile_Entry . dnd_bind ( ' <<Drop>> ' ,
lambda e : drop ( e , accept_mode = ' files ' ) )
def place_widgets ( self ) :
""" Place main widgets """
self . title_Label . place ( x = - 2 , y = - 2 )
self . filePaths_Frame . place ( x = 10 , y = 155 , width = - 20 , height = self . FILEPATHS_HEIGHT ,
relx = 0 , rely = 0 , relwidth = 1 , relheight = 0 )
self . options_Frame . place ( x = 25 , y = 250 , width = - 50 , height = self . OPTIONS_HEIGHT ,
relx = 0 , rely = 0 , relwidth = 1 , relheight = 0 )
self . conversion_Button . place ( x = 10 , y = self . IMAGE_HEIGHT + self . FILEPATHS_HEIGHT + self . OPTIONS_HEIGHT + self . PADDING * 2 , width = - 20 - 40 , height = self . CONVERSIONBUTTON_HEIGHT ,
relx = 0 , rely = 0 , relwidth = 1 , relheight = 0 )
2022-04-15 06:41:57 +02:00
self . efile_Button . place ( x = - 10 - 35 , y = self . IMAGE_HEIGHT + self . FILEPATHS_HEIGHT + self . OPTIONS_HEIGHT + self . PADDING * 2 , width = 35 , height = self . CONVERSIONBUTTON_HEIGHT ,
2022-04-07 09:36:29 +02:00
relx = 1 , rely = 0 , relwidth = 0 , relheight = 0 )
self . command_Text . place ( x = 15 , 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 )
self . progressbar . place ( x = 25 , y = self . IMAGE_HEIGHT + self . FILEPATHS_HEIGHT + self . OPTIONS_HEIGHT + self . CONVERSIONBUTTON_HEIGHT + self . COMMAND_HEIGHT + self . PADDING * 4 , width = - 50 , height = self . PROGRESS_HEIGHT ,
relx = 0 , rely = 0 , relwidth = 1 , relheight = 0 )
def fill_filePaths_Frame ( self ) :
""" Fill Frame with neccessary widgets """
# -Create Widgets-
# Save To Option
self . filePaths_saveTo_Button = ttk . Button ( master = self . filePaths_Frame ,
text = ' Save to ' ,
command = self . open_export_filedialog )
self . filePaths_saveTo_Entry = ttk . Entry ( master = self . filePaths_Frame ,
textvariable = self . exportPath_var ,
state = tk . DISABLED
)
# Select Music Files Option
self . filePaths_musicFile_Button = ttk . Button ( master = self . filePaths_Frame ,
text = ' Select Your Audio File(s) ' ,
command = self . open_file_filedialog )
self . filePaths_musicFile_Entry = ttk . Entry ( master = self . filePaths_Frame ,
textvariable = self . inputPathsEntry_var ,
state = tk . DISABLED
)
# -Place Widgets-
# Save To Option
self . filePaths_saveTo_Button . place ( x = 0 , y = 5 , width = 0 , height = - 10 ,
relx = 0 , rely = 0 , relwidth = 0.3 , relheight = 0.5 )
self . filePaths_saveTo_Entry . place ( x = 10 , y = 7 , width = - 20 , height = - 14 ,
relx = 0.3 , rely = 0 , relwidth = 0.7 , relheight = 0.5 )
# Select Music Files Option
self . filePaths_musicFile_Button . place ( x = 0 , y = 5 , width = 0 , height = - 10 ,
relx = 0 , rely = 0.5 , relwidth = 0.4 , relheight = 0.5 )
self . filePaths_musicFile_Entry . place ( x = 10 , y = 7 , width = - 20 , height = - 14 ,
relx = 0.4 , rely = 0.5 , relwidth = 0.6 , relheight = 0.5 )
def fill_options_Frame ( self ) :
""" Fill Frame with neccessary widgets """
# -Create Widgets-
# -Column 1-
# GPU Selection
self . options_gpu_Checkbutton = ttk . Checkbutton ( master = self . options_Frame ,
text = ' GPU Conversion ' ,
variable = self . gpuConversion_var ,
)
# Postprocessing
self . options_post_Checkbutton = ttk . Checkbutton ( master = self . options_Frame ,
text = ' Post-Process ' ,
variable = self . postprocessing_var ,
)
# TTA
self . options_tta_Checkbutton = ttk . Checkbutton ( master = self . options_Frame ,
text = ' TTA ' ,
variable = self . tta_var ,
)
2022-04-15 06:41:57 +02:00
# Save Ensemble Outputs
self . options_save_Checkbutton = ttk . Checkbutton ( master = self . options_Frame ,
text = ' Save All Outputs ' ,
variable = self . save_var ,
)
2022-04-07 09:36:29 +02:00
# Save Image
self . options_image_Checkbutton = ttk . Checkbutton ( master = self . options_Frame ,
text = ' Output Image ' ,
variable = self . outputImage_var ,
)
2022-04-15 06:41:57 +02:00
# Model Test Mode
2022-04-07 09:36:29 +02:00
self . options_modelFolder_Checkbutton = ttk . Checkbutton ( master = self . options_Frame ,
text = ' Model Test Mode ' ,
variable = self . modelFolder_var ,
)
# -Column 2-
# WINDOW SIZE
self . options_winSize_Label = tk . Label ( master = self . options_Frame ,
text = ' Window Size ' , anchor = tk . CENTER ,
background = ' #404040 ' , font = self . font , foreground = ' white ' , relief = " groove " )
self . options_winSize_Optionmenu = ttk . OptionMenu ( self . options_Frame ,
self . winSize_var ,
None , ' 320 ' , ' 512 ' , ' 1024 ' )
# AGG
self . options_agg_Entry = ttk . Entry ( master = self . options_Frame ,
textvariable = self . agg_var , justify = ' center ' )
self . options_agg_Label = tk . Label ( master = self . options_Frame ,
text = ' Aggression Setting ' ,
background = ' #404040 ' , font = self . font , foreground = ' white ' , relief = " groove " )
# AI model
2022-04-15 06:41:57 +02:00
self . options_aiModel_Label = tk . Label ( master = self . options_Frame ,
text = ' Choose Conversion Method ' , anchor = tk . CENTER ,
background = ' #404040 ' , font = self . font , foreground = ' white ' , relief = " groove " )
self . options_aiModel_Optionmenu = ttk . OptionMenu ( self . options_Frame ,
self . aiModel_var ,
None , ' Single Model ' , ' Ensemble Mode ' )
# Ensemble Mode
self . options_ensChoose_Label = tk . Label ( master = self . options_Frame ,
text = ' Choose Ensemble ' , anchor = tk . CENTER ,
background = ' #404040 ' , font = self . font , foreground = ' white ' , relief = " groove " )
self . options_ensChoose_Optionmenu = ttk . OptionMenu ( self . options_Frame ,
self . ensChoose_var ,
None , ' HP1 Models ' , ' HP2 Models ' , ' All HP Models ' , ' Vocal Models ' )
2022-04-07 09:36:29 +02:00
# "Save to", "Select Your Audio File(s)"", and "Start Conversion" Button Style
s = ttk . Style ( )
s . configure ( ' TButton ' , background = ' blue ' , foreground = ' black ' , font = ( ' Microsoft JhengHei ' , ' 9 ' , ' bold ' ) , relief = " groove " )
# -Column 3-
# Choose Instrumental Model
self . options_instrumentalModel_Label = tk . Label ( master = self . options_Frame ,
text = ' Choose Main Model ' ,
background = ' #404040 ' , font = self . font , foreground = ' white ' , relief = " groove " )
self . options_instrumentalModel_Optionmenu = ttk . OptionMenu ( self . options_Frame ,
self . instrumentalModel_var )
2022-04-07 10:30:15 +02:00
# Add Open Export Directory Button
2022-04-15 06:41:57 +02:00
# self.options_export_Button = ttk.Button(master=self.options_Frame,
# text='Open Export Directory',
# style="Bold.TButton",
# command=self.open_newModel_filedialog)
2022-04-07 09:36:29 +02:00
# -Place Widgets-
# -Column 1-
self . options_gpu_Checkbutton . place ( x = 0 , y = 0 , width = 0 , height = 0 ,
relx = 0 , rely = 0 , relwidth = 1 / 3 , relheight = 1 / self . COL1_ROWS )
self . options_post_Checkbutton . place ( x = 0 , y = 0 , width = 0 , height = 0 ,
relx = 0 , rely = 1 / self . COL1_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL1_ROWS )
self . options_tta_Checkbutton . place ( x = 0 , y = 0 , width = 0 , height = 0 ,
relx = 0 , rely = 2 / self . COL1_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL1_ROWS )
2022-04-15 06:41:57 +02:00
self . options_save_Checkbutton . place ( x = 0 , y = 0 , width = 0 , height = 0 ,
relx = 0 , rely = 4 / self . COL1_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL1_ROWS )
2022-04-07 09:36:29 +02:00
self . options_image_Checkbutton . place ( x = 0 , y = 0 , width = 0 , height = 0 ,
relx = 0 , rely = 3 / self . COL1_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL1_ROWS )
self . options_modelFolder_Checkbutton . place ( x = 0 , y = 0 , width = 0 , height = 0 ,
relx = 0 , rely = 4 / self . COL1_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL1_ROWS )
# -Column 2-
2022-04-15 06:41:57 +02:00
2022-04-07 09:36:29 +02:00
self . options_instrumentalModel_Label . place ( x = - 15 , y = 6 , width = 0 , height = - 10 ,
2022-04-15 06:41:57 +02:00
relx = 1 / 3 , rely = 2 / self . COL2_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL2_ROWS )
2022-04-07 09:36:29 +02:00
self . options_instrumentalModel_Optionmenu . place ( x = - 15 , y = 6 , width = 0 , height = - 10 ,
2022-04-07 10:30:15 +02:00
relx = 1 / 3 , rely = 3 / self . COL2_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL2_ROWS )
2022-04-15 06:41:57 +02:00
self . options_ensChoose_Label . place ( x = - 15 , y = 6 , width = 0 , height = - 10 ,
relx = 1 / 3 , rely = 0 / self . COL2_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL2_ROWS )
self . options_ensChoose_Optionmenu . place ( x = - 15 , y = 6 , width = 0 , height = - 10 ,
relx = 1 / 3 , rely = 1 / self . COL2_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL2_ROWS )
# self.options_export_Button.place(x=0, y=0, width=-30, height=-8,
# relx=2/3, rely=4/self.COL3_ROWS, relwidth=1/3, relheight=1/self.COL3_ROWS)
2022-04-07 09:36:29 +02:00
# -Column 3-
# WINDOW
self . options_winSize_Label . place ( x = 35 , y = 6 , width = - 40 , height = - 10 ,
relx = 2 / 3 , rely = 0 , relwidth = 1 / 3 , relheight = 1 / self . COL3_ROWS )
self . options_winSize_Optionmenu . place ( x = 80 , y = 6 , width = - 133 , height = - 10 ,
relx = 2 / 3 , rely = 1 / self . COL3_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL3_ROWS )
# AGG
self . options_agg_Label . place ( x = 35 , y = 6 , width = - 40 , height = - 10 ,
relx = 2 / 3 , rely = 2 / self . COL3_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL3_ROWS )
self . options_agg_Entry . place ( x = 80 , y = 6 , width = - 133 , height = - 10 ,
relx = 2 / 3 , rely = 3 / self . COL3_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL3_ROWS )
2022-04-15 06:41:57 +02:00
# Conversion Method
self . options_aiModel_Label . place ( x = - 15 , y = 6 , width = 0 , height = - 10 ,
relx = 1 / 3 , rely = 0 / self . COL2_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL2_ROWS )
self . options_aiModel_Optionmenu . place ( x = - 15 , y = 4 , width = 0 , height = - 10 ,
relx = 1 / 3 , rely = 1 / self . COL2_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL2_ROWS )
2022-04-07 09:36:29 +02:00
# Model deselect
2022-04-15 06:41:57 +02:00
self . aiModel_var . trace_add ( ' write ' ,
lambda * args : self . deselect_models ( ) )
2022-04-07 09:36:29 +02:00
# Opening filedialogs
def open_file_filedialog ( self ) :
""" Make user select music files """
if self . lastDir is not None :
if not os . path . isdir ( self . lastDir ) :
self . lastDir = None
paths = tk . filedialog . askopenfilenames (
parent = self ,
title = f ' Select Music Files ' ,
initialfile = ' ' ,
initialdir = self . lastDir ,
)
if paths : # Path selected
self . inputPaths = paths
self . update_inputPaths ( )
self . lastDir = os . path . dirname ( paths [ 0 ] )
def open_export_filedialog ( self ) :
""" Make user select a folder to export the converted files in """
path = tk . filedialog . askdirectory (
parent = self ,
title = f ' Select Folder ' , )
if path : # Path selected
self . exportPath_var . set ( path )
def open_newModel_filedialog ( self ) :
""" Let user paste a " .pth " model to use for the vocal seperation """
filename = self . exportPath_var . get ( )
if sys . platform == " win32 " :
os . startfile ( filename )
else :
opener = " open " if sys . platform == " darwin " else " xdg-open "
subprocess . call ( [ opener , filename ] )
def start_conversion ( self ) :
"""
Start the conversion for all the given mp3 and wav files
"""
# -Get all variables-
export_path = self . exportPath_var . get ( )
input_paths = self . inputPaths
instrumentalModel_path = self . instrumentalLabel_to_path [ self . instrumentalModel_var . get ( ) ] # nopep8
# Get constants
instrumental = self . instrumentalModel_var . get ( )
try :
if [ bool ( instrumental ) ] . count ( True ) == 2 : #CHECKTHIS
window_size = DEFAULT_DATA [ ' window_size ' ]
agg = DEFAULT_DATA [ ' agg ' ]
else :
window_size = int ( self . winSize_var . get ( ) )
agg = int ( self . agg_var . get ( ) )
2022-04-15 06:41:57 +02:00
ensChoose = str ( self . ensChoose_var . get ( ) )
2022-04-07 09:36:29 +02:00
except ValueError : # Non integer was put in entry box
tk . messagebox . showwarning ( master = self ,
title = ' Invalid Input ' ,
message = ' Please make sure you only input integer numbers! ' )
return
except SyntaxError : # Non integer was put in entry box
tk . messagebox . showwarning ( master = self ,
title = ' Invalid Music File ' ,
message = ' You have selected an invalid music file! \n Please make sure that your files still exist and ends with either " .mp3 " , " .mp4 " , " .m4a " , " .flac " , " .wav " ' )
return
# -Check for invalid inputs-
for path in input_paths :
if not os . path . isfile ( path ) :
tk . messagebox . showwarning ( master = self ,
title = ' Invalid Music File ' ,
message = ' You have selected an invalid music file! Please make sure that the file still exists! ' ,
detail = f ' File path: { path } ' )
return
2022-04-15 06:41:57 +02:00
if self . aiModel_var . get ( ) == ' Single Model ' :
if not os . path . isfile ( instrumentalModel_path ) :
tk . messagebox . showwarning ( master = self ,
title = ' Invalid Main Model File ' ,
message = ' You have selected an invalid main model file! \n Please make sure that your model file still exists! ' )
return
2022-04-07 09:36:29 +02:00
if not os . path . isdir ( export_path ) :
tk . messagebox . showwarning ( master = self ,
title = ' Invalid Export Directory ' ,
message = ' You have selected an invalid export directory! \n Please make sure that your directory still exists! ' )
return
2022-04-15 06:41:57 +02:00
if self . aiModel_var . get ( ) == ' Single Model ' :
inference = inference_v5
elif self . aiModel_var . get ( ) == ' Ensemble Mode ' :
inference = inference_v5_ensemble
else :
raise TypeError ( ' This error should not occur. ' )
2022-04-07 09:36:29 +02:00
# -Run the algorithm-
threading . Thread ( target = inference . main ,
kwargs = {
# Paths
' input_paths ' : input_paths ,
' export_path ' : export_path ,
# Processing Options
' gpu ' : 0 if self . gpuConversion_var . get ( ) else - 1 ,
' postprocess ' : self . postprocessing_var . get ( ) ,
2022-04-15 06:41:57 +02:00
' tta ' : self . tta_var . get ( ) ,
' save ' : self . save_var . get ( ) ,
2022-04-07 09:36:29 +02:00
' output_image ' : self . outputImage_var . get ( ) ,
# Models
' instrumentalModel ' : instrumentalModel_path ,
' vocalModel ' : ' ' , # Always not needed
' useModel ' : ' instrumental ' , # Always instrumental
# Model Folder
' modelFolder ' : self . modelFolder_var . get ( ) ,
# Constants
' window_size ' : window_size ,
' agg ' : agg ,
2022-04-15 06:41:57 +02:00
' ensChoose ' : ensChoose ,
2022-04-07 09:36:29 +02:00
# Other Variables (Tkinter)
' window ' : self ,
' text_widget ' : self . command_Text ,
' button_widget ' : self . conversion_Button ,
2022-04-15 06:41:57 +02:00
' inst_menu ' : self . options_instrumentalModel_Optionmenu ,
2022-04-07 09:36:29 +02:00
' progress_var ' : self . progress_var ,
} ,
daemon = True
) . start ( )
# Models
def update_inputPaths ( self ) :
""" Update the music file entry """
if self . inputPaths :
# Non-empty Selection
text = ' ; ' . join ( self . inputPaths )
else :
# Empty Selection
text = ' '
self . inputPathsEntry_var . set ( text )
def update_loop ( self ) :
""" Update the dropdown menu """
self . update_available_models ( )
self . after ( 3000 , self . update_loop )
def update_available_models ( self ) :
"""
Loop through every model ( . pth ) in the models directory
and add to the select your model list
"""
#temp_instrumentalModels_dir = os.path.join(instrumentalModels_dir, self.aiModel_var.get(), 'Main Models') # nopep8
temp_instrumentalModels_dir = os . path . join ( instrumentalModels_dir , ' Main Models ' ) # nopep8
# Instrumental models
new_InstrumentalModels = os . listdir ( temp_instrumentalModels_dir )
if new_InstrumentalModels != self . lastInstrumentalModels :
self . instrumentalLabel_to_path . clear ( )
self . options_instrumentalModel_Optionmenu [ ' menu ' ] . delete ( 0 , ' end ' )
for file_name in new_InstrumentalModels :
if file_name . endswith ( ' .pth ' ) :
# Add Radiobutton to the Options Menu
self . options_instrumentalModel_Optionmenu [ ' menu ' ] . add_radiobutton ( label = file_name ,
command = tk . _setit ( self . instrumentalModel_var , file_name ) )
# Link the files name to its absolute path
self . instrumentalLabel_to_path [ file_name ] = os . path . join ( temp_instrumentalModels_dir , file_name ) # nopep8
self . lastInstrumentalModels = new_InstrumentalModels
def update_states ( self ) :
"""
Vary the states for all widgets based
on certain selections
"""
2022-04-15 06:41:57 +02:00
if self . aiModel_var . get ( ) == ' Single Model ' :
self . options_ensChoose_Label . place_forget ( )
self . options_ensChoose_Optionmenu . place_forget ( )
self . options_save_Checkbutton . configure ( state = tk . DISABLED )
self . options_save_Checkbutton . place_forget ( )
self . options_modelFolder_Checkbutton . configure ( state = tk . NORMAL )
self . options_modelFolder_Checkbutton . place ( x = 0 , y = 0 , width = 0 , height = 0 ,
relx = 0 , rely = 4 / self . COL1_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL1_ROWS )
self . options_instrumentalModel_Label . place ( x = - 15 , y = 6 , width = 0 , height = - 10 ,
relx = 1 / 3 , rely = 3 / self . COL2_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL2_ROWS )
self . options_instrumentalModel_Optionmenu . place ( x = - 15 , y = 6 , width = 0 , height = - 10 ,
relx = 1 / 3 , rely = 4 / self . COL2_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL2_ROWS )
else :
self . options_instrumentalModel_Label . place_forget ( )
self . options_instrumentalModel_Optionmenu . place_forget ( )
self . options_modelFolder_Checkbutton . place_forget ( )
self . options_modelFolder_Checkbutton . configure ( state = tk . DISABLED )
self . options_save_Checkbutton . configure ( state = tk . NORMAL )
self . options_save_Checkbutton . place ( x = 0 , y = 0 , width = 0 , height = 0 ,
relx = 0 , rely = 4 / self . COL1_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL1_ROWS )
self . options_ensChoose_Label . place ( x = - 15 , y = 6 , width = 0 , height = - 10 ,
relx = 1 / 3 , rely = 3 / self . COL2_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL2_ROWS )
self . options_ensChoose_Optionmenu . place ( x = - 15 , y = 6 , width = 0 , height = - 10 ,
relx = 1 / 3 , rely = 4 / self . COL2_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL2_ROWS )
2022-04-07 09:36:29 +02:00
2022-04-15 06:41:57 +02:00
if self . aiModel_var . get ( ) == ' Ensemble Mode ' :
self . options_instrumentalModel_Label . place_forget ( )
self . options_instrumentalModel_Optionmenu . place_forget ( )
self . options_modelFolder_Checkbutton . place_forget ( )
self . options_modelFolder_Checkbutton . configure ( state = tk . DISABLED )
self . options_save_Checkbutton . configure ( state = tk . NORMAL )
self . options_save_Checkbutton . place ( x = 0 , y = 0 , width = 0 , height = 0 ,
relx = 0 , rely = 4 / self . COL1_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL1_ROWS )
self . options_ensChoose_Label . place ( x = - 15 , y = 6 , width = 0 , height = - 10 ,
relx = 1 / 3 , rely = 3 / self . COL2_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL2_ROWS )
self . options_ensChoose_Optionmenu . place ( x = - 15 , y = 6 , width = 0 , height = - 10 ,
relx = 1 / 3 , rely = 4 / self . COL2_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL2_ROWS )
else :
self . options_ensChoose_Label . place_forget ( )
self . options_ensChoose_Optionmenu . place_forget ( )
self . options_save_Checkbutton . configure ( state = tk . DISABLED )
self . options_save_Checkbutton . place_forget ( )
self . options_modelFolder_Checkbutton . configure ( state = tk . NORMAL )
self . options_modelFolder_Checkbutton . place ( x = 0 , y = 0 , width = 0 , height = 0 ,
relx = 0 , rely = 4 / self . COL1_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL1_ROWS )
self . options_instrumentalModel_Label . place ( x = - 15 , y = 6 , width = 0 , height = - 10 ,
relx = 1 / 3 , rely = 3 / self . COL2_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL2_ROWS )
self . options_instrumentalModel_Optionmenu . place ( x = - 15 , y = 6 , width = 0 , height = - 10 ,
relx = 1 / 3 , rely = 4 / self . COL2_ROWS , relwidth = 1 / 3 , relheight = 1 / self . COL2_ROWS )
2022-04-07 09:36:29 +02:00
self . update_inputPaths ( )
def deselect_models ( self ) :
"""
Run this method on version change
"""
if self . aiModel_var . get ( ) == self . last_aiModel :
return
else :
self . last_aiModel = self . aiModel_var . get ( )
self . instrumentalModel_var . set ( ' ' )
2022-04-15 06:41:57 +02:00
self . ensChoose_var . set ( ' HP1 Models ' )
2022-04-07 09:36:29 +02:00
self . winSize_var . set ( DEFAULT_DATA [ ' window_size ' ] )
self . agg_var . set ( DEFAULT_DATA [ ' agg ' ] )
2022-04-15 06:41:57 +02:00
self . modelFolder_var . set ( DEFAULT_DATA [ ' modelFolder ' ] )
2022-04-07 09:36:29 +02:00
self . update_available_models ( )
self . update_states ( )
2022-04-15 06:41:57 +02:00
# def restart(self):
# """
# Restart the application after asking for confirmation
# """
# save = tk.messagebox.askyesno(title='Confirmation',
# message='The application will restart. Do you want to save the data?')
# if save:
# self.save_values()
# subprocess.Popen(f'..App\Python\python.exe "{__file__}"')
# exit()
2022-04-07 09:36:29 +02:00
def save_values ( self ) :
"""
Save the data of the application
"""
# Get constants
instrumental = self . instrumentalModel_var . get ( )
if [ bool ( instrumental ) ] . count ( True ) == 2 : #Checkthis
window_size = DEFAULT_DATA [ ' window_size ' ]
agg = DEFAULT_DATA [ ' agg ' ]
else :
window_size = self . winSize_var . get ( )
agg = self . agg_var . get ( )
# -Save Data-
save_data ( data = {
' exportPath ' : self . exportPath_var . get ( ) ,
' inputPaths ' : self . inputPaths ,
' gpu ' : self . gpuConversion_var . get ( ) ,
' postprocess ' : self . postprocessing_var . get ( ) ,
' tta ' : self . tta_var . get ( ) ,
2022-04-15 06:41:57 +02:00
' save ' : self . save_var . get ( ) ,
2022-04-07 09:36:29 +02:00
' output_image ' : self . outputImage_var . get ( ) ,
' window_size ' : window_size ,
' agg ' : agg ,
' useModel ' : ' instrumental ' ,
' lastDir ' : self . lastDir ,
' modelFolder ' : self . modelFolder_var . get ( ) ,
' modelInstrumentalLabel ' : self . instrumentalModel_var . get ( ) ,
2022-04-15 06:41:57 +02:00
' aiModel ' : self . aiModel_var . get ( ) ,
' ensChoose ' : self . ensChoose_var . get ( ) ,
2022-04-07 09:36:29 +02:00
} )
self . destroy ( )
if __name__ == " __main__ " :
root = MainWindow ( )
root . mainloop ( )