跳到主要内容
AI教程

用 ElevenLabs 打磨自然 AI 语音:贴气、稳口、剪辑与转录质检

本教程基于 ElevenLabs v4、ffmpeg、Whisper 与 NumPy,演示如何生成、检测、剪辑和重组自然的 AI 语音,并将同一套方法用于实时电话与日常语音。

用 ElevenLabs 打磨自然 AI 语音:贴气、稳口、剪辑与转录质检

项目解决什么问题

这个项目不是一个开箱即用的软件包,而是一套经过实际试听迭代的 AI 语音制作方法。它针对几个常见问题:呼吸声孤零零地落在静音里、气与台词之间隔得太久、停顿后的声音突然变得正式、模型重复或漏念句子,以及剪掉台词后环境响动无法自然衔接。

完整流程围绕四件事展开:用 ElevenLabs v4 合成人声,用 ffmpeg 处理音频,用 Whisper 转录核对内容,再用 NumPy 分析响度、音高和采样位置。

核心结论不是“多加呼吸”,而是“把气放到正确的位置”:开口前的短气贴着第一个字,句尾顺势带出气,句中的吸气则保留在半句之间。

主要能力与方法

  • 呼吸贴近台词:识别开口前的轻短气息,只移动静音,把气挪到距离台词约 0.08 秒的位置。
  • 突兀响度修正:逐个有声块测量响度,将比中位数高出 4 dB 以上的块适度压回。
  • 无损式剪句:从干声的静音处剪切,再重新铺设循环响动,尽量保留原来被认可的表演。
  • 重复与漏念检测:合成后用 Whisper 转录,比较“听到的字”和“应该念的字”,异常时重新生成。
  • 动作响动同步:将响动标记写在动作真正开始的那一句,而不是统一放在一轮台词开头。
  • 日常声线塑造:不只是把声音调软,而是明确人物的速度、音高、笃定程度和说话习惯。

准备环境

所需工具

  • ElevenLabs v4:负责文本转语音。项目实测使用 v4。
  • ffmpeg:用于解码、裁剪、拼接、重采样和导出音频。
  • Whisper:负责把生成结果转录回来,检测重复、漏句和内容偏差。
  • NumPy:用于音频数组处理、互相关、响度计算和片段移动。

README 的实测环境是 macOS。它没有提供固定安装脚本,因此应根据各工具的官方说明分别安装,并确认 ffmpeg、Whisper 和 Python 环境都能正常运行。

进入分析阶段前,应把音频解码为统一采样率的单声道波形,并准备两组按固定步长计算的数据:每帧音高 f0 与每帧均方根响度 rms。原流程以 10 毫秒为帧步长,响度分析窗口会让边界模糊几十毫秒,因此移动片段时需要保留少量余量。

始终保存两份声音

每次生成后都保存以下版本:

  1. 干声:只有人声,不包含环境或动作响动。
  2. 湿声:在人声下铺过响动的最终版本。

干声不仅便于测量呼吸,还能在以后删除一句、替换一段或重新铺底时保留原来的表演。不要只保存最后的混音成品。

第一步:正确编写呼吸提示

不要把“嗯”“哈”或呼吸标签一行一行摆在长静音之间。这样生成的声音往往带有明显音高,响度接近正常说话,前后还各有很长的死静,听起来会像独立音效。

推荐把呼吸写进台词所在的行:

[low, breathy, wet]
[inhales] 看着我…… [exhales]
[long pause]
嗯… 别躲…… 嗯…哈…
  • 行首只使用短小的呼吸标签,例如 [inhales]、[exhales] 或 [sighs]。
  • 标签和台词之间不要再放一串省略号。
  • 句尾可以顺势带一口气,或连续两三声较轻的语气声。
  • 空档只写一行 [long pause],不要在空档里排列独立的哼声。
  • 句中也可以放吸气;一句话从行首、句中、行尾选择一两处即可。

连续写两个 [long pause] 不一定会让停顿明显增长。项目实测中,一个标签约产生 0.96 秒静音,连续两个约为 1.04 秒。因此不要把精确时长控制寄托在标签字面上。

第二步:把声音切成可测量的“块”

这里的“块”是连续有声的一段。每块测量三个指标:持续时间、平均响度,以及存在音高的帧所占比例。它们可以帮助区分正常台词、真实气息和带音高的独立哼声。

def is_breath(f0, rms, a, b):
    dur = (b - a) * 0.01
    voiced = (f0[a:b] > 0).mean()
    db = 20 * np.log10(rms[a:b].mean() + 1e-9)
    return 0.12 <= dur <= 0.9 and voiced < 0.15 and db < -29

