用代码生成宣传片(二):edge-tts 配音与多语言批量出片

edge-tts 配音实战

本文是系列第二篇,聚焦语音合成(TTS)环节——用 edge-tts(微软 Azure 免费神经 TTS 接口)批量生成多语言、多音色的配音文件。所有代码来自真实项目(MiBee NVR 45 秒宣传片),可直接复用。

安装

edge-tts 是一个 Python 异步库,建议在虚拟环境中安装:

bash
1
2
python -m venv .venv
.venv\Scripts\pip install edge-tts numpy

numpy 不是 edge-tts 的依赖,但后续 BGM 合成(系列第三篇)会用到,这里一并装好省事。

列出所有可用音色:

bash
1
edge-tts --list-voices

输出包含每个语音的 NameGenderLocaleContentCategoriesVoicePersonality,方便筛选。

语音清单

本项目实战用到的 6 种音色(3 种语言 × 男女各一):

语言男声女声
中文zh-CN-YunxiNeuralzh-CN-XiaoxiaoNeural
英文en-US-GuyNeuralen-US-AriaNeural
粤语zh-HK-WanLungNeuralzh-HK-HiuMaanNeural

以上均为微软 Azure 的神经 TTS 音色,质量优秀。edge-tts --list-voices 可查看完整列表(含日文、韩文、法文等数百种语音)。

批量生成脚本(含重试与语速)

gen_all_voices.py 是配音生成的核心脚本,结构如下:

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import asyncio, os, edge_tts

# 7 段中文旁白文本
ZH = [
    "MiBee NVR,轻量级自托管录像系统……",
    "只需 60 秒,就能把一台树莓派,变成专业级网络录像机。",
    # ...共 7 句
]

# (子目录, 文本列表, 语音, 语速)
VERSIONS = [
    ("voice_zh_f",  ZH, "zh-CN-XiaoxiaoNeural", "+6%"),
    ("voice_zh_m",  ZH, "zh-CN-YunxiNeural",    "+6%"),
    ("voice_en_f",  EN, "en-US-AriaNeural",     "+13%"),
    ("voice_en_m",  EN, "en-US-GuyNeural",      "+13%"),
    ("voice_yue_m", ZH, "zh-HK-WanLungNeural",  "+6%"),
    ("voice_yue_f", ZH, "zh-HK-HiuMaanNeural",  "+6%"),
]

async def gen_one(text, voice, rate, out, retries=5):
    last_err = None
    for attempt in range(1, retries + 1):
        try:
            c = edge_tts.Communicate(text, voice, rate=rate)
            await c.save(out)
            if os.path.getsize(out) > 1000:   # 校验非空
                return
            last_err = RuntimeError("empty output")
        except Exception as e:
            last_err = e
        await asyncio.sleep(1.5 * attempt)     # 指数退避
        print(f"    retry {attempt} for {out} ({last_err})")
    raise RuntimeError(f"failed after {retries} retries: {out}")

async def main():
    for subdir, texts, voice, rate in VERSIONS:
        os.makedirs(subdir, exist_ok=True)
        for i, text in enumerate(texts, start=1):
            await gen_one(text, voice, rate, f"{subdir}/voice_{i}.mp3")
            print(f"[ok] {subdir} clip{i}")

asyncio.run(main())

重试策略是关键。 edge-tts 依赖微软在线服务,偶发 No audio received 错误——服务端瞬时抽风,不加重试的话批量生成会在中途挂掉。gen_one 实现了 5 次重试 + 指数退避1.5 × attempt 秒),足以应对绝大多数间歇性故障。核心要点:

  • 每次重试前等待时间递增(1.5s、3s、4.5s、6s、7.5s),给服务端恢复时间。
  • 输出后校验文件大小(> 1000 bytes),防止静音文件以成功状态通过。
  • 5 次全部失败才抛出异常,不静默吞错误。

语速与 SSML

edge-ttsrate 参数本质上是对应 SSML <prosody rate="..."> 属性——它是合成时的韵律调整,不是事后变速。微软神经 TTS 在生成语音时就按指定语速合成,因此音质无损。这与 ffmpeg atempo(事后变速、可能引入伪影)有本质区别。

实战经验:

  • 中文/粤语+6% 左右,自然又不拖沓。
  • 英文:文本长度明显大于中文,需要 +13% 才能塞进同样时长(因为英文音节数通常多于同义中文)。
  • 语速只影响配音本身,不影响字幕与画面节奏,可以放心单独调节。

SSML 详解

edge-tts 底层使用 SSML(Speech Synthesis Markup Language)控制合成细节。除了 rate,SSML 还支持丰富的控制参数:

xml
1
2
3
4
5
6
7
8
9
<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="zh-CN">
    <voice name="zh-CN-YunxiNeural">
        <prosody rate="+6%" pitch="+1st" volume="+10%">
            MiBee NVR,轻量级自托管录像系统。
            <break time="500ms"/>
            只需 60 秒就能完成部署。
        </prosody>
    </voice>
</speak>

