
当你要为《浅水ShallowEnd - 服务器农场(Server Farm)》这类曲目制作鼓谱时第一个要解决的问题通常不是“怎么排版”而是“鼓点到底发生在什么时候”。鼓组不像钢琴或吉他底鼓、军鼓、踩镲的瞬态短、频率重叠、音色混杂在完整混音里靠耳朵拆出每一个打击事件本身就需要大量听力训练。正因为这样鼓手和制谱人开始把音频信号处理、深度学习和人工校对结合起来形成一条“音频转鼓谱”的工程化流程。这篇博客就以“浅水ShallowEnd 服务器农场(Server Farm) 鼓谱”为例整理一条可以复用的辅助制谱路径环境准备、音源分离、节拍检测、鼓点检测、量化、MIDI 生成、人工校对和常见问题排查。需要先说明这里的流程是“辅助转录”不是纯自动化制谱。任何自动检测结果都只能当作初稿。鼓谱的最终质量仍然取决于对音频的逐段确认和对演奏细节的判断。但借助开源工具可以把原本需要一整天的扒谱工作压缩到几十分钟到几小时这在实际项目中已经非常有价值。1. 先把鼓谱制作拆成四个工程环节1.1 鼓谱里要记录的信息不只是“什么时候敲”一份能用来排练的鼓谱至少包含四类信息打击事件、时间结构、力度变化和段落划分。很多人以为鼓谱只是把“哪一面鼓、哪一拍敲下去”标出来实际开始整理时才会发现真正的细节远比表面复杂。信息类型需要记录的内容自动化检测的难度打击事件底鼓、军鼓、踩镲、镲片、嗵鼓分别在什么时间点发声中等需要结合分离音轨和频段特征时间结构小节、拍号、正拍、反拍、切分音、连音较高需要先稳定估计节拍力度层次强音、弱音、Ghost Note、重音偏移高自动检测通常只能给出粗略力度段落结构前奏、主歌、副歌、间奏、尾奏高需要结合和声、编配和人工判断在工程实现上前两类信息可以通过信号处理得到“候选结果”后两类信息几乎必须依赖人工确认。这也是为什么音频分离、节拍检测、鼓点检测只是辅助手段而不是终点。1.2 为什么不能只靠耳朵记谱人耳在完整混音中识别鼓点有几个天然劣势。第一鼓组瞬态很短很多打击信号在十几毫秒内完成能量上升听感上只是“啪”或“咚”的一下很难精确判断它在时间轴上的位置。第二频率掩蔽效应会让底鼓和贝斯、军鼓和吉他形成叠加听感上像同一个声音实际上却是多个声部同时发声。第三长时间扒谱会造成听觉疲劳越往后越容易漏音或错位。计算机辅助转录的价值不是取代耳朵而是先把“可能发生了打击的时间点”标出来。制谱人只需要面对候选列表做判断而不是从零开始逐毫秒听。这样可以显著降低遗漏率也能让经验不足的乐手更快进入“校对节奏”的状态。1.3 一条四段式流水线从原始音频到最终鼓谱可以拆成四个环节音频预处理统一采样率、声道、格式准备适合模型输入的文件。音源分离用 Demucs 把鼓组音轨从混音中拆出来降低其他乐器干扰。节拍与鼓点检测用 librosa 等库计算节拍网格和候选打击点。量化与制谱先把候选点对齐到拍子网格再生成 MIDI导入制谱软件校对和排版。这四个环节是串行关系。前一步的输出是后一步的输入任何一步如果参数不对都会直接影响最终鼓谱的准确度。下面按顺序展开。2. 环境准备Python、ffmpeg、Demucs 和音频分析库2.1 依赖清单和版本注意事项在开始之前先把工具链准备完整。下面这份依赖清单适用于 Linux、macOS 和 Windows但不同系统在安装 PyTorch 时可能需要选择不同索引源。工具用途安装方式注意事项Python 3.10 / 3.11运行脚本和模型Python 官网或包管理工具Demucs 对 Python 3.8 支持较好3.10/3.11 更稳定ffmpeg音频格式转换、采样率调整系统包管理器或官网下载需要把可执行文件加入 PATHPyTorchDemucs 的深度学习后端pip 安装对应版本先确认 CPU/GPU 版本CPU 环境下速度较慢demucs音源分离拆出鼓组音轨pip install demucs模型文件首次运行时会自动下载librosa节拍跟踪、onset 检测、频谱分析pip install librosa用于分析 drums.wav 中的打击事件numpy数组和数值运算pip install numpylibrosa 的依赖之一midiutil 或 pretty_midi生成 MIDI 文件pip install midiutil推荐 midiutilAPI 更直接MuseScore查看和编辑鼓谱导入 MIDI导出 PDF独立软件安装免费开源支持鼓组符号生产环境中还需要把“版本固定”这一步做好。不要直接使用最新的 PyTorch、Demucs、librosa 组合而不做验证因为上游模型和 API 经常调整。建议在虚拟环境中安装并记录 requirements.txt。2.2 安装命令和自检方法在终端中创建虚拟环境并安装依赖python -m venv .venv source .venv/bin/activate pip install --upgrade pip pip install torch --index-url https://download.pytorch.org/whl/cpu pip install demucs librosa numpy midiutil demucs --versionWindows 下激活命令略有不同.venv\Scripts\activate安装完成后验证工具是否可用。这里不建议只检查pip show而是直接跑一次最小命令ffmpeg -version demucs --help python -c import librosa, numpy; print(librosa.__version__)如果 ffmpeg 没有被找到需要把 ffmpeg 的安装目录加入系统 PATH。如果 demucs 提示缺少模型或 torch 相关错误优先检查 Python 版本和 PyTorch 是否安装成功。学习环境用 CPU 运行 Demucs 是可以接受的只是在处理较长的完整曲目时分离时间会明显增加。2.3 准备音频文件格式、采样率和版权边界音频文件建议统一转换为 WAV 格式采样率固定在 44100 Hz双声道保留。这样可以避免不同解码器、不同采样率带来的时间轴偏移问题。如果是视频文件先提取音频ffmpeg -i server_farm.mp4 -vn -ar 44100 -ac 2 server_farm.wav如果原始文件已经是 MP3也建议先转成 WAVffmpeg -i server_farm.mp3 -ar 44100 -ac 2 server_farm.wav这里要特别注意版权问题。学习和技术演示应使用自己演奏的音频、明确授权的素材或公开的创作共用素材。不要用未授权版权音乐做公开分享“扒谱后加上转载声明”并不等同于获得授权。鼓谱发布涉及原曲版权、词曲版权和录音版权公开发布前需要确认授权情况。3. 第一步用 Demucs 把鼓组从混音里拆出来3.1 为什么要先做音源分离直接在完整混音上检测鼓点结果通常很不稳定。人声、贝斯、吉他和鼓组在频段上有大量重叠尤其底鼓和贝斯都集中在低频军鼓和吉他扫弦又都包含噪声成分。Demucs 这类模型可以把混音拆成不同乐器组常见输出包括人声、贝斯、鼓组和其他乐器。分离之后后续分析只需要处理drums.wav。这不能保证 100% 干净但能让鼓点检测的漏检率明显下降。Demucs 不是无损伴奏生成工具它输出的音轨会带有一定音色损失和伪影但对于“找到打击时间点”这个任务来说已经足够。Demucs 提供了多种预训练模型。常用的是htdemucs和htdemucs_ft。两者对普通流行、摇滚曲目的分离效果都不错htdemucs_ft在某些场景下细节更好但速度更慢。如果对分离质量不满意还可以尝试mdx_extra。3.2 分离命令和输出目录最直接的用法是只拆出鼓组和非鼓组两类demucs --two-stemsdrums -n htdemucs_ft server_farm.wav--two-stemsdrums的含义是把输出限定为两个音轨drums.wav和no_drums.wav。这样做的好处是分离速度更快也避免生成过多无用音轨。输出目录一般在当前目录下的separated文件夹中separated/htdemucs_ft/server_farm/drums.wav separated/htdemucs_ft/server_farm/no_drums.wav如果你的项目需要更细的拆分为目标也可以不指定--two-stems让 Demucs 输出完整的多音轨。但在鼓谱制作场景中通常drums.wav就足够了。3.3 分离质量和相关参数说明如果分离结果不够干净可以调整几个参数。参数作用使用建议-n选择模型名称稳定情况下用htdemucs够用质量优先用htdemucs_ft--shifts对音频做平移平均提升稳定性设置为 1 或 2时间会成倍增加--segment控制模型一次处理的音频切片长度内存不足时降低到 5 或 4--job并发进程数机器性能好时可以调高分离完成后一定要先听一遍drums.wav确认底鼓和军鼓是否明显踩镲是否保留。如果底鼓和贝斯仍然粘连严重可以在后续检测环节针对频段做过滤而不是反复调 Demucs 参数。学习环境中优先用稳定模型跑通流程再针对特定曲目做优化。4. 第二步节拍检测和鼓点检测4.1 用 librosa 加载音频并计算节拍节拍检测是整个流程的骨架。只有知道了 BPM 和小节网格才能把时间点换算成小节、拍数和 16 分音符位置。import numpy as np import librosa audio_path separated/htdemucs_ft/server_farm/drums.wav y, sr librosa.load(audio_path, sr44100, monoTrue) onset_env librosa.onset.onset_strength(yy, srsr) tempo, beat_frames librosa.beat.beat_track(onset_envelopeonset_env, srsr) tempo_value float(np.atleast_1d(tempo)[0]) beat_times librosa.frames_to_time(beat_frames, srsr) print(Estimated BPM:, tempo_value) print(Beat times:, beat_times[:10])librosa.load会把音频重采样到指定采样率并混为单声道。这里是分析阶段单声道即可。onset_env是每个帧的起始强度帧步长默认对应 512 个采样点在 44100 Hz 下大约是 11.6 毫秒。不同版本的 librosa 对beat_track的返回值细节有差异。有的版本tempo是浮点数有的版本是 numpy 数组所以这里用np.atleast_1d统一处理。4.2 用 onset_detect 找出候选打击点节拍网格解决的是“小节和拍子在哪里”但鼓点不一定都落在正拍上。切分音、反拍、Ghost Note 会出现在拍子之间。因此需要用 onset 检测找出所有候选打击时间。hop_length 512 onset_frames librosa.onset.onset_detect( onset_envelopeonset_env, srsr, hop_lengthhop_length, delta0.08, backtrackTrue, ) onset_times librosa.frames_to_time(onset_frames, srsr, hop_lengthhop_length) print(Onset count:, len(onset_times))delta是检测阈值决定一个瞬时能量峰是否算作 onset。这个值调大漏检变多调小误检变多。backtrackTrue会把检测到的峰位置回退到能量开始上升的位置这样得到的打击点更接近实际发声时刻。在实际项目中不要第一次就跑全曲。建议先截取 30 到 60 秒的音频段落观察检测结果调整好阈值后再处理整首曲目。4.3 频段过滤尝试区分底鼓、军鼓和踩镲onst 检测只告诉你“这里有一个打击事件”没有告诉你“这是哪一件鼓”。要把候选点归类可以用频段启发式方法。底鼓的能量集中在 60 到 160 Hz军鼓在中低频有共振峰踩镲和镲片则在高频段 6 kHz 以上有明显能量。利用 scipy 的 Butterworth 滤波器可以分别提取频段from scipy import signal def band_onset_strength(y, sr, low, high): sos signal.butter(8, [low, high], btypebandpass, fssr, outputsos) filtered signal.sosfiltfilt(sos, y, axis0) return librosa.onset.onset_strength(yfiltered, srsr) kick_env band_onset_strength(y, sr, 60, 160) snare_env band_onset_strength(y, sr, 200, 400) hat_env band_onset_strength(y, sr, 6000, 12000)然后分别对每个频段的 onset envelope 做峰值检测。这个方法的原理是底鼓击打时低频能量会快速上升军鼓击打时中频和高频噪声会同时上升而踩镲主要是持续的高频噪声短促且密集。频段启发式并不完美。底鼓和贝斯在实际混音中频率重叠严重Demucs 分离后也可能残留低频贝斯。军鼓某些边缘音听起来接近木鱼频段特征不一定典型。因此这里生成的分类结果需要作为“候选分类”而不是最终结论。5. 第三步把检测结果量化成 MIDI5.1 拍点网格和量化鼓检测得到的时间点是浮点数单位是秒。要让它进入五线谱必须映射到节拍网格上。量化粒度一般用 16 分音符。如果曲目 BPM 是 120那么四分音符时长是 0.5 秒16 分音符时长为 0.125 秒。首先把秒数转换成拍数beat_duration 60.0 / tempo_value onset_beats onset_times / beat_duration再量化到 16 分音符的位置quantized_beats np.round(onset_beats * 4) / 4这一步会把偏移很小的声音吸附到最近的 16 分音符位置上。量化之后会产生重复事件可以用去重逻辑处理保留相位差小于一个量化单位的第一个事件。unique_events [] last_beat -1 for beat_pos in quantized_beats: if beat_pos - last_beat 0.24: unique_events.append(beat_pos) last_beat beat_pos这里0.24只是一个示例阈值具体值要根据实际曲目的密集程度决定。5.2 打击乐 MIDI 的音符约定MIDI 文件中打击乐使用 General MIDI 的鼓映射。不同音色编号对应不同鼓件。生成 MIDI 前先建立一个映射表鼓件MIDI 音符号底鼓 Kick35 或 36军鼓 Snare38 或 40闭镲 Closed Hi-Hat42开镲 Open Hi-Hat46Crash 镲49Ride 镲51低嗵 Tom43 或 41中嗵 Tom45高嗵 Tom48在实际检测中建议先把所有事件保存为标签列表例如(beat_position, note_number, velocity)再统一写入 MIDI。不要边检测边写文件否则后期调整映射会很痛苦。5.3 用 midiutil 生成 MIDI 文件下面代码演示如何把量化后的鼓点写入 MIDI。这里时间单位已经是拍数所以可以直接传给 midiutil。from midiutil import MIDIFile mf MIDIFile(1) track 0 time 0 mf.addTempo(track, time, tempo_value) # MIDI 打击乐通用通道在 GM 规范中是第 10 通道 # 在 midiutil 中通道从 0 开始计数因此使用 9 channel 9 drum_events [ # (beat_position, note_number, velocity) (0.0, 36, 100), (0.25, 42, 90), (0.5, 38, 100), (0.75, 42, 90), ] for beat_pos, note, velocity in drum_events: duration 0.24 # 以拍为单位的音符时值 mf.addNote(track, channel, note, beat_pos, duration, velocity) with open(server_farm_drums.mid, wb) as f: mf.writeFile(f)addTempo的第一个时间参数是“从第几拍开始设置速度”通常从 0 开始。addNote的时间和持续时间单位都是拍。鼓点本身是瞬态声音理论上时长很短但在乐谱中会使用十六分音符或八分音符来表示所以duration0.24只是示意实际值取决于曲目的最小节拍单位。生成 MIDI 后还要检查文件是否真的把通道设成了打击乐通道。如果导入软件后听到的是钢琴音色而不是鼓组通常就是通道或音色设置出了问题。6. 第四步在 MuseScore 里校对并导出鼓谱6.1 导入 MIDI 到 MuseScoreMuseScore 可以导入 MIDI 文件。操作路径是“File - Import - MIDI”。导入后第一步要看音轨轨道是否被识别为打击乐。如果看到的是高音谱表上的普通音符说明软件没有把它当成鼓谱。处理方式是在 MuseScore 中修改乐器设置选择音符所在的轨道打开“Staff/Part Properties”把 Instrument 改为鼓组例如“Drum Set”或“Percussion”。改完之后音符会重新映射为鼓谱符号五线谱也会变成打击乐谱样式。6.2 逐段校对哪些内容MIDI 导入后鼓谱还远不能直接发布。至少要做以下几类校对与小节线对齐。查看每个音符是否落在正确的拍子和小节位置上尤其是切分音。检查底鼓与军鼓的骨架。先看底鼓是否稳定再看军鼓是否在预期位置。补 Ghost Note。自动检测很难识别轻击和 Ghost Note需要对照音频手动添加。检查踩镲的开闭。闭镲和开镲在 MIDI 中是不同的音号自动分类容易混淆。确认段落结构。用波形或频谱概览找到前奏、副歌、间奏的边界并在鼓谱上加入段落标记。这个阶段不要用播放器听 MIDI 来判断是否准确。MIDI 鼓声和真实鼓声差别很大最好一边放着原始音频或drums.wav一边在 MuseScore 中一个小节一个小节地检查。6.3 导出格式和谱面信息校对完成后可以从 MuseScore 导出 PDF、PNG 或 MusicXML。如果只是自己练习PDF 就足够。如果要上传到博客或分享群建议同时导出 PDF 和 PNG方便不同设备查看。一份完整的鼓谱在开始处应该注明曲名、原曲作者、制谱者、BPM、拍号。示例文本浅水ShallowEnd - 服务器农场(Server Farm) Drum Score BPM: 120 Time Signature: 4/4 Transcriber: Your Name关于版权的处理要谨慎。如果原曲不是自己创作且没有获得授权公开发布完整鼓谱可能存在版权风险。个人学习和内部排练通常没有问题但在博客、公众号、付费群分享时需要先确认授权范围。7. 常见问题排查检测结果和音频对不上怎么办7.1 底鼓漏检严重低频被贝斯干扰现象检测结果中底鼓明显偏少很多低音鼓点没有出现在列表中。可能原因Demucs 分离后drums.wav中残留了低频贝斯能量或者底鼓频段与贝斯重叠onset 能量没有达到阈值。排查方法查看kick_env的波形确认低频段是否在底鼓时刻有明显能量峰。如果能量峰很小说明分离不彻底或底鼓本身力度弱。处理时可以降低delta阈值或者把底鼓检测单独限定在 60 到 160 Hz 频段避免中高频噪声干扰。7.2 军鼓被误检成踩镲频段特征不典型现象军鼓事件混在踩镲事件中或者在结果列表中被标注为高音打击乐。可能原因军鼓边缘音、鼓刷演奏、或者军鼓在混音中被吉他噪声遮蔽导致中频特征不明显。排查方法在频谱图上找到军鼓位置确认是否有 200 到 400 Hz 的共振峰。如果军鼓和踩镲在频段上确实难以区分建议手动修正而不是调低阈值否则误检会更多。最好的方式是把自动分类结果当候选用鼓谱编辑器做快速拖拽修正。7.3 踩镲几乎检测不出来连续高频噪声掩盖瞬态现象踩镲事件大量缺失尤其连续八分音符踩镲时只检测出第一下。可能原因踩镲的瞬态比底鼓和军鼓弱高频段能量又容易和镲片、人声的齿音重叠onset 检测算法常常把连续击打合并成一个长事件。排查方法检查hat_env的波形观察是否每个八分音符都有微小的能量峰。如果能量峰存在说明是阈值问题可以降低高频段的检测阈值。如果能量峰本身就是平的说明分离后的踩镲信号已经不完整只能靠人工对照原曲补写。7.4 MIDI 导入 MuseScore 后没有鼓音色现象导入 MIDI 后音符显示在高音谱表上播放出来是钢琴音色不是鼓组。可能原因MIDI 文件中通道没有设置成打击乐通道或者 MuseScore 没有识别鼓谱音轨。排查方法用文本方式打开 MIDI 比较麻烦可以直接在生成代码里检查channel是否为 9。注意 midiutil 的通道从 0 开始所以 General MIDI 打击乐通道 10 在代码里是channel 9。导入 MuseScore 后再手动把乐器改成鼓组。7.5 变速歌曲节拍检测失败现象节拍检测输出的 BPM 变化过大后面的量化结果全乱。可能原因原曲有渐快、渐慢或自由速度。librosa 的beat_track面向恒定速度曲目。排查方法对变速段落单独分段处理。先手动切割段落再对每一段单独估计 BPM。MuseScore 本身支持速度变化标记最终鼓谱里可以按段落设定不同的速度。8. 最佳实践从“能转谱”到“能放心用”8.1 保留完整分析素材形成数据闭环鼓谱制作不是只保留一份最终 PDF 就够了。后续修改原曲、重新校对、更换制谱风格时都需要回到原始分析结果。建议按固定目录组织文件server_farm/ audio/ server_farm_original.wav server_farm_drums.wav analysis/ onset_events.csv beat_grid.csv midi/ server_farm_drums.mid score/ server_farm_drums.mscz server_farm_drums.pdfonset_events.csv至少包含以下列时间秒、拍位置、量化拍位置、检测频段、候选鼓件。这样即使调整了检测参数也能对比新旧结果而不是覆盖原始检测输出。8.2 用一小段人工标注评估检测质量不要凭感觉判断“这次检测准不准”。截取 30 秒音频人工标注出所有底鼓、军鼓、踩镲事件再算出正确率和召回率。指标含义计算方式Precision检测出的事件中有多少是真实事件正确事件数 / 检测事件总数Recall真实事件中有多少被检测出来正确事件数 / 人工标注事件总数F1两者的调和平均2 * Precision * Recall / (Precision Recall)评估的目的是为后续调参提供依据。比如将delta从 0.08 调到 0.05 后Precision 下降但 Recall 上升是否值得接受取决于鼓谱的使用场景。如果是给新手练习宁可多留候选事件如果是出版级鼓谱人工修正比例会更高。8.3 生产级鼓谱还需要补充的内容当流程运行稳定后可以进一步扩展。训练或使用专用鼓转录模型现在有基于 Transformer 的音频事件检测模型识别鼓件类型的能力比频段启发式强很多。引入音符语料库对常见节奏型做模式匹配例如八分音符踩镲、底鼓与军鼓的固定连接让量化结果更接近真实演奏习惯。把鼓谱排版纳入统一模板TAB 谱、五线谱、简化节奏谱共用同一份事件数据避免多版本维护。这些扩展方向的前提都是先把基础流程的数据结构和管理规范建立起来。8.4 可复用的鼓谱制作检查清单每次制作或修改鼓谱时按下面清单检查一遍。原始音频是否确认有合法来源。音频是否统一转换为 WAV采样率是否为 44100 Hz。Demucs 是否成功输出drums.wav。是否已检查drums.wav的分离质量。BPM 是否和原曲试听一致。鼓点检测时是否调过delta阈值而不是使用默认值。是否有对底鼓、军鼓、踩镲的频段分类结果。MIDI 是否使用打击乐通道音符号是否在鼓映射范围内。导入 MuseScore 后是否切换成鼓组乐器。是否逐段对比原始音频校对过切分音和 Ghost Note。谱面是否包含曲名、作者、BPM、拍号等基础信息。公开发布前是否确认版权授权。回到最初的目标为“浅水ShallowEnd 服务器农场(Server Farm) 鼓谱”这类任务制作鼓谱最有价值的技术判断是不要把自动化检测当成制谱的替代品而要把检测结果当成一份带时间标注的候选清单。真正决定鼓谱质量的是人工校对环节和对音乐细节的理解。工程流程能压缩时间但不能抹掉音乐判断。建议从一段 30 秒的音频段落开始跑通整条链路再逐步扩展到整首曲目这也是练习这套工具链最有效的方式。