音频分离与音高估计:扒贝斯声部的完整工作流
发布时间:2026/9/3 14:06:18 作者:尧图编辑部 阅读量:1,286

把《杀死那个石家庄人》当作学习和声与低频编配素材时最尴尬的并不是“这首歌听上去难”而是网上能搜到的贝斯谱很少想靠耳朵复刻又总被鼓组淹没。万能青年旅店的编曲里贝斯声部不会像金属乐那样冲在最前面它和底鼓、钢琴低音区叠在一起形成一种“听得见但抓不着”的复杂感受。这不是听力不够好而是低频段本身存在严重的掩蔽效应。所以这篇文章不打算直接丢一份“抓下来就弹”的谱面而是把贝斯音轨的学习拆成一个音频工程流程从原始歌曲里分离出 bass.wav用频谱图确认贝斯轨的能量位置再用音高估计算法把音频转成候选音高序列最后回到真实乐器上做听感校正。这个流程适合贝斯手、吉他手也适合刚接触音频分离与音乐信息检索的新手。读这篇文章你能得到的不是某一首歌的标准答案而是一套可以反复使用的“扒贝斯工作流”。它能帮你解决三件事第一把贝斯声部从完整混音里单独拿出来第二验证拿出来的贝斯轨是否真的只剩贝斯第三把低频音高从模糊的声波变成可讨论的音符。1. 把贝斯音轨听清楚难在什么地方很多人在扒贝斯时会陷入三个误区。第一个误区是“低音听不清就把耳机音量调大”。低频乐器的能量分布和我们平时说话的频段差别很大人耳对 100Hz 以下信号的感知本来就弱而且心理声学研究表明低频内容的方位感也远不如中高频明显。调大音量只会让底鼓和贝斯一起变得更响并不能把两者分开。你需要的不是更大声而是更清楚的信息来源。第二个误区是“找到贝斯轨就结束了”。分离出一个贝斯音轨只是拿到了一段音频波形离“写出贝斯谱”还有很远。真实的乐器演奏不是 MIDI音与音之间会有滑奏、击弦、勾弦、制音甚至轻微的音高漂移。音频分离只能帮你减少干扰不能直接替你完成音乐听写。第三个误区是“音高估计结果就是最终谱面”。所有自动音高检测算法都只能给出概率意义上的候选值特别是在贝斯这种低音区基频较低泛音又可能被模型误判为基频很容易出现整体高八度或低八度的错误。算法是辅助耳朵才是最终裁判。真正的扒贝斯需要做三层还原音符层确定每个音的起始时间、结束时间、大致音高。节奏层判断音长、休止、切分区分它是八分音符还是延留音。音色层判断是用手指弹、拨片弹、Slap还是合成器贝斯这会影响 EQ 和效果器设置。后面所有步骤都是围绕这三层来设计的。2. 万能青年旅店的贝斯声部为什么值得单独拆《杀死那个石家庄人》并不是一首以“贝斯 Solo”著称的歌曲它真正值得学习的地方是贝斯如何跟鼓组协作在整体混音中承担结构功能。万能青年旅店作品的典型特征是多乐器同时演奏但声部密度并不失控。低音区通常由贝斯和底鼓共同承担贝斯的根音负责定调和声坐标底鼓负责节奏脉冲。如果你只关注吉他或键盘很难意识到这首歌的低频是怎么把主歌、副歌与器乐间奏连接起来的。拆出贝斯音轨不是为了让贝斯压过整首歌而是为了观察乐手在细节处的克制。什么时候走根音什么时候加过渡音什么时候停下来这些问题只有在单独听 bass.wav 时才会变得清晰。对其他乐器学习者来说这也是理解“编曲里谁在撑底”的重要入口。需要注意的是音乐学习过程中我们默认使用自己拥有或获得授权的音频素材分离结果仅用于个人练习与学习参考。商业发行、演出翻录或重新发布他人混音内容之前需要先解决版权问题。3. 环境准备与前置条件下面这套流程基于 Python 3.10 或更高版本操作系统可以是 Windows、macOS 或 Linux。核心依赖包括demucs音频分离模型用来把歌曲拆成鼓、贝斯、人声、其他四个 stem。ffmpeg音频格式转换工具用来统一输入文件的编码和采样率。librosa音频分析与频谱绘图库。soundfile读写 wav 文件。matplotlib绘制频谱图。建议新建独立虚拟环境避免把依赖装进系统 Python。python -m venv .venv # Windows .venv\Scripts\activate # macOS / Linux source .venv/bin/activate python -m pip install --upgrade pip pip install demucs librosa soundfile matplotlib安装完成后可以用下面命令确认命令行入口是否可用demucs --help如果提示找不到命令可以改成python -m demucs --help具体情况取决于你的安装方式和虚拟环境配置。本机显卡显存充足时可以使用 GPU 版本速度会更快即使只有 CPU只要素材时长控制在普通单曲范围内也能完成任务只是耗时较长。4. 音频分离流程从完整混音到独立贝斯轨在开始分离之前先做一次音频格式标准化。中文文件名在部分依赖库的底层解码器中会出现读取问题所以建议先复制一份采样率 44100Hz、16bit 的 WAV 文件再用无中文的文件名保存。ffmpeg -y -i 杀死那个石家庄人.flac -acodec pcm_s16le -ac 2 -ar 44100 source48k.wav如果你的源文件是 mp3、m4a 或其他格式把输入文件名改成实际文件即可。命令里的source48k.wav只是示例命名表示后续用于处理的标准化文件。这里要强调一个关键点不要在这个阶段用普通 EQ 直接从完整歌曲里拉低音。贝斯与底鼓在低频区有重叠简单地加一个低通滤波器只会得到一段贝斯、底鼓和低频键盘糊在一起的声音。想要单独分析贝斯音轨需要用训练好的音频分离模型。demucs 的默认模型 htdemucs 会输出四组轨道vocals人声drums鼓组bass贝斯声部other吉他、键盘、管乐等其余内容执行分离命令demucs -n htdemucs -o ./separated source48k.wav注意这里不要加--two-stemsvocals那个参数会把混音只分成两组不会单独留下 bass.wav。执行完成后目录结构大致如下separated/ └── htdemucs/ └── source48k/ ├── bass.wav ├── drums.wav ├── other.wav └── vocals.wav现在可以先用播放器单独听bass.wav和原曲对比一下。你可能会听到鼓的瞬态被明显削弱贝斯声部的音符轮廓变得更清楚。这个阶段的任务不是判断音高而是先确认低音发声点和鼓组节奏是否对得上。如果 bass.wav 里仍有很明显的鼓声说明输入的混音版本与训练数据差异较大可以考虑换一个分离模型或者在后续频谱分析时进行低通处理。5. 用频谱图验证贝斯轨是否合格拿到 bass.wav 之后不要急着判断音高。先看它的频谱图这是一个很有效的验证手段。贝斯声部的基频通常在 40Hz 到 300Hz 之间具体范围取决于乐曲调性和贝斯类型。频谱图的横轴是时间纵轴是频率颜色深浅代表能量强弱。正常贝斯轨应该能在时域上看到比较明显的横向谐波条纹振幅随低音音符的切换而连续变化而不是碎成一堆无规律的短促爆点。下面这段 Python 脚本可以生成贝斯轨的频谱图# analyze_bass.py import numpy as np import librosa import matplotlib matplotlib.use(Agg) import matplotlib.pyplot as plt AUDIO separated/htdemucs/source48k/bass.wav SR 22050 y, sr librosa.load(AUDIO, srSR, monoTrue) n_fft 2048 hop_length 512 D librosa.amplitude_to_db( np.abs(librosa.stft(y, n_fftn_fft, hop_lengthhop_length)), refnp.max ) fig, ax plt.subplots(figsize(14, 5)) img librosa.display.specshow( D, srsr, hop_lengthhop_length, x_axistime, y_axislog, axax ) ax.set(titleBass Stem Spectrogram) fig.colorbar(img, axax) plt.tight_layout() plt.savefig(bass_stem_spectrogram.png, dpi150) print(saved bass_stem_spectrogram.png)运行方式python analyze_bass.py运行成功后会生成bass_stem_spectrogram.png。观察图片时重点关注两点第一最低的基频线是否清晰。如果基频区域不连续可能存在分离不彻底或混音里贝斯本身音量较低的问题。第二200Hz 以下区域是否与底鼓产生明显冲突。分离较好的 bass.wav 中鼓的瞬态会在频谱图上表现为很窄的竖直亮线而贝斯音则表现为横向延续的水平条纹。两者能区分开说明后续做音高估计会可靠很多。如果频谱图上贝斯能量主要集中在 80Hz 以下并且几乎看不到泛音序列那么你拿到的可能不是标准电贝斯声部而是合成器贝斯或其他低频乐器。这不是错误只是说明后续检测参数需要调整。6. 音高估计把贝斯轨变成候选音高序列频谱图能帮我们确认贝斯轨的存在但要把它变成“可弹的谱”还需要估计每个时间点的基频。这一步常用算法是 pYINlibrosa 已经内置实现。它的原理可以粗略理解为先在每一帧里找出多个局部最优音高候选再用动态规划在时间轴上对候选音高做平滑连接最后输出概率最高的路径。下面的脚本会把分离后的 bass.wav 读入检测每一帧音高然后把连续且接近的音符片段合并输出# estimate_bass_pitch.py import numpy as np import librosa AUDIO separated/htdemucs/source48k/bass.wav SR 22050 def midi_to_event_list(f0, voiced_flag, sr, hop_length512): midis np.full_like(f0, np.nan) midis[voiced_flag] librosa.hz_to_midi(f0[voiced_flag]) events [] start_idx None current_midi None for i, midi in enumerate(midis): if np.isnan(midi): if start_idx is not None: start_time librosa.frames_to_time(start_idx, srsr, hop_lengthhop_length) end_time librosa.frames_to_time(i, srsr, hop_lengthhop_length) events.append((start_time, end_time, current_midi)) start_idx None current_midi None continue rounded int(round(midi)) if current_midi is None: current_midi rounded start_idx i elif abs(rounded - current_midi) 2: if start_idx is None: start_idx i else: if start_idx is not None: start_time librosa.frames_to_time(start_idx, srsr, hop_lengthhop_length) end_time librosa.frames_to_time(i, srsr, hop_lengthhop_length) events.append((start_time, end_time, current_midi)) current_midi rounded start_idx i if start_idx is not None: start_time librosa.frames_to_time(start_idx, srsr, hop_lengthhop_length) end_time librosa.frames_to_time(len(midis), srsr, hop_lengthhop_length) events.append((start_time, end_time, current_midi)) return events def main(): y, sr librosa.load(AUDIO, srSR) f0, voiced_flag, _ librosa.pyin( y, fmin40.0, fmax300.0, srsr, frame_length2048, hop_length512 ) events midi_to_event_list(f0, voiced_flag, sr) for start, end, midi in events: if midi is None: continue note_name librosa.midi_to_note(midi) print(f{start:7.2f}s - {end:7.2f}s MIDI {midi:3d} {note_name}) if __name__ __main__: main()运行脚本python estimate_bass_pitch.py正常输出格式如下1.12s - 1.98s MIDI 43 G2 2.01s - 2.87s MIDI 45 A2这里的音高值只是算法候选不能直接当作答案。尤其要注意以下几点检测出的音高可能是真实基频的倍频也就是实际演奏音高的高八度。低音区音高越接近 40HzpYIN 的置信度往往越低。滑音、击勾弦会造成相邻帧频率快速变化事件合并算法可能把它们拆成多个短音符。分离后的贝斯轨中如果还残留低频键盘检测结果会多出不属于电贝司的音。正确做法是把脚本输出当作一份带时间偏移的“参考提示”打开吉他调音器或用贝斯实琴核对关键位置再在 MuseScore、Guitar Pro 或五线谱软件中逐段重建。7. 贝斯轨中的核心频率区域与常见坑先理解一段常见的频段分工会更容易判断分离结果质量。频段常见内容对扒贝斯的影响20Hz - 40Hz极低频共振、部分合成器低音人耳基本只有身体感知远离标准贝斯基频40Hz - 80Hz贝斯低音区、底鼓腔体共振最容易混叠分离不彻底时鼓声会出现在这里80Hz - 150Hz贝斯基频常见区域音高判断关键区间应重点观察150Hz - 400Hz贝斯泛音、鼓的敲击瞬态分离后仍可能和鼓皮余音粘连400Hz - 1kHz指触噪、拨片声、泛音延续自带音色辨识但容易干扰纯频谱算法如果你在 bass.wav 上做 40Hz 以下的高通滤波一般不会损失太多电贝司基频却能消除不少房间低频杂音。做分析之前用一段带通滤波把 40Hz 到 400Hz 变成重点观察区域能显著减少其他频段内容对算法的干扰。另一个常见坑是单声道化之后再检测会丢失部分立体声信息但通常不会影响音高判断。对于这首歌的学习过程更稳妥的办法是保留立体声波形但在送入 pYIN 前用monoTrue加载。脚本里已经做了这个处理。8. 从检测结果到可演奏谱面的转换当我们把整段贝斯轴拆成时间线后还需要经历一步“清洗”让机器输出变成符合音乐表达的事件序列。建议按下面顺序操作在音频软件中标记主要结构。比如前奏、主歌、副歌、间奏、尾奏先确定段落边界。把 pYIN 输出的时间戳和谱面对齐。如果某一段算法显示连续低音但实际原曲里贝斯手可能每小节只弹一个长音那么不需要把算法输出的每个小节变化都当成不同音符。在每一小节只保留有可信依据的根音和经过音。这个环节最费力但也是学习收益最大的地方。定时循环播放某一句用贝斯实琴逐一试音。当你找到和原曲低音完全吻合的位置时这个位置才算真正确认。最后用固定调或首调标记法把结果写下来。如果你不是绝对音高持有者建议先找到歌曲调性再用级数思维记录例如 I - V - vi - IV这样以后转调更方便。由于万能青年旅店的作品在现场和录音室版本中可能存在不同处理扒带时建议始终标注“我依据的是哪个版本”而不是笼统地说“这就是原版谱”。9. 常见问题与排查思路下面这些问题是音频分离和音高估计阶段最容易遇到的。问题现象可能原因排查方式解决方案demucs 分离速度极慢正在使用 CPU 并且线程数设置不合适查看控制台日志和 CPU 利用率增加--n-jobs或使用 GPU 版本内存或显存不足输入文件采样率太高或时长过长检查文件参数与错误提示在 ffmpeg 阶段统一转为 44100Hz单曲文件控制在 10 分钟以内生成的 bass.wav 中仍有明显鼓声分离模型无法区分同类低频瞬态看频谱图中是否有竖状冲激尝试不同模型不导出 final只作为参考输出文件是中文文件名但无法读取torchaudio 或底层解码库对中文路径支持不一致在 Python 中测试直接读取该路径先用 ffmpeg 改成 ASCII 文件名pYIN 检测出很多相距八度的跳动低音基频较弱算法锁到了倍频观察完整倍频序列 40Hz - 300Hz降低 fmax例如 150Hz再比较结果bass.wav 整段只有很少的 voiced 帧分离结果音量太低或原曲贝斯整体偏轻用播放器监听并查看波形振幅先做响度归一化再用 pYIN音高对得上但节奏不对算法把长音拆成了多个短音比较频谱图和底鼓节奏以鼓点网格为准手动修正音长如果运行过程中遇到缺失包或者版本冲突第一步不是去改代码而是检查虚拟环境是否激活以及pip list里有没有多个版本的 numpy。librosa、demucs 和 PyTorch 对 numpy 的版本有不同要求先统一依赖环境再重跑往往能解决大部分问题。10. 最佳实践与工程建议把贝斯音轨分析当作普通工作流来管理比每次临时写一段脚本更高效。建议在工程目录里保存原曲的标准 WAV 文件和分离后的四个 stem。分离模型会消耗较多磁盘空间建议为每个歌曲建立独立文件夹003_kill_shijiazhuang/ ├── raw/ │ └── source48k.wav ├── separated/ │ └── htdemucs/ │ └── source48k/ │ ├── bass.wav │ ├── drums.wav │ ├── other.wav │ └── vocals.wav ├── analysis/ │ ├── bass_stem_spectrogram.png │ └── bass_pitch_events.txt └── notation/ └── bass_line.mscx这样做的好处是当你对音高估计结果产生争议时可以随时回到分离后的音频重新听不用再次运行昂贵的模型推理。另一个建议是不要过分追求“算法一次给对”。音频智能分析的核心价值是减少重复劳动而不是取代人耳。平时听歌时你已经在潜意识里建立了大量音色经验只是无法把那些经验转换成明确的音符。分离出 bass.wav再配一个节拍器会让你的耳朵更专注。等经验足够多后即使不用 demucs你也能快速把一段低频旋律从完整混音里抓出来。在安全与合规方面尤其要注意不要随意发布从商业录音中分离出的 stem不要在没有授权的情况下把他人的混音作品重新上传到公开平台。个人学习、教学演示和评论性分析属于合理使用的常见场景但“常见”不等于“没有边界”源音频版权和录音版权仍需尊重。11. 把流程固化为自己的听音练习本文描述的方法不仅适用于《杀死那个石家庄人》这一首歌也适用于任何你想单独分析贝斯声部的曲子。下次拿到一首新歌时可以按照这个顺序执行先听完整版三遍记录段落和情绪变化。再用 demucs 分离出 bass.wav。画频谱图确认贝斯声部在哪些时间区间最活跃。调用 pYIN 生成候选音高序列。把候选序列与真实乐器对照修正八度、滑音和节奏。在谱面软件中整理成可播放的 MIDI 片段再用软音源回放验证。如果听起来与目标低频线差异较大回到第 3 步观察泛音结构。对于还没有形成固定听音习惯的新手可以先用低音长音较多的歌曲练习再逐步挑战音符密集的乐句。万能青年旅店这类编曲层次丰富的作品适合用来训练“在混音中分离注意力”的能力。只要你能在鼓、贝斯、键盘共存的前提下稳定追踪低音线扒其他风格歌曲时的压力会小很多。这套流程的最终目的并不是让你依赖软件去弹贝斯。软件只能帮你降低“听不见”的门槛真正决定演奏质量的是你对音符时值、力度和音色的判断。把音频分离、频谱分析和音高估计当作辅助工具耳朵和手才能逐渐形成稳定的反馈回路。