Video Audio Mixer π΅
Stitching two generated clips into one video β audio, BGM and all β without leaving ComfyUI
- images1
- video_info1
- audio1
- images2
- audio2
- video_info2
- bgm
- images_output
- audio_output
- video_info_output
The node that does the boring half of "video editing"
Your video model nailed two short clips. Now you want them joined into one cut, with the dialogue audible and a music bed underneath - the stuff every other "film" thread on r/StableDiffusion is asking about. DJ_VideoAudioMixer is a single node that does that assembly step inside the graph, so you never export to an external editor for the parts you didn't actually generate.
It's a two-for-one: it concatenates the frames of two video clips (the second is optional), and it mixes their audio tracks together with a background-music track that ducks out of the way when someone's talking. Model-generated clips from Wan, LTX-2, Hunyuan and friends are usually a few seconds of near-silence or bare audio; this is the node that turns a pile of them into something you'd post. The name "DJ" is doing a lot of work for what is really an audio-bus mixer, but it earns it.
How it actually works
Read the source and the marketing melts away. The headline feature - "automatic speech detection" - is not a speech-recognition model. It's energy-based ducking: the node computes a sliding-window audio-energy profile of your primary track (a 300ms window, smoothed over 500ms), and wherever energy crosses a threshold, it lowers the BGM volume toward your bgm_volume setting. There's no ML involved, no model download, nothing to tune. It behaves like a VAD for dialogue because speech is loud, and that's usually good enough.
The rest is housekeeping that matters more than it sounds like it does:
- Sanitization. Every audio tensor gets NaN/infinity scrubbed (
nan_to_num), clamped, and run through a soft limiter. This is the fix for the classic "FFmpeg errors out on NaN audio" failure you'll hit with ComfyUI's AUDIO type. - Resampling. Tracks at different sample rates get resampled via torchaudio to match.
- Channel matching. Mono BGM becomes stereo to match your primary track, or vice versa.
- Short audio handling. An audio track shorter than its video gets either silence padded in (
pad_with_silence) or looped to fill (repeat_audio).
No video encoding happens here - you get frames and an audio tensor back, and VideoHelperSuite's VHS_VideoCombine does the actual encode. The node just feeds it.
The inputs that matter
Only two things are truly required: images1 and video_info1 (the VHS_VIDEOINFO dict from VideoHelperSuite - that's why VHS is a dependency). Everything else is optional, which means the node doubles as a "single clip + BGM" mixer if you only feed it one video.
bgm_mode(defaultall): apply the music to the whole combined cut, or only the first/second video segment with a fade at the join. Handy if clip one is a voiceover and clip two is just b-roll.bgm_volume(default 0.3): the floor volume for music under speech. If your dialogue still gets buried, this is the knob, not the node.fade_in_sec/fade_out_sec(both default 1): global fades on the BGM.audio_match_method(defaultpad_with_silence): how a short track stretches to fit.
Installation
Two videos' worth of glue, one install:
cd ComfyUI/custom_nodes/
git clone https://github.com/ShmuelRonen/DJ_VideoAudioMixer.git
Restart ComfyUI and it lands in the audio/video processing category. Or just search "DJ_VideoAudioMixer" in ComfyUI Manager. There's no requirements.txt - the two real dependencies are torchaudio (for resampling, and you almost certainly already have it, since ComfyUI's PyTorch bundles it) and VideoHelperSuite (for the VHS_VIDEOINFO type). No model files, no API key, nothing that downloads gigabytes on first run. If video_info1 shows as a missing type, that's your VHS install talking - fix that first.
Where people get burned
Three things, in order of how often they show up:
- "My FFmpeg encode fails on NaN" - the built-in sanitization handles most of it, but if it still trips, lower
bgm_volume. Nothing else in the node makes audio louder than you ask it to. - Audio out of sync - the node computes durations from the fps in your
video_info, and it warns if your two clips have different fps (it uses clip 1's). Make the fps values in your video loaders honest and this mostly stops biting. - "The node says it detected speech but nothing ducks" - ducking only kicks in when there's actual signal (
abs().max() > 0.01); near-silent primary audio just means the BGM plays at full level. That's correct behavior, not a bug.
It's a thin, single-purpose pack with near-zero community footprint yet, but for the specific job of stitching clips and adding a music bed it's the one I reach for - one node, no ffmpeg command-line archaeology.
Inputs (12)
| Name | Type | Default | Description |
|---|---|---|---|
| images1 | IMAGE | β | |
| video_info1 | VHS_VIDEOINFO | β | |
| audio1opt | AUDIO | β | |
| images2opt | IMAGE | β | |
| audio2opt | AUDIO | β | |
| video_info2opt | VHS_VIDEOINFO | β | |
| bgmopt | AUDIO | β | |
| bgm_modeopt | COMBO | all | 3 options: all, first_video, second_video |
| bgm_volumeopt | FLOAT | 0.300β1 | β |
| fade_in_secopt | FLOAT | 1.00β5 | β |
| fade_out_secopt | FLOAT | 1.00β5 | β |
| audio_match_methodopt | COMBO | pad_with_silence | 2 options: pad_with_silence, repeat_audio |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| images_output | IMAGE | β |
| audio_output | AUDIO | β |
| video_info_output | VHS_VIDEOINFO | β |