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, через basic-pitch от Spotify

  • to_score.py — MIDI-файл → MusicXML, через music21

  • score_to_notes.py — файл партитуры (MIDI, MusicXML или что угодно, что умеет читать music21) → JSON-массив нот в формате batch_set_notes из daw-mcp

  • mcp_server.py — MCP-сервер, оборачивающий все три как инструменты (transcribe_audio, midi_to_score, score_to_notes)

Каждый шаг — отдельный реальный артефакт на диске, а не скрытый промежуточный результат. Пауза между MIDI и нотацией намеренная: автоматическая транскрипция теряет данные, поэтому на сырой MIDI стоит взглянуть (или вручную поправить), прежде чем он станет партитурой.

score_to_notes.py намеренно не привязан к формату, а не только к MIDI: music21.converter.parse() обрабатывает MIDI и MusicXML одинаково, поэтому передача ему .mid из transcribe.py или .mxl из внешнего OMR-инструмента (см. «Форматы, с которыми это работает») идёт по одному и тому же пути кода. В этом проекте нет отдельного инструмента 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, чьи wheels заканчиваются на cp311; на 3.12 и 3.13 зависимости не разрешатся. Получившийся venv занимает ~2 ГБ (полный 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 зафиксирован отдельно, потому что новые версии ломают транзитивный импорт resampy, который нужен basic-pitch.

Использование: 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 (внешний, см. «Форматы, с которыми это работает») → score_to_notes для .mxl

.mxl, .notes.json (вообще без MIDI-шага)

Просмотр/редактирование отсканированных нот как партитуры

только Audiveris

.mxl — это уже MusicXML, открывайте напрямую, никакой инструмент здесь не нужен

.mid в первых двух строках — это не столько «результат», сколько неизбежная контрольная точка: basic-pitch умеет выдавать только MIDI, и на него стоит взглянуть, прежде чем доверять тому, что идёт дальше (почему — см. «Известная проблема» ниже).

Рабочий пример

Реальный прогон, а не гипотетический. Вход: синтетический моно-WAV, арпеджио до мажор (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 теперь корректно скрывает, не повреждая поток stdout у mcp_server.py (см. 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 корректно определил высоту и скорость (velocity) для всех четырёх (60/64/67/72, точно совпадает с арпеджио), но разбил последнюю ноту (C5) на две последовательные записи вместо одной — хвост затухающей огибающей, судя по всему, был воспринят как вторая атака. Это та самая потеря данных при автоматической транскрипции, о которой предупреждает раздел «Что здесь есть» выше, — поймано вживую на самой первой ноте с естественной (не плоской) формой громкости: проверяйте .mid, прежде чем слепо доверять .musicxml/.notes.json, особенно в области выдержанных или затухающих нот.

c_major_arpeggio.musicxml без проблем открывается в любом нотном приложении (проверено, что файл корректный: правильный DOCTYPE MusicXML 4.0, высоты <step>/<octave> для C4/E4/G4/G4/C5/C5/C5 — расщеплённая C5 отображается как связанные ноты через границу такта, что является стандартным MusicXML для ноты, не помещающейся в один такт, а не второй ошибкой).

Использование: 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 (формат массива нот batch_set_notes из daw-mcp; принимает MIDI или MusicXML)

Под капотом то же поведение, что и в CLI (та же защита от перезаписи, те же ошибки) — MCP-сервер это тонкая обёртка, а не другая реализация.

Что стоит знать, если вызов выглядит зависшим: если вызов transcribe_audio выглядит так, будто истёк тайм-аут, или был отменён, транскрипция всё равно может продолжаться в фоне и завершит запись файла .mid независимо ни от чего. При повторе вы тогда упрётесь в защиту от перезаписи («уже существует»), хотя первый вызов выглядел так, будто никогда не завершился. Это не баг — перед повтором проверьте, не существует ли уже .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, audio, tab, MIDI

MuseScore Studio или Guitar Pro, открытые обычным способом

Намеренно не обёрнуто здесь — см. выше. (Режим конвертера CLI в MuseScore, -j job.json, действительно может надёжно автоматизировать экспорт PDF, если вам это нужно для ваших собственных скриптов, — просто не встроено в этот проект)

PDF (отсканированные/набранные ноты) → MusicXML

Audiveris (C:\Program Files\Audiveris\Audiveris.exe): Audiveris.exe -batch -export -output "<folder>" "<input>.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 как «повреждённый»

Сильно полифонические транскрипции могут дать .musicxml, который MuseScore Studio отказывается открывать, называя его «повреждённым». Корневая причина: собственный MusicXML-писатель music21 пропускает тег <voice> в некоторых элементах <note>, когда произведению требуется много одновременных голосов (5+) — проверено на реальной 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-мелодия, транскрибированная и повторно проверенная без каких-либо проблем с тегами голосов) — это специфично для грязного, плотного вывода транскрипции реального аудио.

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
    -