基于 ComfyUI-LTXVideo 官方源码 + T2A 工作流分析 + 实测数据 | 2026-08-05
SolidMask(value=0) 完全冻结,模型只能从音频 latent 噪声生成;当帧数太少(≤39帧=1.6s),音频 VAE 解码出的信号极弱(-85dB)LTXVAudioOnlyModel 跳过视频流 + LTXVAudioOnlyEmptyVideoLatent(固定 64×64 占位符),完全不受视频帧数限制LTX2AudioLatentNormalizingSampling(KJNodes),在采样步骤归一化音频 latent,改善音质euler_ancestral_cfg_pp(非普通 euler),帧数 161(~6.7s @24fps)流程:H3 视频 → VHS_LoadVideoFFmpeg → VHS_VAEEncodeBatched → SolidMask(冻结) → 与音频 latent 合并 → 联合采样 → 分离音频
VHS_LoadVideoFFmpeg (1280×704, 24fps)
↓
VHS_VAEEncodeBatched → video latent (frozen via SolidMask value=0)
↓
LTXVConcatAVLatent (video_latent + audio_latent) ← LTXVEmptyLatentAudio
↓
SamplerCustomAdvanced (联合采样, 但视频被冻结)
↓
LTXVSeparateAVLatent → LTXVAudioVAEDecode → 音频
问题:虽然视频被 SolidMask(0) 冻结(理论上不应变化),但模型仍然运行视频自注意力和音视频交叉注意力(run_vx=True, a2v_cross_attn=True, v2a_cross_attn=True),这带来两个问题:
流程:LTXVAudioOnlyModel(跳过视频流) + LTXVAudioOnlyEmptyVideoLatent(64×64占位) → 与音频 latent 合并 → 纯音频采样 → 解码
LTXVAudioOnlyModel (model patch: run_vx=False, a2v_cross_attn=False, v2a_cross_attn=False)
↓
LTXVAudioOnlyEmptyVideoLatent (固定 1帧 64×64 全零占位)
↓
LTXVConcatAVLatent (dummy_video + audio_latent) ← LTXVEmptyLatentAudio(frames=161)
↓
SamplerCustomAdvanced (纯音频采样, 视频流被跳过)
↓
LTXVSeparateAVLatent → LTXVAudioVAEDecode → 音频
优势:
LTXVEmptyLatentAudio(frames_number=161) 独立控制)来源:ComfyUI-LTXVideo 插件 audio_only.py + 官方 README
| 参数 | 当前管线 (V2A) | 官方 T2A | 差异说明 |
|---|---|---|---|
| 模型加载 | UNETLoader (distilled fp8) + LTX2LoraLoaderAdvanced (Foley LoRA) |
CheckpointLoaderSimple (dev model) + LoraLoaderModelOnly (distilled LoRA, strength=0.5) |
官方用 dev 模型 + distilled LoRA;当前用 distilled 模型 + Foley LoRA |
| 视频流控制 | SolidMask(value=0) 冻结 video latent | LTXVAudioOnlyModel 关闭视频流 (run_vx=False) |
关键差异 SolidMask 只冻结 latent,模型仍计算视频注意力 |
| 视频输入 | VHS_LoadVideoFFmpeg → VHS_VAEEncodeBatched (1280×704) | LTXVAudioOnlyEmptyVideoLatent (固定 64×64 × 1帧) |
T2A 无需视频输入 |
| 音频帧数 | = 视频帧数 (probeFrameCount → alignLtxFrames) | 独立设置 (默认 161 帧 ≈ 6.7s @24fps) | 关键差异 T2A 帧数不受视频限制 |
| 音频 frame_rate | 24 | 24 (通过 PrimitiveFloat) | 一致 |
| 采样器 | euler |
euler_ancestral_cfg_pp |
差异 官方用 ancestral + cfg predictor |
| Sigmas | 1.0, 0.99375, 0.9875, 0.98125, 0.975, 0.909375, 0.725, 0.421875, 0.0 |
相同(9 步蒸馏调度) | 一致 |
| CFG | 1.0 | 1.0 | 一致(distilled 模型固定) |
| 文本编码器 | DualCLIPLoader (gemma + text_projection) |
LTXAVTextEncoderLoader (gemma + projection) |
等价但 API 不同 |
| NAG 链 | LTX2_NAG (scale=11, alpha=0.25, tau=2.5) 自研 |
无 | 当前管线独有的 BGM 压制机制 |
| Foley LoRA | ltx-2.3-foley-400-steps (strength=1.0) 自研 |
无 | 当前管线独有的环境音增强 LoRA |
| 音频归一化 | 无(后处理 dynaudnorm) | 无 | 缺失 两者都未用 LTX2AudioLatentNormalizingSampling |
| 帧数 | 时长 | raw Foley | 状态 |
|---|---|---|---|
| 39 | 1.6s | -85 dB | 静音 |
| 124 | 5.2s | -43 dB | 正常 |
| 345 | 14.4s | -34 dB | 正常 |
根因:V2A 模式下,视频 latent 用 SolidMask 冻结,但 v2a_cross_attn=True 仍然激活。短视频的视频 latent 帧数太少,在交叉注意力中提供的上下文信号不足,导致音频生成器输出信号极弱。
官方解法:T2A 模式直接关掉 v2a_cross_attn,音频不再依赖视频内容。
发现官方 KJNodes 提供的 LTX2AudioLatentNormalizingSampling 节点:
"Improves LTX2 generated audio quality by normalizing audio latents at specified sampling steps." 参数: model: MODEL audio_normalization_factors: "1,1,0.25,1,1,0.25,1,1" (逗号分隔的因子列表, 对应每个采样步骤)
这个节点在采样过程中对音频 latent 做统计归一化(类似 LTXVStatNormLatent),可以在第 3/6 步以 0.25 的强度拉回分布。当前管线完全没有使用这个节点。
官方 T2A 工作流用 euler_ancestral_cfg_pp(带 CFG predictor 的祖先采样),当前用普通 euler。ancestral 采样器在每步注入随机噪声,可能对音频这种需要"创造性"的生成任务更合适。
官方 T2A 模式完全不需要视频文件。对于"给已有视频生成环境音"的场景,可以用 T2A + prompt 描述场景 的方式,而非 V2A。这极大简化了管线:
LTXVEmptyLatentAudio(frames_number) 控制官方默认 frames_number=161(≈6.7s @24fps)。161 = 8×20+1(满足 8n+1 对齐)。这暗示官方认为 ~7 秒是音频生成的合理最小长度。
用 LTXVAudioOnlyModel 完全替代 SolidMask 冻结方案。
模型加载: 3: UNETLoader (distilled transformer_only fp8) 10: LTX2LoraLoaderAdvanced (Foley LoRA, video=0 audio=1) ← 保留 Foley LoRA NEW 9: LTXVAudioOnlyModel (model=[10,0]) ← 关闭视频流 NEW 11: LTX2AudioLatentNormalizingSampling (model=[9,0], factors="1,1,0.25,1,1,0.25,1,1") ← 音频归一化 NAG 链 (保留 BGM 压制): 99: PromptRelayEncode (model=[11,0], clip=[26,0], latent=[23,0]) 121: LTX2_NAG (model=[99,0], nag_scale=11) 文本: 26: DualCLIPLoader (gemma + text_projection) 5: CLIPTextEncode (positive) 6: CLIPTextEncode (negative) 7: LTXVConditioning (frame_rate=24) 音频潜在: 50: LTXVEmptyLatentAudio (frames_number=161, frame_rate=24) ← 独立帧数 NEW 15: LTXVAudioOnlyEmptyVideoLatent ← 64×64 占位符 合并 AV: 23: LTXVConcatAVLatent (video_latent=[15,0], audio_latent=[50,0]) ← dummy_video 采样 (distilled 9步): 15n: RandomNoise 27: ManualSigmas (9 sigmas) 13: KSamplerSelect (euler_ancestral_cfg_pp ← 改用 ancestral) 37: CFGGuider (model=[121,0], cfg=1.0) 16: SamplerCustomAdvanced 解码: 24: LTXVSeparateAVLatent 25: LTXVAudioVAEDecode 110: SaveAudio
SolidMask + VHS_VAEEncodeBatched → LTXVAudioOnlyEmptyVideoLatentLTXVAudioOnlyModel(关闭 run_vx/a2v/v2a)LTX2AudioLatentNormalizingSamplingframes_number 独立于视频帧数,固定 161(或按需调整)euler → euler_ancestral_cfg_pp如果不方便改架构,最小修复:
LTXVAudioOnlyModel:在 Foley LoRA 之后插入,关闭视频流。视频 latent 仍然存在(SolidMask 不变),但模型不再对它做注意力计算。等效于 T2A 但保留 V2A 的输入路径。LTX2AudioLatentNormalizingSampling:在 NAG 链之后、采样之前插入。euler → euler_ancestral_cfg_ppalignLtxFrames 中,强制 numFrames ≥ 97(≈4s),低于此值的补零到 97| # | 模式 | 变量 | 目的 | 优先级 |
|---|---|---|---|---|
| E1 | T2A | 基本模式 (无 Foley LoRA, 无 NAG) | 基线:纯 T2A 音频质量 | P0 |
| E2 | T2A | + Foley LoRA (strength=1.0) | Foley LoRA 对 T2A 的影响 | P0 |
| E3 | T2A | + Foley LoRA + NAG | 完整 BGM 压制链在 T2A 下是否有效 | P0 |
| E4 | T2A | + LTX2AudioLatentNormalizingSampling | 音频归一化对音质/响度的影响 | P1 |
| E5 | T2A | 采样器对比: euler vs euler_ancestral_cfg_pp | 采样器对音频质量的影响 | P1 |
| E6 | T2A | 帧数对比: 97 vs 161 vs 257 | 最小可用帧数 | P1 |
| E7 | V2A+修复 | 当前管线 + LTXVAudioOnlyModel | 最小改动修复短视频问题 | P2 |
| E8 | V2A+修复 | 当前管线 + AudioNormSampling | 响度归一化替代方案 | P2 |
| 文件 | 内容 |
|---|---|
audio_only.py | LTXVAudioOnlyModel + LTXVAudioOnlyEmptyVideoLatent 实现 |
latent_norm.py | LTXVAdainLatent + LTXVStatNormLatent + PerStepNormPatcher |
LTX-2.3_T2A_Single_Stage_Distilled.json | 官方 T2A 工作流模板 |
replace-audio.ts | 当前 V2A Foley 管线 (buildLtxAmbientWorkflow) |
generate.ts | 统一管线 (H3 + Foley + merge) |
| 版本 | 模式 | 帧数 | steps | raw Foley dB | final dB | BGM risk |
|---|---|---|---|---|---|---|
| v4 | V2A | 39 (1.6s) | 50 | -55 | -55.4 | LOW |
| v5 | V2A | 39 (1.6s) | 15 | -85 | -85.5 | LOW |
| v6-Case1 | V2A | 124 (5.2s) | 15 | -43.3 | -26.6 | LOW |
| v6-Case2 | V2A+TTS | 124 (5.2s) | 15 | -36.4 | -23.3 | LOW |
| replace-audio 测试 | V2A | 345 (14.4s) | 50 | -34.5 | N/A | LOW (1次重试) |
规律:帧数 → 音频响度。帧数越多,音频 VAE 有更多"素材"生成有效信号。15 步(v5)比 50 步(v4)更差——步数不足也可能影响音频质量。
| 当前生产路径 (replace-audio.ts) | 旧路径 (msr.ts) | |
|---|---|---|
| 函数 | buildLtxAmbientWorkflow() | buildFoleyWorkflow() + executeFoleyPipeline() |
| 调用者 | generate.ts ✅ 当前管线 | msr.ts handler (audioStrategy=foley) |
| 节点依赖 | 标准 LTXV 节点 ✅ 全部可用 | 9 个 LTXFoley* 节点 ❌ 容器中不存在 |
| LoRA strength | 1.0 | 2.0(验证过:1.0偏弱,2.0最佳) |
| 分辨率 | 1280×704 | 640×352(更低,省显存) |
| 帧数策略 | 整段视频帧数 (8n+1) | 滑窗 89帧/窗 (≈3.7s), overlap 1.0s |
| NAG 链 | ✅ LTX2_NAG (scale=11) | ❌ 无 |
| BGM 检测重试 | ✅ 最多2次换seed | ❌ 无 |
| 混音策略 | 后处理 dynaudnorm | sidechain ducking (ambient×0.55) |
结论:msr.ts 的 Foley 路径(滑窗架构)当前无法运行(LTXFoley* 节点缺失),但不影响生产。可以考虑将其滑窗 + LoRA strength=2.0的经验移植到当前路径。
| 参数 | replace-audio.ts (当前) | msr.ts (旧/参考) | 官方 T2A |
|---|---|---|---|
| 底模 | ltx-2.3-22b-distilled_transformer_only_fp8_input_scaled_v3 (22B 蒸馏) | ||
| Foley LoRA | ltx-2.3-foley-400-steps.safetensors (227MB, CivitAI) | ||
| LoRA strength | 1.0 | 2.0 ✅验证最佳 | — |
| Video VAE | LTX23_video_vae_bf16.safetensors (1.45GB) | ||
| Audio VAE | LTX23_audio_vae_bf16.safetensors (365MB) | ||
| CLIP | gemma_3_12B_it_fp8_scaled + ltx-2.3_text_projection_bf16 (DualCLIP) | ||
| CFG | 1.0 (distilled 硬性) | ||
| Sigmas | 1.0, 0.99375, 0.9875, 0.98125, 0.975, 0.909375, 0.725, 0.421875, 0.0 (9步) | ||
| 采样器 | euler | euler | euler_ancestral_cfg_pp |
| 分辨率 | 1280×704 | 640×352 | N/A (无视频) |
| 帧数 | 整段 (8n+1) | 89/窗 | 161 (独立) |
| frame_rate | 24 fps | ||
| Seed | 42 | 42 | 42 |
| 视频流控制 | SolidMask(0) 冻结 | SolidMask(0) 冻结 | LTXVAudioOnlyModel 关闭 |
| NAG | ✅ scale=11, α=0.25, τ=2.5 | ❌ | ❌ |
| BGM 检测 | ✅ 频谱分析 + 重试 | ❌ | ❌ |
| AudioNormSampling | ❌ 三者都未用 | ||
| 响度处理 | dynaudnorm (后处理) | sidechain ducking | 无 |
调研方法:ComfyUI-LTXVideo 官方插件源码 (audio_only.py, latent_norm.py) + T2A 工作流模板 + object_info API + generate.ts/replace-audio.ts/msr.ts/config.ts 源码审计 + 实测数据
生成时间:2026-08-05 | 环境:RTX 3090 + ComfyUI v0.30.1 + LTX-2.3 distilled
注:msr.ts 中的 LTXFoley* 节点路径(9个节点)在容器中不存在,不影响当前 generate.ts → replace-audio.ts 生产路径