From 5713448015262cb349d2348827c7f0a8bcccbecf Mon Sep 17 00:00:00 2001 From: AIFSH <1509359472@qq.com> Date: Thu, 11 Apr 2024 00:44:03 +0000 Subject: [PATCH] change ui --- __init__.py | 6 +- __pycache__/__init__.cpython-310.pyc | Bin 0 -> 402 bytes __pycache__/nodes.cpython-310.pyc | Bin 0 -> 7594 bytes nodes.py | 7 +- uvr5/.ipynb_checkpoints/mdxnet-checkpoint.py | 261 ------------ uvr5/.ipynb_checkpoints/vr-checkpoint.py | 378 ------------------ uvr5/__pycache__/mdxnet.cpython-310.pyc | Bin 6790 -> 0 bytes uvr5/__pycache__/vr.cpython-310.pyc | Bin 7143 -> 0 bytes uvr5/lib/__pycache__/utils.cpython-310.pyc | Bin 3004 -> 3004 bytes .../layers_123821KB.cpython-310.pyc | Bin 4075 -> 4075 bytes .../__pycache__/layers_new.cpython-310.pyc | Bin 4445 -> 4445 bytes .../model_param_init.cpython-310.pyc | Bin 1650 -> 1650 bytes .../__pycache__/nets_61968KB.cpython-310.pyc | Bin 3452 -> 3452 bytes .../__pycache__/nets_new.cpython-310.pyc | Bin 3808 -> 3808 bytes .../__pycache__/spec_utils.cpython-310.pyc | Bin 13676 -> 13676 bytes web/js/audioUpload.js | 171 -------- web/js/playAudio.js | 85 ---- web/js/previewAudio.js | 155 +++++++ web/js/uploadAudio.js | 203 ++++++++++ 19 files changed, 365 insertions(+), 901 deletions(-) create mode 100644 __pycache__/__init__.cpython-310.pyc create mode 100644 __pycache__/nodes.cpython-310.pyc delete mode 100644 uvr5/.ipynb_checkpoints/mdxnet-checkpoint.py delete mode 100644 uvr5/.ipynb_checkpoints/vr-checkpoint.py delete mode 100644 uvr5/__pycache__/mdxnet.cpython-310.pyc delete mode 100644 uvr5/__pycache__/vr.cpython-310.pyc delete mode 100644 web/js/audioUpload.js delete mode 100644 web/js/playAudio.js create mode 100644 web/js/previewAudio.js create mode 100644 web/js/uploadAudio.js diff --git a/__init__.py b/__init__.py index 274a442..b6efde6 100644 --- a/__init__.py +++ b/__init__.py @@ -1,5 +1,5 @@ WEB_DIRECTORY = "./web" -from .nodes import LoadAudio, UVR5,PlayAudio +from .nodes import LoadAudio, UVR5,PreViewAudio # Set the web directory, any .js file in that directory will be loaded by the frontend as a frontend extension # WEB_DIRECTORY = "./somejs" @@ -9,12 +9,12 @@ from .nodes import LoadAudio, UVR5,PlayAudio NODE_CLASS_MAPPINGS = { "UVR5_Node": UVR5, "LoadAudio": LoadAudio, - "PlayAudio": PlayAudio + "PreViewAudio": PreViewAudio } # A dictionary that contains the friendly/humanly readable titles for the nodes NODE_DISPLAY_NAME_MAPPINGS = { "UVR5_Node": "UVR5 Node", "LoadAudio": "AudioLoader", - "PlayAudio": "PlayAudio" + "PreViewAudio": "PreView Audio" } diff --git a/__pycache__/__init__.cpython-310.pyc b/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..733e7957ef13c603e8736399cd9dd81606ff3124 GIT binary patch literal 402 zcmYk2-A=+V6vz9q@ul-d5)-eu-39DM?u>Dc#VmobFu~B9Ms0~p7$qBoz$^F)zJRaP zTd#Zt6B64Z#*_5lo?m7$AT_hUPFw1m&3E z+#(hP9CO4ihTk!_%eq{NoSK`Cu&rO=QJO8X6{Vf!R@Sa_!Pawrqd%f-DzQKlq8fq-R`!RvvHt<3 CA!XSB literal 0 HcmV?d00001 diff --git a/__pycache__/nodes.cpython-310.pyc b/__pycache__/nodes.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c9e0644dd3cd9670a7e9d62fd0b4d16f4c49d4ea GIT binary patch literal 7594 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 chunk_size: - margin = chunk_size - - segmented_mix = {} - - if self.args.chunks == 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_base(segmented_mix, margin_size=margin) - """ - mix:(2,big_sample) - segmented_mix:offset->(2,small_sample) - sources:(1,2,big_sample) - """ - return sources - - def demix_base(self, mixes, margin_size): - chunked_sources = [] - progress_bar = tqdm(total=len(mixes)) - progress_bar.set_description("Processing") - for mix in mixes: - cmix = mixes[mix] - sources = [] - n_sample = cmix.shape[1] - model = self.model_ - 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.model - spek = model.stft(mix_waves) - if self.args.denoise: - spec_pred = ( - -_ort.run(None, {"input": -spek.cpu().numpy()})[0] * 0.5 - + _ort.run(None, {"input": spek.cpu().numpy()})[0] * 0.5 - ) - tar_waves = model.istft(torch.tensor(spec_pred).to(cpu)) - else: - tar_waves = model.istft( - torch.tensor(_ort.run(None, {"input": spek.cpu().numpy()})[0]).to(cpu) - ) - tar_signal = ( - tar_waves[:, :, trim:-trim] - .transpose(0, 1) - .reshape(2, -1) - .cpu() - .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]) - - progress_bar.update(1) - - chunked_sources.append(sources) - _sources = np.concatenate(chunked_sources, axis=-1) - # del self.model - progress_bar.close() - return _sources - - def prediction(self, m, vocal_root, others_root, format): - os.makedirs(vocal_root, exist_ok=True) - os.makedirs(others_root, exist_ok=True) - basename = os.path.basename(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) - opt = sources[0].T - if format in ["wav", "flac"]: - vocal_AUDIO = "%s/%s_main_vocal.%s" % (vocal_root, basename, format) - sf.write( - vocal_AUDIO, mix - opt, rate - ) - bgm_AUDIO = "%s/%s_others.%s" % (others_root, basename, format) - sf.write(bgm_AUDIO, opt, rate) - else: - vocal_AUDIO = "%s/%s_main_vocal.wav" % (vocal_root, basename) - bgm_AUDIO = "%s/%s_others.wav" % (others_root, basename) - sf.write(vocal_AUDIO, mix - opt, rate) - sf.write(bgm_AUDIO, opt, rate) - opt_path_vocal = vocal_AUDIO[:-4] + ".%s" % format - opt_path_other = bgm_AUDIO[:-4] + ".%s" % format - if os.path.exists(vocal_AUDIO): - os.system( - "ffmpeg -i %s -vn %s -q:a 2 -y" % (vocal_AUDIO, opt_path_vocal) - ) - if os.path.exists(opt_path_vocal): - try: - os.remove(vocal_AUDIO) - except: - pass - if os.path.exists(bgm_AUDIO): - os.system( - "ffmpeg -i %s -vn %s -q:a 2 -y" % (bgm_AUDIO, opt_path_other) - ) - if os.path.exists(opt_path_other): - try: - os.remove(bgm_AUDIO) - except: - pass - return vocal_AUDIO,bgm_AUDIO - - -class MDXNetDereverb: - def __init__(self, chunks): - self.onnx = "%s/uvr5_weights/onnx_dereverb_By_FoxJoy"%os.path.dirname(os.path.abspath(__file__)) - self.shifts = 10 # 'Predict with randomised equivariant stabilisation' - self.mixing = "min_mag" # ['default','min_mag','max_mag'] - self.chunks = chunks - self.margin = 44100 - self.dim_t = 9 - self.dim_f = 3072 - self.n_fft = 6144 - self.denoise = True - self.pred = Predictor(self) - self.device = cpu - - def _path_audio_(self, input, others_root, vocal_root, format, is_hp3=False): - return self.pred.prediction(input, vocal_root, others_root, format) diff --git a/uvr5/.ipynb_checkpoints/vr-checkpoint.py b/uvr5/.ipynb_checkpoints/vr-checkpoint.py deleted file mode 100644 index 32d70b8..0000000 --- a/uvr5/.ipynb_checkpoints/vr-checkpoint.py +++ /dev/null @@ -1,378 +0,0 @@ -import os,sys -parent_directory = os.path.dirname(os.path.abspath(__file__)) -import logging,pdb -logger = logging.getLogger(__name__) - -import librosa -import numpy as np -import soundfile as sf -import torch -from .lib.lib_v5 import nets_61968KB as Nets -from .lib.lib_v5 import spec_utils -from .lib.lib_v5.model_param_init import ModelParameters -from .lib.lib_v5.nets_new import CascadedNet -from .lib.utils import inference - - -class AudioPre: - def __init__(self, agg, model_path, device, is_half, tta=False): - self.model_path = model_path - self.device = device - self.data = { - # Processing Options - "postprocess": False, - "tta": tta, - # Constants - "window_size": 512, - "agg": agg, - "high_end_process": "mirroring", - } - mp = ModelParameters("%s/lib/lib_v5/modelparams/4band_v2.json"%parent_directory) - model = Nets.CascadedASPPNet(mp.param["bins"] * 2) - cpk = torch.load(model_path, map_location="cpu") - model.load_state_dict(cpk) - model.eval() - if is_half: - model = model.half().to(device) - else: - model = model.to(device) - - self.mp = mp - self.model = model - - def _path_audio_( - self, music_file, ins_root=None, vocal_root=None, format="flac", is_hp3=False - ): - if ins_root is None and vocal_root is None: - return "No save root." - name = os.path.basename(music_file) - if ins_root is not None: - os.makedirs(ins_root, exist_ok=True) - if vocal_root is not None: - os.makedirs(vocal_root, exist_ok=True) - X_wave, y_wave, X_spec_s, y_spec_s = {}, {}, {}, {} - bands_n = len(self.mp.param["band"]) - # print(bands_n) - for d in range(bands_n, 0, -1): - bp = self.mp.param["band"][d] - if d == bands_n: # high-end band - ( - X_wave[d], - _, - ) = librosa.core.load( # 理论上librosa读取可能对某些音频有bug,应该上ffmpeg读取,但是太麻烦了弃坑 - music_file, - sr = bp["sr"], - mono = False, - dtype = np.float32, - res_type = bp["res_type"], - ) - if X_wave[d].ndim == 1: - X_wave[d] = np.asfortranarray([X_wave[d], X_wave[d]]) - else: # lower bands - X_wave[d] = librosa.core.resample( - X_wave[d + 1], - orig_sr = self.mp.param["band"][d + 1]["sr"], - target_sr = bp["sr"], - res_type = bp["res_type"], - ) - # Stft of wave source - X_spec_s[d] = spec_utils.wave_to_spectrogram_mt( - X_wave[d], - bp["hl"], - bp["n_fft"], - self.mp.param["mid_side"], - self.mp.param["mid_side_b2"], - self.mp.param["reverse"], - ) - # pdb.set_trace() - if d == bands_n and self.data["high_end_process"] != "none": - input_high_end_h = (bp["n_fft"] // 2 - bp["crop_stop"]) + ( - self.mp.param["pre_filter_stop"] - self.mp.param["pre_filter_start"] - ) - input_high_end = X_spec_s[d][ - :, bp["n_fft"] // 2 - input_high_end_h : bp["n_fft"] // 2, : - ] - - X_spec_m = spec_utils.combine_spectrograms(X_spec_s, self.mp) - aggresive_set = float(self.data["agg"] / 100) - aggressiveness = { - "value": aggresive_set, - "split_bin": self.mp.param["band"][1]["crop_stop"], - } - with torch.no_grad(): - pred, X_mag, X_phase = inference( - X_spec_m, self.device, self.model, aggressiveness, self.data - ) - # Postprocess - if self.data["postprocess"]: - pred_inv = np.clip(X_mag - pred, 0, np.inf) - pred = spec_utils.mask_silence(pred, pred_inv) - y_spec_m = pred * X_phase - v_spec_m = X_spec_m - y_spec_m - - if is_hp3 == True: - ins_root,vocal_root = vocal_root,ins_root - - if ins_root is not None: - if self.data["high_end_process"].startswith("mirroring"): - input_high_end_ = spec_utils.mirroring( - self.data["high_end_process"], y_spec_m, input_high_end, self.mp - ) - wav_instrument = spec_utils.cmb_spectrogram_to_wave( - y_spec_m, self.mp, input_high_end_h, input_high_end_ - ) - else: - wav_instrument = spec_utils.cmb_spectrogram_to_wave(y_spec_m, self.mp) - logger.info("%s instruments done" % name) - if is_hp3 == True: - head = "vocal_" - else: - head = "instrument_" - if format in ["wav", "flac"]: - bgm_AUDIO = os.path.join( - ins_root, - head + "{}_{}.{}".format(name, self.data["agg"], format), - ) - sf.write( - bgm_AUDIO, - (np.array(wav_instrument) * 32768).astype("int16"), - self.mp.param["sr"], - ) # - else: - bgm_AUDIO = os.path.join( - ins_root, head + "{}_{}.wav".format(name, self.data["agg"]) - ) - sf.write( - bgm_AUDIO, - (np.array(wav_instrument) * 32768).astype("int16"), - self.mp.param["sr"], - ) - if os.path.exists(bgm_AUDIO): - opt_format_path = bgm_AUDIO[:-4] + ".%s" % format - os.system("ffmpeg -i %s -vn %s -q:a 2 -y" % (bgm_AUDIO, opt_format_path)) - if os.path.exists(opt_format_path): - try: - os.remove(bgm_AUDIO) - except: - pass - if vocal_root is not None: - if is_hp3 == True: - head = "instrument_" - else: - head = "vocal_" - if self.data["high_end_process"].startswith("mirroring"): - input_high_end_ = spec_utils.mirroring( - self.data["high_end_process"], v_spec_m, input_high_end, self.mp - ) - wav_vocals = spec_utils.cmb_spectrogram_to_wave( - v_spec_m, self.mp, input_high_end_h, input_high_end_ - ) - else: - wav_vocals = spec_utils.cmb_spectrogram_to_wave(v_spec_m, self.mp) - logger.info("%s vocals done" % name) - if format in ["wav", "flac"]: - vocal_AUDIO = os.path.join( - vocal_root, - head + "{}_{}.{}".format(name, self.data["agg"], format), - ) - sf.write( - vocal_AUDIO, - (np.array(wav_vocals) * 32768).astype("int16"), - self.mp.param["sr"], - ) - else: - vocal_AUDIO = os.path.join( - vocal_root, head + "{}_{}.wav".format(name, self.data["agg"]) - ) - sf.write( - vocal_AUDIO, - (np.array(wav_vocals) * 32768).astype("int16"), - self.mp.param["sr"], - ) - if os.path.exists(vocal_AUDIO): - opt_format_path = vocal_AUDIO[:-4] + ".%s" % format - os.system("ffmpeg -i %s -vn %s -q:a 2 -y" % (vocal_AUDIO, opt_format_path)) - if os.path.exists(opt_format_path): - try: - os.remove(vocal_AUDIO) - except: - pass - if is_hp3 == True: - return bgm_AUDIO,vocal_AUDIO - return vocal_AUDIO, bgm_AUDIO - - -class AudioPreDeEcho: - def __init__(self, agg, model_path, device, is_half, tta=False): - self.model_path = model_path - self.device = device - self.data = { - # Processing Options - "postprocess": False, - "tta": tta, - # Constants - "window_size": 512, - "agg": agg, - "high_end_process": "mirroring", - } - mp = ModelParameters("%s/lib/lib_v5/modelparams/4band_v3.json"%parent_directory) - nout = 64 if "DeReverb" in model_path else 48 - model = CascadedNet(mp.param["bins"] * 2, nout) - cpk = torch.load(model_path, map_location="cpu") - model.load_state_dict(cpk) - model.eval() - if is_half: - model = model.half().to(device) - else: - model = model.to(device) - - self.mp = mp - self.model = model - - def _path_audio_( - self, music_file, vocal_root=None, ins_root=None, format="flac", is_hp3=False - ): # 3个VR模型vocal和ins是反的 - if ins_root is None and vocal_root is None: - return "No save root." - name = os.path.basename(music_file) - if ins_root is not None: - os.makedirs(ins_root, exist_ok=True) - if vocal_root is not None: - os.makedirs(vocal_root, exist_ok=True) - X_wave, y_wave, X_spec_s, y_spec_s = {}, {}, {}, {} - bands_n = len(self.mp.param["band"]) - # print(bands_n) - for d in range(bands_n, 0, -1): - bp = self.mp.param["band"][d] - if d == bands_n: # high-end band - ( - X_wave[d], - _, - ) = librosa.core.load( # 理论上librosa读取可能对某些音频有bug,应该上ffmpeg读取,但是太麻烦了弃坑 - music_file, - sr = bp["sr"], - mono = False, - dtype = np.float32, - res_type = bp["res_type"], - ) - if X_wave[d].ndim == 1: - X_wave[d] = np.asfortranarray([X_wave[d], X_wave[d]]) - else: # lower bands - X_wave[d] = librosa.core.resample( - X_wave[d + 1], - orig_sr = self.mp.param["band"][d + 1]["sr"], - target_sr = bp["sr"], - res_type = bp["res_type"], - ) - # Stft of wave source - X_spec_s[d] = spec_utils.wave_to_spectrogram_mt( - X_wave[d], - bp["hl"], - bp["n_fft"], - self.mp.param["mid_side"], - self.mp.param["mid_side_b2"], - self.mp.param["reverse"], - ) - # pdb.set_trace() - if d == bands_n and self.data["high_end_process"] != "none": - input_high_end_h = (bp["n_fft"] // 2 - bp["crop_stop"]) + ( - self.mp.param["pre_filter_stop"] - self.mp.param["pre_filter_start"] - ) - input_high_end = X_spec_s[d][ - :, bp["n_fft"] // 2 - input_high_end_h : bp["n_fft"] // 2, : - ] - - X_spec_m = spec_utils.combine_spectrograms(X_spec_s, self.mp) - aggresive_set = float(self.data["agg"] / 100) - aggressiveness = { - "value": aggresive_set, - "split_bin": self.mp.param["band"][1]["crop_stop"], - } - with torch.no_grad(): - pred, X_mag, X_phase = inference( - X_spec_m, self.device, self.model, aggressiveness, self.data - ) - # Postprocess - if self.data["postprocess"]: - pred_inv = np.clip(X_mag - pred, 0, np.inf) - pred = spec_utils.mask_silence(pred, pred_inv) - y_spec_m = pred * X_phase - v_spec_m = X_spec_m - y_spec_m - - if ins_root is not None: - if self.data["high_end_process"].startswith("mirroring"): - input_high_end_ = spec_utils.mirroring( - self.data["high_end_process"], y_spec_m, input_high_end, self.mp - ) - wav_instrument = spec_utils.cmb_spectrogram_to_wave( - y_spec_m, self.mp, input_high_end_h, input_high_end_ - ) - else: - wav_instrument = spec_utils.cmb_spectrogram_to_wave(y_spec_m, self.mp) - logger.info("%s instruments done" % name) - if format in ["wav", "flac"]: - bgm_AUDIO = os.path.join( - ins_root, - "vocal_{}_{}.{}".format(name, self.data["agg"], format), - ) - sf.write( - bgm_AUDIO, - (np.array(wav_instrument) * 32768).astype("int16"), - self.mp.param["sr"], - ) # - else: - bgm_AUDIO = os.path.join( - ins_root, "vocal_{}_{}.wav".format(name, self.data["agg"]) - ) - sf.write( - bgm_AUDIO, - (np.array(wav_instrument) * 32768).astype("int16"), - self.mp.param["sr"], - ) - if os.path.exists(bgm_AUDIO): - opt_format_path = bgm_AUDIO[:-4] + ".%s" % format - os.system("ffmpeg -i %s -vn %s -q:a 2 -y" % (bgm_AUDIO, opt_format_path)) - if os.path.exists(opt_format_path): - try: - os.remove(bgm_AUDIO) - except: - pass - if vocal_root is not None: - if self.data["high_end_process"].startswith("mirroring"): - input_high_end_ = spec_utils.mirroring( - self.data["high_end_process"], v_spec_m, input_high_end, self.mp - ) - wav_vocals = spec_utils.cmb_spectrogram_to_wave( - v_spec_m, self.mp, input_high_end_h, input_high_end_ - ) - else: - wav_vocals = spec_utils.cmb_spectrogram_to_wave(v_spec_m, self.mp) - logger.info("%s vocals done" % name) - if format in ["wav", "flac"]: - vocal_AUDIO = os.path.join( - vocal_root, - "instrument_{}_{}.{}".format(name, self.data["agg"], format), - ) - sf.write( - vocal_AUDIO, - (np.array(wav_vocals) * 32768).astype("int16"), - self.mp.param["sr"], - ) - else: - vocal_AUDIO = os.path.join( - vocal_root, "instrument_{}_{}.wav".format(name, self.data["agg"]) - ) - sf.write( - vocal_AUDIO, - (np.array(wav_vocals) * 32768).astype("int16"), - self.mp.param["sr"], - ) - if os.path.exists(vocal_AUDIO): - opt_format_path = vocal_AUDIO[:-4] + ".%s" % format - os.system("ffmpeg -i %s -vn %s -q:a 2 -y" % (vocal_AUDIO, opt_format_path)) - if os.path.exists(opt_format_path): - try: - os.remove(vocal_AUDIO) - except: - pass - return bgm_AUDIO,vocal_AUDIO diff --git a/uvr5/__pycache__/mdxnet.cpython-310.pyc b/uvr5/__pycache__/mdxnet.cpython-310.pyc deleted file mode 100644 index 1e21ea19787fa5e9a58ff368cc122b2aa20dc2cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6790 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 diff --git a/uvr5/__pycache__/vr.cpython-310.pyc b/uvr5/__pycache__/vr.cpython-310.pyc deleted file mode 100644 index 9009abf12ccee26c37dad2f5cc2f25a35369164c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7143 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 HiQ5VQrL8RO delta 187 zcmdlZzDJxppO=@50SMmP3vc9>V-tyDEhtJ&DZa&(S&~|mSdy8aR~)t3mW`81(-f$x zNE1Y8fe397!3`peK!gQ|Far_hlk+(oL=AwTg+rfUg61qShyGsCqLj3MA(1`Yanrpy*M*HH$O9_$PUC~bSv@zNjZTy z93@4GnR%Ic=|%P+F^A2!xuO~6qCjkC5a9&=hZg_uJefbzFkiZiQH zi(G)rB3BTh3nKJDgd2!(2N51X;ud>xW_oUZW=fG4h{xzw6kvWKK0U|6xgdm6j8=3@SrGN;l$$ESelGZ>b$jQYZ-*PbUF>)wys0ncvSx=7V SGh_^&Jdsa=(R%VKJ~IH}EIFM3 delta 278 zcmaDL`#_dEpO=@50SMmP3vc8WVr7h)EXUf)Xu5d`s~r=g)#k_SLd+rdK>1rN#hF#9 zMb1EGkqd~>1rd56!WBfgfe3dXaf`h;Gd(vyGo{EA#A9?T@&idZfH)i_MTwbtnR)3& zUYk9+!x&}aKvIq%A^=EeG8ZX=*!mzMX7X;H<81LDX2RqSUIoUO$t!t-jIBWeHb6p? z(NB}3$PC0a2N4z^LJ&lN4NU~Gl0k&!WIa9!Nh=@|xJrzFnojrIj{J!&@^PS7R-*>lrw|jF! zMq_rGxSky?T*%opfkq!pHsL>00|ZrH!Cy&C>dZ4RM8C|-Frq%N)TcX8bZAlpy_x}) zNPBcJtjy?ejI+8xC>X+85#l)I7MH>}9Vz}H8VgF|0CVc&{Rse7yR!}vupmjUJ}v&v-c!k>>x3du!~R7d3-V2+B6W(ZvFi}r;324y`C z^O9wU2qPWANesx;G$Q{@!kTYWX5FGF_`M zPhTqb856uJ6Rq44i&-rsxeJOoX^_&=BK$IWAZ{rS@&Oa%c6%-BymmvN={gl9tY!H7 zdb)$SP804n{T3JB({Fbhyr$EYEoG@s=A*!IW`arWz$8a8W)JUY-dhn~(OrOPr7z8srwd!}Gh0k0IKsI(Z_< z;Se*z%rPpn$gD74Cdu%A;wEEe64dB92Crz$a~N*XlIIkBq8(42Z8 zvFa2(rM?6ct!cN3Xi1<+S`iT$?4^2$3Z&?%@Tu?Y!F%ENo$s9QT<-n8yVJMRmlxFQ zb2G&C+i6(H+cbcOJ{l~-e}*RTsqUh`l9)J+GcZCwjVmywJ~TCE+CriuC56$I(xDRW zhzy0484ZqeR^tx_g4iHJj8c9{8AR!L$#>CMR5}eXt0oUU0hm`WnVkR$iXRT`pX0R} z<`MIlDlFxqbk6b=7F6lTmIN{SQ)Ym1`g+s`6O?0h!#th08eobPYcs@Y(OM>|+tzhh zrs;}Ob;%Zm>J@$%zbNK2z&vA~GdX+k=VOwBaxo;;s5}Bj6q%IHf7uu54f%#-EspY% zC9+i3!zx{t0r|GO`y9wf-%ajegSjz zx$1yE!K<>-%pI{iW)n&FqGC?!q>PL(zf1v$TPlD;zy#UtF4G#XT^FP@U5XM)WqEzQ zJpo*!oA!3?TQ0t%U-ov`q_Z_`<>^o6qrfP0ok{P&1V=GuAMaXWRwQ*Y%cEOCF#3*OFTrL@~B^{$*3>aX7oRFHD~)nQ(1%98&U8s4c8qke3|ZR?eKehu%G+ZDPDI{{OsTA M%3)Z|t-lEW0R*VwnE(I) diff --git a/web/js/audioUpload.js b/web/js/audioUpload.js deleted file mode 100644 index f390053..0000000 --- a/web/js/audioUpload.js +++ /dev/null @@ -1,171 +0,0 @@ -import { app } from "../../../scripts/app.js"; -import { api } from '../../../scripts/api.js' -import { ComfyWidgets } from "../../../scripts/widgets.js" - -function audioUpload(node, inputName, inputData, app) { - const audioWidget = node.widgets.find((w) => w.name === "audio"); - let uploadWidget; - /* - A method that returns the required style for the html - */ - function playAudio(node, name) { - let url = `/view?filename=${encodeURIComponent(name)}&type=input&subfolder=${app.getPreviewFormatParam()}${app.getRandParam()}` - - while (node.widgets.length > 2){ - node.widgets.pop() - } - - let isTick = true; - const audio = new Audio(url); - const slider = node.addWidget( - "slider", - "loading", - 0, - (v) => { - if (!isTick) { - audio.currentTime = v; - } - isTick = false; - }, - { - min: 0, - max: 0, - } - ); - - const button = node.addWidget("button", `Play ${name}`, "play", () => { - try { - if (audio.paused) { - audio.play(); - button.name = `Pause ${name}`; - } else { - audio.pause(); - button.name = `Play ${name}`; - } - } catch (error) { - alert(error); - } - app.canvas.setDirty(true); - }); - audio.addEventListener("timeupdate", () => { - isTick = true; - slider.value = audio.currentTime; - app.canvas.setDirty(true); - }); - audio.addEventListener("ended", () => { - button.name = `Play ${name}`; - app.canvas.setDirty(true); - }); - audio.addEventListener("loadedmetadata", () => { - slider.options.max = audio.duration; - slider.name = `(${audio.duration})`; - app.canvas.setDirty(true); - }); - } - - var default_value = audioWidget.value; - Object.defineProperty(audioWidget, "value", { - set : function(value) { - this._real_value = value; - }, - - get : function() { - let value = ""; - if (this._real_value) { - value = this._real_value; - } else { - return default_value; - } - - if (value.filename) { - let real_value = value; - value = ""; - if (real_value.subfolder) { - value = real_value.subfolder + "/"; - } - - value += real_value.filename; - - if(real_value.type && real_value.type !== "input") - value += ` [${real_value.type}]`; - } - return value; - } - }); - async function uploadFile(file, updateNode, pasted = false) { - try { - // Wrap file in formdata so it includes filename - const body = new FormData(); - body.append("image", file); - if (pasted) body.append("subfolder", "pasted"); - const resp = await api.fetchApi("/upload/image", { - method: "POST", - body, - }); - - if (resp.status === 200) { - const data = await resp.json(); - // Add the file to the dropdown list and update the widget value - let path = data.name; - if (data.subfolder) path = data.subfolder + "/" + path; - - if (!audioWidget.options.values.includes(path)) { - audioWidget.options.values.push(path); - } - - if (updateNode) { - audioWidget.value = path; - // showAudio(path) - playAudio(node, path); - } - } else { - alert(resp.status + " - " + resp.statusText); - } - } catch (error) { - alert(error); - } - } - - const fileInput = document.createElement("input"); - Object.assign(fileInput, { - type: "file", - accept: "audio/mp3,audio/wav,audio/flac,audio/m4a", - style: "display: none", - onchange: async () => { - if (fileInput.files.length) { - await uploadFile(fileInput.files[0], true); - } - }, - }); - document.body.append(fileInput); - - // Create the button widget for selecting the files - uploadWidget = node.addWidget("button", "choose audio file to upload", "Audio", () => { - fileInput.click(); - }); - - uploadWidget.serialize = false; - playAudio(node, audioWidget.value); - - const cb = node.callback; - audioWidget.callback = function () { - playAudio(node, audioWidget.value); - if (cb) { - return cb.apply(this, arguments); - } - }; - - return { widget: uploadWidget }; -} - -ComfyWidgets.AUDIOUPLOAD = audioUpload; - -app.registerExtension({ - name: "UVR5.UploadAudio", - async beforeRegisterNodeDef(nodeType, nodeData, app) { - if (nodeData?.name == "LoadAudio") { - nodeData.input.required.upload = ["AUDIOUPLOAD"]; - } - }, -}); - diff --git a/web/js/playAudio.js b/web/js/playAudio.js deleted file mode 100644 index d3585c1..0000000 --- a/web/js/playAudio.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * File: playAudio.js - * Project: comfyui_jags_audiotools - * Author: jags111 - * - * Copyright (c) 2023 jags111 - * - */ -import { app } from "../../../scripts/app.js"; -import { api } from '../../../scripts/api.js' -import { ComfyWidgets } from "../../../scripts/widgets.js" - - -/* -A method that returns the required style for the html -*/ -function addPlaybackWidget(node, name, root) { - - try { - while (node.widgets.length > 0){ - node.widgets.pop() - } - } catch (error) { - //console.log(error); - } - let url = `/view?filename=${encodeURIComponent(name)}&type=${root}&subfolder=${app.getPreviewFormatParam()}${app.getRandParam()}`; - let isTick = true; - const audio = new Audio(url); - const slider = node.addWidget( - "slider", - "loading", - 0, - (v) => { - if (!isTick) { - audio.currentTime = v; - } - isTick = false; - }, - { - min: 0, - max: 0, - } - ); - - const button = node.addWidget("button", `Play ${name}`, "play", () => { - try { - if (audio.paused) { - audio.play(); - button.name = `Pause ${name}`; - } else { - audio.pause(); - button.name = `Play ${name}`; - } - } catch (error) { - alert(error); - } - app.canvas.setDirty(true); - }); - - audio.addEventListener("timeupdate", () => { - isTick = true; - slider.value = audio.currentTime; - app.canvas.setDirty(true); - }); - audio.addEventListener("ended", () => { - button.name = `Play ${name}`; - app.canvas.setDirty(true); - }); - audio.addEventListener("loadedmetadata", () => { - slider.options.max = audio.duration; - slider.name = `(${audio.duration})`; - app.canvas.setDirty(true); - }); -} - -app.registerExtension({ - name: "UVR5.AudioPlayer", - async beforeRegisterNodeDef(nodeType, nodeData, app) { - if (nodeData?.name == "PlayAudio") { - nodeType.prototype.onExecuted = function (data) { - addPlaybackWidget(this, data.audio[0], data.audio[1]); - } - } - } -}); diff --git a/web/js/previewAudio.js b/web/js/previewAudio.js new file mode 100644 index 0000000..86ab47c --- /dev/null +++ b/web/js/previewAudio.js @@ -0,0 +1,155 @@ +import { app } from "../../../scripts/app.js"; +import { api } from '../../../scripts/api.js' + +function fitHeight(node) { + node.setSize([node.size[0], node.computeSize([node.size[0], node.size[1]])[1]]) + node?.graph?.setDirtyCanvas(true); +} +function chainCallback(object, property, callback) { + if (object == undefined) { + //This should not happen. + console.error("Tried to add callback to non-existant object") + return; + } + if (property in object) { + const callback_orig = object[property] + object[property] = function () { + const r = callback_orig.apply(this, arguments); + callback.apply(this, arguments); + return r + }; + } else { + object[property] = callback; + } +} + +function addPreviewOptions(nodeType) { + chainCallback(nodeType.prototype, "getExtraMenuOptions", function(_, options) { + // The intended way of appending options is returning a list of extra options, + // but this isn't used in widgetInputs.js and would require + // less generalization of chainCallback + let optNew = [] + try { + const previewWidget = this.widgets.find((w) => w.name === "audiopreview"); + + let url = null + if (previewWidget.audioEl?.hidden == false && previewWidget.audioEl.src) { + //Use full quality audio + //url = api.apiURL('/view?' + new URLSearchParams(previewWidget.value.params)); + url = previewWidget.audioEl.src + } + if (url) { + optNew.push( + { + content: "Open preview", + callback: () => { + window.open(url, "_blank") + }, + }, + { + content: "Save preview", + callback: () => { + const a = document.createElement("a"); + a.href = url; + a.setAttribute("download", new URLSearchParams(previewWidget.value.params).get("filename")); + document.body.append(a); + a.click(); + requestAnimationFrame(() => a.remove()); + }, + } + ); + } + if(options.length > 0 && options[0] != null && optNew.length > 0) { + optNew.push(null); + } + options.unshift(...optNew); + + } catch (error) { + console.log(error); + } + + }); +} +function previewAudio(node,file,type){ + var element = document.createElement("div"); + const previewNode = node; + var previewWidget = node.addDOMWidget("audiopreview", "preview", element, { + serialize: false, + hideOnZoom: false, + getValue() { + return element.value; + }, + setValue(v) { + element.value = v; + }, + }); + previewWidget.computeSize = function(width) { + if (this.aspectRatio && !this.parentEl.hidden) { + let height = (previewNode.size[0]-20)/ this.aspectRatio + 10; + if (!(height > 0)) { + height = 0; + } + this.computedHeight = height + 10; + return [width, height]; + } + return [width, -4];//no loaded src, widget should not display + } + // element.style['pointer-events'] = "none" + previewWidget.value = {hidden: false, paused: false, params: {}} + previewWidget.parentEl = document.createElement("div"); + previewWidget.parentEl.className = "audio_preview"; + previewWidget.parentEl.style['width'] = "100%" + element.appendChild(previewWidget.parentEl); + previewWidget.audioEl = document.createElement("audio"); + previewWidget.audioEl.controls = true; + previewWidget.audioEl.loop = false; + previewWidget.audioEl.muted = false; + previewWidget.audioEl.style['width'] = "100%" + previewWidget.audioEl.addEventListener("loadedmetadata", () => { + + previewWidget.aspectRatio = previewWidget.audioEl.audioWidth / previewWidget.audioEl.audioHeight; + fitHeight(this); + }); + previewWidget.audioEl.addEventListener("error", () => { + //TODO: consider a way to properly notify the user why a preview isn't shown. + previewWidget.parentEl.hidden = true; + fitHeight(this); + }); + + let params = { + "filename": file, + "type": type, + } + + previewWidget.parentEl.hidden = previewWidget.value.hidden; + previewWidget.audioEl.autoplay = !previewWidget.value.paused && !previewWidget.value.hidden; + let target_width = 256 + if (element.style?.width) { + //overscale to allow scrolling. Endpoint won't return higher than native + target_width = element.style.width.slice(0,-2)*2; + } + if (!params.force_size || params.force_size.includes("?") || params.force_size == "Disabled") { + params.force_size = target_width+"x?" + } else { + let size = params.force_size.split("x") + let ar = parseInt(size[0])/parseInt(size[1]) + params.force_size = target_width+"x"+(target_width/ar) + } + + previewWidget.audioEl.src = api.apiURL('/view?' + new URLSearchParams(params)); + + previewWidget.audioEl.hidden = false; + previewWidget.parentEl.appendChild(previewWidget.audioEl) +} + +app.registerExtension({ + name: "UVR5.AudioPreviewer", + async beforeRegisterNodeDef(nodeType, nodeData, app) { + if (nodeData?.name == "PreViewAudio") { + nodeType.prototype.onExecuted = function (data) { + previewAudio(this, data.audio[0], data.audio[1]); + } + addPreviewOptions(nodeType) + } + } +}); \ No newline at end of file diff --git a/web/js/uploadAudio.js b/web/js/uploadAudio.js new file mode 100644 index 0000000..b1acb67 --- /dev/null +++ b/web/js/uploadAudio.js @@ -0,0 +1,203 @@ +import { app } from "../../../scripts/app.js"; +import { api } from '../../../scripts/api.js' +import { ComfyWidgets } from "../../../scripts/widgets.js" + +function fitHeight(node) { + node.setSize([node.size[0], node.computeSize([node.size[0], node.size[1]])[1]]) + node?.graph?.setDirtyCanvas(true); +} + +function previewAudio(node,file){ + while (node.widgets.length > 2){ + node.widgets.pop(); + } + try { + var el = document.getElementById("uploadAudio"); + el.remove(); + } catch (error) { + console.log(error); + } + var element = document.createElement("div"); + element.id = "uploadAudio"; + const previewNode = node; + var previewWidget = node.addDOMWidget("audiopreview", "preview", element, { + serialize: false, + hideOnZoom: false, + getValue() { + return element.value; + }, + setValue(v) { + element.value = v; + }, + }); + previewWidget.computeSize = function(width) { + if (this.aspectRatio && !this.parentEl.hidden) { + let height = (previewNode.size[0]-20)/ this.aspectRatio + 10; + if (!(height > 0)) { + height = 0; + } + this.computedHeight = height + 10; + return [width, height]; + } + return [width, -4];//no loaded src, widget should not display + } + // element.style['pointer-events'] = "none" + previewWidget.value = {hidden: false, paused: false, params: {}} + previewWidget.parentEl = document.createElement("div"); + previewWidget.parentEl.className = "audio_preview"; + previewWidget.parentEl.style['width'] = "100%" + element.appendChild(previewWidget.parentEl); + previewWidget.audioEl = document.createElement("audio"); + previewWidget.audioEl.controls = true; + previewWidget.audioEl.loop = false; + previewWidget.audioEl.muted = false; + previewWidget.audioEl.style['width'] = "100%" + previewWidget.audioEl.addEventListener("loadedmetadata", () => { + + previewWidget.aspectRatio = previewWidget.audioEl.audioWidth / previewWidget.audioEl.audioHeight; + fitHeight(this); + }); + previewWidget.audioEl.addEventListener("error", () => { + //TODO: consider a way to properly notify the user why a preview isn't shown. + previewWidget.parentEl.hidden = true; + fitHeight(this); + }); + + let params = { + "filename": file, + "type": "input", + } + + previewWidget.parentEl.hidden = previewWidget.value.hidden; + previewWidget.audioEl.autoplay = !previewWidget.value.paused && !previewWidget.value.hidden; + let target_width = 256 + if (element.style?.width) { + //overscale to allow scrolling. Endpoint won't return higher than native + target_width = element.style.width.slice(0,-2)*2; + } + if (!params.force_size || params.force_size.includes("?") || params.force_size == "Disabled") { + params.force_size = target_width+"x?" + } else { + let size = params.force_size.split("x") + let ar = parseInt(size[0])/parseInt(size[1]) + params.force_size = target_width+"x"+(target_width/ar) + } + + previewWidget.audioEl.src = api.apiURL('/view?' + new URLSearchParams(params)); + + previewWidget.audioEl.hidden = false; + previewWidget.parentEl.appendChild(previewWidget.audioEl) +} + +function audioUpload(node, inputName, inputData, app) { + const audioWidget = node.widgets.find((w) => w.name === "audio"); + let uploadWidget; + /* + A method that returns the required style for the html + */ + var default_value = audioWidget.value; + Object.defineProperty(audioWidget, "value", { + set : function(value) { + this._real_value = value; + }, + + get : function() { + let value = ""; + if (this._real_value) { + value = this._real_value; + } else { + return default_value; + } + + if (value.filename) { + let real_value = value; + value = ""; + if (real_value.subfolder) { + value = real_value.subfolder + "/"; + } + + value += real_value.filename; + + if(real_value.type && real_value.type !== "input") + value += ` [${real_value.type}]`; + } + return value; + } + }); + async function uploadFile(file, updateNode, pasted = false) { + try { + // Wrap file in formdata so it includes filename + const body = new FormData(); + body.append("image", file); + if (pasted) body.append("subfolder", "pasted"); + const resp = await api.fetchApi("/upload/image", { + method: "POST", + body, + }); + + if (resp.status === 200) { + const data = await resp.json(); + // Add the file to the dropdown list and update the widget value + let path = data.name; + if (data.subfolder) path = data.subfolder + "/" + path; + + if (!audioWidget.options.values.includes(path)) { + audioWidget.options.values.push(path); + } + + if (updateNode) { + audioWidget.value = path; + previewAudio(node,path) + + } + } else { + alert(resp.status + " - " + resp.statusText); + } + } catch (error) { + alert(error); + } + } + + const fileInput = document.createElement("input"); + Object.assign(fileInput, { + type: "file", + accept: "audio/mp3,audio/wav,audio/flac,audio/m4a", + style: "display: none", + onchange: async () => { + if (fileInput.files.length) { + await uploadFile(fileInput.files[0], true); + } + }, + }); + document.body.append(fileInput); + + // Create the button widget for selecting the files + uploadWidget = node.addWidget("button", "choose audio file to upload", "Audio", () => { + fileInput.click(); + }); + + uploadWidget.serialize = false; + + previewAudio(node, audioWidget.value); + const cb = node.callback; + audioWidget.callback = function () { + previewAudio(node,audioWidget.value); + if (cb) { + return cb.apply(this, arguments); + } + }; + + return { widget: uploadWidget }; +} + +ComfyWidgets.AUDIOPLOAD = audioUpload; + +app.registerExtension({ + name: "UVR5.UploadAudio", + async beforeRegisterNodeDef(nodeType, nodeData, app) { + if (nodeData?.name == "LoadAudio") { + nodeData.input.required.upload = ["AUDIOPLOAD"]; + } + }, +}); +