Metadata-Version: 2.4
Name: ly-to-musicxml
Version: 0.1.1
Summary: Compiler-assisted LilyPond to MusicXML conversion
Project-URL: Homepage, https://github.com/xvb8/ly-to-musicxml
Project-URL: Repository, https://github.com/xvb8/ly-to-musicxml
Project-URL: Issues, https://github.com/xvb8/ly-to-musicxml/issues
Project-URL: Documentation, https://github.com/xvb8/ly-to-musicxml/tree/main/docs
Author-email: xvb8 <v3qu7ruif@mozmail.com>
Maintainer-email: xvb8 <v3qu7ruif@mozmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: lilypond,music-notation,musicxml,score-conversion
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Artistic Software
Classifier: Topic :: Multimedia :: Sound/Audio :: Conversion
Classifier: Topic :: Text Processing :: Markup :: XML
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# 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:

```powershell
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:

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

Install from PyPI once published:

```powershell
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

```powershell
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:

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

Or via environment variable:

```powershell
$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:

```text
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:

```powershell
$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:

```powershell
python -m unittest tests.test_converter
```

Manual smoke tests used during validation:

```powershell
$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:

```powershell
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"
```