From c877b8c77034bab83aacb11e64d6ce157a98f61a Mon Sep 17 00:00:00 2001 From: SayanoAI <28544690+SayanoAI@users.noreply.github.com> Date: Mon, 5 Aug 2024 01:13:10 -0400 Subject: [PATCH] added unbatch node & audio duration_list input --- __init__.py | 8 +++++--- custom_nodes/utils.py | 41 +++++++++++++++++++++++++++++++++++------ web/js/ui_handlers.js | 7 +++++++ 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/__init__.py b/__init__.py index 46644b6..d96c169 100644 --- a/__init__.py +++ b/__init__.py @@ -3,7 +3,7 @@ from .custom_nodes.uvr import UVR5Node from .custom_nodes.rvc import RVCNode from .custom_nodes.loaders import DownloadAudio, LoadAudio, LoadWhisperModelNode, LoadRVCModelNode, LoadHubertModel, LoadPitchExtractionParams from .custom_nodes.output import PreviewAudio -from .custom_nodes.utils import Any2ListNode, AudioBatchValueNode, MergeImageBatches, MergeLatentBatches, ImageRepeatInterleavedNode, LatentRepeatInterleavedNode, MergeAudioNode, SimpleMathNode, SliceNode, ZipImagesNode +from .custom_nodes.utils import Any2ListNode, AudioBatchValueNode, List2AnyNode, MergeImageBatches, MergeLatentBatches, ImageRepeatInterleavedNode, LatentRepeatInterleavedNode, MergeAudioNode, SimpleMathNode, SliceNode, ZipImagesNode # Set the web directory, any .js file in that directory will be loaded by the frontend as a frontend extension WEB_DIRECTORY = "./web" @@ -31,7 +31,8 @@ NODE_CLASS_MAPPINGS = { "SimpleMathNode": SimpleMathNode, "SliceNode": SliceNode, "ZipNode": ZipImagesNode, - "Any2ListNode": Any2ListNode + "Any2ListNode": Any2ListNode, + "List2AnyNode": List2AnyNode } # A dictionary that contains the friendly/humanly readable titles for the nodes @@ -56,5 +57,6 @@ NODE_DISPLAY_NAME_MAPPINGS = { "SimpleMathNode": "🌺Simple Math Operations", "SliceNode": "🌺Slice Array", "ZipNode": "🌺Zip Images", - "Any2ListNode": "🌺Any to List" + "Any2ListNode": "🌺Any to List", + "List2AnyNode": "🌺List to Any", } \ No newline at end of file diff --git a/custom_nodes/utils.py b/custom_nodes/utils.py index 90e4f5d..4595756 100644 --- a/custom_nodes/utils.py +++ b/custom_nodes/utils.py @@ -168,14 +168,14 @@ class AudioBatchValueNode: return { "required": { "audio": ('VHS_AUDIO',), - "num_segments": ('INT', {"min": 1, "max": 128, "step": 1, "forceInput": True}), + "num_segments": ('INT', {"min": 2, "max": 128, "step": 1, "forceInput": True}), "output_min": ('FLOAT', {'default': 0., "min": -1000., "max": 1000., "step": .01}), "output_max": ('FLOAT', {'default': 1., "min": 0., "max": 1000., "step": .01}), "norm": (["scale","tanh","sigmoid"], {"default": "scale"}), }, "optional": { "silence_threshold": ("INT", {"default": 1000, "min": 1, "max": MAX_INT16, "step": 1, "display": "slider"}), - "frame_multiplier": ("INT", {"default": 1, "min": 1, "max": 120, "step": 1}), + "duration_list": ("INT", {"default": None, "min": 1, "forceInput": True}), "print_output": ("BOOLEAN", {"default": False}), "inverse": ("BOOLEAN", {"default": False}), } @@ -193,12 +193,12 @@ class AudioBatchValueNode: return np.sqrt(np.nanmean(audio**2)) def get_frame_weights(self, audio, num_segments, output_min, output_max, norm, - silence_threshold=1000, frame_multiplier=1, print_output=False, inverse=False): + silence_threshold=1000, duration_list=None, print_output=False, inverse=False): assert output_max>=output_min, f"{output_max=} must be greater or equal to {output_min=}!" audio_data = bytes_to_audio(audio()) audio,_ = remix_audio(audio_data,norm=True,to_int16=True) - num_values = int(num_segments*frame_multiplier) + num_values = int(num_segments) audio_rms = np.nan_to_num(list(map(self.get_rms,np.array_split(audio.flatten()/silence_threshold, num_values))),nan=0) audio_zscore = (audio_rms-audio_rms.mean())/audio_rms.std() output_range = output_max-output_min @@ -221,7 +221,16 @@ class AudioBatchValueNode: if print_output: print(f"{audio_rms.min()=} {audio_rms.max()=} {audio_rms.mean()=} {len(audio_rms)=}") print(f"{x_norm.min()=} {x_norm.max()=} {x_norm.mean()=} {len(x_norm)=}") - return (list(x_norm),list(map(int,x_norm)),num_values) + + if duration_list is not None: + segments = np.cumsum(duration_list) + x_norm = np.array_split(x_norm,segments) + x_norm = map(list,x_norm) + x_norm_int = [list(map(int,norms)) for norms in x_norm] + else: + x_norm_int = map(int,x_norm) + + return (list(x_norm),list(x_norm_int),num_values) class ImageRepeatInterleavedNode: @classmethod @@ -519,4 +528,24 @@ class Any2ListNode: CATEGORY = CATEGORY def to(self, any): - return (list(any),) \ No newline at end of file + return (list(any),) + +class List2AnyNode: + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "any": (AlwaysEqualProxy("*"),), + }, + } + + RETURN_TYPES = (AlwaysEqualProxy("*"),) + INPUT_IS_LIST = (True, ) + FUNCTION = "to" + CATEGORY = CATEGORY + + def to(self, any): + return (any,) \ No newline at end of file diff --git a/web/js/ui_handlers.js b/web/js/ui_handlers.js index 2ec7a18..06b8612 100644 --- a/web/js/ui_handlers.js +++ b/web/js/ui_handlers.js @@ -316,6 +316,13 @@ app.registerExtension({ }) break; + case "List2AnyNode": + chainCallback(nodeType.prototype, "onConnectInput", function (_, inputs) { + this.outputs[0].name = inputs; + this.outputs[0].type = inputs; + }) + break; + default: break