Skip to content

Commit d9c6539

Browse files
authored
Merge branch 'master' into feat/partner-nodes/seedance-25-task-type
2 parents 6618aa3 + a736507 commit d9c6539

30 files changed

Lines changed: 2676 additions & 148 deletions

comfy/cli_args.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ def from_string(cls, value: str):
180180
parser.add_argument("--disable-dynamic-vram", action="store_true", help="Disable dynamic VRAM and use estimate based model loading.")
181181
parser.add_argument("--enable-dynamic-vram", action="store_true", help="Enable dynamic VRAM on systems where it's not enabled by default.")
182182
parser.add_argument("--fast-disk", action="store_true", help="Prefer disk-backed dynamic loading and offload over unpinned RAM. Can be faster for users with fast NVME disks.")
183+
parser.add_argument("--disable-cuda-graphs", action="store_true", help="Disable CUDA graphs.")
183184

184185
parser.add_argument("--force-non-blocking", action="store_true", help="Force ComfyUI to use non-blocking operations for all applicable tensors. This may improve performance on some non-Nvidia systems but can cause issues with some workflows.")
185186

comfy/latent_formats.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,11 @@ class ACEAudio15(LatentFormat):
957957
latent_dimensions = 1
958958
temporal_downscale_ratio = 1764
959959

960+
class MiniMaxMusic3(LatentFormat):
961+
latent_channels = 128
962+
latent_dimensions = 1
963+
temporal_downscale_ratio = 512
964+
960965
class ChromaRadiance(LatentFormat):
961966
latent_channels = 3
962967
spacial_downscale_ratio = 1

comfy/ldm/minimax/model.py

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,18 @@ def _video_t_grid(n, origin):
9191
return float(origin) + torch.cat([torch.zeros(1, dtype=torch.float64), spans[:-1].cumsum(0)])
9292

9393

94+
def _ref_t_span(blk):
95+
# time-axis span a reference block occupies ahead of the target streams
96+
kind = blk["kind"]
97+
if kind == "image":
98+
return 1.0
99+
if kind == "audio":
100+
return float(blk["ref_audio_t"])
101+
if kind in ("video", "video_audio"):
102+
return max(float(blk["ref_audio_t"]), sum(_video_t_spans(blk["latent_t"])))
103+
return 0.0
104+
105+
94106
def _audio_grid(cursor, t, w_low, w_high):
95107
# channel-major stereo rows: t advances per latent frame, w pinned to the grid extremes per stereo channel, h stays 0
96108
g = torch.zeros(t * 2, 3, dtype=torch.float64)
@@ -288,7 +300,7 @@ def forward(self, x, t_emb, video_seg, audio_seg):
288300
class PackedLayout:
289301
"""Static packed-sequence structure for one shape/conditioning signature."""
290302

291-
def __init__(self, text_len, latent_t, latent_h, latent_w, audio_t, keyframes=None, refs=None, frame_count=None):
303+
def __init__(self, text_len, latent_t, latent_h, latent_w, audio_t, keyframes=None, refs=None):
292304
frame, w_grid = _frame_grid(latent_h, latent_w)
293305
frame_rows = frame.shape[0]
294306

