mirror of
https://github.com/kennethreitz/interpretations.git
synced 2026-06-05 14:50:20 +00:00
Sheet music auto-detects LilyPond for PDF output
[s] and --sheet now compile LilyPond PDFs when lilypond is installed, falling back to abcjs HTML otherwise. No config needed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -770,7 +770,7 @@ examples:
|
||||
insp.add_argument("--parts", action="store_true",
|
||||
help="List all parts with details")
|
||||
insp.add_argument("--sheet", action="store_true",
|
||||
help="Open sheet music (ABC notation) in browser")
|
||||
help="Open sheet music (LilyPond PDF if available, otherwise abcjs HTML)")
|
||||
|
||||
play = p.add_argument_group("playback")
|
||||
play.add_argument("--from", dest="from_measure", type=int, metavar="N",
|
||||
@@ -863,27 +863,63 @@ def _render_and_cache(path, args):
|
||||
return buf, sr, offset_sec, score, mod
|
||||
|
||||
|
||||
def _has_lilypond():
|
||||
"""Check if LilyPond is installed."""
|
||||
import shutil
|
||||
return shutil.which("lilypond") is not None
|
||||
|
||||
|
||||
def _open_sheet(path):
|
||||
"""Render a track's score as ABC notation and open sheet music in the browser."""
|
||||
"""Render sheet music — LilyPond PDF if available, otherwise abcjs HTML."""
|
||||
import tempfile
|
||||
import webbrowser
|
||||
import subprocess
|
||||
|
||||
score, mod = load_score(path)
|
||||
title = get_title(mod, Path(path))
|
||||
stem = Path(path).stem
|
||||
|
||||
# Derive ABC key from the module's Key object (e.g. Key("Eb", "minor"))
|
||||
abc_key = "C"
|
||||
# Extract key info from module
|
||||
key_root = "C"
|
||||
mode = "major"
|
||||
if hasattr(mod, "key"):
|
||||
k = mod.key
|
||||
root = getattr(k, "tonic_name", "C")
|
||||
mode = getattr(k, "mode", "major")
|
||||
abc_key = str(root)
|
||||
if "minor" in mode.lower():
|
||||
abc_key += "m"
|
||||
key_root = getattr(mod.key, "tonic_name", "C")
|
||||
mode = getattr(mod.key, "mode", "major")
|
||||
|
||||
if _has_lilypond():
|
||||
# LilyPond path — publication-quality PDF
|
||||
ly = score.to_lilypond(title=title, key=key_root, mode=mode)
|
||||
ly_path = Path(tempfile.gettempdir()) / f"{stem}.ly"
|
||||
pdf_path = Path(tempfile.gettempdir()) / f"{stem}.pdf"
|
||||
ly_path.write_text(ly)
|
||||
|
||||
print(f" Compiling LilyPond...")
|
||||
result = subprocess.run(
|
||||
["lilypond", "-o", str(pdf_path.with_suffix("")), str(ly_path)],
|
||||
capture_output=True, text=True
|
||||
)
|
||||
if pdf_path.exists():
|
||||
subprocess.run(["open", str(pdf_path)])
|
||||
print(f" Sheet music -> {pdf_path}")
|
||||
else:
|
||||
# LilyPond failed — fall back to abcjs
|
||||
print(f" LilyPond failed, falling back to abcjs...")
|
||||
_open_sheet_abc(score, title, key_root, mode, stem)
|
||||
else:
|
||||
_open_sheet_abc(score, title, key_root, mode, stem)
|
||||
|
||||
|
||||
def _open_sheet_abc(score, title, key_root, mode, stem):
|
||||
"""Fallback: render sheet music as abcjs HTML in the browser."""
|
||||
import tempfile
|
||||
import webbrowser
|
||||
|
||||
abc_key = key_root
|
||||
if "minor" in mode.lower():
|
||||
abc_key += "m"
|
||||
|
||||
html = score.to_abc(title=title, key=abc_key, html=True)
|
||||
|
||||
out = Path(tempfile.gettempdir()) / f"{Path(path).stem}_sheet.html"
|
||||
out = Path(tempfile.gettempdir()) / f"{stem}_sheet.html"
|
||||
out.write_text(html)
|
||||
webbrowser.open(f"file://{out}")
|
||||
print(f" Sheet music -> {out}")
|
||||
|
||||
Reference in New Issue
Block a user