Nodes/H3 Audio Drive Auto/H3 Audio Drive Long (any length)
ComfyUI Node

H3 Audio Drive Long (any length)

27 seconds of dialogue, six windows, one honest catch

By lebao-arch·Created 21 days ago·Updated 10 days ago· 3
H3 Audio Drive Long (any length)
  • model
  • clip
  • video_vae
  • audio_vae
  • audio
  • first_frame
  • ref_image
  • frames
  • audio
  • frames_total
  • report
◄prompt►
◄width864►
◄height480►
◄max_window_seconds5.00►
◄steps12►
◄sampler_name▾►
◄scheduler▾►
◄seed42►
◄seam_fade_frames0►
◄chain_framesfalse►
◄max_windows0►
◄audio_offset_frames0►

One node instead of a graph you can't build

H3 generates 4–15 second clips, full stop. Anything longer is windows: sample a chunk, take its last frame, feed that into the next chunk, stitch. In a normal ComfyUI graph that's a cycle - latent → sample → decode → next first_frame → sample - and you can't express a cycle in a DAG.

So H3AudioDriveLong chews the loop internally. Give it the H3 loaders, a prompt, an audio file of any length, and it plans grid-legal windows, freezes the matching slice of your track into each window's AV latent, samples that window with its own guider and sigma schedule, decodes it, carries the last frame forward, concatenates the lot, and hands back a track that's exactly as long as the frames it produced. One node, four outputs, no subgraph bookkeeping.

Measured on a 27.19 s MP3 at 864×480 / 12 steps: 6 windows, 659 frames (27.458 s), about 13 minutes on a 3090 Ti. Cost scales linearly, as you'd expect.

The catch, stated plainly

This is the part the README is refreshingly honest about, and it's the thing to know before you plan a five-minute talking-head short.

When a window carries an image anchor, H3 switches to image-to-video semantics and largely stops listening to the audio half of the latent. So:

  • chain_frames=True (the stable choice): the subject stays the same person, the pose is continuous, and window 2 onward scores 0.00 against its own audio. It does score ~0.40 against window 1's audio - it's still performing the previous take's rhythm, just not the new slice.
  • chain_frames=False: window 2 tracks its audio properly (0.55 in the same measurement) and the subject walks off into being a different person at the seam.
  • chain_frames=False plus a ref_image: same person, but the take goes static.

Null controls on the same frames - shuffled audio 0.08, white noise 0.01, an unrelated speaker −0.09 - tell you that 0.00 is a real absence, not a flat measurement.

Which leaves you with: a stable subject or tracking lips across a seam, not both. Not with this model, today. The honest recipes are chain plus a post-hoc lip-sync pass on the result (the pack's Wav2Lip node, or H3LipSyncTransfer onto the stable face), or unchain and cut between windows like an editor would. If you find that disappointing, you're not alone - it's the reason this pack has five nodes instead of one.

Inputs worth setting

The loaders are the usual H3 four: model, clip, video_vae, audio_vae, plus audio and prompt. Then:

max_window_seconds defaults to 5 and gets snapped down onto the 17k+5 grid. Five seconds keeps VRAM flat and seams predictable; 5.0 s becomes 124 frames.

max_windows at 0 means automatic - as many windows as the audio needs. A positive value is a safety cap, and it's the good kind of cap: it refuses with the exact count you need rather than quietly truncating your track. 27.19s of audio needs 6 windows of 5.17s, but max_windows=4 only covers 20.67s is a much better error message than a half-rendered take.

chain_frames is the decision above. seam_fade_frames cross-fades around the seam if you want it, though with chaining on, the seam is usually invisible and 0 is fine. steps (12), sampler_name, scheduler, seed are your sampling controls. audio_offset_frames shifts the returned track - mux only, length preserved - because H3 plays the mouth a consistent ~10 frames ahead of the audio.

Optional inputs: first_frame anchors window 1 at frame zero, and ref_image gives the text encoder an identity reference (it sees it as <Picture 1>) without an actual frame anchor, so window 1 stays audio-driven.

Outputs: frames into VHS_VideoCombine or CreateVideo, audio into the same node's audio input (already length-matched, so the mux can't drift), frames_total as an integer, and report - read it, it prints the window plan and the measured-limits reminder.

Install

Manager → H3 Audio Drive Auto, or:

cd ComfyUI/custom_nodes
git clone https://github.com/lebao-arch/comfyui-h3-audio-drive-auto
pip install soundfile   # the pack imports it at load time but doesn't declare it

Restart, and make sure all four H3 model files are in place - this node needs the video VAE and audio VAE, and it fails informatively-but-annoyingly if either is missing. No external tools, no second venv; everything here runs in ComfyUI's own process.

Troubleshooting

It refused before sampling, complaining about frame memory. That's the roughly 16 GB budget guard for collected frames. It tells you the chunk length to render separately - the message is the fix.

Window 2 scores 0.00. If chain_frames is on, that's the model behaving as documented, not a bug in your wiring. Score window 1 separately to confirm the graph is right, then decide which recipe you're on.

Everything scores well on a music bed. The scorer correlates picture motion with loudness. A good score on non-speech audio proves the mouth moves with the beat, not that it forms words.

The audio is longer than the picture. Expected - the node pads or trims to frame count and says so in report. Trust the returned track, not your source file.

Categoryminimax/h3/audio

Inputs (19)

NameTypeDefaultDescription
modelMODELMiniMax H3 diffusion model (a patched/EasyCache model is fine).
clipCLIPThe MiniMax H3 text encoder (CLIPLoader type=minimax).
video_vaeVAEminimax_h3_video_vae_fp16.
audio_vaeVAEminimax_h3_audio_vae_fp32.
audioAUDIODrives every window. The same waveform is returned for the mux.
promptSTRING—
widthINT86464–4096—
heightINT48064–4096—
max_window_secondsFLOAT5.001–15Window length. H3 was trained around 5-15 s; 5 s keeps VRAM flat and seams predictable.
stepsINT121–100—
sampler_nameCOMBO44 options: euler, euler_cfg_pp, euler_ancestral, euler_ancestral_cfg_pp, heun, heunpp2, +38
schedulerCOMBO9 options: simple, sgm_uniform, karras, exponential, ddim_uniform, beta, +3
seedINT420–18446744073709550000—
seam_fade_framesINT00–120 = hard cut (the new window is generated from the previous last frame, so the seam is normally invisible). >0 cross-fades that many frames around the seam.
chain_framesBOOLEANfalseAnchor each window on the previous last frame. Keeps the subject stable across seams, but an image anchor makes H3 treat window 2+ as image-to-video and they stop following their own audio (measured 0.00 vs 0.55 unchained). Off = lips track, subject may walk away from you.
max_windowsINT00–2000 = automatic: use as many windows as the audio needs. A positive value is a safety cap; the node refuses (with the exact window count you need) instead of silently truncating your audio.
audio_offset_framesINT0-48–48Shift the RETURNED audio against the rendered frames, in frames at 24 fps (length preserved). H3 plays the mouth ~10 frames ahead of the track, so -10 lands them on the same frame; use the offset H3LipSyncScore reports. The conditioning audio is never shifted.
first_frameoptIMAGEAnchors window 1 at frame 0.
ref_imageoptIMAGEIdentity reference seen by the text encoder as <Picture 1> (or <Picture 2> when first_frame is also connected). No frame anchor, so window 1 stays audio-driven - but window 2+ still stop tracking their own audio when this is connected (measured 0.00).

Outputs (4)

NameTypeDescription
framesIMAGE—
audioAUDIO—
frames_totalINT—
reportSTRING—