LTX-2.3 Audio-Video Captioner (Local)
Your LTX-2.3 LoRA is deaf — this node writes the audio half of the caption
- final_caption
Here's the thing about training an LTX-2.3 LoRA: that model generates synchronized audio and video, and its trainer has whole conditioning modes for it. But every captioner people reach for - the Qwen-based VLM tools that spin out flowing cinematic prose - describes the picture and completely ignores what's being said. LTX-2.3 is the first mainstream local video model where the audio half of the caption genuinely matters, and this little node is the piece that fills that gap.
LTX-2.3 Audio-Video Captioner (Local) runs Whisper locally on your video, transcribes the dialog, guesses whether it's singing or speaking, detects music, and stitches it all into a caption written next to the file as {video}.txt - the exact spot your LoRA trainer is going to look. No API, no key, no per-caption cost.
How it works
The mechanism is simple and honest: the node shells out to ffmpeg to pull raw audio from the video, feeds it to a local openai-whisper model for transcription, then does a couple of lightweight numpy analyses on top. If there's speech you get something like The woman walks through the cafe. character says, "One black coffee, please." If there's no speech, it falls back to an ambient description ("accompanied by absolute dead silence and no audio", or the subtle room-tone variant). Toggle detect_singing and it runs an RMS-window analysis - long held notes plus low energy variance means sings, otherwise says. A spectral-flatness check looks for harmonic peaks to add "with music playing." Everything lands in the single final_caption output, which is also printed to the sidecar .txt.
That singing detector is a heuristic, not a classifier. It falls back to "says" on any error or ambiguity, and on a noisy mix it's going to be wrong some of the time. It's a dataset-prep nicety, not something to build your life around - flip it on, and if the captions look dumb, just turn it off.
Inputs that matter
Most of the knobs are thresholds you will never touch. The ones you actually set:
video_path(required) - path to the video. It's a forced input, so you can wire it from a loader, but a plain string works too. The node strips quotes and brackets, so pasting a path with spaces in quotes is fine.trigger_name- the subject's name that goes into the caption. Defaults tocharacter; set it to whatever your LoRA trigger word is.whisper_model_type-base,tiny,small,medium… andcharacter. That last one is a weird legacy label that just loadsbase. The default ischaracter, so out of the box you're onbase: fast, light, and fine for clean dialog, but if captions are garbling accents or music, move up tosmallormedium.visual_caption(optional) - your existing visual description. Hand this a string from your Qwen-style captioner and the node prepends it, so you end up with one combined caption instead of two files fighting.
overwrite_existing controls whether a stale .txt gets clobbered, and all the *_rms_threshold / audio_window_ms / music_*_threshold floats are the tuning guts. Leave them alone unless you're chasing a specific failure.
Installation
ComfyUI Manager will find it as ComfyUI-LTX-AudioCaptioner, or clone it manually:
cd ComfyUI/custom_nodes
git clone https://github.com/nerdydude364/ComfyUI-LTX-AudioCaptioner.git
cd ComfyUI-LTX-AudioCaptioner
pip install -r requirements.txt
Then restart ComfyUI. Two real gotchas here. First, openai-whisper is a heavy dependency - it drags torch and friends along, so the install is not instant. Second, and this burns Windows users specifically: ffmpeg is not pip-installed by this pack, it has to exist on your system PATH. If the node errors out on audio extraction, that's almost certainly why.
Common issues
- "Target path not found" printed in the console - the path doesn't exist from ComfyUI's working directory. Use an absolute path.
- First run is slow / looks stuck - that's Whisper downloading its model (the base model is roughly 142MB) into its cache. It's one-time.
- Wrong or empty transcriptions -
basejust isn't great on music, strong accents, or bad audio. Bump the model size. It's a local-quality tradeoff, not a bug. - The
.txtshows up next to the video, not in your dataset folder - that's by design. The node writes beside the source, so if your trainer reads captions from elsewhere, plan your file layout around it.
It's a niche tool, no two ways about it - you only want it if you're actually prepping LTX-2.3 training data with audio. But that's precisely the niche that had nothing, and for that job it's the one I'd reach for.
Inputs (16)
| Name | Type | Default | Description |
|---|---|---|---|
| video_path | STRING | — | |
| trigger_name | STRING | character | — |
| whisper_model_type | COMBO | character | 5 options: base, tiny, small, medium, character |
| overwrite_existing | BOOLEAN | true | — |
| detect_singing | BOOLEAN | false | — |
| avg_segment_length_threshold | FLOAT | 1.80.1–10 | — |
| energy_variance_threshold | FLOAT | 0.00500.0001–0.1 | — |
| audio_channels | COMBO | 1 | 2 options: 1, 2 |
| audio_sample_rate | COMBO | 16000 | 5 options: 8000, 16000, 22050, 44100, 48000 |
| silence_rms_threshold | FLOAT | 0.00100–0.01 | — |
| low_rms_threshold | FLOAT | 0.0100.001–0.1 | — |
| vocal_window_rms_threshold | FLOAT | 0.0150.001–0.5 | — |
| audio_window_ms | INT | 305–200 | — |
| music_rms_threshold | FLOAT | 0.1000.001–0.5 | — |
| music_tonal_threshold | FLOAT | 0.300.01–1 | — |
| visual_captionopt | STRING | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| final_caption | STRING | — |