2022-05-11 02:11:40 +02:00
import os
from pickle import STOP
from tracemalloc import stop
from turtle import update
import subprocess
from unittest import skip
from pathlib import Path
import os . path
from datetime import datetime
import pydub
import shutil
#MDX-Net
#----------------------------------------
import soundfile as sf
import torch
import numpy as np
from demucs . model import Demucs
from demucs . utils import apply_model
from models import get_models , spec_effects
import onnxruntime as ort
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 , demucs_name ,
channels = 64 ) :
if data [ ' demucsmodel ' ] :
self . demucs = Demucs ( sources = [ " drums " , " bass " , " other " , " vocals " ] , channels = channels )
widget_text . write ( base_text + ' Loading Demucs model... ' )
update_progress ( * * progress_kwargs ,
step = 0.05 )
self . demucs . to ( device )
self . demucs . load_state_dict ( torch . load ( demucs_name ) )
widget_text . write ( ' Done! \n ' )
self . demucs . eval ( )
self . onnx_models = { }
c = 0
self . models = get_models ( ' tdf_extra ' , load = False , device = cpu , stems = ' vocals ' )
widget_text . write ( base_text + ' Loading ONNX model... ' )
update_progress ( * * progress_kwargs ,
step = 0.1 )
c + = 1
if data [ ' gpu ' ] > = 0 :
if torch . cuda . is_available ( ) :
run_type = [ ' CUDAExecutionProvider ' ]
else :
data [ ' gpu ' ] = - 1
widget_text . write ( " \n " + base_text + " No NVIDIA GPU detected. Switching to CPU... " )
run_type = [ ' CPUExecutionProvider ' ]
else :
run_type = [ ' CPUExecutionProvider ' ]
self . onnx_models [ c ] = ort . InferenceSession ( os . path . join ( ' models/MDX_Net_Models ' , model_set ) , providers = run_type )
widget_text . write ( ' Done! \n ' )
def prediction ( self , m ) :
#mix, rate = sf.read(m)
mix , rate = librosa . load ( m , mono = False , sr = 44100 )
if mix . ndim == 1 :
mix = np . asfortranarray ( [ mix , mix ] )
mix = mix . T
sources = self . demix ( mix . T )
widget_text . write ( base_text + ' Inferences complete! \n ' )
c = - 1
#Main Save Path
save_path = os . path . dirname ( _basename )
#Vocal Path
vocal_name = ' (Vocals) '
if data [ ' modelFolder ' ] :
vocal_path = ' {save_path} / {file_name} .wav ' . format (
save_path = save_path ,
file_name = f ' { os . path . basename ( _basename ) } _ { vocal_name } _ { model_set_name } ' , )
vocal_path_mp3 = ' {save_path} / {file_name} .mp3 ' . format (
save_path = save_path ,
file_name = f ' { os . path . basename ( _basename ) } _ { vocal_name } _ { model_set_name } ' , )
vocal_path_flac = ' {save_path} / {file_name} .flac ' . format (
save_path = save_path ,
file_name = f ' { os . path . basename ( _basename ) } _ { vocal_name } _ { model_set_name } ' , )
else :
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
Instrumental_name = ' (Instrumental) '
if data [ ' modelFolder ' ] :
Instrumental_path = ' {save_path} / {file_name} .wav ' . format (
save_path = save_path ,
file_name = f ' { os . path . basename ( _basename ) } _ { Instrumental_name } _ { model_set_name } ' , )
Instrumental_path_mp3 = ' {save_path} / {file_name} .mp3 ' . format (
save_path = save_path ,
file_name = f ' { os . path . basename ( _basename ) } _ { Instrumental_name } _ { model_set_name } ' , )
Instrumental_path_flac = ' {save_path} / {file_name} .flac ' . format (
save_path = save_path ,
file_name = f ' { os . path . basename ( _basename ) } _ { Instrumental_name } _ { model_set_name } ' , )
else :
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 } ' , )
#Non-Reduced Vocal Path
vocal_name = ' (Vocals) '
if data [ ' modelFolder ' ] :
non_reduced_vocal_path = ' {save_path} / {file_name} .wav ' . format (
save_path = save_path ,
file_name = f ' { os . path . basename ( _basename ) } _ { vocal_name } _ { model_set_name } _No_Reduction ' , )
non_reduced_vocal_path_mp3 = ' {save_path} / {file_name} .mp3 ' . format (
save_path = save_path ,
file_name = f ' { os . path . basename ( _basename ) } _ { vocal_name } _ { model_set_name } _No_Reduction ' , )
non_reduced_vocal_path_flac = ' {save_path} / {file_name} .flac ' . format (
save_path = save_path ,
file_name = f ' { os . path . basename ( _basename ) } _ { vocal_name } _ { model_set_name } _No_Reduction ' , )
else :
non_reduced_vocal_path = ' {save_path} / {file_name} .wav ' . format (
save_path = save_path ,
file_name = f ' { os . path . basename ( _basename ) } _ { vocal_name } _No_Reduction ' , )
non_reduced_vocal_path_mp3 = ' {save_path} / {file_name} .mp3 ' . format (
save_path = save_path ,
file_name = f ' { os . path . basename ( _basename ) } _ { vocal_name } _No_Reduction ' , )
non_reduced_vocal_path_flac = ' {save_path} / {file_name} .flac ' . format (
save_path = save_path ,
file_name = f ' { os . path . basename ( _basename ) } _ { vocal_name } _No_Reduction ' , )
if os . path . isfile ( non_reduced_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 '
print ( ' Is there already a voc file there? ' , file_exists_v )
if not data [ ' noisereduc_s ' ] == ' None ' :
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 )
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 )
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 } " ,
shell = True , stdout = subprocess . PIPE ,
stdin = subprocess . PIPE , stderr = subprocess . PIPE )
widget_text . write ( ' Done! \n ' )
update_progress ( * * progress_kwargs ,
step = ( 0.95 ) )
else :
if data [ ' inst_only ' ] :
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 ( 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 } " ,
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 data [ ' inst_only ' ] :
widget_text . write ( base_text + ' Preparing Instrumental... ' )
else :
widget_text . write ( base_text + ' Saving Vocals... ' )
sf . write ( vocal_path , sources [ c ] . T , rate )
update_progress ( * * progress_kwargs ,
step = ( 0.9 ) )
widget_text . write ( ' Done! \n ' )
else :
if data [ ' inst_only ' ] :
widget_text . write ( base_text + ' Preparing Instrumental... ' )
else :
widget_text . write ( base_text + ' Saving Vocals... ' )
sf . write ( vocal_path , sources [ 3 ] . T , rate )
update_progress ( * * progress_kwargs ,
step = ( 0.9 ) )
widget_text . write ( ' Done! \n ' )
if data [ ' voc_only ' ] and not data [ ' inst_only ' ] :
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 ' ] :
if file_exists_v == ' there ' :
pass
else :
try :
os . remove ( vocal_path )
except :
pass
widget_text . write ( ' Done! \n ' )
if data [ ' saveFormat ' ] == ' Mp3 ' :
try :
if data [ ' inst_only ' ] == 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 ' ] == 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
if data [ ' non_red ' ] == True :
musfile = pydub . AudioSegment . from_wav ( non_reduced_vocal_path )
musfile . export ( non_reduced_vocal_path_mp3 , format = " mp3 " , bitrate = " 320k " )
if file_exists_n == ' there ' :
pass
else :
try :
os . remove ( non_reduced_vocal_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: MDX-Net \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 ' \n Error Time Stamp: [ { datetime . now ( ) . strftime ( " % Y- % m- %d % H: % M: % S " ) } ] \n ' )
except :
pass
if data [ ' saveFormat ' ] == ' Flac ' :
try :
if data [ ' inst_only ' ] == 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 ' ] == 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
if data [ ' non_red ' ] == True :
musfile = pydub . AudioSegment . from_wav ( non_reduced_vocal_path )
musfile . export ( non_reduced_vocal_path_flac , format = " flac " )
if file_exists_n == ' there ' :
pass
else :
try :
os . remove ( non_reduced_vocal_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: MDX-Net \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 ' \n Error 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
elif data [ ' non_red ' ] == True :
pass
elif data [ ' inst_only ' ] :
if file_exists_n == ' there ' :
pass
else :
try :
os . remove ( non_reduced_vocal_path )
except :
pass
else :
try :
os . remove ( non_reduced_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 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 ( 5 ) :
chunk_set = int ( 5 )
widget_text . write ( base_text + ' Chunk size auto-set to 5... \n ' )
if gpu_mem in [ 6 , 7 ] :
chunk_set = int ( 30 )
widget_text . write ( base_text + ' Chunk size auto-set to 30... \n ' )
if gpu_mem in [ 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 ] :
chunk_set = int ( 40 )
widget_text . write ( base_text + ' Chunk size auto-set to 40... \n ' )
if int ( gpu_mem ) > = int ( 16 ) :
chunk_set = int ( 60 )
widget_text . write ( base_text + ' Chunk size auto-set to 60... \n ' )
if data [ ' gpu ' ] == - 1 :
sys_mem = psutil . virtual_memory ( ) . total >> 30
if int ( sys_mem ) < = int ( 4 ) :
chunk_set = int ( 1 )
widget_text . write ( base_text + ' Chunk size auto-set to 1... \n ' )
if sys_mem in [ 5 , 6 , 7 , 8 ] :
chunk_set = int ( 10 )
widget_text . write ( base_text + ' Chunk size auto-set to 10... \n ' )
if sys_mem in [ 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 ] :
chunk_set = int ( 25 )
widget_text . write ( base_text + ' Chunk size auto-set to 25... \n ' )
if int ( sys_mem ) > = int ( 17 ) :
chunk_set = int ( 60 )
widget_text . write ( base_text + ' Chunk size auto-set to 60... \n ' )
elif data [ ' chunks ' ] == ' Full ' :
chunk_set = 0
widget_text . write ( base_text + " Chunk size set to full... \n " )
else :
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
b = np . array ( [ [ [ 0.5 ] ] , [ [ 0.5 ] ] , [ [ 0.7 ] ] , [ [ 0.9 ] ] ] )
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
if not data [ ' demucsmodel ' ] :
sources = self . demix_base ( 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 )
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 = ' default ' ,
value = b [ 3 ] ) * 1.03597672895 ) # compensation
return sources
def demix_base ( self , mixes , margin_size ) :
chunked_sources = [ ]
onnxitera = len ( mixes )
onnxitera_calc = onnxitera * 2
gui_progress_bar_onnx = 0
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 ' ] :
update_progress ( * * progress_kwargs ,
step = ( 0.1 + ( 0.5 / onnxitera_calc * gui_progress_bar_onnx ) ) )
else :
update_progress ( * * progress_kwargs ,
step = ( 0.1 + ( 0.9 / onnxitera * gui_progress_bar_onnx ) ) )
cmix = mixes [ mix ]
sources = [ ]
n_sample = cmix . shape [ 1 ]
mod = 0
for model in self . models :
mod + = 1
trim = model . n_fft / / 2
gen_size = model . chunk_size - 2 * trim
pad = gen_size - n_sample % gen_size
mix_p = np . concatenate ( ( np . zeros ( ( 2 , trim ) ) , cmix , np . zeros ( ( 2 , pad ) ) , np . zeros ( ( 2 , trim ) ) ) , 1 )
mix_waves = [ ]
i = 0
while i < n_sample + pad :
waves = np . array ( mix_p [ : , i : i + model . chunk_size ] )
mix_waves . append ( waves )
i + = gen_size
mix_waves = torch . tensor ( mix_waves , dtype = torch . float32 ) . to ( cpu )
with torch . no_grad ( ) :
_ort = self . onnx_models [ mod ]
spek = model . stft ( mix_waves )
tar_waves = model . istft ( torch . tensor ( _ort . run ( None , { ' input ' : spek . cpu ( ) . numpy ( ) } ) [ 0 ] ) ) #.cpu()
tar_signal = tar_waves [ : , : , trim : - trim ] . transpose ( 0 , 1 ) . reshape ( 2 , - 1 ) . numpy ( ) [ : , : - pad ]
start = 0 if mix == 0 else margin_size
end = None if mix == list ( mixes . keys ( ) ) [ : : - 1 ] [ 0 ] else - margin_size
if margin_size == 0 :
end = None
sources . append ( tar_signal [ : , start : end ] )
chunked_sources . append ( sources )
_sources = np . concatenate ( chunked_sources , axis = - 1 )
del self . onnx_models
widget_text . write ( ' Done! \n ' )
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.35 + ( 1.05 / 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 ( )
shift_set = 0
with torch . no_grad ( ) :
sources = apply_model ( self . demucs , cmix . to ( device ) , split = True , overlap = overlap_set , shifts = shift_set )
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 ' : 10 ,
' non_red ' : False ,
' noisereduc_s ' : 3 ,
' mixing ' : ' default ' ,
' modelFolder ' : False ,
' voc_only ' : False ,
' inst_only ' : False ,
' break ' : False ,
# Choose Model
' mdxnetModel ' : ' UVR-MDX-NET 1 ' ,
' high_end_process ' : ' mirroring ' ,
}
default_chunks = data [ ' chunks ' ]
default_noisereduc_s = data [ ' noisereduc_s ' ]
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 ' )
device = torch . device ( ' cuda:0 ' if torch . cuda . is_available ( ) else ' 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 channel_set
global margin_set
global overlap_set
global default_chunks
global default_noisereduc_s
global _basename
global _mixture
global progress_kwargs
global base_text
global model_set
global model_set_name
# Update default settings
default_chunks = data [ ' chunks ' ]
default_noisereduc_s = data [ ' noisereduc_s ' ]
channel_set = int ( 64 )
margin_set = int ( 44100 )
overlap_set = float ( 0.5 )
widget_text = text_widget
gui_progress_bar = progress_var
#Error Handling
onnxmissing = " [ONNXRuntimeError] : 3 : NO_SUCHFILE "
2022-05-11 23:05:05 +02:00
onnxmemerror = " onnxruntime::CudaCall CUDA failure 2: out of memory "
2022-05-11 02:11:40 +02:00
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 "
2022-05-11 23:05:05 +02:00
2022-05-11 02:11:40 +02:00
try :
with open ( ' errorlog.txt ' , ' w ' ) as f :
f . write ( f ' No errors to report at this time. ' + f ' \n \n Last Process Method Used: MDX-Net ' +
f ' \n Last Conversion Time Stamp: [ { datetime . now ( ) . strftime ( " % Y- % m- %d % H: % M: % S " ) } ] \n ' )
except :
pass
data . update ( kwargs )
if data [ ' mdxnetModel ' ] == ' UVR-MDX-NET 1 ' :
model_set = ' UVR_MDXNET_9703.onnx '
model_set_name = ' UVR_MDXNET_9703 '
if data [ ' mdxnetModel ' ] == ' UVR-MDX-NET 2 ' :
model_set = ' UVR_MDXNET_9682.onnx '
model_set_name = ' UVR_MDXNET_9682 '
if data [ ' mdxnetModel ' ] == ' UVR-MDX-NET 3 ' :
model_set = ' UVR_MDXNET_9662.onnx '
model_set_name = ' UVR_MDXNET_9662 '
if data [ ' mdxnetModel ' ] == ' UVR-MDX-NET Karaoke ' :
model_set = ' UVR_MDXNET_KARA.onnx '
model_set_name = ' UVR_MDXNET_Karaoke '
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 ) ) :
_mixture = f ' { data [ " input_paths " ] } '
_basename = f ' { data [ " export_path " ] } / { file_num } _ { os . path . splitext ( os . path . basename ( music_file ) ) [ 0 ] } '
# -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 \n at least 3 GB \' s of storage in order for this application function properly. \n \n Please 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 \n at 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
if data [ ' noisereduc_s ' ] == ' None ' :
pass
else :
if not os . path . isfile ( " lib_v5 \ sox \ sox.exe " ) :
data [ ' noisereduc_s ' ] = ' None '
data [ ' non_red ' ] = False
widget_text . write ( base_text + ' SoX is missing and required for noise reduction. \n ' )
widget_text . write ( base_text + ' See the \" More Info \" tab in the Help Guide. \n ' )
widget_text . write ( base_text + ' Noise Reduction will be disabled until SoX is available. \n \n ' )
update_progress ( * * progress_kwargs ,
step = 0 )
e = os . path . join ( data [ " export_path " ] )
demucsmodel = ' models/Demucs_Model/demucs_extra-3646af93_org.th '
pred = Predictor ( )
pred . prediction_setup ( demucs_name = demucsmodel ,
channels = channel_set )
# 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 ' \n Error Received: \n \n ' )
text_widget . write ( f ' Your PC cannot process this audio file with the chunk size selected. \n Please 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: MDX-Net \n \n ' +
f ' Your PC cannot process this audio file with the chunk size selected. \n Please 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 ' \n Error 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 ' \n Error 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: MDX-Net \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 ' \n Error 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 ' \n Error 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: MDX-Net \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 ' \n Error 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 ' \n Error 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: MDX-Net \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 ' \n Error 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 ' \n Error Received: \n \n ' )
2022-05-11 08:42:20 +02:00
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 \n until it is available on this system. \n \n ' )
2022-05-11 02:11:40 +02:00
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: MDX-Net \n \n ' +
2022-05-11 08:42:20 +02:00
f ' The input file type is not supported or FFmpeg is missing. \n Please 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 ' +
2022-05-11 02:11:40 +02:00
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 ' \n Error 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 ' \n Error 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: MDX-Net \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 ' \n Error Time Stamp [ { datetime . now ( ) . strftime ( " % Y- % m- %d % H: % M: % S " ) } ] \n ' )
2022-05-11 23:05:05 +02:00
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 ' \n Error 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 ' \n Please do the following: \n \n 1. Close any GPU intensive applications. \n 2. Lower the set chunk size. \n 3. 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: MDX-Net \n \n ' +
f ' The application was unable to allocate enough GPU memory to use this model. \n ' +
f ' \n Please do the following: \n \n 1. Close any GPU intensive applications. \n 2. Lower the set chunk size. \n 3. Then try again. \n \n ' +
f ' If the error persists, your GPU might not be supported. \n \n ' +
message + f ' \n Error Time Stamp [ { datetime . now ( ) . strftime ( " % Y- % m- %d % H: % M: % S " ) } ] \n ' )
2022-05-11 02:11:40 +02:00
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 ' \n Error 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 " \n For raw error details, go to the Error Log tab in the Help Guide. \n " )
text_widget . write ( f ' \n If 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: Ensemble Mode \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 ' \n Error 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: MDX-Net \n \n ' +
f ' If this error persists, please contact the developers with the error details. \n \n ' +
message + f ' \n Error 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 ' \n Error Received: \n ' )
text_widget . write ( " \n For 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 ) ) ) } ' )
torch . cuda . empty_cache ( )
button_widget . configure ( state = tk . NORMAL ) # Enable Button
return
progress_var . set ( 0 )
text_widget . write ( f ' \n Conversion(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 ) )