Source code for partitura.display

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
This module defines a function "show" that creates a rendering of one
or more parts or partgroups and opens it using the desktop default
application.
"""

import platform
import warnings
import os
import subprocess
import shutil
from tempfile import NamedTemporaryFile, TemporaryFile
from typing import Optional

from partitura import save_musicxml
from partitura.io.musescore import render_musescore
from partitura.score import ScoreLike

from partitura.utils.misc import PathLike, deprecated_alias


__all__ = ["render"]

# def ly_install_msg():
#     """Issue a platform specific installation suggestion for lilypond

#     """
#     if platform.system() == 'Linux':
#         s = ('Is lilypond installed? On debian based '
#              'installations you can install it using the '
#              'command "sudo apt install lilypond"')
#     elif platform.system() == 'Darwin':
#         s = ('Is lilypond installed? Lilypond can be '
#              'installed using brew ( https://brew.sh/ ) '
#              'using the command "brew cask install lilypond"')
#     elif platform.system() == 'Windows':
#         s = ('Is lilypond installed? It can be downloaded from '
#              'http://lilypond.org/')
#     return s


[docs]@deprecated_alias(out_fn="out", part="score_data") def render( score_data: ScoreLike, fmt: str = "png", dpi: int = 90, out: Optional[PathLike] = None, ) -> None: """Create a rendering of one or more parts or partgroups. The function can save the rendered image to a file (when `out_fn` is specified), or shown in the default image viewer application. Rendering is first attempted through musecore, and if that fails through lilypond. If that also fails the function returns without raising an exception. Parameters ---------- score_data : ScoreLike The score content to be displayed fmt : {'png', 'pdf'}, optional The image format of the rendered material out_fn : str or None, optional The path of the image output file. If None, the rendering will be displayed in a viewer. """ img_fn = render_musescore(score_data, fmt, out, dpi) if img_fn is None or not os.path.exists(img_fn): img_fn = render_lilypond(score_data, fmt) if img_fn is None or not os.path.exists(img_fn): return if not out: # NOTE: the temporary image file will not be deleted. if platform.system() == "Linux": subprocess.call(["xdg-open", img_fn]) elif platform.system() == "Darwin": subprocess.call(["open", img_fn]) elif platform.system() == "Windows": os.startfile(img_fn)
@deprecated_alias(part="score_data") def render_lilypond( score_data, fmt="png", out=None, ) -> Optional[PathLike]: """ Render a score-like object using Lilypond Parameters ---------- score_data : ScoreLike Score-like object to be rendered fmt : {'png', 'pdf'} Output image format out : str or None, optional The path of the image output file, if not specified, the rendering will be saved to a temporary filename. Defaults to None. Returns ------- out : PathLike Path of the generated output image (or None if no image was generated). """ if fmt not in ("png", "pdf"): warnings.warn("warning: unsupported output format") return None prvw_sfx = ".preview.{}".format(fmt) with TemporaryFile() as xml_fh, NamedTemporaryFile( suffix=prvw_sfx, delete=False ) as img_fh: # save part to musicxml in file handle xml_fh save_musicxml(score_data, xml_fh) # rewind read pointer of file handle before we pass it to musicxml2ly xml_fh.seek(0) img_stem = img_fh.name[: -len(prvw_sfx)] # convert musicxml to lilypond format (use stdout pipe) cmd1 = ["musicxml2ly", "-o-", "-"] try: ps1 = subprocess.run( cmd1, stdin=xml_fh, stdout=subprocess.PIPE, check=False ) if ps1.returncode != 0: warnings.warn( "Command {} failed with code {}".format(cmd1, ps1.returncode), stacklevel=2, ) return None except FileNotFoundError as f: warnings.warn( 'Executing "{}" returned {}.'.format(" ".join(cmd1), f), ImportWarning, stacklevel=2, ) return None # convert lilypond format (read from pipe of ps1) to image, and save to # temporary filename cmd2 = [ "lilypond", "--{}".format(fmt), "-dno-print-pages", "-dpreview", "-o{}".format(img_stem), "-", ] try: ps2 = subprocess.run(cmd2, input=ps1.stdout, check=False) if ps2.returncode != 0: warnings.warn( "Command {} failed with code {}".format(cmd2, ps2.returncode), stacklevel=2, ) return None except FileNotFoundError as f: warnings.warn( 'Executing "{}" returned {}.'.format(" ".join(cmd2), f), ImportWarning, stacklevel=2, ) return if out is not None: shutil.copy(img_fh.name, out) else: out = img_fh.name return out