LuaLaTeXでLilyPondを使って楽譜の入った文書を作る

>   これは「[TeX ＆ LaTeX Advent Calendar 2018](https://adventar.org/calendars/3382)」の17日目の記事です。
>   16日目の記事はbd_gfngfnさん、18日目の記事はkeisuke495500さんです。

（[昨年の記事](https://qiita.com/trueroad/items/d548087d5d7e716f1730)はTexinfoを使っていましたが、今回はLuaLaTeXです。）

[LilyPond](http://lilypond.org)は高品位の楽譜を作成することができ、楽器屋さんで「楽譜」として売られているような本の中の楽譜だけのページが続いているような部分を単独で作ることができます。一方、楽譜と文章を組み合わせたようなページが必要になることもありますが、LilyPondは文章の組版が得意ではありません。そういうときは文章の組版が得意なTeXと組み合わせて使おう、ということになります。本稿ではそういった方法をご紹介します。

## はじめに

[昨年の記事](https://qiita.com/trueroad/items/d548087d5d7e716f1730)では[Texinfo](https://www.gnu.org/software/texinfo/)を使って、楽譜と文章を組み合わせたものを作るご紹介をしました[^texinfo]。今年はLaTeXで同じようなことをしてみようと思います。あわせてLilyPondもGhostscriptも昨年とはバージョンが変わって、微妙に変わっている部分もあるのでご紹介しようと思います。昨年の記事も合わせてご覧いただけると幸いです。

[^texinfo]: 昨年の記事はなぜTexinfoにしたのかかというと、LilyPondのドキュメントがTexinfoで書かれているからというのもありますが、筆者がTexinfoのコミッタだからです。。。

## やってみよう

それでは、LaTeX文書に楽譜を埋め込んだものを作ってみましょう。

### ソースファイル

まずはLuaLaTeXのソースファイル[^lualatex]です。

[^lualatex]: 実はLuaLaTeXである必要性はあまりありません。LilyPondは文字コードUTF-8でなければならないのでUTF-8のLaTeX文書であればよく、それさえ満たせばXeLaTeXでもpLaTeXでもupLaTeXでも大丈夫なハズです。英語だけでよいならpdfLaTeXでもOKです、というか `lilypond-book` のデフォルトはpdfLaTeXなので日本語が使えません。ただ、筆者は普段pLaTeXもupLaTeXも全然使っておらず、LuaLaTeXしか使っておりません。

```tex:sample.lytex
%  -*- mode: latex; coding: utf-8 -*-
\documentclass{ltjsarticle}

\usepackage[unicode=true]{hyperref}

\usepackage[sourcehan]{luatexja-preset}

\setmainfont[Ligatures=TeX]{TeXGyreTermes}
\setsansfont[Ligatures=TeX]{TeXGyreHeros}
\setmonofont[Ligatures=TeX]{TeXGyreCursor}

\begin{document}

\title{雪に関する音楽}
\author{細田真道}
\date{2018年12月17日}
\maketitle

\tableofcontents
\clearpage

\section{童謡}

雪や☃に関する童謡を探してみました。

\subsection{雪}

雪に関する童謡としては非常に有名ですね。
おそらくほとんどの方がご存じなのではないでしょうか。
題名はそのままストレートに「雪」、
「尋常小学校唱歌」第二学年用（明治44年/ 1911年）が初出だそうです。
冒頭部分を以下に示します。

\begin{lilypond}
<<
  \relative
  {
    \clef treble
    \key f \major
    \time 2/4

    c''8. d16 c8. d16 | c4 a8 r |
    a8. bes16 a8. bes16 | a4 f8 r |
  }
  \addlyrics
  {
    ゆ "" き や こん こ
    あ ら れ や こん こ
  }
>>
\end{lilypond}

\subsection{☃雪達磨}

☃に関する童謡を探してみたところ、こんなものを見つけました。
題名は「雪達磨」、
「新訂尋常小学唱歌」第一学年用（昭和7年/ 1932年）に掲載されているそうです。
冒頭部分を以下に示します。

\begin{lilypond}
<<
  \relative
  {
    \clef treble
    \key f \major
    \time 2/4

    a'8. bes16 c8 r | a8. bes16 c8 r |
    a8. bes16 d8 c | c4 r |
  }
  \addlyrics
  {
    だ る ま だ る ま
    ☃ゆ き だ る ま
  }
>>
\end{lilypond}

\end{document}
```

通常、LaTeXのソースファイルは拡張子 `.tex` ですが、これから使う `lilypond-book` で処理するものについては `.lytex` にします。ソースファイル中の `\begin{lilypond}` と `\end\{lilypond}` で挟まれた `lilypond` 環境の中身がLilyPondによる楽譜の記述です。また、LaTeXとLilyPondでフォントがなるべく一致するように設定しています。和文フォントについて、LilyPond側は環境によって変わりますが、筆者の環境では源ノ明朝・源ノ角ゴシックになるので、LaTeX側にも源ノ明朝・源ノ角ゴシックを設定してみました。欧文フォントはLilyPondのデフォルトフォントがTeX Gyreなので、LaTeX側にもTeX Gyreを設定してみました。

### 楽譜の処理（中間ファイルの生成）

LilyPond がインストールされていれば以下のコマンド[^latex-program]を実行します。

[^latex-program]: 昨年の記事ではオプション `--latex-program` を付けていませんでした。これを付けないと、 `lilypond-book` は `pdflatex` を使ってデフォルトの横幅を取得しようとしますが、ここで使っているソースはLuaLaTeX用なので失敗してしまいます。

```
$ lilypond-book --pdf --latex-program=lualatex sample.lytex
```

これでいくつかの中間ファイルが生成されます。2桁16進数のディレクトリが2つ掘られて、その中にそれぞれ楽譜断片のPDFなどが生成されます。また、 `sample.lytex` から作られた `sample.tex` も生成されます。これは `.lytex` にあった `lilypond` 環境が楽譜断片のPDFを張り付けるコマンドに置き換わったものです。

### PDF生成

中間ファイルが生成できたら、いよいよPDFの生成です。LuaLaTeXを使います。目次を含んでいるので2回実行する必要があります。

```
$ lualatex sample.tex
$ lualatex sample.tex
```

**出力**

`sample.pdf` ができました。

|![sample_1.png](https://qiita-image-store.s3.amazonaws.com/0/212298/7ade7ae4-2777-0b40-ac73-80dba8ee9306.png)|
|:-:|

|![sample_2.png](https://qiita-image-store.s3.amazonaws.com/0/212298/d231d4bc-3597-b2e1-7908-eb7e0a9e2bae.png)|
|:-:|

## ファイルサイズ削減

筆者の環境で生成したPDFは2 MBを超えるファイルサイズになりました。これを昨年の記事でもご紹介したGhostscriptと[Extract PDFmark](https://github.com/trueroad/extractpdfmark)を使った方法で小さくしてみましょう。中間ファイルも更新する必要がありますので、以下のようにして一旦削除してください。

```
$ rm -r ??/
```

### 楽譜の処理（中間ファイルの生成）

ファイルサイズ削減用の新しい中間ファイルを作ります[^lilypond-version]。

```
$ lilypond-book --pdf --latex-program=lualatex --process='lilypond -dbackend=eps --pdf -dfont-export-dir=fonts --pspdfopt=TeX-GS' sample.lytex
```

[^lilypond-version]: コマンドラインオプションは本稿執筆時点での最新 LilyPond 2.19.82 の場合です。昨年度の記事（LilyPond 2.19.80を使用）では今後オプションが変更される予定である旨を書きましたが、予定通り変更されたものになっています。次期安定板となる LilyPond 2.20 系列も同じオプションで使えるようになると思います。

楽譜断片のPDFにはフォントが埋め込まれなくなりました[^truetype]。そして新しく `fonts` ディレクトリ以下に楽譜断片で使っていたフォントがPostScript形式で置かれます。

[^truetype]: TrueTypeフォントは埋め込まれます。これは埋め込まないと文字化けを起こすからです。

### PDF生成

最初のPDF生成は今までと同じで以下のようにします。

```
$ lualatex sample.tex
$ lualatex sample.tex
```

です。これで生成された `sample.pdf` には楽譜断片のフォントが埋め込まれていませんのでファイルサイズは小さいですが正常に表示できません。筆者の環境では38 KBでした。

次にExtract PDFmarkで宛先名などを抽出します。

```
$ extractpdfmark sample.pdf > sample.pdfmark.ps
```

そして最後にGhostscriptでPDFを処理し、最終PDFを生成します[^gs926option]。ただしこの処理、Ghostscript 9.25なら問題なくできるのですが、Ghostscript 9.26だとうまくいきません[^gs926embed] 。。。

```
$ gs -dBATCH -dNOPAUSE -dPrinted=false -sDEVICE=pdfwrite -sOutputFile=sample-embeded.pdf fonts/*.font.ps sample.pdf sample.pdfmark.ps
```

[^gs926option]: Ghostscript 9.26以降では `-dPrinted=false` コマンドラインオプションを付けないと、目次ページからのリンクが消えてしまいます。Ghostscript 9.25であれば、このオプションは不要です。

[^gs926embed]: Ghostscript 9.26はこの方法で楽譜断片で使われているCIDフォントを埋め込むことができず、変なフォントにフォールバックして文字化けしてしまいます([bug700367](https://bugs.ghostscript.com/show_bug.cgi?id=700367))。Ghostscript 9.25であれば問題ありません。Ghostscript 9.26でも、[9.25相当に戻すパッチ](https://bugs.ghostscript.com/show_bug.cgi?id=700367#c2)を当てると一応問題なくなります。どうも、[今後はPostscriptでフォント定義してもPDFから使えなくなる](https://bugs.ghostscript.com/show_bug.cgi?id=700367#c4)ようです。正攻法でいくなら一時的に使うだけのフォントであってもGhostscriptへフォントを登録しなければならなりません。[フォントの登録にはほとんどのシステムでrootやAdministrators権限を要するため、必要になった時にツールが自動的に登録して使い終わったら削除するような処理の実現も困難？](https://bugs.ghostscript.com/show_bug.cgi?id=700367#c6)と思っていたのですが、[ローカルのディレクトリでも登録はできそう](https://bugs.ghostscript.com/show_bug.cgi?id=700367#c7)なのでとりあえず何とかする方法はありそうです。が、LilyPond側の改修が必要ですね。。。

これで正常に表示できて、ファイルサイズが小さいPDFが得られました。筆者の環境では1,118 KBとなりました。サイズが半分ぐらいになりましたので、かなり小さくなりましたね。

## おわりに

LuaLaTeXとLilyPondを使って、楽譜と文章を組み合わせたドキュメントを作る方法をご紹介しました。[昨年の記事](https://qiita.com/trueroad/items/d548087d5d7e716f1730)では[Texinfo](https://www.gnu.org/software/texinfo/)を使って同じことをしていましたので、今年は単なる焼き直しで簡単に済ますつもりだったのですが、またまた新しいGhostscriptの変更による影響[^gs926embed]を受けてしまいました。ちょっとイレギュラー？な使い方をしていると、バージョンアップでいきなり使えなくなることがあって困ります。。。