@@ -299,29 +311,37 @@ def __init__(self, text_len, latent_t, latent_h, latent_w, audio_t, keyframes=No
299311

300312
img_pos, img_update = [], []
301313
audio_pos, audio_update = [], []
302-
cursor = text_len
303314
row = text_len
304315

316+
target_audio_w = (float(w_grid[0]), float(w_grid[-1]))
317+
# refs pack between text and the targets, so the target timeline starts after their spans
318+
cursor = float(text_len)
319+
for blk in refs or ():
320+
cursor += _ref_t_span(blk)
321+
305322
if keyframes:
306-
# fl2va: keyframe cond rows right after text, sharing the target spatial grid
323+
# fl2va: keyframe cond rows right after text, sharing the target spatial grid;
324+
# anchors count from the target timeline origin, FRAME_RESCALE per pixel frame, 1.0 per audio latent frame
307325
for kf in keyframes:
308-
pixel_index = kf["resolved_frame_index"]
309-
if pixel_index == 0:
310-
cond_t = float(text_len)
311-
elif frame_count is not None and pixel_index == frame_count - 1:
312-
cond_t = float(text_len) + sum(_video_t_spans(latent_t)) - FRAME_RESCALE
313-
else:
314-
raise ValueError("only first/last keyframe anchors are supported")
315-
g = torch.empty(frame_rows, 3, dtype=torch.float64)
316-
g[:, 0] = cond_t
317-
g[:, 1:] = frame
318-
segments.append(("cond", frame_rows))
319-
pos.append(g)
320-
img_pos.append(torch.arange(row, row + frame_rows))
321-
img_update.append(torch.zeros(frame_rows, dtype=torch.bool))
322-
row += frame_rows
326+
cond_t = cursor + FRAME_RESCALE * kf["resolved_frame_index"]
327+
video_latent = kf.get("latent")
328+
if video_latent is not None:
329+
vt = video_latent.shape[2]
330+
n = vt * frame_rows
331+
segments.append(("cond", n))
332+
pos.append(_video_grid(vt, frame, cond_t))
333+
img_pos.append(torch.arange(row, row + n))
334+
img_update.append(torch.zeros(n, dtype=torch.bool))
335+
row += n
336+
audio_latent = kf.get("audio_latent")
337+
if audio_latent is not None:
338+
rt = audio_latent.shape[-1]
339+
segments.append(("cond_audio", rt * 2))
340+
pos.append(_audio_grid(cond_t, rt, *target_audio_w))
341+
audio_pos.append(torch.arange(row, row + rt * 2))
342+
audio_update.append(torch.zeros(rt * 2, dtype=torch.bool))
343+
row += rt * 2
323344

324-
target_audio_w = (float(w_grid[0]), float(w_grid[-1]))
325345
if refs:
326346
cursor = float(text_len)
327347
for blk in refs:
@@ -389,7 +409,7 @@ def __init__(self, text_len, latent_t, latent_h, latent_w, audio_t, keyframes=No
389409
self.audio_update = torch.cat(audio_update)
390410
self.signature = (text_len, latent_t, latent_h, latent_w, audio_t)
391411
# contiguous segment table (start, stop, kind)
392-
# kinds: text / cond / ref_img / ref_audio / audio / video
412+
# kinds: text / cond / cond_audio / ref_img / ref_audio / audio / video
393413
# the packed sequence is uniform per segment in (modality tag, timestep class),
394414
# except the text span (tag runs resolved at forward time from the presentation tags)
395415
seg_abs = []
@@ -529,8 +549,7 @@ def _forward(self, x, timestep, context, transformer_options={}, minimax_payload
529549
if layout is None or layout.signature != (text_len, latent_t, lat_h, lat_w, audio_t):
530550
layout = PackedLayout(text_len, latent_t, lat_h, lat_w, audio_t,
531551
keyframes=payload.get("keyframes"),
532-
refs=payload.get("refs"),
533-
frame_count=payload.get("frame_count"))
552+
refs=payload.get("refs"))
534553

535554
# model_base passes model_sampling.timestep(sigma) = sigma * 1000
536555
shift_v = float(transformer_options.get("minimax_h3_sigma_shift_video", self.sigma_shift_video))
@@ -543,14 +562,14 @@ def _forward(self, x, timestep, context, transformer_options={}, minimax_payload
543562
vis_aug = float(payload.get("visual_cond_noise_aug", VISUAL_COND_TIMESTEP))
544563
aud_aug = float(payload.get("audio_cond_noise_aug", AUDIO_COND_TIMESTEP))
545564
has_vis_cond = any(k in ("cond", "ref_img") for _, _, k in layout.segments)
546-
has_aud_cond = any(k == "ref_audio" for _, _, k in layout.segments)
565+
has_aud_cond = any(k in ("cond_audio", "ref_audio") for _, _, k in layout.segments)
547566
seg_t = {"text": t_v, "video": t_v, "audio": t_a,
548567
"cond": max(t_v, vis_aug), "ref_img": max(t_v, vis_aug),
549-
"ref_audio": max(t_a, aud_aug)}
568+
"cond_audio": max(t_a, aud_aug), "ref_audio": max(t_a, aud_aug)}
550569
unique_t = sorted({t_v, t_a} | ({seg_t["cond"]} if has_vis_cond else set())
551570
| ({seg_t["ref_audio"]} if has_aud_cond else set()))
552571
t_row = {t: i for i, t in enumerate(unique_t)}
553-
seg_tag = {"text": 1, "video": 0, "audio": 2, "cond": 0, "ref_img": 0, "ref_audio": 2}
572+
seg_tag = {"text": 1, "video": 0, "audio": 2, "cond": 0, "ref_img": 0, "cond_audio": 2, "ref_audio": 2}
554573

555574
text_tags = payload.get("text_token_tags")
556575
mod_segments = []

comfy/ldm/minimax_music/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)