H3 AudioFirst Check Audio Lock
The Node That Refuses to Save a Video Whose Voice Changed
- samples
- audio_latent
- LATENT
Most custom nodes do something. This one mostly asserts. H3AudioFirstCheckLock sits between your video sampler and the save node, compares the audio half of the finished latent against the audio latent you locked in earlier, and throws if they disagree. Wire it up, and a three-minute H3 render that quietly lost its nice audio fails loudly at the end instead of writing a file you'd only notice was wrong on playback.
It's the least glamorous node in the pack and the one I'd argue you shouldn't delete.
Why it needs to exist
The whole AudioFirst pack rests on one assumption: that if you stuff a finished audio latent into the video-pass latent with a zero denoise mask, the sampler leaves it alone. That works - the lock node that does the stuffing builds a nested latent with ones for the video half and zeros for the audio half - but it's an assumption about ComfyUI's internals and about H3's own sampler wrapper, not a guarantee the model gives you. Model code changes. Someone swaps in a different sampler, an upscaler, a VAE, a handoff node. The audio half quietly gets re-noised or mixed, and the result is a perfectly normal-looking video with the metal-pipe voice back, and no error anywhere.
So the pack's author wrote the check into the graph. The node does exactly one thing and does it honestly.
What it compares
You give it two latents:
- samples - the output of the video pass, the finished AV latent.
- audio_latent - the audio pass output, the same one you fed into H3AudioFirstLockAudio.
It pulls the second tensor out of the nested latent, converts both to CPU float, checks the shapes match and that every value is finite, and then computes the max absolute difference. The tolerance is 2e-5. Above that, you get:
Audio lock changed the audio latent (max abs diff 0.0043)
Below it, it logs [H3 AudioFirst] Audio lock preserved (max abs diff ...) and hands the latent through unchanged to its single LATENT output, which is what you feed to the save node (H3X2StreamSave in the examples).
Note what it is not: it isn't a save node, it doesn't touch pixels, and its output is the same latent you gave it. It's a wire with an opinion.
Where it fails, and what that means
Two error paths, both in the source, both useful:
Shape mismatch or non-finite values. Usually the wrong length upstream, or a NaN that crept in during sampling. If you get this, check that H3AudioFirstConditioning's length and MiniMaxH3ImageToVideo's frame count match - 17k+5, so 124 / 243 / 345 for 5 / 10 / 14 seconds - and that your image crop is sane.
Max abs diff above tolerance. Something after the lock touched the audio. Ranked by what I'd check first:
- You're on the fast LBH workflow and only locked once. LBH splits into a low-res pass and an upscale-then-one-step pass, the 3D latent upscaler has no idea about the audio half, so the example splits the AV latent with
LTXVSeparateAVLatent, runs the video throughH3LBHVideoHandoff, re-concatenates withLTXVConcatAVLatent, and uses a second H3AudioFirstLockAudio before the final step. One lock, two passes, diverged audio. - Something else re-sampled the latent after the lock without carrying the zero mask through. Any node that rebuilds the latent drops the
noise_mask, and the audio is back in play. - A dtype conversion in the chain. The check casts both sides to float for comparison, which is generous, but a genuine precision change on the audio side will show up.
One shape of mistake produces a crash rather than a message: this node assumes it's looking at the nested audio+video latent and indexes into it directly. Hand it a plain video-only latent and you get an attribute error, not a friendly explanation. If you see that, you wired the wrong thing into samples.
Install
Manager → H3 AudioFirst X2 Stream (plus H3 X2 Stream for the save node the examples use). Or:
cd ComfyUI/custom_nodes
git clone https://github.com/sepiablue-ai/ComfyUI-H3-AudioFirst-X2-Stream
Restart ComfyUI. The pack ships no Python dependencies of its own; it needs ComfyUI 0.38.0+ with native MiniMax H3, plus the hand-placed model files listed in the README and a one-time run of 00_prepare_x2.json. If you install with Manager, don't also run setup.bat - the two use different folder names and you'll end up with every node registered twice.
Is it worth the wire?
It costs one CPU copy of the audio latent - small, since it's audio only - plus the seconds you'd spend re-running a failed render. Put it where the examples put it, immediately before the save node, and leave it alone. If it ever fires, you've learned something real about your graph. That's a better deal than most nodes offer.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| samples | LATENT | — | |
| audio_latent | LATENT | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| LATENT | LATENT | — |