关键元素说明:

  • <voice name="...">:显式指定音色。edge-tts.Communicate(text, voice=...) 内部就是包装为这个元素。
  • <prosody rate="...">:语速调整,百分比(如 +50% 变快 50%,-20% 变慢 20%)。
  • <prosody pitch="...">:音高调整,可以用相对值(+2st 升两个半音)或绝对值(220Hz)。
  • <prosody volume="...">:音量调整,如 +20%silentx-loud
  • <break time="..."/>:插入静音停顿,控制朗读节奏。

需要精细控制时,可以直接将 SSML 文本传给 edge_tts.Communicate(),替代纯文本输入。这在需要不同句子用不同音色/语速时尤其有用。

edge-tts 原理

TTS 流水线:文本怎么变成人声

TTS(Text-to-Speech)的本质是一条数据处理流水线,将文本一步步转换为可播放的波形:

mermaid
flowchart TD
    Text["📝 文本输入"]:::process
    Text --> Linguistic["🔤 语言学特征<br/>音素 / 重音"]:::process
    Linguistic --> Acoustic["🎵 声学特征<br/>梅尔频谱"]:::special
    Acoustic --> Waveform["🔊 波形生成"]:::special
    Waveform --> Audio["🎧 mp3 输出"]:::output

    classDef process fill:#2196F3,color:#fff
    classDef special fill:#9C27B0,color:#fff
    classDef output fill:#4CAF50,color:#fff

处理流程详解:

  1. 文本 → 语言学特征:输入文本经过分词、词性标注、韵律预测,转换为音素序列和重音标记。中文还需 G2P(字素转音素)确定每个汉字的发音。
  2. 语言学特征 → 声学特征:神经网络根据音素序列预测梅尔频谱(mel-spectrogram),即声音在频域上的能量分布。这是 TTS 最核心的步骤。
  3. 声学特征 → 波形:声码器(Vocoder)将梅尔频谱还原成可播放的 PCM 波形。微软使用 HiFi-GAN 等高质量神经声码器。
  4. 编码输出:原始 PCM 波形被编码为 mp3 格式输出。

神经 TTS 与 Speaker Embedding

微软 Azure TTS 基于端到端深度神经网络(类似 FastSpeech / VITS 架构),输入文本直接输出高质量声学特征。其中一项关键技术是 speaker embedding(说话人向量):

  • 每个音色对应一个固定维度的向量(如 256 维)。
  • 模型本身是单一共享网络,不因音色不同而切换——中文男声「Yunxi」和英文女声「Aria」用的是同一个模型。
  • 推理时,把目标 speaker embedding 注入网络的特定层,网络输出就会「学会」模仿该音色的音高、语调、共鸣等特征。
  • 这就是同一个服务能输出几十种声音的原因:模型共享,只有 speaker embedding 不同。

在线服务与流式合成

edge-tts 不在本地合成语音,它是 Azure 在线 TTS 的客户端:

  • 连接微软 Azure TTS 端点(与 Edge 浏览器「朗读此页」同源)。
  • 免费、无需 API Key,因此广受欢迎。
  • 但有服务端限流(rate limit),不适用于生产环境的高并发场景。批量生成时的重试机制正是为此设计。
  • 使用 WebSocket 长连接流式传输
mermaid
sequenceDiagram
    participant Client as 客户端
    participant Azure as Azure TTS 端点

    Client->>Azure: WebSocket 连接建立
    Client->>Azure: 发送 SSML 请求<br/>文本 + 音色 + 语速
    loop 流式合成
        Azure-->>Client: mp3 分片数据
    end
    Azure-->>Client: 传输完成

流式合成的工作原理: 建立 WebSocket 连接后,客户端发送一个包含 SSML 参数的请求。Azure 开始逐句合成,每合成完一段就立即通过 WebSocket 推送给客户端。edge_tts.Communicate().save() 内部正是持续接收这些分片、逐步写入本地文件的。这种架构的好处是首字节延迟低(不需要等全部合成完才能开始播放),但网络抖动可能导致连接中断——这就是必须加重试的根本原因

⚠️ edge-tts 是免费工具,适合个人项目与原型开发。生产环境请使用 Azure Speech Service 正式 SDK(付费、有 SLA)。

粤语读中文的 G2P 机制

一个常见的疑问:粤语语音 zh-HK-WanLungNeural 为什么能直接读简体中文文本?

答案在于 G2P(Grapheme-to-Phoneme,字素转音素) 前端模块:

  1. 模型收到简体中文文本后,并非直接套用普通话发音。
  2. 文本前端模块检测目标语音为 zh-HK,自动使用香港粤语的 G2P 映射表——将「录像」映射为粤语读音 luk6 zoeng6(举例而非真实 IPA),而非普通话的 lù xiàng
  3. 因此你喂简体中文文本即可,无需手动转粤拼,模型会自动处理发音映射。

反过来,如果你用英文语音 en-US-GuyNeural 读中文文本,G2P 会尝试按英文发音规则处理汉字,结果必然是乱念——必须选择与目标语言匹配的语音 ID