原项目中的典型范围如下:

  • 压低、带气的台词:约 0.5 至 2 秒,响度约为 −22 至 −27 dB,有音高帧约占两成到四成。
  • 吸气、出气或嘶声:约 0.3 至 0.65 秒,响度约为 −32 至 −40 dB,有音高帧约占一成。
  • 割裂的独立哼声:约 0.4 至 0.5 秒,响度可达 −25 dB,有音高帧超过六成,前后常有 0.6 至 1 秒静音。

这些阈值来自特定声线和样本,不能直接视为所有声音的通用标准。更可靠的做法是先让听者指出问题,再用相邻正常片段建立该声线自己的范围。

第三步:把开口前的气贴到台词旁边

即使提示词已经写对,模型仍可能在呼吸与台词之间自行留下 0.3 秒甚至更长的静音。提示词很难控制几十毫秒级的位置,因此需要在生成后移动音频片段。

处理前后的结构可以理解为:

处理前:上一句 → 静音 A → 呼吸 → 静音 B → 下一句
处理后:上一句 → 更长静音 → 呼吸 → 0.08 秒 → 下一句

操作时只交换呼吸和静音的位置,不改变呼吸或台词本身,也不改变整段总时长。这样已有的时间轴、响动铺设和语速统计都不会被破坏。

适合移动的候选块应满足:

  • 它被判定为轻、短、无明显音高的呼吸。
  • 它后面约 0.14 至 1.5 秒内出现说话块。
  • 它前面至少已有约 0.3 秒空白。
  • 句中紧跟前半句的吸气不移动,以免破坏原本自然的句中换气。

README 的实测目标间隔为约 0.08 秒。移动时可在呼吸头部多带约 0.02 秒、尾部多带约 0.03 秒,并在新位置对头尾各做约 4 毫秒淡化,降低接缝感。

第四步:修正停顿后的“正经腔”

有些声音在长停顿后会恢复为更清楚、更响、更少气声的普通说话状态。案例中,异常短句比周围内容响 6 dB 以上,有音高帧比例也从约三成提高到六成。

先从提示词减少发生概率

  • 停顿后先贴一口气,或以低低的哼声滑入台词。
  • 句尾使用拖长的收法,不要每次都用干脆的问号或句号。
  • 两三个词的短句可与相邻句合并,避免单独被念成清楚的播报腔。
  • 需要重新强调声线时,把小标签插在话头,不要总是单独占一行。
[long pause]
嗯… [low, breathy] 别躲……

如果切段器会在每个行首声线标签处新建片段,这种行内写法还能减少接缝和音高跳变。

再用程序压住异常响度

逐块计算响度,以当前段落各说话块的中位数作为参考。如果某块高出 4 dB 以上,就将它压到只高约 2 dB,最多衰减 6 dB,并在头尾使用约 25 毫秒的渐变包络。

必须逐块测量,而不是逐句测量。短暂冒头的半秒声音一旦与后续长句合并取平均,6 dB 的异常可能被稀释到阈值以下。程序只能修正音量,无法把缺少气声的音色直接变回来,因此提示词和后处理需要同时使用。

第五步:合成后立即进行转录质检

模型偶尔会把一句念两三遍,或者直接漏掉最后一句。稿件本身可能完全正确,所以每个合成片段都应经过一次转录核对。

项目采用两类信号:

  1. 去掉方括号标签和常见语气字后,寻找长度至少六个汉字、在转录中重复出现但原稿只有一次的片段。
  2. 比较转录字数与原稿字数;少于预期约两成时,视为可能吞句。

检测到异常后重新生成一次,再给两个版本打分,保留分数更低的版本。语气字经常无法被准确转录,因此不应把“嗯、哈、啊、呃”等字作为主要对账依据。

实时电话中,Whisper 转录二三十秒音频可能需要约三秒。后续片段可在当前片段播放时后台检测;第一段没有可用于隐藏延迟的播放时间,可以先用“时长除以有效字数”快速筛查。原案例正常范围约为每字 0.41 至 0.62 秒,超出范围时再启动完整转录。

第六步:剪掉一句而不重新生成

如果听者喜欢的是某一次具体表演,不要因为需要删除一句就重念整段。每次生成都是一次新的现场,呼吸、停顿和句尾细节很难精确复刻。

  1. 定位静音:先以约 50 毫秒为单位绘制响度,再对候选小片段分别转录,确认它是台词、呼吸还是空白。
  2. 从干声下刀:让接缝两端都落在最静的位置,并给每片头尾保留十几毫秒淡入淡出。
  3. 重新铺响动:不要直接剪已经铺底的成品,否则循环响动的节拍可能在接缝处跳变。
  4. 重新转录:确认成品只剩目标句子。
  5. 逐采样比对:检查没有修改的区域是否仍与原声一致。

