从录音中删除“嗯”比听起来更难

2026-06-12 1 阅读 dougcalobrisi
erm:从语音中去除 Ums、Uhs 和 Erms 的本地 CLI 2026 年 5 月 2 日 · 1547 个单词 · 阅读 8 分钟 语言学家有一个词来表示 um s、uh s、ers 和拉长版本(ummmm 、 uhhhhh ),这些词会填充英语口语:不流利。我不会录制很多语音音频,但有几个朋友会录制,他们告诉我手动编辑这些音频很痛苦。所以我构建了 erm 来做到这一点。 uvx erm input.wav 这是常见情况的整个界面。它会在输入旁边写入一个清理过的 .wav 和一个 JSON 剪切列表。这篇文章将介绍它的工作原理,因为显而易见的方法听起来不太好,而且大部分代码都是用来解决这个问题的。天真的版本不起作用🔗您期望的工作是:使用单词级时间戳进行转录,找到像 um 和 uh 这样的标记,使用 ffmpeg 剪切这些范围。这样你可能就完成了 60%,而且结果听起来比原来的还要糟糕。三个原因:Whisper 悄悄地在成绩单中留下了很多填充物,因此一开始就没有 um 标记可以匹配。在任意时间点对音频进行切片会在波形中产生微小的阶跃。您的耳朵会听到咔嗒声。即使拼接本身干净,剪切前后的背景嘶嘶声也不太匹配,因此每次编辑时您都会听到微弱的变化。大部分的工作就是解决这三件事。关于 Whisper 的简单介绍 🔗 Whisper 是 OpenAI 的开源语音转文本模型。你给它音频,它给你回一份文字记录,并且通过正确的标志,它还会告诉你每个单词的开始和结束时间戳。它在本地运行,这使得这样的工具成为可能,而无需将录音发送到任何地方。 erm 使用 fast-whisper ,这是一种比参考版本快几倍并且使用更少内存的重新实现。相同的模型权重,相同的输出,只是更好的运行时间。默认是medium.en模型,这是一个很好的速度/精度平衡。如果你想要small.en(更快),你可以用--model覆盖,但我实际上会使用large-v3。它在拾取填充物方面明显更好,并且值得额外的计算。检测 🔗 首先,运行 Whisper。 erm 要求提供字级时间戳,并预先给它一条小指令,告诉它不要清理记录。如果不去管 Whisper,它会删除填充内容,因为它的大部分训练记录都是简洁的散文。任何作为已知填充词返回的单词( um 、 uh 、 er 等)都会被标记为要剪切。像 ummmm 这样的加长版本会与 um 词干即时匹配。 Whisper 仍然遗漏了一些东西,所以另外三遍直接查看音频:间隙填充。如果两个转录单词之间有异常长的停顿(默认情况下超过 350 毫秒),erm 会检查在该“停顿”期间是否有人真正发出声音。如果 Whisper 标记为沉默的区域中存在大量声音,则 Whisper 会将其完全删除。它确实只是丢弃它们。根本没有任何标记,只是记录中原来“嗯”所在的地方出现了一个洞。填充物隐藏在单词中。 Whisper 有时会将填充词粘到相邻的单词上,因此“in, uhhhhh”会作为单个 in 标记返回。 erm 会查看较长的单标记单词,在音频中的短暂下降处将它们分开,找出哪个块是实际单词(基于该单词应该合理地说出的时间),并将其余部分视为填充词。单词太长了。如果一个单词的持续时间比其文本可能需要的时间长得多,那么尾部就值得怀疑。 erm 扫描尾部是否有浊音,并且可以选择通过音调测试进行双重检查:可疑块听起来像是有人拿着元音( uhhhhh ),还是像有人只是慢慢地说?保持元音具有稳定、简单的声学形状;当您在声音之间移动时,真实的语音会不断变化。音高测试可以防止该工具对说话速度慢的人进行修剪。所有四个通道(Whisper 通道和三个音频通道)独立生成候选剪辑,并且在下一步之前合并列表。细化切割点🔗 精确地 t = 1.234s 处的切割落在该时刻波形恰好出现的位置,几乎从不为零。将任意两个点拼接在一起会在波形中留下一个阶跃,该阶跃就是您听到的咔嗒声。按顺序进行了两个小修复。首先,允许每个切割端点滑动一点点(最多 60 毫秒)以落在附近最安静的位置。如果音频在原始剪切点之前或之后出现短暂的停顿,请滑到那里。幻灯片是有界的,因此它不能跨入相邻的单词,否则你会咀嚼掉真正的语音。其次,从那个安静点开始,端点会捕捉到波形恰好过零时的最近时刻。两个零点拼接在一起产生一个连续的波形,没有阶跃,也没有喀哒声。毕竟,非常短的幸存片段会被清理掉:如果两个相邻的剪切会在它们之间留下一段短于大约 120 毫秒的音频片段,那么该片段会被合并到一个更大的剪切中。这么小的片段无法在任何一个上进行平滑处理