Skip to content

Commit

Permalink
NEW. Added abjad.show(..., flags="") keyword.
Browse files Browse the repository at this point in the history
``flags`` is passed to the LilyPond commandline.

Use ``flags`` for LilyPond --include statements:

    >>> flags = "--include=/Users/user/abjad/abjad/scm"
    >>> abjad.show(score, flags=flags)

Recall that LilyPond --include statements do not specify included files;
rather, LilyPond --include statements specify directories which LilyPond
should search for included files, somewhat like the behavior of Python's
PYTHONPATH environment variable. This means that this ...

    lilypond --include=/Users/user/abjad/abjad/scm/abjad.ily

... will not work, but that this ...

    lilypond --include=/Users/user/abjad/abjad/scm

... will work (and correctly point LilyPond to the scm/abjad.ily file).

NEW. Added the same functionality to the following:

    * abjad.persist.as_midi(..., flags="")
    * abjad.persist.as_pdf(..., flags="")
    * abjad.persist.as_png(..., flags="")

Tag #1575.

NEW. Added abjad.TextMark indicator.

Tag #1572.
  • Loading branch information
trevorbaca committed Dec 28, 2023
1 parent 7669df8 commit d537f51
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 12 deletions.
2 changes: 2 additions & 0 deletions abjad/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
StopSlur,
StopTextSpan,
StopTrillSpan,
TextMark,
Tie,
TimeSignature,
VoiceNumber,
Expand Down Expand Up @@ -466,6 +467,7 @@
"TenorSaxophone",
"TenorTrombone",
"TenorVoice",
"TextMark",
"Tie",
"TimeSignature",
"Timer",
Expand Down
1 change: 1 addition & 0 deletions abjad/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@ def list_all_classes(modules="abjad", ignored_classes=None):
<class 'abjad.indicators.StopSlur'>
<class 'abjad.indicators.StopTextSpan'>
<class 'abjad.indicators.StopTrillSpan'>
<class 'abjad.indicators.TextMark'>
<class 'abjad.indicators.Tie'>
<class 'abjad.indicators.TimeSignature'>
<class 'abjad.indicators.VoiceNumber'>
Expand Down
108 changes: 107 additions & 1 deletion abjad/indicators.py
Original file line number Diff line number Diff line change
Expand Up @@ -2987,7 +2987,7 @@ def _get_contributions(self, component=None):
@dataclasses.dataclass(frozen=True, order=True, slots=True, unsafe_hash=True)
class RehearsalMark:
r"""
Rehearsal mark.
LilyPond ``\mark`` command.
.. container:: example
Expand Down Expand Up @@ -5872,6 +5872,112 @@ def _get_contributions(self, component=None):
return contributions


@dataclasses.dataclass(frozen=True, order=True, slots=True, unsafe_hash=True)
class TextMark:
r"""
LilyPond ``\textMark``, ``\textEndMark`` commands.
Text mark:
.. container:: example
>>> staff = abjad.Staff("c'4 d' e' f'")
>>> score = abjad.Score([staff])
>>> mark = abjad.TextMark(r'\textMark \markup \italic "V.S."')
>>> abjad.attach(mark, staff[-1])
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(score)
>>> print(string)
\new Score
<<
\new Staff
{
c'4
d'4
e'4
\textMark \markup \italic "V.S."
f'4
}
>>
Tweaks:
>>> staff = abjad.Staff("c'4 d' e' f'")
>>> score = abjad.Score([staff])
>>> mark = abjad.TextMark(r'\textMark \markup \italic "V.S."')
>>> bundle = abjad.bundle(mark, r"\tweak color #blue")
>>> abjad.attach(bundle, staff[-1])
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(score)
>>> print(string)
\new Score
<<
\new Staff
{
c'4
d'4
e'4
\tweak color #blue
\textMark \markup \italic "V.S."
f'4
}
>>
.. container:: example
Text end mark:
>>> staff = abjad.Staff("c'4 d' e' f'")
>>> score = abjad.Score([staff])
>>> mark = abjad.TextMark(r'\textEndMark \markup \italic "V.S."', site="after")
>>> abjad.attach(mark, staff[-1])
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(score)
>>> print(string)
\new Score
<<
\new Staff
{
c'4
d'4
e'4
f'4
\textEndMark \markup \italic "V.S."
}
>>
"""

string: str
_: dataclasses.KW_ONLY
site: str = "before"

# find_context_on_attach: typing.ClassVar[bool] = True
context: typing.ClassVar[str] = "Score"

def __post_init__(self):
assert isinstance(self.string, str), repr(self.string)

def _get_lilypond_format(self):
return self.string

def _get_contributions(self, component=None):
contributions = _contributions.ContributionsBySite()
site = getattr(contributions, self.site)
string = self._get_lilypond_format()
site.commands.append(string)
return contributions


@dataclasses.dataclass(frozen=True, order=True, slots=True, unsafe_hash=True)
class Tie:
r"""
Expand Down
4 changes: 2 additions & 2 deletions abjad/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,7 @@ def graph(
return format_time, render_time


def show(illustrable, return_timing=False, **keywords):
def show(illustrable, *, flags: str = "", return_timing: bool = False, **keywords):
r"""
Shows ``argument``.
Expand Down Expand Up @@ -668,7 +668,7 @@ def show(illustrable, return_timing=False, **keywords):
Returns pair of ``abjad_formatting_time`` and ``lilypond_rendering_time``
when ``return_timing`` is true.
"""
illustrator = Illustrator(illustrable, **keywords)
illustrator = Illustrator(illustrable, flags=flags.split(), **keywords)
result = illustrator()
if not result:
return
Expand Down
29 changes: 20 additions & 9 deletions abjad/persist.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def as_ly(
return ly_file_path, abjad_formatting_time


def as_midi(argument, midi_file_path, **keywords):
def as_midi(argument, midi_file_path, *, flags: str = "", **keywords):
"""
Persists ``argument`` as MIDI file.
Expand All @@ -65,7 +65,7 @@ def as_midi(argument, midi_file_path, **keywords):
ly_file_path, abjad_formatting_time = as_ly(argument, ly_file_path, **keywords)
timer = _contextmanagers.Timer()
with timer:
success = _io.run_lilypond(ly_file_path)
success = _io.run_lilypond(ly_file_path, flags=flags)
lilypond_rendering_time = timer.elapsed_time
if os.name == "nt":
extension = "mid"
Expand All @@ -85,6 +85,7 @@ def as_pdf(
argument,
pdf_file_path,
*,
flags: str = "",
illustrate_function=None,
tags=False,
**keywords,
Expand All @@ -110,11 +111,12 @@ def as_pdf(
**keywords,
)
ly_file_path, abjad_formatting_time = result
assert isinstance(ly_file_path, str)
without_extension = os.path.splitext(ly_file_path)[0]
pdf_file_path = f"{without_extension}.pdf"
timer = _contextmanagers.Timer()
with timer:
success = _io.run_lilypond(ly_file_path)
success = _io.run_lilypond(ly_file_path, flags=flags)
lilypond_rendering_time = timer.elapsed_time
return (
pdf_file_path,
Expand All @@ -128,11 +130,11 @@ def as_png(
argument,
png_file_path,
*,
flags="--png",
flags: str = "--png",
illustrate_function=None,
preview=False,
preview: bool = False,
resolution=False,
tags=False,
tags: bool = False,
**keywords,
):
"""
Expand All @@ -142,6 +144,7 @@ def as_png(
Returns output path(s), elapsed formatting time and elapsed rendering time.
"""
assert isinstance(flags, str), repr(flags)
if png_file_path is not None:
png_file_path = os.path.expanduser(png_file_path)
without_extension = os.path.splitext(png_file_path)[0]
Expand All @@ -156,16 +159,17 @@ def as_png(
**keywords,
)
ly_file_path, abjad_formatting_time = result
assert isinstance(ly_file_path, str)
original_directory = os.path.split(ly_file_path)[0]
original_ly_file_path = ly_file_path
temporary_directory = tempfile.mkdtemp()
assert isinstance(temporary_directory, str)
temporary_ly_file_path = os.path.join(
temporary_directory, os.path.split(ly_file_path)[1]
)
shutil.copy(original_ly_file_path, temporary_ly_file_path)
# render lilypond flags
if preview:
flags = "-dpreview"
flags += " -dpreview"
if resolution and isinstance(resolution, int):
flags += f" -dresolution={resolution}"
timer = _contextmanagers.Timer()
Expand All @@ -183,7 +187,14 @@ def as_png(
shutil.rmtree(temporary_directory)
if 1 < len(png_file_paths):
_png_page_pattern = re.compile(r".+page(\d+)\.png")
png_file_paths.sort(key=lambda x: int(_png_page_pattern.match(x).groups()[0]))

def _key(path):
match = _png_page_pattern.match(path)
assert match is not None
group = match.groups()[0]
return group

png_file_paths.sort(key=_key)
return (
tuple(png_file_paths),
abjad_formatting_time,
Expand Down
1 change: 1 addition & 0 deletions tests/test_class_design.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
abjad.Markup: (r"\markup Allegro",),
abjad.MetricModulation: (abjad.Note("c'4"), abjad.Note("c'4.")),
abjad.MetronomeMark: (abjad.Duration(1, 4), 90),
abjad.TextMark: (r'\textMark \markup \italic "V.S."',),
abjad.ShortInstrumentName: (r"\markup Vc.",),
abjad.StaffChange: ("RH_Staff",),
abjad.TimeSignature: ((4, 4),),
Expand Down

0 comments on commit d537f51

Please sign in to comment.