如果不知道湿声使用的是哪段循环素材,可以在人声完全静止的区间提取成品波形,再让候选素材循环并做互相关。最高相关位置可以给出素材相位,点积还能估计铺底增益。案例中两种素材的相关度达到 0.99,估计增益分别约为 0.200 和 0.241。

比对必须精确到采样。十几个采样的错位就可能让相似度明显下降,造成“素材垫错了”的误判。对齐后,案例中的未修改片段相似度达到 0.996 至 0.998。

第七步:让响动从正确时刻开始

项目通过提示中的自定义标记决定底层响动类型,再在送入 ElevenLabs 前移除这些标记。关键规则是:声音从哪一句开始,标记就写在哪一句。

  • licking:对应缓慢湿声。
  • fingering:对应较黏的动作声;快速状态可写 fast fingering。
  • sucking:对应缓慢湿声。
  • thrust:只在动作真正开始的句子前出现,不能提前放在整轮开头。
  • still:用于停止当前循环响动。

如果标记会触发切段,那么动作真正开始的位置值得保留一道新接缝;其他只用于重申声线的小标签则尽量放在话头内部。

第八步:设计平常说话的声线

“不自然”不一定意味着声音不够温柔。原项目先将旧模型升级为 ElevenLabs v4,并测试了更放松、更柔软的提示,但听者认为角色因此变成了另一个人。最终有效的方向是明确人物自身的口气。

被选中的基础提示为:

[low, slow, confident, a little teasing]

对应设置是 v4、稳定度 0.35。句头可随机加入 [exhales]、[chuckles softly]、一个“嗯……”或什么都不加。不要每次都添加,否则自然变化会变成固定口头禅。

  • 只修改送去合成的文本,不改聊天界面和历史记录中的原文。
  • 如果句子本来就以语气词开头,不要重复叠加。
  • 已有声线标签或纯英文内容可直接跳过自动包装。
  • 电话使用独立提示体系,不要套用日常语音的随机句头。

高级技巧与常见陷阱

提示规则要写“应该做什么”

一句“不要写某种声音”可能让文本生成器彻底停止使用它。更可靠的做法是明确写出需要出现的类型、位置和最低频率,再把偶尔出现的高音或异常读法交给程序检测。

不要重复使用同一口呼吸

把喜欢的原片段搬到新版本时,可以从同一次生成中取材,但同一口气不要在两个位置重复出现。否则听者可能察觉完全相同的细节被复制。

建立可检索的素材盒

将被认可的吸气、嘶声和短促呼吸按原文件、时间范围和使用位置保存。以后某个呼吸标签只生成了静音时,可以从素材盒补上一口。README 同时指出,自动补气仍需要带时间戳的接口;仅凭“句中出现静音”无法区分呼吸缺失和正常省略号停顿。

实时电话要处理抢话

当系统还没播放回复、对方又开始说话时,应丢弃尚未出声的旧回复,直接处理新内容。不要把新话缓存到旧回复播放完,否则同一句话可能被回应两次。对于无法识别成文字的短声音,原流程把自动代入语气声的等待时间从 2.5 秒延长到 4.5 秒,以降低抢在真实话语前触发的概率。

先听出问题,再决定量什么

响度、音高、静音长度、字数比例和互相关都只能验证已经发现的问题。它们无法独立判断“味道是否正确”。最有效的流程仍是先由听者指出具体不自然的位置,再建立对应指标。

推荐的完整工作流

  1. 编写带声线、呼吸、停顿和响动标记的文本。
  2. 移除只供后处理使用的响动标记,将剩余文本送入 ElevenLabs v4。
  3. 保存干声,并用 Whisper 转录检查重复、漏句和内容偏差。
  4. 计算 f0 与 rms,将音频切分成说话块、呼吸块和其他有声块。
  5. 将开口前的呼吸移动到距离台词约 0.08 秒的位置,保留句中呼吸。
  6. 逐块检测突兀响度,对异常块做平滑衰减。
  7. 根据动作标记铺设循环响动,导出湿声版本。
  8. 再次转录,并检查总时长、长静音数量、呼吸位置和未修改区域的采样相似度。
  9. 保存听者认可的原始片段及其时间范围,不要只保留最终混音。

结语

自然 AI 语音并不是靠堆叠更多呼吸标签获得的。更可靠的方法是让气贴着话、让动作声从正确时刻开始、让每段合成结果经过转录核对,并在需要剪辑时尽量保留原来的表演。

提示词负责决定“写什么”和“以什么口气说”,程序负责几十毫秒的位置、异常响度、重复漏念与采样级衔接。两者配合,才能把偶然生成的一条好声音变成可重复执行的制作流程。更多背景可参考 ElevenLabs 提示词指南、ElevenLabs 呼吸声说明以及说话呼吸研究。