Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07bfda783d | ||
|
|
d74fdb8de7 | ||
|
|
5def36f87f | ||
|
|
08a0a06820 | ||
|
|
5ce2e63f01 | ||
|
|
ebed0e60d9 | ||
|
|
f65df84de6 | ||
|
|
c5579afb12 | ||
|
|
7d5b6d8f4a | ||
|
|
af492b7669 | ||
|
|
15084a9264 |
+3
-2
@@ -29,12 +29,13 @@ _NODE_CLASSES: List[Type] = [DreamSineWave, DreamLinear, DreamCSVCurve, DreamBea
|
||||
DreamFrameCounterInfo, DreamBoolToFloat, DreamBoolToInt, DreamSawWave, DreamTriangleWave,
|
||||
DreamTriangleEvent, DreamSmoothEvent, DreamCalculation, DreamImageColorShift,
|
||||
DreamComparePalette, DreamImageContrast, DreamImageBrightness, DreamLogFile,
|
||||
DreamLaboratory, DreamStringToLog, DreamIntToLog, DreamFloatToLog, DreamJoinLog]
|
||||
DreamLaboratory, DreamStringToLog, DreamIntToLog, DreamFloatToLog, DreamJoinLog,
|
||||
DreamStringTokenizer, DreamWavCurve, DreamFrameCounterTimeOffset]
|
||||
_SIGNATURE_SUFFIX = " [Dream]"
|
||||
|
||||
MANIFEST = {
|
||||
"name": "Dream Project Animation",
|
||||
"version": (4, 0, 0),
|
||||
"version": (4, 3, 1),
|
||||
"author": "Dream Project",
|
||||
"project": "https://github.com/alt-key-project/comfyui-dream-project",
|
||||
"description": "Various utility nodes for creating animations with ComfyUI",
|
||||
|
||||
@@ -3,7 +3,7 @@ import glob
|
||||
|
||||
from .categories import NodeCategories
|
||||
from .shared import *
|
||||
from .types import *
|
||||
from .dreamtypes import *
|
||||
|
||||
|
||||
class DreamFrameCounterInfo:
|
||||
@@ -95,6 +95,32 @@ class DreamFrameCounterOffset:
|
||||
def result(self, frame_counter: FrameCounter, offset):
|
||||
return (frame_counter.incremented(offset),)
|
||||
|
||||
class DreamFrameCounterTimeOffset:
|
||||
NODE_NAME = "Frame Counter Time Offset"
|
||||
|
||||
ICON = "±"
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": SharedTypes.frame_counter | {
|
||||
"offset_seconds": ("FLOAT", {"default": 0.0}),
|
||||
},
|
||||
}
|
||||
|
||||
CATEGORY = NodeCategories.ANIMATION
|
||||
RETURN_TYPES = (FrameCounter.ID,)
|
||||
RETURN_NAMES = ("frame_counter",)
|
||||
FUNCTION = "result"
|
||||
|
||||
@classmethod
|
||||
def IS_CHANGED(cls, frame_counter, offset):
|
||||
return hashed_as_strings(frame_counter, offset)
|
||||
|
||||
def result(self, frame_counter: FrameCounter, offset_seconds):
|
||||
offset = offset_seconds * frame_counter.frames_per_second
|
||||
return (frame_counter.incremented(offset),)
|
||||
|
||||
|
||||
class DreamSimpleFrameCounter:
|
||||
NODE_NAME = "Frame Counter (Simple)"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
from .categories import NodeCategories
|
||||
from .shared import *
|
||||
from .types import *
|
||||
from .dreamtypes import *
|
||||
|
||||
|
||||
class DreamImageAreaSampler:
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import csv
|
||||
import functools
|
||||
import math
|
||||
import os
|
||||
|
||||
from scipy.io.wavfile import read as wav_read
|
||||
|
||||
from .categories import NodeCategories
|
||||
from .shared import hashed_as_strings
|
||||
from .types import SharedTypes, FrameCounter
|
||||
from .dreamtypes import SharedTypes, FrameCounter
|
||||
|
||||
|
||||
def _linear_value_calc(x, x_start, x_end, y_start, y_end):
|
||||
@@ -119,6 +123,70 @@ class DreamTriangleWave:
|
||||
return _curve_result(y)
|
||||
|
||||
|
||||
class WavData:
|
||||
def __init__(self, sampling_rate: float, single_channel_samples, fps: float):
|
||||
self._length_in_seconds = len(single_channel_samples) / sampling_rate
|
||||
self._num_buckets = round(self._length_in_seconds * fps * 3)
|
||||
self._bucket_size = len(single_channel_samples) / float(self._num_buckets)
|
||||
self._buckets = list()
|
||||
self._rate = sampling_rate
|
||||
self._max_bucket_value = 0
|
||||
for i in range(self._num_buckets):
|
||||
start_index = round(i * self._bucket_size)
|
||||
end_index = round((i + 1) * self._bucket_size) - 1
|
||||
samples = list(map(lambda n: abs(n), single_channel_samples[start_index:end_index]))
|
||||
bucket_total = sum(samples)
|
||||
self._buckets.append(bucket_total)
|
||||
self._max_bucket_value=max(bucket_total, self._max_bucket_value)
|
||||
|
||||
for i in range(self._num_buckets):
|
||||
self._buckets[i] = float(self._buckets[i]) / self._max_bucket_value
|
||||
|
||||
def value_at_time(self, second: float) -> float:
|
||||
if second < 0.0 or second > self._length_in_seconds:
|
||||
return 0.0
|
||||
nsample = second * self._rate
|
||||
nbucket = min(max(0, round(nsample / self._bucket_size)), self._num_buckets - 1)
|
||||
return self._buckets[nbucket]
|
||||
|
||||
|
||||
@functools.lru_cache(4)
|
||||
def _wav_loader(filepath, fps):
|
||||
sampling_rate, samples = wav_read(filepath)
|
||||
single_channel = samples[:, 0]
|
||||
return WavData(sampling_rate, single_channel, fps)
|
||||
|
||||
|
||||
class DreamWavCurve:
|
||||
NODE_NAME = "WAV Curve"
|
||||
CATEGORY = NodeCategories.ANIMATION_CURVES
|
||||
RETURN_TYPES = ("FLOAT", "INT")
|
||||
RETURN_NAMES = ("FLOAT", "INT")
|
||||
FUNCTION = "result"
|
||||
ICON = "∿"
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": SharedTypes.frame_counter | {
|
||||
"wav_path": ("STRING", {"default": "audio.wav"}),
|
||||
"scale": ("FLOAT", {"default": 1.0, "multiline": False})
|
||||
},
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def IS_CHANGED(cls, *values):
|
||||
return hashed_as_strings(*values)
|
||||
|
||||
def result(self, frame_counter: FrameCounter, wav_path, scale):
|
||||
if not os.path.isfile(wav_path):
|
||||
return (0.0, 0)
|
||||
data = _wav_loader(wav_path, frame_counter.frames_per_second)
|
||||
frame_counter.current_time_in_seconds
|
||||
v = data.value_at_time(frame_counter.current_time_in_seconds)
|
||||
return (v * scale, round(v * scale))
|
||||
|
||||
|
||||
class DreamTriangleEvent:
|
||||
NODE_NAME = "Triangle Event Curve"
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+1097
-869
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -9,7 +9,7 @@ from PIL.Image import Resampling
|
||||
from .categories import *
|
||||
from .shared import ALWAYS_CHANGED_FLAG, convertTensorImageToPIL, DreamImageProcessor, \
|
||||
DreamImage, DreamMask
|
||||
from .types import SharedTypes, FrameCounter
|
||||
from .dreamtypes import SharedTypes, FrameCounter
|
||||
|
||||
|
||||
class DreamImageMotion:
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import json
|
||||
|
||||
from .categories import *
|
||||
from .shared import ALWAYS_CHANGED_FLAG, DreamStateFile
|
||||
from .types import *
|
||||
from .dreamtypes import *
|
||||
|
||||
_laboratory_state = DreamStateFile("laboratory")
|
||||
|
||||
|
||||
+6
-4
@@ -1,7 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from .categories import NodeCategories
|
||||
from .shared import ALWAYS_CHANGED_FLAG, list_images_in_directory, DreamImage
|
||||
from .types import SharedTypes, FrameCounter
|
||||
from .dreamtypes import SharedTypes, FrameCounter
|
||||
import os
|
||||
|
||||
|
||||
class DreamImageSequenceInputWithDefaultFallback:
|
||||
@@ -22,8 +23,8 @@ class DreamImageSequenceInputWithDefaultFallback:
|
||||
}
|
||||
|
||||
CATEGORY = NodeCategories.IMAGE_ANIMATION
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
RETURN_NAMES = ("image",)
|
||||
RETURN_TYPES = ("IMAGE","STRING")
|
||||
RETURN_NAMES = ("image","frame_name")
|
||||
FUNCTION = "result"
|
||||
|
||||
@classmethod
|
||||
@@ -37,5 +38,6 @@ class DreamImageSequenceInputWithDefaultFallback:
|
||||
if not entry:
|
||||
return (default_image, "")
|
||||
else:
|
||||
image_names = [os.path.basename(file_path) for file_path in entry]
|
||||
images = map(lambda f: DreamImage(file_path=f), entry)
|
||||
return (DreamImage.join_to_tensor_data(images),)
|
||||
return (DreamImage.join_to_tensor_data(images), image_names[0])
|
||||
|
||||
+4
-1
@@ -25,6 +25,7 @@
|
||||
"Frame Counter (Simple) [Dream]": "Integer value used as frame counter",
|
||||
"Frame Counter Info [Dream]": "Extracts information from the frame counter",
|
||||
"Frame Counter Offset [Dream]": "Adds an offset to a frame counter",
|
||||
"Frame Counter Time Offset [Dream]": "Adds an offset to a frame counter in seconds",
|
||||
"Image Brightness Adjustment [Dream]": "Adjusts the brightness of an image by a factor",
|
||||
"Image Color Shift [Dream]": "Adjust the colors (or brightness) of an image",
|
||||
"Image Contrast Adjustment [Dream]": "Adjusts the contrast of an image by a factor",
|
||||
@@ -49,9 +50,11 @@
|
||||
"Sine Curve [Dream]": "Simple sine wave curve",
|
||||
"Smooth Event Curve [Dream]": "Single event/peak curve with a slight bell-shape",
|
||||
"String Input [Dream]": "String input (until primitive routing issues are solved)",
|
||||
"String Tokenizer [Dream]": "Extract individual words or phrases from a text as tokens",
|
||||
"String to Log Entry [Dream]": "Use any string as a log entry",
|
||||
"Text Input [Dream]": "Multiline string input (until primitive routing issues are solved)",
|
||||
"Triangle Curve [Dream]": "Triangle wave curve",
|
||||
"Triangle Event Curve [Dream]": "Single event/peak curve with triangular shape",
|
||||
"Video Encoder (mpegCoder) [Dream]": "Post processing for animation sequences using mpegCoder module to generate video file"
|
||||
"Video Encoder (mpegCoder) [Dream]": "Post processing for animation sequences using mpegCoder module to generate video file",
|
||||
"WAV Curve [Dream]": "WAV audio file as a curve"
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import math
|
||||
|
||||
from .categories import NodeCategories
|
||||
from .shared import *
|
||||
from .types import *
|
||||
from .dreamtypes import *
|
||||
|
||||
|
||||
def _generate_noise(image: DreamImage, color_function, rng: random.Random, block_size, blur_amount,
|
||||
|
||||
@@ -8,7 +8,7 @@ from PIL.PngImagePlugin import PngInfo
|
||||
from .categories import NodeCategories
|
||||
from .shared import hashed_as_strings, DreamImageProcessor, DreamImage, \
|
||||
list_images_in_directory, DreamConfig
|
||||
from .types import SharedTypes, FrameCounter, AnimationSequence, LogEntry
|
||||
from .dreamtypes import SharedTypes, FrameCounter, AnimationSequence, LogEntry
|
||||
|
||||
CONFIG = DreamConfig()
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
from .categories import NodeCategories
|
||||
from .shared import hashed_as_strings
|
||||
from .types import PartialPrompt
|
||||
from .dreamtypes import PartialPrompt
|
||||
|
||||
|
||||
class DreamWeightedPromptBuilder:
|
||||
|
||||
@@ -186,7 +186,10 @@ counter.
|
||||
Extracts information from the frame counter.
|
||||
|
||||
### Frame Counter Offset [Dream]
|
||||
Adds an offset to a frame counter.
|
||||
Adds an offset (in frames) to a frame counter.
|
||||
|
||||
### Frame Counter Time Offset [Dream]
|
||||
Adds an offset in seconds to a frame counter.
|
||||
|
||||
### Image Brightness Adjustment [Dream]
|
||||
Adjusts the brightness of an image by a factor.
|
||||
@@ -255,12 +258,18 @@ Simple sine wave curve.
|
||||
### Smooth Event Curve [Dream]
|
||||
Single event/peak curve with a slight bell-shape.
|
||||
|
||||
### String Tokenizer [Dream]
|
||||
Splits a text into tokens by a separator and returns one of the tokens based on a given index.
|
||||
|
||||
### Triangle Curve [Dream]
|
||||
Triangle wave curve.
|
||||
|
||||
### Triangle Event Curve [Dream]
|
||||
Single event/peak curve with triangular shape.
|
||||
|
||||
### WAV Curve [Dream]
|
||||
Use an uncompressed WAV audio file as a curve.
|
||||
|
||||
### Other custom nodes
|
||||
|
||||
Many of the nodes found in 'WAS Node Suite' are useful the Dream Project Animation nodes - I suggest you install those
|
||||
@@ -292,6 +301,12 @@ This flow demonstrates prompt building with weights based on curves and brightne
|
||||
|
||||
[prompt-morphing](examples/prompt-morphing.json)
|
||||
|
||||
### Laboratory
|
||||
|
||||
This flow demonstrates use of the Laboratory and Logging nodes.
|
||||
|
||||
[laboratory](examples/laboratory.json)
|
||||
|
||||
## Known issues
|
||||
|
||||
### FFMPEG
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ from PIL import Image as PilImage
|
||||
from .categories import NodeCategories
|
||||
from .err import on_error
|
||||
from .shared import DreamConfig, MpegEncoderUtility
|
||||
from .types import *
|
||||
from .dreamtypes import *
|
||||
|
||||
CONFIG = DreamConfig()
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
from .categories import NodeCategories
|
||||
from .err import *
|
||||
from .shared import ALWAYS_CHANGED_FLAG, hashed_as_strings
|
||||
from .types import RGBPalette
|
||||
from .dreamtypes import RGBPalette
|
||||
|
||||
|
||||
def _generate_switch_input(type: str):
|
||||
|
||||
+40
-7
@@ -7,7 +7,7 @@ import folder_paths as comfy_paths
|
||||
|
||||
from .categories import NodeCategories
|
||||
from .shared import hashed_as_strings, DreamStateFile
|
||||
from .types import LogEntry, SharedTypes, FrameCounter
|
||||
from .dreamtypes import LogEntry, SharedTypes, FrameCounter
|
||||
|
||||
_logfile_state = DreamStateFile("logging")
|
||||
|
||||
@@ -97,10 +97,43 @@ class DreamStringToLog:
|
||||
"required": {
|
||||
"text": ("STRING", {"default": ""}),
|
||||
},
|
||||
"optional": {
|
||||
"label": ("STRING", {"default": ""}),
|
||||
}
|
||||
}
|
||||
|
||||
def convert(self, text):
|
||||
return (LogEntry.new(text),)
|
||||
def convert(self, text, **values):
|
||||
label = values.get("label", "")
|
||||
if label:
|
||||
return (LogEntry.new(label + ": " + text),)
|
||||
else:
|
||||
return (LogEntry.new(text),)
|
||||
|
||||
|
||||
class DreamStringTokenizer:
|
||||
NODE_NAME = "String Tokenizer"
|
||||
ICON = "🪙"
|
||||
OUTPUT_NODE = True
|
||||
CATEGORY = NodeCategories.UTILS
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("token",)
|
||||
FUNCTION = "exec"
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"text": ("STRING", {"default": "", "multiline": True}),
|
||||
"separator": ("STRING", {"default": ","}),
|
||||
"selected": ("INT", {"default": 0, "min": 0})
|
||||
},
|
||||
}
|
||||
|
||||
def exec(self, text: str, separator: str, selected: int):
|
||||
if separator is None or separator == "":
|
||||
separator = " "
|
||||
parts = text.split(sep=separator)
|
||||
return (parts[abs(selected) % len(parts)].strip(),)
|
||||
|
||||
|
||||
class DreamLogFile:
|
||||
@@ -169,10 +202,10 @@ class DreamLogFile:
|
||||
for (t, text) in log_entry.get_filtered_entries(ts):
|
||||
dt = datetime.datetime.fromtimestamp(t)
|
||||
output_text.append("[frame {}/{} (~{}%), timestamp {}]\n{}".format(frame_counter.current_frame + 1,
|
||||
frame_counter.total_frames,
|
||||
round(frame_counter.progress * 100),
|
||||
dt.strftime(self._get_tm_format(
|
||||
clock_has_24_hours)), text.rstrip()))
|
||||
frame_counter.total_frames,
|
||||
round(frame_counter.progress * 100),
|
||||
dt.strftime(self._get_tm_format(
|
||||
clock_has_24_hours)), text.rstrip()))
|
||||
output_text.append("---")
|
||||
last_t = max(t, last_t)
|
||||
output_text = "\n".join(output_text) + "\n"
|
||||
|
||||
Reference in New Issue
Block a user