Files
mcDandy-more_math/more_math/StringMathNode.py
T
2026-03-26 11:17:11 +01:00

112 lines
4.1 KiB
Python

from .helper_functions import (
generate_dim_variables,
parse_expr,
getIndexTensorAlongDim,
as_tensor,
normalize_to_common_shape,
make_zero_like,
get_v_variable,
get_f_variable,
checkLazyNew
)
from .Parser.UnifiedMathVisitor import UnifiedMathVisitor
from comfy_api.latest import io
import torch
from .Stack import MrmthStack
import copy
from .ParseTree import MrmthParseTree
class StringMathNode(io.ComfyNode):
"""
Enables math expressions on Audio.
Inputs:
I: Autogrow image inputs (I0, I1, ...)
F: Autogrow float inputs (F0, F1, ...)
Image: Expression
"""
@classmethod
def define_schema(cls) -> io.Schema:
return io.Schema(
node_id="mrmth_ag_AudioMathNode",
category="More math",
display_name="Audio math",
inputs=[
io.Autogrow.Input(id="V",template=io.Autogrow.TemplatePrefix(io.String.Input("values", optional=True), prefix="V", min=1, max=50)),
io.Autogrow.Input(id="F", template=io.Autogrow.TemplatePrefix(io.Float.Input("float", default=0.0, optional=True, lazy=True, force_input=True), prefix="F", min=1, max=50)),
io.MultiType.Input(
io.String.Input("Expression", default="", multiline=False),
types=[io.String,MrmthParseTree],
tooltip="3D model file or path string",
),
io.Int.Input(id="batching", default=0),
io.Bool.Input(
id="remember_stack",
default=False,
display_name="Remember stack across batch",
tooltip=(
"If enabled, stack is copied at output leading to changes being remembered during batch operations (node runs multiple times in sucession). If disabled each batch gets it's own copy of the stack."
),
),
MrmthStack.Input(id="stack", tooltip="Access stack between nodes",optional=True)
],
outputs=[
io.Audio.Output(is_output_list=True),
MrmthStack.Output(),
],
)
@classmethod
def check_lazy_status(cls, Expression, V, F,batching=0, remember_stack=False,stack={}):
return checkLazyNew(Expression,V,F)
@classmethod
def execute(cls, V, F, Expression, batching=0, remember_stack=False, stack={}):
variables = {
"a": V.get(0,""), "b": V.get(1,""), "c": V.get(2,""), "d": V.get(3,""),
"w": F.get("F0", 0.0) if F.get("F0") is not None else 0.0,
"x": F.get("F1", 0.0) if F.get("F1") is not None else 0.0,
"y": F.get("F2", 0.0) if F.get("F2") is not None else 0.0,
"z": F.get("F3", 0.0) if F.get("F3") is not None else 0.0
}
v_stacked, v_cnt = get_v_variable(V, length_mismatch="do nothing")
if v_stacked is not None:
variables["V"] = v_stacked
variables["Vcnt"] = float(v_cnt)
variables["V_count"] = float(v_cnt)
f_stacked, f_cnt = get_f_variable(F)
if f_stacked is not None:
variables["F"] = f_stacked
variables["Fcnt"] = float(f_cnt)
variables["F_count"] = float(f_cnt)
for k, val in F.items():
variables[k] = val if val is not None else 0.0
tree = None
if isinstance(Expression,str):
tree = parse_expr(Expression)
else:
tree = Expression
visitor = UnifiedMathVisitor(variables, len(V[0]),torch.device("cpu"),state_storage=stack)
result = visitor.visit(tree)
result = str(result)
if batching and batching > 0:
def chunks(s, n):
"""Produce `n`-character chunks from `s`."""
for start in range(0, len(s), n):
yield s[start:start+n]
stack = stack if remember_stack else copy.deepcopy(stack)
return (chunks(result,batching), stack)
else:
stack = stack if remember_stack else copy.deepcopy(stack)
return (result, stack)