把一首歌的歌词换掉,旋律一个音都不改——这个需求听起来简单,做起来却踩穿了音频处理、MIDI 编码、歌声合成三个领域的坑。本文记录一次完整的实战:以成龙《醉拳》为素材,把歌词改成「怕老婆叨叨版」,用一条 5 步 Python 流水线全自动跑通。
文章不只讲「怎么做」,更讲「为什么这样做」——每一个坑的根因、每一种技术方案的取舍边界、以及「保留旋律」这四个字背后隐藏的物理约束。如果你也想做歌曲改词翻唱,这篇能帮你少走至少两周弯路。
一、需求拆解:保留旋律改歌词,到底难在哪
先说结论:「保留旋律改歌词」本质上是一个「音高时序不变、音色重生成」的问题。听起来只是一个文本替换,但它牵涉到三个层次的技术挑战。
第一层是分离。一首完整的歌是人声和伴奏混在一起的。要改人声的歌词,得先把人声单独拆出来,伴奏原封不动保留。这靠的不是简单的高通低通滤波,而是深度学习模型对频谱的精准建模。
第二层是旋律提取。人声拆出来后是一段音频波形,波形里没有「歌词」这个概念,只有频率和振幅随时间的变化。要把歌词替换掉,得先把这段波形翻译成机器能编辑的结构化数据——MIDI。MIDI 记录的是每个音的音高、起止时间、力度,但不记录「唱的是什么字」。
第三层是歌声重合成。新歌词塞进 MIDI 后,还需要把带歌词的 MIDI 重新唱出来。这一步是整个流水线里选择最多、限制也最多的一步——用虚拟歌姬?用 AI 声音克隆?还是用 Suno 这类大模型重新生成?每种方案的音色还原度、操作复杂度、版权风险完全不同。
二、流水线全景:5 步从原曲到新歌
整个流水线由 5 个 Python 脚本串接,每一步的输出是下一步的输入,中间产物全部落盘到 output 目录,方便单步调试和断点续跑。
五步的技术栈分别是:Demucs(Meta 开源的人声分离模型)、basic-pitch(Spotify 开源的音高提取模型)、pretty_midi + mido(MIDI 读写库)、Synthesizer V / Suno API(歌声合成)、FFmpeg(音频合并)。全部本地可跑,只有 Suno 备选方案需要联网调 API。
实战案例选了成龙《醉拳》——这首歌节奏鲜明、人声清晰、音域适中,适合做技术验证。新歌词 368 字,原曲 MIDI 提取出 343 个音符,两者字数对齐是第三步歌词注入的核心挑战。
三、第一步人声分离:Demucs 拆出纯人声
Demucs 是 Meta(Facebook AI Research)开源的音源分离模型,能把一首歌拆成人声、鼓、贝斯、其他四个音轨。我们只需要人声和伴奏两个,但 Demucs 默认四轨全输出,取 vocals 和剩下三轨混合即可。
# 01_separate.py 核心逻辑 from demucs.separate import main as demucs_main demucs_main([ "--two-stems", "vocals", # 只分人声和伴奏两轨 "-n", "htdemucs", # 用最新模型 "-o", output_dir, input_audio ]) # 产物:vocals.wav(纯人声)+ no_vocals.wav(纯伴奏)
这一步的坑不在代码,在依赖安装。Demucs 的 PyPI 包有两个隐形依赖不会自动装:julius(因果卷积库)和 huggingface-hub(模型下载器)。缺了前者,import 直接报 ModuleNotFoundError;缺了后者,模型下载阶段卡住。正确装法:
pip install demucs julius huggingface-hub
~/.cache/torch/hub/checkpoints/ 目录。分离一段 3 分钟的歌,CPU 约需 2-3 分钟,有 GPU 则 10 秒内完成。四、第二步人声转 MIDI:basic-pitch 提取旋律
basic-pitch 是 Spotify 开源的轻量级音高追踪模型,能把单旋律音频(人声、乐器独奏)转成 MIDI。它的优势是速度快、不需要 GPU、对歌唱人声的识别准确率在 90% 以上。
from basic_pitch.inference import predict_and_save predict_and_save( output_dir, ["vocals.wav"], save_midi=True, sonify_midi=False, save_model_outputs=False, save_notes=False ) # 产物:vocals.mid,包含音高、起止时间、力度
这里的坑比 Demucs 更深。basic-pitch 依赖 resampy 库做重采样,而 resampy 内部用了 pkg_resources——这个模块在 setuptools 83.0 以上版本被移除了。如果你用的是较新的 Python 环境(setuptools >= 83),import basic-pitch 会直接崩。
_version.py 用 import pkg_resources 读版本号,setuptools 83 把这个模块删了,导致整个 basic-pitch 无法 import。pip install setuptools<83 降级。方案二(推荐):改 resampy 源码,把 import pkg_resources 替换为 import importlib.resources,一劳永逸。转出来的 MIDI 文件,用 pretty_midi 读取后会得到一个 instrument,里面有若干个 note,每个 note 有 pitch(音高,MIDI 编号 0-127)、start(开始时间,秒)、end(结束时间,秒)、velocity(力度)。这些 note 就是歌词要注入的「槽位」——每个 note 对应一个音节,一个字。
五、第三步歌词注入:中文编码的生死突围
这是整个流水线技术含量最高、踩坑最深的一步。目标很清晰:把新歌词的每个字,按顺序填进 MIDI 的每个 note 里。MIDI 标准里,note 的「歌词」是存在 meta message 的 lyrics 字段里的。但就是这一个字段,差点让整个流水线报废。
5.1 字数对齐:368 字塞进 343 个音符
新歌词 368 字,MIDI 提取出 343 个音符。差 25 个字,怎么对齐?这不是简单截断能解决的——歌词有断句、有拖音、有衬词(「啊」「哦」),硬塞会导致音节和音高错位,听起来像乱码。
实战解法是音节映射策略:先按空格和标点把歌词切成词组,再按音节数把词组分配给音符簇。遇到字数多于音符的情况,把多出的字合并到相邻音符上(一个音符唱两个字);字数少于音符的情况,用空拍或延长音补齐。这个过程 03_modify_lyrics.py 自动处理,但对纯中文歌词(没有空格分词)效果一般,需要人工微调断句。
5.2 致命陷阱:mido 的 latin-1 编码
歌词对齐后,往 MIDI 写入中文时,mido 库直接抛出 UnicodeEncodeError: 'latin-1' codec can't encode characters。根因在 mido 的源码深处:它把所有 meta message 的字符串都用 latin-1 编码成字节——这个编码只支持 0-255 的拉丁字符,中文 Unicode 码点远超此范围。
翻遍 mido 文档没有配置项可以改编码。唯一的出路是 monkey-patch(运行时替换)——在 import mido 之后、使用之前,把它的编码函数偷换成 UTF-8 版本:
import mido # === 关键 hack:强制 mido 用 UTF-8 编码字符串 === # mido.charset 默认是 'latin-1',不支持中文 # 直接替换模块级常量,所有后续编码都走 UTF-8 mido.midifiles.meta.setattr('charset', 'utf-8') # 更稳的做法:替换 _encode_string 和 _decode_string def _encode_string(text): return text.encode('utf-8') def _decode_string(data): return data.decode('utf-8', errors='replace') mido.midifiles.meta._encode_string = _encode_string mido.midifiles.meta._decode_string = _decode_string # 至此,中文歌词可正常写入 MIDI
5.3 歌词对照:从醉拳到叨叨
实战案例的歌词改写思路是「保留原曲节奏感,内容从武侠豪情转为家庭幽默」。截取副歌第一句对照:
字数完全对齐,音节结构相近,注入 MIDI 后旋律不跑调。这种「语义对仗 + 字数一致」的改写策略,是歌词替换不违和的关键。
六、第四步歌声合成:虚拟歌姬与原声线的真相
带歌词的 MIDI 做好了,下一步是让它「唱出来」。这一步是方案分歧最大的一步,也是「保留旋律」这个需求最容易翻车的一步。
三种主流方案的对比如下:
| 方案 | 保留旋律 | 保留原声线 | 操作难度 | 适用场景 |
|---|---|---|---|---|
| Synthesizer V | 完全保留 | 声线变为虚拟歌姬 | GUI 操作,无 CLI | 高质量翻唱,接受换声线 |
| Suno API | 重新作曲 | AI 生成新声线 | API 调用,全自动 | 快速demo,不要求原旋律 |
| So-VITS-SVC / RVC | 保留 | 克隆原声线 | 需 GPU + 训练数据 | 最高还原度翻唱 |
6.1 Synthesizer V:质量最高但无 CLI
Synthesizer V(简称 SV)是当前最强的虚拟歌姬引擎,音质逼真、中文支持好。问题是它只有 GUI,没有命令行接口,无法自动化。免费版已下架,Studio 版需付费。在流水线里,这一步只能人工导入 MIDI、选声库、导出音频,是全自动流程里唯一的「人肉断点」。
6.2 Suno API:能自动化但会跑调
Suno 是当前最火的 AI 音乐生成大模型,有 API 可调。但用它做「保留旋律改歌词」有个致命问题:Suno 的 Cover 模式(上传原曲+新歌词)会被版权指纹系统拦截。绕过方式是用 custom_mode 直接传歌词让它重新生成——但这样一来,旋律就是 Suno 重新作的,不是原曲的。
# 04_synthesize.py 中的 Suno 备选方案 payload = { "custom_mode": True, # 绕过 Cover 模式的版权检测 "prompt": "", # 不用风格提示,避免重作曲 "lyrics": new_lyrics, # 新歌词内容 "title": "醉拳叨叨版", "make_instrumental": False } # 注意:custom_mode 下 Suno 会重新生成旋律 # 无法保证与原曲旋律一致,这是 Suno 方案的硬伤
6.3 终极方案:So-VITS-SVC 声音克隆
如果一定要「既保留旋律、又保留原歌手声线」,技术路径是:Synthesizer V 合成虚拟歌姬演唱 → So-VITS-SVC 把虚拟声线转换回原歌手声线。这需要用原歌手的纯人声数据训练一个声线模型,训练需要 GPU(至少 8GB 显存)和 10-30 分钟的纯净人声素材。
七、第五步合并与实战反思:从跑通到好用
最后一步最简单:用 FFmpeg 把新合成的歌声和第一步分离出的原伴奏合并成完整歌曲。
# 05_merge.py 核心命令 ffmpeg -i new_vocals.wav -i no_vocals.wav \ -filter_complex "[0:a]volume=1.2[a1];[1:a]volume=0.9[a2]; [a1][a2]amix=inputs=2:duration=longest" \ -acodec libmp3lame -q:a 2 output.mp3 # volume 调整人声和伴奏比例,amix 混音
合并时的关键参数是人声和伴奏的音量比例。原曲混音时人声通常略大于伴奏,翻唱合成的人声偏「干净」缺乏混响,需要适当提亮(+1.2 倍)并给伴奏降一点(0.9 倍),听感才平衡。如果合成的歌声干涩,可额外加 aecho 或 aformat 滤镜做简单混响。
7.1 质量评估:三个维度
跑通流水线后,从三个维度评估成品质量:
| 维度 | 评估方法 | 本次实战表现 |
|---|---|---|
| 旋律保真度 | 对比原曲和新歌声的 MIDI 音高序列 | 100% 一致(MIDI 直接复用) |
| 歌词对齐度 | 人工听辨每个字的起止是否与音符匹配 | 约 85%,25 处需人工微调断句 |
| 声线还原度 | 与原歌手声纹对比(主观+频谱) | 0%(虚拟歌姬声线,需 SVC 补足) |
7.2 改进方向
这条流水线跑通了,但离「好用」还有距离。三个可改进的方向:
第一,歌词对齐自动化。当前中文歌词断句靠人工,可引入拼音分词 + 音节计数,让脚本自动把中文字符映射到 MIDI 音符簇。难点在于中文一字一音节,但 MIDI 音符有拖音和连音,需要区分「一个字占两个音符」和「两个字占一个音符」。
第二,Synthesizer V 自动化。SV 没有 CLI 是全自动流程的唯一断点。可以用 AutoHotkey 或 pyautogui 做 GUI 自动化脚本,模拟导入 MIDI、选声库、导出音频的操作。但 SV 的 UI 结构复杂,脚本脆弱性高,版本更新易失效。
第三,声线还原闭环。接入 So-VITS-SVC 做声音转换,让最终成品保留原歌手声线。这需要额外搭建 SVC 训练和推理环境,GPU 是硬门槛。没有 GPU 的环境,只能接受虚拟歌姬声线或用 Suno 重生成。
7.3 成本与收益
回到开头的问题:一首歌只换歌词不换旋律,5 步能不能搞定?答案是能跑通,但每一步都有它的脾气。Demucs 的依赖缺失、basic-pitch 的 setuptools 冲突、mido 的中文编码、Synthesizer V 的无 CLI、Suno 的版权拦截——这五个坑,每一个都能让流水线停摆。但只要跨过去,你就有了一条可以从任何歌曲生成改词翻唱的自动化产线。
更重要的是,这条产线的每一步都是可替换的模块。Demucs 可以换成 Spleeter,basic-pitch 可以换成 SPICE,Synthesizer V 可以换成 ACE 虚拟歌姬,Suno 可以换成其他音乐大模型。理解了每一步「做什么」和「为什么这么做」,技术的更新换代不会让这套方法失效——你只是在换零件,不是换引擎。
参考资料
- Meta AI Research, «Demucs: Hybrid Spectral and Waveform Domain Music Source Separation», GitHub: facebookresearch/demucs https://github.com/facebookresearch/demucs
- Spotify Research, «basic-pitch: A lightweight pitch tracking model», GitHub: spotify/basic-pitch https://github.com/spotify/basic-pitch
- mido: MIDI Objects for Python, Read the Docs https://mido.readthedocs.io/
- Dreamtonics, «Synthesizer V Studio», 官方网站 https://dreamtonics.com/synthesizerv/
- Suno API 文档,Suno Inc. https://docs.suno.ai/
- FFmpeg Filters Documentation https://ffmpeg.org/ffmpeg-filters.html