Skip to main content
Glama
David7ce
by David7ce

audio2score-mcp

将录制的音频文件转换为可编辑的乐谱:音频 → MIDI → MusicXML。

选择 MusicXML 作为目标格式,因为它是"乐谱界的 SVG"——一种开放的、基于文本的格式,任何记谱应用(MuseScore、Sibelius、Guitar Pro、Finale、Dorico)都可以打开、编辑和重新导出,而无需拥有生成它的流水线。本项目只生成 .mid 和 .musicxml 文件;打开、编辑以及导出为任何其他格式(PDF、音频、六线谱)都在你选择的记谱应用中手动完成——关于本项目为何刻意不封装这部分,请参阅下文"此项目连接到的格式"。

两种运行方式:作为普通 CLI 脚本运行,或作为 MCP 服务器运行,将相同的步骤暴露为 Claude 可以调用的工具。

目录内容

  • transcribe.py — 音频文件 → MIDI,通过 Spotify 的 basic-pitch

  • to_score.py — MIDI 文件 → MusicXML,通过 music21

  • score_to_notes.py — 乐谱文件(MIDI、MusicXML,或任何 music21 能读取的格式)→ 以 daw-mcp 的 batch_set_notes 格式输出的 JSON 音符数组

  • mcp_server.py — MCP 服务器,将以上三个脚本封装为工具(transcribe_audio、midi_to_score、score_to_notes)

每一步都是磁盘上独立、真实存在的产物——不是隐藏的中间结果。MIDI 与记谱之间的停顿是刻意设计的:自动转写是有损的,因此在它变成乐谱之前,原始 MIDI 值得检查(或手动修正)一下。

score_to_notes.py 刻意设计为格式无关的,而非 MIDI 专用——music21.converter.parse() 对 MIDI 和 MusicXML 的处理完全相同,因此将 transcribe.py 生成的 .mid 或外部 OMR 工具(参见"此项目连接到的格式")生成的 .mxl 喂给它,走的是同一条代码路径。本项目没有单独的 MusicXML→MIDI 或 MusicXML→PDF 工具——一旦生成了 .musicxml,任何记谱应用都能直接打开并导出它,所以在这里构建这些功能只是重复安装已有的东西。

Related MCP server: whisper-mcp

文件存放位置

建议:将输入文件放入 workspace/(仓库本地目录,已被 gitignore——参见 .gitignore——放在这里的任何内容都不会被提交,包括输入文件)。不过这不是硬性要求——任何路径都可以。每个输出文件都生成在其输入文件旁边,同名不同扩展名:

