mirror of
https://github.com/RichieCahill/dotfiles.git
synced 2026-04-21 06:39:09 -04:00
Adds a Typer CLI (sheet-music-ocr) that converts scanned sheet music (PDF, PNG, JPG, TIFF) to MusicXML via Audiveris, preserving lyrics and text annotations. Includes Audiveris in the nix dev shell. https://claude.ai/code/session_017GqUbuRDT58toRaxMtfRmf
63 lines
1.7 KiB
Python
63 lines
1.7 KiB
Python
"""Audiveris subprocess wrapper for optical music recognition."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import shutil
|
|
import subprocess
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
|
from pathlib import Path
|
|
|
|
|
|
class AudiverisError(Exception):
|
|
"""Raised when Audiveris processing fails."""
|
|
|
|
|
|
def find_audiveris() -> str:
|
|
"""Find the Audiveris executable on PATH.
|
|
|
|
Returns:
|
|
Path to the audiveris executable.
|
|
|
|
Raises:
|
|
AudiverisError: If Audiveris is not found.
|
|
"""
|
|
path = shutil.which("audiveris")
|
|
if not path:
|
|
msg = "Audiveris not found on PATH. Install it via 'nix develop' or add it to your environment."
|
|
raise AudiverisError(msg)
|
|
return path
|
|
|
|
|
|
def run_audiveris(input_path: Path, output_dir: Path) -> Path:
|
|
"""Run Audiveris on an input file and return the path to the generated .mxl.
|
|
|
|
Args:
|
|
input_path: Path to the input sheet music file (PDF, PNG, JPG, TIFF).
|
|
output_dir: Directory where Audiveris will write its output.
|
|
|
|
Returns:
|
|
Path to the generated .mxl file.
|
|
|
|
Raises:
|
|
AudiverisError: If Audiveris fails or produces no output.
|
|
"""
|
|
audiveris = find_audiveris()
|
|
result = subprocess.run(
|
|
[audiveris, "-batch", "-export", "-output", str(output_dir), str(input_path)],
|
|
capture_output=True,
|
|
text=True,
|
|
check=False,
|
|
)
|
|
if result.returncode != 0:
|
|
msg = f"Audiveris failed (exit {result.returncode}):\n{result.stderr}"
|
|
raise AudiverisError(msg)
|
|
|
|
mxl_files = list(output_dir.rglob("*.mxl"))
|
|
if not mxl_files:
|
|
msg = f"Audiveris produced no .mxl output in {output_dir}"
|
|
raise AudiverisError(msg)
|
|
|
|
return mxl_files[0]
|