Skip to main content

ly-to-musicxml

Compiler-assisted conversion from LilyPond .ly files to MusicXML 4.0.

This project has been manually validated both from the local source tree and from an installed TestPyPI package.

Approach

This converter does not statically parse LilyPond source and it does not use PDF or optical music recognition. It runs LilyPond itself in a no-print extraction mode, lets LilyPond resolve \include files and embedded Scheme, exports LilyPond's internal music tree to XML, then translates that compiler-resolved XML into MusicXML.

Normal conversion does not generate PDF output.

Installation

Install the project in editable mode:

pip install -e .

For packaging, testing, and documentation tasks, use a standard CPython install or a normal virtual environment. Avoid using LilyPond's bundled Python as your main project interpreter because it does not include normal packaging tooling such as pip, build, or twine.

You can also run it without installation:

$env:PYTHONPATH = (Resolve-Path .\src)
python -m ly_to_musicxml "input.ly" -o "output.musicxml"

Install from PyPI once published:

pip install ly-to-musicxml

This package depends on an external LilyPond installation at runtime. Installing with pip only installs the Python package and CLI; it does not install LilyPond itself.

Requirements

  • Python 3.10 or newer
  • A working LilyPond installation available either through --lilypond-bin, LY_TO_MUSICXML_LILYPOND_BIN, or the default configured path

The converter executes LilyPond during every run, so a missing or incompatible LilyPond install is the most common setup problem.

Usage

ly-to-musicxml "input.ly" -o "output.musicxml"

If -o is omitted, the converter writes the first output file next to the input using the same stem and a .musicxml extension.

LilyPond Binary Selection

The converter looks for LilyPond in this order:

  1. --lilypond-bin
  2. LY_TO_MUSICXML_LILYPOND_BIN
  3. The reference path from the project brief: C:\Users\kkris\Documents\lilypond-2.26.0-mingw-x86_64\lilypond-2.26.0\bin\lilypond.exe

Example:

ly-to-musicxml "input.ly" -o "output.musicxml" --lilypond-bin "C:\path\to\lilypond.exe"

Or via environment variable:

$env:LY_TO_MUSICXML_LILYPOND_BIN = "C:\path\to\lilypond.exe"
ly-to-musicxml "input.ly" -o "output.musicxml"

Multi-Score Inputs

If the input produces multiple non-empty scores or books, the converter preserves them by writing multiple MusicXML files.

  • The first non-empty score is written to the requested output path.
  • Additional non-empty scores are written into a sibling directory named stem.exports/ using the pattern book-NN-score-NN.musicxml.
  • Empty scores are skipped with warnings.

If you rerun the converter for the same output path, it clears the previous stem.exports/ directory and any legacy stem.bookNN.scoreNN.musicxml files before writing fresh outputs.

Example output layout for a multi-score input:

Shostakovich-String-Quartet-8.musicxml
Shostakovich-String-Quartet-8.exports/
	book-01-score-02.musicxml
	book-02-score-01.musicxml
	...

What Is Currently Mapped

The current translator maps these runtime LilyPond constructs to MusicXML:

  • Parts and staves
  • Notes, rests, chords, tuplets, and unfolded repeats
  • Key signatures, time signatures, pickups, and barlines
  • Ties, slurs, dynamics, text directions, tempo marks, and wedges
  • Breath marks, ottava shifts, fermatas, and common articulation/bowing marks

Scheme Handling

If the source file contains embedded Scheme syntax, the converter emits a warning that the output reflects one compiler evaluation. This is intentional: the converter uses the actual LilyPond runtime result instead of guessing what the Scheme might do.

Troubleshooting

If the CLI reports that it cannot find LilyPond:

$env:LY_TO_MUSICXML_LILYPOND_BIN = "C:\path\to\lilypond.exe"
ly-to-musicxml "input.ly" -o "output.musicxml"

If a conversion writes multiple files unexpectedly, check for a sibling stem.exports/ directory next to the main output file. That directory contains additional non-empty scores extracted from the same LilyPond input.

If the output looks wrong in another notation program, first confirm you are opening the newly generated .musicxml file rather than an older export from a previous run.

If VS Code auto-selects LilyPond's bundled Python for this workspace, switch to a standard CPython interpreter or a normal venv before doing package builds, pip install, or twine upload. The bundled interpreter can run LilyPond internals but is not a good development environment for this project.

Test

Run the focused regression test with:

python -m unittest tests.test_converter

Manual smoke tests used during validation:

$env:PYTHONPATH = (Resolve-Path .\src)
python -m ly_to_musicxml --help
python -m ly_to_musicxml "Shostakovich-String-Quartet-8.ly" -o "local-manual-smoke.musicxml" --lilypond-bin "C:\Users\kkris\Documents\lilypond-2.26.0-mingw-x86_64\lilypond-2.26.0\bin\lilypond.exe"

TestPyPI smoke test after publishing:

py -3.13 -m venv .testpypi-venv
.\.testpypi-venv\Scripts\python.exe -m pip install --upgrade pip
.\.testpypi-venv\Scripts\python.exe -m pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple ly-to-musicxml
.\.testpypi-venv\Scripts\ly-to-musicxml.exe "Shostakovich-String-Quartet-8.ly" -o "testpypi-smoke.musicxml" --lilypond-bin "C:\Users\kkris\Documents\lilypond-2.26.0-mingw-x86_64\lilypond-2.26.0\bin\lilypond.exe"

Metadata

Release files for ly-to-musicxml 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ly-to-musicxml 0.1.1
File Size Uploaded
ly_to_musicxml-0.1.1.tar.gz 18.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ly-to-musicxml 0.1.1
File Interpreter ABI Platform
ly_to_musicxml-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 39.5 kB

Release files / ly_to_musicxml-0.1.1.tar.gz

Download URL ly_to_musicxml-0.1.1.tar.gz
Size 18.1 kB
Tags Source
SHA-256 checksum
How to use checksums
8ca3bc5286ad8e8cf130ccb9c7bb09d3147273aa9cf8da1f5bdf6a9f63311e4c
BLAKE2b-256 checksum
How to use checksums
a4da05255e67cbc3db5fffc4a8f2d9f8a934296c1b7ae4191adee0cd4d5d5a4f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 2, 2026.

Transparency log

Release files / ly_to_musicxml-0.1.1-py3-none-any.whl

Download URL ly_to_musicxml-0.1.1-py3-none-any.whl
Size 21.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
be14f4194e38f48d7f540615ee85a5a69ded84cb9df72713e7b74c67ab593417
BLAKE2b-256 checksum
How to use checksums
4f91bb9d8f2e75dbbe15e031ba82700563453d124a983ef0a202d8b947106a4b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 2, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page