Convert sheet music PDFs into MusicXML, with optional MuseScore export, using open-source Optical Music Recognition.
Maintained by Divergent AI
PDF2Muse is an early revived project. It can render PDF pages, run the open-source oemer OMR engine, combine generated MusicXML pages, and optionally export a MuseScore .mscx file when the MuseScore CLI is available.
It is not yet quality-proven. The current pipeline may produce weak or malformed notation, even for clean PDFs, and every generated score should be reviewed in notation software before use in performance, teaching, publication, or archival work.
The next phase of development is about measurement first: building repeatable evaluation tools, comparing output against ground-truth MusicXML/MEI datasets, and using those results to decide whether synthetic degradation or fine-tuning work is justified.
PDF2Muse has seen enough interest that it is worth picking up again with a more honest, evidence-driven approach.
The original idea still matters: many musicians, composers, teachers, archivists, and hobbyists have PDFs or scanned scores that they would rather edit, transpose, search, and preserve as structured notation. The project is not there yet. In its current state, it is useful for experimentation and development, but not something I want to present as a polished or reliably useful product.
I am bringing the project back with a stronger focus on evaluation, quality thresholds, and practical ML workflows. The immediate goal is to find or assemble datasets that pair score images or PDFs with trusted symbolic notation, run PDF2Muse against them, and let the results guide the work instead of relying on vague accuracy claims.
If the project can be made genuinely useful, I want it to serve the community of passionate music lovers, composers, and open-source builders who care about making notation more accessible.
-- Divergent AI
| Start | Use | Evaluate | Understand | Contribute |
|---|---|---|---|---|
| Quick Start | How To Use | Quality Roadmap | Architecture | Development |
PDF2Muse is a Python tool for converting sheet music PDFs into editable notation formats:
- It renders PDF pages into high-resolution page images with
pypdfium2. - It runs
oemeron each page image to generate page-level MusicXML. - It combines generated page MusicXML files into
combined.musicxml. - It optionally calls the MuseScore CLI to export
combined.mscx.
MusicXML is the primary output. MuseScore .mscx export is a convenience layer and depends on MuseScore being installed or passed with --musescore-path.
PDF2Muse is most likely to behave reasonably on clean, standard Western staff notation. It is more likely to fail on handwritten manuscripts, low-contrast scans, skewed or cropped pages, complex layouts, heavy annotations, tablature, and unusual contemporary notation.
The current project does not publish measured accuracy numbers yet. Until evaluation reports exist, treat every conversion as a draft that needs human review.
Install with the Web UI dependencies:
pip install -U "pdf2muse[ui]"Launch the local Web UI:
pdf2muse uiOr run a small CLI smoke test on the first page of a score:
pdf2muse convert path/to/sheet_music.pdf --first-page 1 --last-page 1 -o outputPDF2Muse supports Windows, macOS, and Linux with Python 3.9 or newer.
pip install pdf2musepip install "pdf2muse[ui]"git clone https://github.com/thedivergentai/PDF2Muse.git
cd PDF2Muse
python -m venv venv
venv\Scripts\pip.exe install -e ".[dev,ui]"On macOS or Linux:
python3 -m venv venv
venv/bin/pip install -e ".[dev,ui]"The installer scripts are still available for local source installs:
install.batchmod +x install.sh
./install.shConvert a PDF and write outputs to output/:
pdf2muse convert path/to/sheet_music.pdfUseful options:
| Option | Description |
|---|---|
-o, --output DIR |
Directory for generated files. |
--first-page N |
First PDF page to convert, 1-indexed. Useful for quick checks. |
--last-page N |
Last PDF page to convert, 1-indexed. |
--render-dpi N |
PDF render DPI for OMR input images. Defaults to 300. |
--oemer-timeout N |
Seconds before one page-level oemer process is marked failed. |
--no-deskew |
Disable automatic deskewing. |
--use-tf |
Use oemer's TensorFlow path instead of the default CPU ONNX wrapper. |
--save-cache |
Ask oemer to save prediction cache data. |
--musescore-path PATH |
Path to a MuseScore executable for .mscx export. |
--model-backend NAME |
OMR backend slot for experiments: oemer-stock, reserved oemer-custom, or non-runnable legato-experimental. |
--checkpoint-dir DIR |
Reserved custom oemer-compatible checkpoint directory option; do not use for model claims until runtime override validation passes. |
--verbose |
Enable detailed logging. |
Each conversion writes conversion_report.json beside the outputs. The report
records page-level OMR status, MusicXML merge status, final MusicXML parse
status, and optional MuseScore export status. Treat generated notation as a
draft and review it in notation software before use.
pdf2muse uiRun on a custom port:
pdf2muse ui --port 8080Create a Gradio share link:
pdf2muse ui --shareThe evaluation command is intended for developers and maintainers. It compares generated MusicXML against local ground-truth samples described by a manifest.
pdf2muse evaluate evaluation/manifests/smoke.local.example.json --output evaluation/runs/smokeThis command is part of the quality roadmap. It reports parseability, optional
MusicXML library import status, optional MuseScore import status, structural
metrics, failure categories, and optional musicdiff/OMR-NED integration when
evaluation dependencies are installed.
For a generated local clean-typeset fixture set:
venv\Scripts\python.exe scripts\clean_typeset_benchmark.py --sample-count 20 --output-dir datasets\cache\clean-typeset-generated --manifest evaluation\manifests\clean-typeset.local.json
venv\Scripts\python.exe -m pdf2muse.cli evaluate evaluation\manifests\clean-typeset.local.json --output evaluation\runs\clean-typeset-stock-smoke --limit 1 --no-musicdiff --oemer-timeout 90The first smoke report is documented in
docs/evaluation/clean-typeset-baseline-report.md. It is a runtime baseline,
not an accuracy claim: the generated smoke fixture currently times out before
MusicXML is produced.
A real public-domain Mutopia PDF smoke is documented in
docs/evaluation/public-score-smoke-report.md. With a 300-second page timeout,
that run produced parseable MusicXML. MuseScore .mscx export still requires a
local MuseScore CLI.
The first OpenScore CC0 ground-truth benchmark attempt is documented in
docs/evaluation/openscore-benchmark-report.md. OpenScore provides suitable
symbolic ground truth, but this environment still needs MuseScore CLI or another
trusted renderer to create benchmark-quality PDF inputs.
The degradation command creates deterministic damaged image variants for OMR experiments. It does not change ground-truth notation; use manifests to keep degraded images linked to their source MusicXML.
pdf2muse degrade datasets/raw/example/images datasets/cache/example-scan-noise --profile scan-noise --severity medium --seed 123Available profiles are scan-noise, blur, low-contrast, shadow,
jpeg-artifacts, skew, and uneven-lighting. Severity can be light,
medium, or heavy. These degraded variants are robustness stress tests, not
accuracy claims.
from pathlib import Path
from pdf2muse.core import PDF2MusePipeline
pipeline = PDF2MusePipeline(
pdf_path="piano_sonata.pdf",
output_dir="my_transcriptions",
deskew=True,
use_tf=False,
save_cache=False,
first_page=1,
last_page=1,
)
result_path: Path = pipeline.run()
print(result_path)Lower-level helpers are available for checkpoint management and MusicXML conversion:
from pathlib import Path
from pdf2muse.musicxml import join_musicxml_files, convert_to_musescore_format
from pdf2muse.oemer_utils import download_checkpoints, ensure_checkpoints
download_checkpoints(force=False)
ensure_checkpoints()
join_musicxml_files(
input_dir=Path("./temp_pages"),
output_file=Path("./output/combined.musicxml"),
)
convert_to_musescore_format(
input_file=Path("./output/combined.musicxml"),
output_file=Path("./output/combined.mscx"),
)The project needs repeatable evidence before it can claim usefulness. The current roadmap is:
- Identify public OMR datasets with score images or PDFs plus MusicXML, MEI, MIDI, Humdrum, or comparable ground truth.
- Build a manifest-driven evaluation harness that runs PDF2Muse on curated local samples.
- Measure parseability, structural differences, and notation-level differences where tooling supports it.
- Run small baseline evaluations across clean printed, scanned, degraded, and handwritten examples.
- Use observed failures to design synthetic degradation workflows.
- Consider fine-tuning only after licensing, output representation, data quality, and compute requirements are clear.
Candidate datasets under review include DoReMi, OpenScore Lieder/String Quartets, Debussy handwritten OMR datasets, MusiCorpus, CollabScore, zzsi/openscore, GrandStaff-LMX, PrIMuS/Camera-PrIMuS, DeepScoresV2, and MUSCIMA++.
The preferred metric direction is parseability first, then musicdiff/OMR-NED where possible, with structural MusicXML fallbacks for malformed or unsupported outputs.
flowchart TD
inputPdf[Input PDF] --> renderPdf[pypdfium2 PDF Renderer]
renderPdf --> pageImages[Page PNG Images]
pageImages --> oemerEngine[oemer OMR Engine]
oemerEngine --> pageXml[Page MusicXML Files]
pageXml --> joinXml[join_musicxml_files]
joinXml --> combinedXml[combined.musicxml]
combinedXml --> museScore[MuseScore CLI Optional]
museScore --> mscx[combined.mscx]
combinedXml --> primaryXml[Primary MusicXML Output]
Package layout:
PDF2Muse/
βββ src/pdf2muse/
β βββ __init__.py
β βββ cli.py
β βββ core.py
β βββ degrade.py
β βββ evaluation.py
β βββ musicxml.py
β βββ oemer_utils.py
β βββ ui.py
βββ tests/
βββ docs/
βββ evaluation/
βββ datasets/
βββ pyproject.toml
βββ README.md
Use the project virtual environment for tests and local commands:
venv\Scripts\python.exe -m pytest tests/ -vOn macOS or Linux:
venv/bin/python -m pytest tests/ -vFor quick conversion checks, limit the page range:
venv\Scripts\python.exe -m pdf2muse.cli convert path\to\score.pdf --first-page 1 --last-page 1Real OMR runs can be slow on CPU. Unit tests should mock OMR, model downloads, and MuseScore export unless a manual slow test is explicitly intended.
The project does not publish measured accuracy yet. Some outputs may be useful drafts; others may be poor or malformed. Always inspect the generated MusicXML or MuseScore file manually.
MuseScore .mscx export requires the MuseScore CLI. If MuseScore is missing or conversion fails, PDF2Muse falls back to the combined MusicXML file.
PDF rendering and OMR inference can be CPU-heavy. Use --first-page and --last-page for quick checks.
Installation success and notation quality are separate concerns. The current oemer-backed pipeline still needs systematic evaluation and likely targeted improvements.
PDF2Muse builds on the open-source oemer project and the broader Optical Music Recognition research community.
PDF2Muse is open-source software licensed under the MIT License.
Authored and maintained by Divergent AI