前面第 17 篇,我们分析了 Pixelle-Video 的 TTS 语音生成流程。
简单回顾一下,在 Pixelle-Video 里,每个分镜都会先把 narration 转成音频:
text
StoryboardFrame.narration
↓
FrameProcessor._step_generate_audio()
↓
TTSService
↓
Edge-TTS 或 ComfyUI TTS workflow
↓
frame.audio_path
↓
frame.duration
这一篇继续往下看一个更高级的语音能力:
声音克隆。
也就是用户上传一段参考音频后,Pixelle-Video 如何把它传入 TTS 工作流,让生成的解说声音更接近参考声音。
从源码角度看,Pixelle-Video 的声音克隆不是直接在 Python 代码里实现一个克隆算法,而是通过一个非常灵活的参数通道实现:
text
ref_audio
↓
StoryboardConfig
↓
FrameProcessor
↓
TTSService
↓
ComfyUI / RunningHub TTS workflow
↓
Index-TTS 或其他支持声音克隆的工作流
所以这一篇的重点不是讲 Index-TTS 模型内部怎么训练,而是分析 Pixelle-Video 如何在工程上支持"参考音频影响语音生成"。
一、声音克隆在 Pixelle-Video 中解决什么问题?
普通 TTS 只能选择固定音色。
比如 Edge-TTS 中,你可以选择:
text
zh-CN-YunjianNeural
zh-CN-XiaoxiaoNeural
en-US-AriaNeural
en-US-GuyNeural
这些音色适合快速生成旁白,但它们有一个问题:
声音风格是预设的,不是用户自己的。
如果你想做一个固定 IP 账号,或者希望每条视频都是同一个"主播声音",只靠预设音色就不够了。
声音克隆要解决的就是这个问题:
text
用户上传一段参考音频
↓
TTS 工作流提取声音特征
↓
生成的新旁白尽量模仿参考音频的音色和说话感觉
Pixelle-Video 的 README 中也把"参考音频"放在语音设置里,说明用户可以上传 MP3、WAV、FLAC 等音频用于声音克隆,并且它适用于支持声音克隆的 TTS 工作流,例如 Index-TTS;预览语音时也支持使用参考音频。
这说明声音克隆在 Pixelle-Video 中不是一个孤立概念,而是语音设置体系中的一个可选增强能力。
二、声音克隆和普通 TTS 的区别
普通 TTS 的输入通常是:
text
text
voice
speed
也就是说:
text
要读什么
用哪个预设声音读
读多快
声音克隆多了一个关键输入:
text
ref_audio
它代表参考音频。
所以声音克隆的输入更像:
text
text
voice / speaker 参数
speed
ref_audio
普通 TTS 更像"从音色库里选一个声音"。
声音克隆更像"给模型一个声音样本,让它参考这个声音说新内容"。
在 Pixelle-Video 的设计里,这两类能力被放进了同一个 TTSService 入口中。TTSService 的 __call__() 支持 text、workflow、voice、speed、inference_mode、output_path,并且通过 **params 接收额外工作流参数。
这个 **params 就是声音克隆这种扩展能力的关键入口。
三、为什么 Edge-TTS 不是真正的声音克隆路线?
先区分一个概念:
Edge-TTS 是本地轻量旁白路线,不是声音克隆路线。
在 Pixelle-Video 中,如果 tts_inference_mode == "local",TTSService 会走 _call_local_tts()。这个分支会读取 voice 和 speed,把 speed 转成 Edge-TTS 的 rate 参数,然后调用 edge_tts() 生成音频。
简化流程是:
text
text
↓
voice
↓
speed
↓
Edge-TTS
↓
output.mp3
这条路线的优点是:
text
简单
稳定
不需要 ComfyUI
不需要本地显卡
适合快速生成普通旁白
但它没有 ref_audio 这个核心输入。
所以,如果你想让参考音频影响生成结果,通常不能走 local Edge-TTS,而应该走 ComfyUI TTS workflow。
这就是 Pixelle-Video 的设计边界:
text
local 模式:
适合预设音色 TTS。
comfyui 模式:
适合 Index-TTS、声音克隆、自定义 TTS workflow。
四、声音克隆真正走的是 ComfyUI TTS workflow
在 Pixelle-Video 中,Index-TTS 这类声音克隆方案一般不是在 TTSService 里写死调用逻辑,而是通过 ComfyUI 或 RunningHub 的 TTS workflow 接入。
README 中也明确说明,语音设置可以从下拉菜单选择 TTS workflow,系统会自动扫描 workflows/ 文件夹中的 TTS 工作流;如果用户懂 ComfyUI,可以自定义 TTS workflow;参考音频适用于支持声音克隆的 TTS workflow,比如 Index-TTS。
所以它的架构是:
text
Pixelle-Video
↓
TTSService
↓
ComfyKit
↓
ComfyUI / RunningHub TTS workflow
↓
Index-TTS / 声音克隆节点
↓
audio_path
这里 Pixelle-Video 并不关心 Index-TTS 的内部实现。
它只负责把参数传进去:
text
text
voice
speed
ref_audio
至于 workflow 里到底怎么使用参考音频,是由具体 ComfyUI 工作流决定的。
这就是 Pixelle-Video 声音克隆设计的核心:
项目本身只做调度和参数传递,把具体声音克隆能力交给可替换的 TTS workflow。
五、ref_audio 在数据结构中的位置
先看数据结构。
Pixelle-Video 的 StoryboardConfig 中有一组音频相关字段:
text
tts_inference_mode
voice_id
tts_workflow
tts_speed
ref_audio
其中 ref_audio 的注释就是:用于声音克隆的参考音频,并且只用于 ComfyUI 模式。
这说明参考音频不是挂在某一个 frame 上,而是作为 storyboard 级别的配置进入生成流程。
可以理解为:
text
一条视频
↓
一个 StoryboardConfig
↓
同一个 ref_audio
↓
影响多个 frame 的 TTS 生成
也就是说,如果用户上传了一段参考音频,整条视频里的多个分镜旁白都可以使用同一段参考声音。
这对短视频账号很重要。
因为一个视频通常有多个分镜:
text
frame 1:开头钩子
frame 2:提出问题
frame 3:解释原因
frame 4:给出方法
frame 5:总结收尾
如果每段声音都不一样,观众听起来会很割裂。
把 ref_audio 放在 StoryboardConfig 中,就可以让所有 frame 共用同一个参考音频,保持整条视频的人声一致性。
六、ref_audio 是如何进入 StoryboardConfig 的?
在 StandardPipeline.initialize_storyboard() 中,Pixelle-Video 会创建 StoryboardConfig。
创建配置时,源码会从 ctx.params 中读取:
python
ref_audio=ctx.params.get("ref_audio")
同时也会读取 tts_inference_mode、tts_workflow、tts_speed、voice_id、media_workflow、frame_template 等参数。
也就是说,参考音频的入口是:
text
用户上传或选择参考音频
↓
生成请求 params
↓
ctx.params["ref_audio"]
↓
StoryboardConfig.ref_audio
这一层只是保存参数,还没有真正生成音频。
它的作用是把"用户上传了参考音频"这个信息放进后续每一帧都能访问到的配置里。
七、FrameProcessor 如何把 ref_audio 传给 TTS?
真正使用 ref_audio 的地方在 FrameProcessor._step_generate_audio()。
FrameProcessor 处理每个 frame 时,会先构造 tts_params:
text
text = frame.narration
inference_mode = config.tts_inference_mode
output_path = 当前 frame 的音频输出路径
index = frame.index + 1
如果是 local 模式,它只传 voice 和 speed。
如果是 comfyui 模式,它会传 workflow、voice、speed,并且如果 config.ref_audio 存在,就把它加入 tts_params["ref_audio"]。
简化后的逻辑是:
python
tts_params = {
"text": frame.narration,
"inference_mode": config.tts_inference_mode,
"output_path": output_path,
"index": frame.index + 1,
}
if config.tts_inference_mode == "comfyui":
if config.tts_workflow:
tts_params["workflow"] = config.tts_workflow
if config.voice_id:
tts_params["voice"] = config.voice_id
if config.tts_speed is not None:
tts_params["speed"] = config.tts_speed
if config.ref_audio:
tts_params["ref_audio"] = config.ref_audio
audio_path = await self.core.tts(**tts_params)
这段逻辑说明了一件事:
ref_audio 只在 ComfyUI TTS 路线中传入。
这也符合前面说的:声音克隆依赖支持参考音频的 workflow,而不是 Edge-TTS 本地分支。
八、TTSService 如何接收 ref_audio?
有意思的是,TTSService.__call__() 的函数签名里没有单独写一个 ref_audio 参数。
它是通过:
python
**params
接收额外参数的。
也就是说,FrameProcessor 传入:
python
ref_audio=xxx
之后,在 TTSService 里会进入 **params。
如果当前是 local 模式,TTSService 会调用 _call_local_tts(),额外参数不会进入 Edge-TTS。
如果当前是 comfyui 模式,TTSService 会把这些额外参数继续传给 _call_comfyui_workflow()。
这就是参考音频能进入 workflow 的原因。
完整链路是:
text
FrameProcessor
↓
self.core.tts(
text=frame.narration,
inference_mode="comfyui",
workflow="selfhost/tts_index.json",
ref_audio="xxx.wav"
)
↓
TTSService.__call__(..., **params)
↓
params = {"ref_audio": "xxx.wav"}
↓
_call_comfyui_workflow(..., **params)
这种设计很灵活。
因为未来不仅可以传 ref_audio,还可以继续传:
text
speaker_id
emotion
language
temperature
top_p
voice_clone_strength
noise_scale
只要对应 workflow 支持这些参数,就可以继续扩展。
九、ref_audio 如何进入 ComfyUI workflow_params?
进入 _call_comfyui_workflow() 后,Pixelle-Video 会构造 workflow_params。
源码中它先放入:
python
workflow_params = {"text": text}
然后如果传入 voice,就放入:
python
workflow_params["voice"] = voice
如果 speed 不为空且不等于 1.0,就放入:
python
workflow_params["speed"] = speed
最后关键一步:
python
workflow_params.update(params)
这会把 ref_audio 等额外参数全部合并进去。
所以声音克隆的参数传递链路是:
text
config.ref_audio
↓
tts_params["ref_audio"]
↓
TTSService.__call__(**params)
↓
_call_comfyui_workflow(**params)
↓
workflow_params.update(params)
↓
workflow_params["ref_audio"]
↓
ComfyKit.execute(workflow_input, workflow_params)
最终传给 ComfyKit 的参数大致是:
python
{
"text": "这一段要朗读的旁白",
"speed": 1.2,
"ref_audio": "uploads/reference_voice.wav",
"index": 1
}
具体 workflow 是否使用 ref_audio,取决于 workflow 内部节点有没有接收并处理这个参数。
十、ComfyKit 如何执行声音克隆工作流?
TTSService 并不直接调用 Index-TTS。
它会先解析 TTS workflow,然后通过共享的 ComfyKit 实例执行。
源码中,如果 workflow 来源是 RunningHub 并且有 workflow_id,就把 workflow_id 作为输入传给 ComfyKit;否则就把 selfhost 本地 workflow 文件路径传给 ComfyKit。最后统一调用:
python
result = await kit.execute(workflow_input, workflow_params)
所以声音克隆可能有两种部署方式:
text
selfhost:
workflow_input = workflows/selfhost/tts_index.json
本地 ComfyUI 执行声音克隆
runninghub:
workflow_input = workflow_id
RunningHub 云端执行声音克隆
两条路线对 Pixelle-Video 来说是统一的:
text
同样的 text
同样的 ref_audio
同样的 workflow_params
不同的执行后端
这就是 workflow 架构的优势。
十一、参考音频到底会影响什么?
从用户感知上看,参考音频通常会影响这些方面:
text
音色
口音
发声习惯
语气倾向
声音年龄感
声音厚度
部分停顿和节奏感
但要注意,Pixelle-Video 源码本身并不直接控制这些细节。
它只是把 ref_audio 传给 TTS workflow。真正如何提取声音特征、如何模仿参考声音、模仿到什么程度,是由 Index-TTS 或其他声音克隆模型决定的。
所以更准确地说:
Pixelle-Video 让参考音频有机会影响解说效果,但最终效果取决于具体 TTS workflow 和模型能力。
这也是为什么 README 中说参考音频适用于支持声音克隆的 TTS workflow,而不是说所有 TTS workflow 都能使用参考音频。
如果你使用的是普通 Edge-TTS workflow,ref_audio 可能没有意义。
如果你使用的是 Index-TTS 这类支持声音克隆的 workflow,ref_audio 才会真正影响输出声音。
十二、声音克隆为什么适合短视频账号?
短视频账号最重要的不是单条视频,而是长期一致性。
画风要一致。
标题风格要一致。
口播语气也要一致。
如果每条视频都换一个声音,观众很难形成记忆点。
声音克隆可以让账号拥有更稳定的听觉识别:
text
同一个参考音频
↓
多条视频使用相近音色
↓
用户形成"这个声音就是这个账号"的印象
这对这些内容尤其有价值:
text
知识科普账号
健康口播账号
财经解读账号
故事解说账号
小说推文账号
产品介绍账号
虚拟人物账号
数字人口播账号
Pixelle-Video 的设计中,ref_audio 是 storyboard 配置的一部分,后续每个 frame 生成语音时都能使用它。这样一条视频中的多段旁白可以保持统一声音,进一步也可以让多条视频复用同一个参考声音。
十三、参考音频和 voice_id 的关系
在 Pixelle-Video 中,voice_id 和 ref_audio 都属于语音相关参数,但它们不是一回事。
voice_id 更像音色选择。
ref_audio 更像声音样本。
在 local Edge-TTS 模式中,voice_id 是 Edge-TTS 的音色 ID。
在 comfyui 模式中,voice_id 是 workflow-specific 的,也就是说它具体代表什么,要看工作流怎么定义。TTSService 的注释也说明:voice 在 local 模式是 Edge TTS voice ID,在 ComfyUI 模式则是工作流相关的参数。
可以这样理解:
text
Edge-TTS:
voice_id = 选择哪个官方音色
ref_audio = 不使用
Index-TTS / 声音克隆 workflow:
voice_id = 可能代表说话人、语言或 workflow 内部参数
ref_audio = 参考声音样本
所以,如果你做二次开发,不要简单地把 voice_id 和 ref_audio 混成一个字段。
更好的设计是:
text
voice_id:
用于预设声音或 workflow 内部 speaker 参数。
ref_audio:
用于声音克隆参考样本。
tts_workflow:
决定到底如何解释 voice_id 和 ref_audio。
十四、参考音频和 speed 的关系
speed 控制语速。
ref_audio 控制声音参考。
两者也不是一回事。
在 local Edge-TTS 模式中,Pixelle-Video 会把 speed 转成 Edge-TTS 的 rate 参数。
在 ComfyUI workflow 模式中,TTSService 只有在 speed 不为空且不等于 1.0 时,才会把 speed 放入 workflow_params。
也就是说,声音克隆 workflow 可能同时收到:
python
{
"text": "...",
"ref_audio": "...",
"speed": 1.2
}
但最终语速是否生效,也取决于 workflow 内部是否支持 speed 参数。
实际使用时要注意:
text
语速太快:
可能让克隆声音不自然,口齿变糊。
语速太慢:
可能让视频节奏拖沓。
参考音频语速和生成语速差距太大:
可能影响自然度。
所以声音克隆不只是"上传音频就行",还要配合合适的语速。
十五、参考音频和视频时长的关系
声音克隆最终输出的是 audio_path。
Pixelle-Video 生成音频后,会立即读取音频时长,并写入:
text
frame.duration
FrameProcessor 源码中,TTS 生成完成后会设置 frame.audio_path,再通过 _get_audio_duration() 获取音频时长。
这意味着参考音频虽然是声音克隆输入,但它可能间接影响视频节奏。
例如,使用不同参考音频后,生成的语音可能有不同节奏:
text
参考音频 A:说话快,停顿少
↓
生成音频较短
↓
frame.duration 较短
参考音频 B:说话慢,停顿多
↓
生成音频较长
↓
frame.duration 较长
后续视频生成也会受到影响。
在视频 workflow 分支中,如果当前帧是视频生成,并且已经有 frame.duration,FrameProcessor 会把这个 duration 作为目标视频时长传给媒体生成服务,从而尽量让视频长度匹配 TTS 音频。
所以声音克隆影响的不只是"声音像不像",还可能影响:
text
每个分镜持续时间
AI 视频目标时长
图片转视频片段长度
最终视频节奏
这就是 Pixelle-Video 语音模块和视频模块耦合的地方。
十六、声音克隆和数字人口播的关系
声音克隆还和数字人口播有关。
第 16 篇我们讲过,数字人口播通常需要:
text
人物参考图
+
语音音频
↓
数字人视频
Pixelle-Video 的 API 视频能力表中,wan2.7-r2v 被标记为 reference_to_video,能力中包含 digital_human、native_audio、voice_reference 等;其说明中也提到数字人会使用参考图片,并且可以附加 TTS 音频作为角色参考声音。
这说明在更复杂的视频能力里,音频可能有两层作用:
text
第一层:
作为最终视频的旁白音轨。
第二层:
作为数字人 / 音频驱动视频模型的输入。
Pixelle-Video 的 API 视频参数映射里,也为 DashScope 分支保留了 reference_audio_path、audio_path 等参数通道。
所以,声音克隆生成的音频不一定只是"后期配音"。
在数字人口播场景中,它还可能成为驱动人物嘴型、语音风格或口播节奏的输入。
这也是为什么 audio_path 在 Pixelle-Video 中是非常核心的中间产物。
十七、声音克隆流程图
把前面的内容串起来,Pixelle-Video 的声音克隆链路可以画成这样:
text
【用户输入】
上传参考音频 ref_audio
输入主题或固定文案
选择 TTS workflow,例如 Index-TTS workflow
设置 tts_inference_mode = comfyui
【Pipeline 阶段】
StandardPipeline.initialize_storyboard()
↓
StoryboardConfig.ref_audio = ctx.params["ref_audio"]
【Frame 阶段】
FrameProcessor._step_generate_audio()
↓
tts_params = {
text: frame.narration,
inference_mode: "comfyui",
workflow: config.tts_workflow,
speed: config.tts_speed,
ref_audio: config.ref_audio
}
【TTSService 阶段】
TTSService.__call__()
↓
_call_comfyui_workflow()
↓
workflow_params = {
text: frame.narration,
speed: ...,
ref_audio: ...
}
【Workflow 阶段】
ComfyKit.execute(workflow_input, workflow_params)
↓
ComfyUI / RunningHub 执行 Index-TTS 或其他声音克隆 workflow
↓
返回音频文件
【回填阶段】
frame.audio_path = output.mp3
frame.duration = audio_duration
↓
进入图片 / 视频生成和 segment 合成
从这张流程图可以看出:
声音克隆并没有改变 Pixelle-Video 的主流程,它只是增强了 TTS 生成音频的方式。
主流程仍然是:
text
narration → audio_path → duration → video_segment_path
只是 audio_path 的来源从普通 TTS 变成了"带参考音频的 TTS workflow"。
十八、为什么 Pixelle-Video 不把声音克隆写死?
如果 Pixelle-Video 直接在代码里写死 Index-TTS,会有什么问题?
首先,TTS 模型很多。
text
Index-TTS
CosyVoice
Fish Speech
ChatTTS
GPT-SoVITS
XTTS
其他自定义声音克隆模型
每个模型的参数、环境、输出格式都不一样。
如果每个模型都在 Python 代码里写一套适配,TTSService 会越来越复杂:
text
if model == "edge":
...
elif model == "index_tts":
...
elif model == "cosyvoice":
...
elif model == "fish_speech":
...
elif model == "gpt_sovits":
...
Pixelle-Video 选择 workflow 方式,就把复杂度交给 ComfyUI:
text
Pixelle-Video:
只负责传 text / voice / speed / ref_audio。
ComfyUI workflow:
负责具体模型、节点、参数映射、输出音频。
TTSService:
负责执行 workflow,并拿回 audio_path。
这使得声音克隆功能有更强的扩展性。
用户想换声音克隆模型,不一定要改 Pixelle-Video 主代码。
只要新的 TTS workflow 能接收同样的参数,并返回音频文件,就可以接入。
十九、TTS workflow 输出如何回到本地?
声音克隆 workflow 执行后,Pixelle-Video 需要拿到音频结果。
TTSService 会从 ComfyKit 返回结果中查找音频。源码中它会依次检查 result.audios、result.files,以及 result.outputs 中以 .mp3、.wav、.flac 结尾的字符串;如果都找不到,就抛出 "No audio file generated by workflow"。
如果返回的是远程 URL,并且传入了 output_path,Pixelle-Video 会用 httpx.AsyncClient() 下载音频并写入本地路径。
这一步很重要。
因为后续视频合成更适合处理本地文件:
text
远程音频 URL
↓
下载到 output_path
↓
frame.audio_path
↓
ffmpeg 读取音频时长
↓
合成视频片段
所以声音克隆 workflow 的输出,最终必须被统一成一个可访问的 audio_path。
二十、什么样的参考音频效果更好?
从工程角度看,Pixelle-Video 只负责传 ref_audio,但从实际使用效果看,参考音频质量会明显影响声音克隆结果。
更适合作为参考音频的素材,一般有这些特点:
text
人声清晰
背景噪声少
没有背景音乐
没有多人同时说话
语速稳定
情绪不要过度夸张
音量适中
格式常见,例如 mp3 / wav / flac
不太适合的参考音频包括:
text
背景音乐很大
环境噪声很重
多人对话
录音太短
声音忽远忽近
严重爆音或失真
语气过于极端
README 中虽然只说明参考音频支持 MP3、WAV、FLAC 等格式,并适用于支持声音克隆的 TTS workflow,但实际生成质量还会取决于音频内容本身和具体工作流能力。
所以,使用声音克隆时,不要只关心格式能不能上传,还要关心声音样本是否干净、稳定、代表性强。
二十一、声音克隆常见问题
1. 上传参考音频后,声音没有变化
常见原因是:
text
当前 TTS 模式仍然是 local
当前 workflow 不支持 ref_audio
ref_audio 参数名和 workflow 节点不匹配
workflow 没有正确加载声音克隆模型
Pixelle-Video 只负责把 ref_audio 作为额外参数传给 ComfyUI workflow;如果 workflow 内部没有使用这个参数,声音就不会明显变化。
2. Edge-TTS 使用 ref_audio 没有效果
这是正常的。
Edge-TTS local 分支只处理 voice 和 speed,然后调用 Edge-TTS 生成音频;ref_audio 是在 comfyui 分支中作为额外 workflow 参数传递的。
3. Workflow 执行成功,但没有音频文件
TTSService 会查找 result.audios、result.files 和 result.outputs 中的音频路径。如果 workflow 没有返回 .mp3、.wav、.flac,Pixelle-Video 就会认为没有生成音频。
这时要检查 ComfyUI workflow 的输出节点。
4. 声音像,但节奏不自然
可能原因是:
text
参考音频节奏太特殊
生成文本太长
tts_speed 设置不合适
声音克隆模型对目标语言支持不好
参考音频和目标文本语言不一致
例如,用一段英语参考音频去生成中文旁白,效果可能不稳定。
5. 生成音频很长,视频节奏变慢
Pixelle-Video 会把 TTS 音频时长写入 frame.duration。如果声音克隆模型输出节奏偏慢,每个 frame 的持续时间也会变长,最终视频节奏就会拖。
解决方式通常是缩短 narration、调整 speed,或者换更稳定的参考音频。
二十二、二次开发:如何把声音克隆做得更好用?
如果基于 Pixelle-Video 做二次开发,声音克隆这块可以继续增强。
1. 增加参考音频校验
上传后先检查:
text
文件格式
文件时长
采样率
是否能被 ffmpeg 读取
音量是否过低
是否存在明显静音段
这样可以在生成前发现问题。
2. 增加参考音频预处理
可以自动做:
text
降噪
去静音
音量标准化
裁剪前后空白
转成 wav
统一采样率
这样能提高声音克隆稳定性。
3. 增加声音预览缓存
预览语音时,可以根据:
text
text + tts_workflow + ref_audio + speed
生成 hash。
同样配置重复预览时,直接读取缓存,减少重复调用。
4. 增加 workflow 参数映射说明
不同 TTS workflow 对参数名要求不同。
有的叫:
text
ref_audio
有的可能叫:
text
reference_audio
speaker_audio
prompt_audio
voice_sample
可以在 workflow metadata 中声明参数映射,让 Pixelle-Video 自动适配。
5. 增加声音一致性测试
生成多段 frame audio 后,可以检查:
text
音量是否一致
语速是否一致
是否出现明显音色漂移
是否有异常静音
这对多分镜视频很重要。
6. 增加数字人口播联动
如果用户选择数字人口播,可以让声音克隆流程和数字人流程联动:
text
ref_audio
↓
克隆 TTS audio_path
↓
作为 digital human driving audio
↓
生成口播视频
Pixelle-Video 当前已经有 audio_path、reference_audio_path、voice_reference 等相关通道,后续可以进一步产品化。
二十三、源码阅读建议
如果你要阅读 Pixelle-Video 的声音克隆相关源码,建议按这个顺序:
text
1. README_EN.md
看语音设置中对 TTS workflow、Index-TTS、参考音频、语音预览的说明。
2. pixelle_video/models/storyboard.py
看 StoryboardConfig 中 ref_audio 字段的位置。
3. pixelle_video/pipelines/standard.py
看 initialize_storyboard() 如何把 ctx.params["ref_audio"] 写入 StoryboardConfig。
4. pixelle_video/services/frame_processor.py
看 _step_generate_audio() 如何在 comfyui 模式下把 ref_audio 放入 tts_params。
5. pixelle_video/services/tts_service.py
看 TTSService.__call__() 如何通过 **params 接收额外参数。
6. pixelle_video/services/tts_service.py
看 _call_comfyui_workflow() 如何把 params 合并到 workflow_params,并通过 ComfyKit 执行 workflow。
7. workflows/selfhost/ 或 workflows/runninghub/
看具体 Index-TTS 或声音克隆 workflow 是否接收 ref_audio,并如何输出音频。
8. pixelle_video/services/api_media.py
如果研究数字人口播,再看 reference_audio_path、audio_path、voice_reference 等视频模型参数通道。
这条路线可以完整串起:
text
用户参考音频
↓
ref_audio 参数
↓
TTS workflow
↓
audio_path
↓
视频片段
二十四、总结
这一篇我们分析了 Pixelle-Video 的声音克隆功能。
它的核心不是在 Pixelle-Video 代码里直接实现声音克隆模型,而是通过 ref_audio 参数,把参考音频传入支持声音克隆的 TTS workflow。
完整链路可以总结为:
text
用户上传参考音频
↓
ctx.params["ref_audio"]
↓
StoryboardConfig.ref_audio
↓
FrameProcessor._step_generate_audio()
↓
tts_params["ref_audio"]
↓
TTSService.__call__(**params)
↓
_call_comfyui_workflow()
↓
workflow_params.update(params)
↓
ComfyKit.execute()
↓
Index-TTS / 声音克隆 workflow
↓
生成 audio_path
↓
写回 frame.audio_path
↓
读取 frame.duration
↓
进入视频片段合成
从设计上看,它有几个关键点:
text
Edge-TTS 适合普通预设音色,不负责参考音频克隆。
Index-TTS 这类声音克隆能力更适合通过 ComfyUI / RunningHub workflow 接入。
ref_audio 被放在 StoryboardConfig 中,可以影响整条视频的多段旁白。
FrameProcessor 只在 comfyui TTS 模式下传 ref_audio。
TTSService 通过 **params 和 workflow_params.update(params) 保持扩展性。
最终声音效果取决于具体 TTS workflow 是否支持并正确使用 ref_audio。
一句话总结:
Pixelle-Video 的声音克隆功能,本质是把用户上传的参考音频作为 ref_audio 参数传入 ComfyUI / RunningHub TTS 工作流,让 Index-TTS 等支持声音克隆的模型在生成每段 narration 音频时参考这个声音样本,最终生成更统一、更有账号辨识度的解说音频。