神经网络 TTS 全景:从 WaveNet 到零样本克隆

TTS(文本转语音)技术在过去三十年经历了多次范式跃迁,从机械的规则拼接到如今可零样本克隆人类声音,每一次突破都大幅拉近了机器语音与真人语音之间的距离。

演进路线

早期的规则合成(共振峰合成)拼接合成依赖手工设计的声学规则或预录语音库,音质机械且扩展成本极高。

2005 年前后,HMM 统计参数合成引入隐马尔可夫模型,用统计方法生成声学参数后由声码器合成波形,但"嗡嗡"的声码器音质始终无法突破。

2016 年 DeepMind 发布 WaveNet,直接建模原始音频波形,MOS(平均意见分)首次超过 4.0,将合成语音自然度推至接近真人水平——这标志着神经 TTS 时代的开端。

此后演进加速。Tacotron(2017)将文本到梅尔频谱变为端到端序列学习,大幅简化了传统流程。

FastSpeech(2019)引入非自回归并行生成,速度提升 30–50 倍,解决了 Tacotron 推理慢的问题。

VITS(2021)将声学模型和声码器合并为单一模型,引入 VAE + GAN 实现端到端联合训练,成为后续大量开源项目的基础架构。

2023 年起,生成式范式LLM 范式成为新的分水岭。

F5-TTSCosyVoice 2 为代表的 Flow Matching 技术完全消除音素对齐需求,合成质量与速度达到新的平衡。

VALL-E(2023)将 TTS 重新定义为语言建模问题,仅需 3 秒参考音频即可零样本克隆任意说话人音色——这已不是简单的"发声",而是对声音身份的生成式理解。

mermaid
flowchart TD
    N1["🎛️ 规则/拼接"]:::start
    N2["📊 统计参数HMM"]:::process
    N3["🧠 神经声码器<br/>WaveNet 2016"]:::special
    N4["⚡ 端到端合成<br/>Tacotron/VITS"]:::process
    N5["🎯 生成式/LLM<br/>零样本克隆"]:::output

    N1 --> N2 --> N3 --> N4 --> N5

    classDef start fill:#FF9800,color:#fff
    classDef process fill:#2196F3,color:#fff
    classDef special fill:#9C27B0,color:#fff
    classDef output fill:#4CAF50,color:#fff

图解: 橙色起点(规则/拼接)代表机械 TTS 时代;蓝色节点(统计参数 HMM、端到端合成)为技术演进的主体;紫色节点(神经声码器 WaveNet)是第一次质变,将 TTS 拉入深度学习;绿色终点(生成式/LLM + 零样本克隆)代表当前最新范式。核心趋势是数据驱动取代规则驱动,端到端取代模块化流水线,生成式理解取代统计拟合。

edge-tts 在 TTS 谱系中的位置

回到本系列的实战场景。你运行的 edge-tts 实际是微软 Azure 云端神经网络 TTS 的免费客户端——基于类 FastSpeech 架构,通过 speaker embedding 在一个共享模型中容纳上百种音色。它的优势是完全免费、无需 API Key、400+ 语音覆盖 100+ 语言,非常适合批量宣传片配音。

但 edge-tts 也有明确的边界:

  • 不支持零样本克隆:它只使用微软预置音色(如 zh-CN-XiaoxiaoNeural),无法像 VALL-E 或 CosyVoice 那样用 3 秒参考音频克隆任意说话人。这是架构层面的限制——云端模型固定了 speaker embedding 字典,没有注入任意向量的接口。
  • 云端限流:免费接口有服务端频率限制,批量生成必须加重试(如前文 gen_one 的 5 次重试 + 指数退避)。
  • 无 SLA:非官方接口,不适合生产级高并发;正式商用应使用 Azure Speech Service SDK(付费)或 ElevenLabs 等服务。

如果项目需要零样本音色克隆(例如为特定角色生成独一无二的配音),可考虑本地部署 CosyVoice(Apache-2.0 可商用,3 秒参考音频)或 F5-TTS(MIT 代码,Flow Matching 质量)。它们运行在本地 GPU 上,不依赖外部 API,但需要自行管理 GPU 环境和模型权重。

免费 vs 付费:速览

方案成本零样本克隆延迟适用场景
edge-tts免费(限流)❌ 不支持~秒级原型、批量、个人项目
CosyVoice / F5-TTS免费开源✅ 支持~150ms(本地 GPU)生产级本地部署
Azure Speech SDK付费($16/百万字符)❌ 需定制低延迟生产商用
ElevenLabs付费($5/月起)✅ 即时克隆~75ms广播级质量

⚠️ 价格与具体数字为报告时点(2026-07),实际以各官网为准。

这份全景为你在项目中选型提供参考:批量宣传片配音用 edge-tts 完全足够;需要声音克隆或生产 SLA 时,升级到本地模型或付费 API 即可。


本系列:① 总览与 Remotionedge-tts 配音numpy BGMffmpeg 合成