workspace/song.mp3          <- you put this here (any format basic-pitch/librosa reads: mp3, wav, ogg, flac...)
workspace/song.mid          <- transcribe_audio writes this
workspace/song.musicxml     <- midi_to_score writes this (open in MuseScore/Guitar Pro/Sibelius/Finale/Dorico)
workspace/song.notes.json   <- score_to_notes writes this (feed into daw-mcp's batch_set_notes)

查看方式:直接用你手头的任何记谱应用打开 .mid 或 .musicxml——本项目不会为你启动任何应用。如果 MuseScore 提示 .musicxml"已损坏",在断定文件有问题之前,请先查看下面的复调注意事项。

环境搭建

需要 Python 3.11 特定版本——basic-pitch 依赖 TensorFlow 2.15,其 wheel 只支持到 cp311;3.12 和 3.13 将无法解析。生成的虚拟环境约为 2GB(完整版 TensorFlow,而非更轻量的后端)。

uv venv --python 3.11 venv
uv pip install -r requirements.txt --python venv/Scripts/python.exe

依赖项已精确锁定(basic-pitch==0.4.0、music21==10.5.0、setuptools==65.5.0、mcp==2.0.0)——本项目没有自动化测试套件,因此一个与已验证环境完全一致的全新环境就是替代方案。setuptools 特别被锁定,是因为较新版本会破坏 basic-pitch 所需的传递依赖 resampy 的导入。

用法:CLI

venv/Scripts/python.exe transcribe.py "C:\path\to\song.mp3"
# -> C:\path\to\song.mid

venv/Scripts/python.exe to_score.py "C:\path\to\song.mid"
# -> C:\path\to\song.musicxml

venv/Scripts/python.exe score_to_notes.py "C:\path\to\song.mid"
# -> C:\path\to\song.notes.json  (daw-mcp's batch_set_notes format - also
#    takes a .musicxml/.mxl directly, e.g. from OMR, no separate step needed)

输出始终生成在输入旁边,同名不同扩展名。三个脚本都拒绝覆盖已存在的输出文件——如果想重新运行,请先删除或移动旧文件。错误(输入缺失、库故障)会向 stderr 打印清晰的消息并以非零状态退出;不会有静默失败。

只运行你的实际目标所需的工具——不要默认把三个全部串联起来。 每个工具只生成一个文件;运行超出需要的工具只会产生没人要的文件。

目标

运行

生成的文件

将录音作为记谱查看/编辑

transcribe_audio → midi_to_score

.mid、.musicxml

将录音的音符导入 daw-mcp

transcribe_audio → score_to_notes

.mid、.notes.json(跳过 midi_to_score——此目标不需要)

将扫描/排版好的乐谱导入 daw-mcp

Audiveris(外部工具,参见"此项目连接到的格式")→ 对 .mxl 运行 score_to_notes

.mxl、.notes.json(完全没有 MIDI 步骤)

将扫描乐谱作为记谱查看/编辑

仅 Audiveris

.mxl——已经是 MusicXML,直接打开即可,这里不需要任何工具

前两行中的 .mid 与其说是"输出",不如说是不可避免的检查点——basic-pitch 只能输出 MIDI,而且在信任其后续结果之前值得检查一下(原因参见下面的"已知问题")。

实际示例

这是一个真实运行,而非假设。输入:一个合成的单声道 WAV,C 大调琶音(C4-E4-G4-C5,四分音符,带有短衰减包络,因此起音清晰)——这是本项目关心的意义上的"真实音频"(磁盘上实际的波形,而非手打的 MIDI),只是合成而非录制,因此转写结果可以在没有版权文件散落在公共仓库中的情况下复现。

$ venv/Scripts/python.exe transcribe.py c_major_arpeggio.wav
WARNING:root:Coremltools is not installed. ...
WARNING:root:tflite-runtime is not installed. ...
WARNING:root:onnxruntime is not installed. ...
Wrote c_major_arpeggio.mid

$ venv/Scripts/python.exe to_score.py c_major_arpeggio.mid
Wrote c_major_arpeggio.musicxml

$ venv/Scripts/python.exe score_to_notes.py c_major_arpeggio.mid
Wrote c_major_arpeggio.notes.json

三行 WARNING:root 是 basic-pitch 提示可选后端(CoreML、TFLite、ONNX)未安装——无害,实际使用的是 TensorFlow 后端,而且这正是 transcribe.py v1.1.1 现在正确隐藏的内容,不会破坏 mcp_server.py 的 stdout 流(参见 CHANGELOG.md)——它只出现在终端上,不会进入 MCP 协议通道。

c_major_arpeggio.notes.json,即 daw-mcp 就绪的输出:

[[0.0, 60, 83, 1.0], [1.25, 64, 80, 1.0], [2.3333, 67, 80, 1.0], [3.5, 72, 78, 0.5], [4.0, 72, 78, 0.5]]

输入了四个音符(C4、E4、G4、C5);basic-pitch 正确检测了全部四个音符的音高和力度(60/64/67/72,与琶音完全一致),但将最后一个音符(C5)拆成了两个连续的条目而非一个——衰减包络的尾部显然被识别为第二个起音。这就是上文"目录内容"部分警告的自动转写有损性,在第一个具有自然(非平直)音量形状的音符上就实际出现了:在盲目信任 .musicxml/.notes.json 之前,请检查 .mid,尤其是在持续音或衰减音附近。

c_major_arpeggio.musicxml 可以在任何记谱应用中正常打开(已验证格式良好:正确的 MusicXML 4.0 DOCTYPE,C4/E4/G4/G4/C5/C5/C5 的 <step>/<octave> 音高——被拆分的 C5 以跨小节线的连音形式出现,这是 MusicXML 中一个音符无法放入单个小节时的标准表示,而非第二个 bug)。

用法:MCP 服务器

在 Claude Code 的配置中注册为 audio2score——全新安装后请重启 Claude Code 才能看到它(MCP 服务器在启动时加载)。

三个工具,与三个脚本完全对应:

  • transcribe_audio(audio_path) → 返回 .mid 路径

  • midi_to_score(midi_path) → 返回 .musicxml 路径

  • score_to_notes(score_path) → 返回 .notes.json 路径(daw-mcp 的 batch_set_notes 音符数组格式;接受 MIDI 或 MusicXML)

底层行为与 CLI 相同(相同的覆盖保护、相同的错误)——MCP 服务器是薄封装,而非不同的实现。

如果调用似乎挂起,需要知道一件事: 如果 transcribe_audio 调用看起来超时或被取消,转写可能仍在后台运行,并且无论如何都会完成 .mid 文件的写入。重试时就会触发覆盖保护("已存在"),即使第一次调用看起来从未成功。这不是 bug——重试前先检查 .mid 是否已存在。

要在其他地方自行注册服务器,请将以下内容添加到你的 MCP 配置(mcpServers)中,两个字段都使用绝对路径——客户端启动 stdio 服务器时没有定义工作目录,因此相对路径无法解析:

"audio2score": {
  "type": "stdio",
  "command": "<absolute path to>\\venv\\Scripts\\python.exe",
  "args": ["<absolute path to>\\mcp_server.py"],
  "env": {}
}

此项目不做什么

  • 不提供乐谱/MIDI → 音频、PDF 或六线谱输出,也不提供 MusicXML → MIDI 转换——原因及替代方案参见下文"此项目连接到的格式"

  • 不提供声部分离或多乐器拆分

  • 刻意不设自动化测试套件——验证始终是对真实音频的真实运行

此项目连接到的格式

一旦生成了 .musicxml,本项目就刻意止步——每个记谱应用都已原生支持打开 MusicXML,并从自己的菜单中导出所需内容(PDF、音频、六线谱、MIDI)。围绕这些导出构建自动化封装的做法曾被尝试过,但大部分已回退(完整的反复过程参见 CHANGELOG.md v1.2.0 至 v2.0.0)——在确认 score_to_notes.py 可以直接接受 MusicXML 而无需单独转换步骤之后,最终发现仍然值得自动化的方向一个都没有。

方向

使用

备注

MusicXML → PDF、音频、六线谱、MIDI

MuseScore Studio 或 Guitar Pro,正常打开

刻意不在此封装——见上文。(MuseScore 的 CLI 转换模式 -j job.json 确实可以可靠地自动化 PDF 导出,如果你想在自己的脚本中使用的话——只是没有内置到本项目中)

PDF(扫描/排版乐谱)→ MusicXML

Audiveris(C:\Program Files\Audiveris\Audiveris.exe):Audiveris.exe -batch -export -output "<文件夹>" "<输入>.pdf"

-batch 确实会跳过其 GUI。已在 3 个真实 PDF 上测试:2 个干净的单页乐谱正确导出(其中一个有轻微拍号警告);一本 24 页的吉他六线谱书在多个页面上遇到了 Audiveris 内部崩溃(其节奏分析中的 NullPointerException/IndexOutOfBoundsException)——OMR 在复杂、多页或六线谱密集的输入上可靠性会迅速下降

PDF → daw-mcp 的音符格式

Audiveris(上文)→ 本项目的 score_to_notes.py,直接对 .mxl 运行

两步,都是真实的,并且已在真实乐谱上端到端测试——中间无需 MIDI 转换

对待 OMR 输出的怀疑程度至少应与对待 basic-pitch 的音频转写相同——在信任之前检查中间的 .musicxml,并且不要期望 Audiveris 能成功处理每个 PDF(参见上面六线谱书的失败案例)。

已知问题:MuseScore 可能会将转录的 .musicxml 文件视为“已损坏”并拒绝打开

高度复调的转录可能会生成一个 MuseScore Studio 拒绝打开并称之为“已损坏”的 .musicxml 文件。根本原因:当一首曲子需要多个同时进行的声部(5+)时,music21 自带的 MusicXML 写入器会在某些 <note> 元素上省略 <voice> 标签——这已通过一段真实的 45 秒录音得到验证,该录音被转录为密集且经常重叠的音符(这是 basic-pitch 在真实音频上拾取泛音/伪影所导致的副作用,而不是干净的单一旋律线)。已确认这是 music21 写入器的问题,而不是本项目的代码:to_score.py 只是一个两行的 parse() + write() 调用,本身没有任何音符/声部逻辑;即使在写入前显式调用 score.makeNotation() 也无法修复。用 music21 本身重新解析同一文件时,它只会发出警告(Cannot put in an element with a missing voice tag),并通过将这些音符默认归入声部 1 来恢复;而 MuseScore 的导入器只是更严格,直接拒绝,而不是容忍这种情况。

变通方法:点击“仍然打开”——文件可以正常加载,只是那些特定音符会进入声部 1,而不是原先检测到的声部;这只是小的排版异常,不是数据丢失。在干净、低复调的输入(手工创作的旋律 MIDI,转录并重新验证后没有任何 voice 标签问题)上不会出现——这专门针对杂乱、密集的真实音频转录输出。

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    MCP server that provides a transcribe_audio tool to convert voice messages from channels into text using OpenAI Whisper, enabling Claude Code to process audio attachments.
    1
    MIT
  • -
    license
    Not graded
    quality
    Not graded
    maintenance
    MCP server for vibe coding with music, enabling format conversion (LilyPond, MusicXML, MIDI, ABC, etc.), audio-to-sheet transcription, and transposition with robust fallback outputs.
    1
    -