让电脑用我的音色说话:从零搭起一条语音链路
记录第一天:从环境清理到第一段"像我"的声音。
15:31 起点不是语音,是一次工具迁移
工作目录在 15:31 建好。真正开工前先处理了旧助手的资产盘点——那个工具年底就要停运,得先把里面的技能、会话记录和配置盘清楚,决定后面所有脚本和素材放哪、凭证从哪读。
15:55 出了盘点报告:技能 56 个、会话记录 23 个、定时任务为空;配置文件里混着网关口令和第三方接口密钥,属于不能随手外发的敏感内容,当场做了隔离提醒。
16:00 先让它出声
语音的最短路径是找一个免费、不需要 API Key 的合成引擎。选了 edge-tts(对,就是 Edge 浏览器那个在线合成),装进独立的 Python 环境:
bash
python -m edge_tts --voice zh-CN-XiaoxiaoNeural \
--text "随便说点什么" --write-media voice_reply.mp3
16:00 拿到第一段机器女声。标准播音腔,能听,但一听就不是我。
16:37 换成我自己的音色
转折在这里。之前已经做过一次声音复刻——用一段本人的录音训练出一个专属音色,参数存在配置里:
json
{ "voice_id": "m_zhou_ruolin_v3_...", "model": "flow_01_ex", "sdkappid": 1600166179 }
于是写了个脚本,跳过官方 SDK、用 TC3-HMAC-SHA256 手工签名直接调腾讯云 TRTC 的 TextToSpeech,再用 ffmpeg 做 60–8000Hz 带通去杂。16:37 产出 8.6 秒的成品——这一次,声音是我自己的。
中间踩了两个"报错措辞误导人"的坑:地域参数必须写 ap-shanghai,写广州会报 AppId 不匹配;Voice.Volume 传 0 会被拒绝,最优解是只传音色 ID,其余参数一律不加。
16:56 把过程写成文档
链路跑通后,把整条"造声"经过(音频格式对接、零样本克隆、云端复刻、样本导入、完整文件名清单)整理成 Word,16:56 产出《语音助手诞生全记录.docx》。
排版走的是自动化流水线:内容、版式、转换三段式,中间有一道六维质量门禁,最终满分通过。踩的规则坑挺典型——任何带单位的间距都要走变量、裸色值会被判违规、每一个表格都必须带表头。
17:00 同一份内容做成 PPT
17:00 生成了一份 16 页、16:9 的演示文稿,四色池配黑体加等宽的固定组合,全矢量配图,没用一张位图。
自检只能靠几何越界检查和逐段文本宽度估算——因为这台机器上没装任何能渲染演示文稿的软件,没法截图做视觉复核,只能靠"算"。
17:51 打包带走
最后把整套东西原样打包,好上传到服务器保持功能一致。17:51 产出 13.17 GB 的压缩包,1845 个条目,耗时 95 秒。
这么大的包能这么快,靠两件事:对已经压缩过的高熵文件(模型权重、音频、压缩包)改用"只存储不压缩",省掉大量 CPU;输出文件放在被排除的目录里,避免打包程序把自己也打进去。
包里含明文密钥,说明文件里加了醒目警告。
这一天的关键词
edge-tts:免费,能出声,不像我
云端声音复刻:收费,但像
手工 TC3 签名直调 API:不装官方 SDK,省下几百 MB 依赖
自动化文档流水线:内容、版式、转换三段式
让克隆音色开口唱歌:从"念白"到歌声转换,再到模型微调
记录第二天:三次方案迭代——念白、零样本转换、链式微调。
一个假设,先被推翻
最初的思路很直接:既然合成能出我的音色,那让它唱不就行了。核查之后发现此路不通。
现有的三个语音引擎全是朗读型 TTS,接口里只有文本、音色、语速、采样率,没有音符、没有音高曲线、没有时长控制。它们能"念",不能"唱"。
同时把硬件底细摸清:CPU 12 核、内存只有 8 GB,显卡型号一开始取不到(系统把 wmic 和 reg 都拉黑了),后来靠 nvidia-smi 才问出来是 RTX 3070 / 8 GB 显存,CUDA 12.1 可用。
17:07 先做一版"念白"
不能唱,那就先按原曲的时间轴念。脚本把 22 句歌词逐句合成,再按每句的起始时间把音频填进静音轨,拼出 4 分 21 秒的念白版(17:08)。
这一步的价值在于验证了整条"合成、对齐、拼接"的管线,而且分段做了缓存——已生成的片段会跳过,重跑不会重复计费。
换方案:零样本歌声转换
真正的转折是决定用 Seed-VC——一个零样本歌声转换模型:不需要训练,给一段 1–30 秒的参考音频,它就能把一段歌声换成那个人的音色,同时保留原唱的旋律、颤音、换气。
拿到原曲文件后,整条链路当天跑通:
bash
# 分离人声与伴奏
demucs -n htdemucs_ft --two-stems=vocals
# 歌声转换
python inference.py --f0-condition True --diffusion-steps 40 \
--inference-cfg-rate 0.7 --fp16 True
# 混音
python mix.py
18:35 交付第一版《陪你去流浪》音色版。
网络与依赖的七个坑
这台机器在"下载"上格外费劲,几乎每一步都撞墙:
GitHub 不通,走
gh-proxy.com镜像下源码HuggingFace 不通,换
hf-mirror.com,且必须同时关掉 Xet 分片协议,否则 401PyTorch 的 CUDA 版只有官方源有,国内镜像清一色是 CPU 版
torch 在 Windows 上报
fbgemm.dll加载失败,缺一个 OpenMP 运行库,从本地现成副本拷过去解决模型硬依赖的一个音频编解码库根本没发布到 PyPI,改成惰性导入绕开
HuggingFace 缓存在 Windows 下把快照变成 0 字节占位文件,写脚本按哈希从数据块里还原真实文件
检查点里带着分布式训练遗留的前缀,加载时会自动剥离,日志里那句"Skipped loading 11 keys"是正常的
一个必须记住的参数
--auto-f0-adjust 不能用。它想把旋律整体平移到参考音色的音域,实测却把音高拉低了大约 1.2 个半音,导致人声和伴奏不合调。
正确做法是用 --semi-tone-shift N 手动移调。实测很准:+7 半音对应 229.7 Hz、+12 对应 304.1 Hz,和理论值分毫不差。
18:40 顺手让它说一句话
用第一天训练好的音色直接合成了一句问候语(18:40)。又暴露两个参数坑:音高参数必须是整数、音量传 0 会被拒绝,最后发现"只传音色 ID"最稳。另外采样率只支持 8k / 16k / 24k 三档,请求 48k 会直接报错。
18:47 与 18:59 把当天写成复盘
按惯例,把当天全链路整理成 Word(18:47)和 PPT(18:59)。PPT 走受限的页面描述语法逐页生成,又踩了几个语法坑:正文里不能出现裸的小于号、加粗要用内联样式而不是标签、百分比宽度得写成字符串。
20:15 用户不满意,重做一版
第一版交付后收到反馈:发闷、发糊。
诊断出三个病根,每一个都能追溯到具体数据:音色参考素材是从 64kbps 的音频里截的,频谱在 6 kHz 就断崖;参考音频电平极低(整轨 RMS 低到 −46 dB),而模型并不做归一化,等于"参考条件太弱";混音链里还加了回声和压缩。
重做版的改动逐项对症:
分离改用 4 模型集成的
htdemucs_ft,人声和伴奏分得更干净参考音频重建为 5 条 44.1kHz 单声道、峰值统一归一化到 −0.9 dBFS
混音里伴奏单位增益、无滤波、无变调,人声按实唱段的功率对齐,而不是整轨 RMS
结果可量化:8 kHz 以上能量从 −57.7 dB 提到 −17.5 dB(原曲是 −19.5),音高中位偏差 0.13 个半音,音高轨迹相关 0.9905,颤音保留 98.6%。
21:30 又一首:《演员》
同一套流程迁移到另一首歌,参考素材改用"留一法"筛选——把每条候选参考拿去生成,再反过来算它和其余参考的相似度,挑最"稳定像同一个人"的那条。
这一版新增了一个指标:振幅包络相关 0.885,说明渐强渐弱、呼吸起伏是跟着原唱走的,而不是机器自己发挥。
21:39 第三轮:模型微调
零样本再好也有天花板。用户反馈"AI 感太重"之后,做了两件事来定位:零样本只取参考的前 25 秒频谱、不做自适应,相似度上不去;而用朗诵素材微调,会把"这个人的高频是空的"一起学进去,8 kHz 以上掉 9–20 dB。
于是设计了链式微调:分三段各 600 步(累计 1800 步),每段单独存模型,避免只保留最新两个检查点的问题。显卡 8 GB 满载但能跑,约 1.7 次迭代每秒。
最终把微调版和未微调版做分频混合:0–8 kHz 用微调版,8 kHz 以上用未微调版。效果是音色相似度从 0.381 提到 0.438(+14.9%),8 kHz 能量从 −15.6 提到 −10.7 dB。
三条硬教训
绝不要在后台任务运行时覆盖它正在执行的脚本——脚本是按字节偏移边读边跑的,覆盖后偏移错位,会执行到错行的内容
用
nohup ... &起的进程在这套工具里活不下来,必须用工具自身的后台机制两个版本的输出如果同名,新旧对比的差异检测会失效,跑完要立刻手工留档
这一天的关键词
Seed-VC:零样本歌声转换,不训练也能换音色
Demucs:4 模型集成分离人声
留一法选参考:用"像不像同一个人"来挑素材
链式微调:把天花板从 0.381 顶到 0.438
全程 0 元:纯本地显卡运算,没调付费云接口
收尾:一首《那些年》,和一次"到底会不会重复扣费"的实测
记录第三天:用微调模型换唱新歌,顺带用账单接口把自己最担心的一件事查清楚。
先换一首歌唱
《演员》的效果还是不理想,反馈是"没情感、不像"。于是换了《那些年》,用同一套链路重跑:
bash
# 320kbps 音源分离,残差 −26.5 dB
demucs -n htdemucs_ft --two-stems=vocals
# 微调模型(1800 步)+ 选定参考,全曲转换
svc_ft.sh
# 零错位高频修复
python spectral_restore.py
# 混音
python mix_v4.py
指标:音色相似度 0.412(基线 0.363)、音高中位偏差 0.11 个半音、音高轨迹相关 0.9965、颤音比 1.001、装饰音相关 0.9908、削波 0。交付完整版、纯净版、副歌试听和 A-B 对照各一份。
一个被翻出来的隐藏缺陷
复盘上一版《演员》时发现,所谓的"高频修复"其实有硬伤:微调版和基线版在全曲范围内根本没有时间对齐(相关只有 0.02–0.04,扩散采样有随机性),低通加高通一混合就会错位,齿音加倍、相位出问题——这可能正是"AI 感重"的一部分来源。
40 秒的短试听能对上(相关 0.9)极具误导性。这种对齐必须用全曲验证。
修复方案换成"零错位"的做法:低频段按源人声的长期频谱做静态均衡,高频段直接用同一信号搬移自造——因为是在同一条信号上做操作,时间必然对齐。修完 8 kHz 处从 −28.1 dB 提到 −13.0 dB。
07:41 一个悬了两天的疑问
前两天查本月账单时看到一个反常的条目:声音克隆,计价单位写着「元/个/天」。而官方文档明明白白写的是「9.9 元/次,按次计费」「音色可反复使用,后续使用不计费」。
两者直接矛盾。如果文档对,那是一次性收费;如果单位对,那我前一天建的几个音色每天都要扣一笔——差别是持续扣费还是一锤子买卖。
07:41 先查了一次,当天账单还没出(日结在 08:22 左右)。只能等。
08:26 到 08:35 实测
结算窗口过去之后,每隔 60 秒查一次本月账单明细,连续 10 次采样:
08:26:17 — 总条数 6,当天新增 0
08:27:18 — 总条数 6,当天新增 0
…(中间 7 次完全一致)
08:35:22 — 总条数 6,当天新增 0
最新的条目还停在昨天的域名注册,完全没有出现新的"声音克隆"条目。
参照物很关键:前一天同一窗口在 08:22 就已经出账了。如果真按天收费,此刻必然已经生成一笔。没有,就是没有。
结论:一次性收费
官方文档双证一致——
产品文档:「声音克隆 9.9 元/次,按次计费」
增值服务计费说明:「每个音色 9.9 元,可反复使用,后续使用不计费」
那「元/个/天」是怎么来的?那是后付费日结账单的展示单位,不是计费单位。该条的类型是"按量计费日结"、周期"1 天"——"天"指的是结算周期(每天结一次账),而费用的归属时间起止都等于创建那天,此后不再有同项目的费用期间。属于账单文案歧义。
本月现金支出合计 138.70 元:声音克隆 29.70(一次性,三个音色)、域名注册 109.00(三年,与语音无关);语音合成的字符费全部被赠送包抵扣,实际 0。
那三个克隆音色放着不删也不花钱。
一个账单接口的坑
顺带记一笔:之前写的汇总脚本合计恒为 0。原因是它读行级的"总费用"字段,但那个接口的行级根本没有这个字段——金额只存在于组件明细里,必须逐组件求和。这类"字段存在但为空"的坑,比报错更难发现。
这一天的关键词
spectral_restore:零错位高频修复,靠同信号搬移保证对齐
全曲验证:短片段对齐不代表整首对齐
10 次采样实测:用真实接口数据终结一个计费疑问
字段为空 ≠ 没有数据:金额藏在组件明细里
评论