MiniMax H3 Audio Preview
Your MiniMax H3 clip has audio you've been silently throwing away
- model
- audio_vae
- MODEL
MiniMax H3's whole party trick is that it generates stereo audio in the same forward pass as the picture - dialogue, sound effects and room tone, synced to the video it was denoised next to. And then every live preview in the ecosystem throws that half away. ComfyUI's built-in preview literally keeps x0.tensors[0] (the video) and drops the audio stream, and the preview socket has no audio event to carry sound on anyway. This node is the fix: it sits in your H3 workflow, decodes the audio half of the latent as the sampler runs, and draws a waveform in the node you can play before the render even finishes. No API, no key, nothing to sign up for.
How it works
The clever part is how it finds the audio. H3 ships a packed audio+video latent - one tensor with both streams - and the pack deliberately reads H3's numbers rather than hard-coding them. The audio stream is found by matching your VAE's latent channel count, not by assuming it's stream number two. The sample rate comes from the decode itself, and the latent frame rate behind window_seconds is measured from the first decode (frames in versus samples out). So a VAE variant at a different rate or channel count decodes correctly instead of quietly producing nonsense, and mono stays mono instead of getting doubled.
It also undoes a scale trick that would otherwise bite you. H3 denoises audio and video on different flow shifts, and ComfyUI reconciles that by scaling the audio latent onto the video schedule (ModelSamplingAV.audio_scale, typically 4.0). Decode without dividing that back out and the audio VAE gets a latent several times too large - which comes back as loud noise at every step, while the video decodes perfectly. That's the kind of bug that looks like a broken model.
The node registers itself as an outer-sample wrapper with its own key, so it chains with whatever draws your frames instead of replacing it. You keep KJNodes' Preview Override with Kijai's taeh3 for video and add this alongside. The decoded clip is served from ComfyUI's own server over HTTP (the author tried data: and blob: URLs; browsers refused both), and the panel draws a per-channel envelope - blue left above, green right below.
The inputs that matter
Only two of the six need real thought. model is the model to attach to - and this is the trap: its output is what the sampler must read, or nothing happens. A node whose output goes nowhere is never executed. audio_vae gets minimax_h3_audio_vae, the real decoder. Wire the video VAE here and the preview logs which two channel counts didn't match.
The rest are quality-of-life. window_seconds (default 3, up to 15) decodes from the start of the shot - the part that lines up with a looping preview; 0 does the whole clip (~520 MB). Cost scales with it, but a three-second window is only ~110 MB and a fraction of a second, so there's no need for a "tiny audio VAE" like video's taeh3. start_at_percent (default 50) skips the early steps, when the audio stream is still mostly noise and every decode would be spent on hiss. every_n_steps and max_preview_overhead (default 15%) are throttles.
Install
From ComfyUI Manager, search "MiniMax H3 Preview", or:
cd ComfyUI/custom_nodes
git clone https://github.com/Brioch/ComfyUI-MiniMaxH3-Preview
then restart ComfyUI. There are no Python dependencies beyond what ComfyUI already installs, but you need ComfyUI 0.30.0+ - that's where H3's packed audio+video latent landed. You also need the audio VAE, minimax_h3_audio_vae_fp32.safetensors, in ComfyUI/models/vae/. It's the same file your finished render decodes with, so if you've rendered an H3 clip you likely already have it.
Gotchas
- Sound is off until you click it. Browsers refuse audio on a page you haven't interacted with, and a queued render shouldn't start talking. The button tells you which is happening:
🔇 click for soundmeans a click fixes it;⚠ clip unplayablemeans the browser refused the audio itself - check the console. - Nothing plays and the log says "no audio stream found" means your latent isn't H3's packed one. It has to come from
EmptyMiniMaxH3LatentAV,MiniMaxH3ImageToVideo, orMiniMaxH3ReferenceToVideo. - H3 itself is the real prerequisite, and it's heavy - roughly 42 GB reported for the weights, with no verified consumer-hardware floor yet. And check the MiniMax H3 Community License: the open weights exclude the US, EU, UK and South Korea from its Applicable Territory, so in those regions the local-weights path isn't licensed at all.
There's also a bundled offline test (test_audio_preview.py) that runs with no GPU, model or server - handy before committing to a long H3 render.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | Model to attach the audio preview to. | |
| audio_vae | VAE | minimax_h3_audio_vae. The real decoder, and the one that says how many channels the audio stream has so it can be picked out of the pack. H3's audio has no tiny equivalent of taeh3, and does not need one: a three-second window is ~110 MB and a fraction of a second. | |
| window_seconds | FLOAT | 3.00–15 | Seconds of audio to decode, from the START of the shot — the part that lines up with a preview animation looping from frame one. Cost scales with it. 0 decodes the whole clip (~520 MB at 15s). |
| start_at_percent | INT | 500–100 | Don't decode until this share of the steps is done. Early on the audio stream is still mostly noise, so the decodes would be spent on hiss. |
| every_n_stepsopt | INT | 11–50 | Never update more often than every N sampler steps. |
| max_preview_overheadopt | INT | 150–100 | Cap on how much of the render time this may use, in percent. Updates are also never sent faster than the clip plays, so you always hear one through. 0 disables the cap. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| MODEL | MODEL | Model with the audio preview attached. |