MediaWikiのページに楽譜を埋め込む

MediaWikiでのLilyPondの使い方・使われ方について簡単なメモ。

MediaWikiのScoreエクステンションを使うと、LilyPondのコードで記述した楽譜をレンダリングして画像としてページに埋め込むことができるようになる。
執筆時点の最新バージョンは0.3.0で、MediaWikiのバージョン1.25以降で対応している。
本稿のスクリーンショットはWikipedia日本語版のプレビュー画面を使って取得した。
[WikiApiary](https://wikiapiary.com/wiki/Extension:Score)によるとWikipedia日本語版で使われているScoreのバージョンは0.3.0とのこと。
# 使い方
[Extension:Scoreのページ](https://www.mediawiki.org/wiki/Extension:Score)に使い方も導入方法も簡潔にまとまっていて、それ以上に書くことがほとんどないのだが、紹介記事ということで。

`<score>`タグの中にLilyPondのコードを書く。

```
<score vorbis="1">
\relative { c' d e f g a b c }
\addlyrics { ど れ み ふぁ そ ら し \markup { \with-color #red ど }}
</score>
```

すると以下のスクリーンショットのように楽譜の画像と（TimedMediaHandlerエクステンションを導入していたら）楽譜に対する音声ファイルのプレイヤーがページに埋め込まれる。
もし音声ファイルが必要なければ、`vorbis`属性を省略するとよい。

![シンプルな利用例](http://cdn-ak.f.st-hatena.com/images/fotolife/n/naraba/20171209/20171209141151.png?1512796548) 


比較的"シンプルな"LilyPondのコードの場合はこれで充分だが、"完全な"コードを書きたい場合には`raw`属性に1を指定する。
こうすることで、たとえばScheme関数も定義できたりする。
以下のコードはLilyPondの[公式マニュアル](http://lilypond.org/doc/v2.18/Documentation/notation/controlling-midi-dynamics.ja.html)で示されているものに`\header`ブロックを追加した。追加の理由は後述する。

```
<score raw="1" vorbis="1">
\header {
  tagline = ##f
}

#(define (myDynamics dynamic)
    (if (equal? dynamic "rfz")
      0.9
      (default-dynamic-absolute-volume dynamic)))

\score {
  \new Staff {
    \set Staff.midiInstrument = #"cello"
    \set Score.dynamicAbsoluteVolumeFunction = #myDynamics
    \new Voice {
      \relative c'' {
        a4\pp b c-\rfz
      }
    }
  }
  \layout {}
  \midi {}
}
</score>
```

次の結果となる。

![完全モードの利用例](http://cdn-ak.f.st-hatena.com/images/fotolife/n/naraba/20171209/20171209141152.png?1512796592) 

`raw="1"`場合はコードに`\midi`ブロックを書かないと`vorbis="1"`としていても次のエラーメッセージが出てプレイヤーが埋め込まれない。
>No MIDI file generated despite being requested. If you are working in raw LilyPond mode, make sure to provide a proper \midi block.

これはScoreが、LilyPondのMIDI出力結果を変換することでVorbis形式の音声ファイルを生成しているためである。

<br/>
ちなみにVisualEditorエクステンションはScoreに対応している。しているが楽譜に関してはコード編集が逐次レンダリングされること以外には恩恵がない。
WYSIWYGぽいものを求める場合はLilyPondコードはFrescobaldiなどで書きませう。

![VisualEditorの編集画面](http://cdn-ak.f.st-hatena.com/images/fotolife/n/naraba/20171209/20171209141154.png?1512796609) 

<br/><br/>
Scoreによって生成した楽譜が埋め込まれたページは `score` プロパティを持つ。
Wikipedia日本語版で `score` を持つページの一覧は[こちら](https://ja.wikipedia.org/w/index.php?title=%E7%89%B9%E5%88%A5:%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%81%8C%E3%81%82%E3%82%8B%E3%83%9A%E3%83%BC%E3%82%B8/score)。
利用例：[日本行進曲](https://ja.wikipedia.org/wiki/%E6%97%A5%E6%9C%AC%E8%A1%8C%E9%80%B2%E6%9B%B2_(%E3%83%A8%E3%83%BC%E3%82%BC%E3%83%95%E3%83%BB%E3%82%B7%E3%83%A5%E3%83%88%E3%83%A9%E3%82%A6%E3%82%B9))


# 使われ方
ScoreではLilyPondがどう使われているか触れる。主に[ここ](https://phabricator.wikimedia.org/diffusion/ESCR/browse/master/includes/Score.php)を眺めた。

## "シンプルな"コード
`raw="1"`を指定しない場合は、ユーザの記述するコードは次のPHPヒアドキュメントの`$lilypondCode`に入れられてLilyPond全体のコードが作られ、`lilypond`コマンドに渡される。
つまりこの形式で対応可能な範囲であれば`raw="1"`を指定する必要はない。

```php
    $raw = <<<LILYPOND
      \\header {
        tagline = ##f
      }
      \\paper {
        raggedright = ##t
        raggedbottom = ##t
        indent = 0\mm
      }
      \\version "$version"
      \\score {
        $lilypondCode
        $options
      }
LILYPOND;
```

一方で、"完全な"コードの場合はユーザの記述したLilyPondコードがそのまま渡される。

## セキュリティ対策
"完全な"コードには任意のSchemeコードが書けてコンパイルできるので対策なしだとやりたい放題である。
LilyPondの[公式マニュアル](http://lilypond.org/doc/v2.18/Documentation/usage/command_002dline-usage#advanced-command-line-options-for-lilypond)には次の記載がある。
>Web サーバ経由で LilyPond 譜刻が利用可能な場合、‘--safe’ オプションか ‘--jail’ オプションのどちらかを **指定する必要があります**。‘--safe’ オプションはインライン Scheme コードが無茶をする – 例えば、以下のような – ことを防ぎます。
>
>```scheme
>    #(system "rm -rf /")
>    {
>      c4^$(ly:gulp-file "/etc/passwd")
>    }
>```
>
>‘-dsafe’ オプションはインライン Scheme 表記を特別なセーフ モジュールの中で評価します。

というわけで、Scoreの[README](https://phabricator.wikimedia.org/diffusion/ESCR/browse/master/README)にはこのオプションを指定するための指示が書いてある。
>   $wgScoreSafeMode = false; /* Set to true if the Lilypond executable is running in a Firejail or equivalent */
>
> to your LocalSettings.php file. 

余談だが、[LilyBin](http://lilybin.com/)の方は、LilyPondのコンパイルのたびにDockerでサンドボックス環境を作って実行しているそうだ。

## 出力画像のトリミング
LilyPondの外側の話だが、ごく短いフレーズの楽譜であっても出力結果の画像をそのまま埋め込むと（デフォルトの紙面サイズはA4なので）無駄に余白があるページになってしまう。これを防ぐために、Scoreは余白をカットする処理が組まれている。処理といっても出力された画像をImageMagickの`convert`コマンドに`-trim`オプションを付けて食わせているだけ。
このオプションは画像の四隅と同じ色の上下左右部分をトリミングするためのもので、楽譜の領域があらかじめわかっていなくても良い感じに切り詰めてくれる。
ただし、LilyPondでは特に指定しない限り譜面の最後のページの最下段にタグラインが配置されるため、この部分が余白ではないとみなされてトリミングが期待通りに行われない。

![タグラインのある楽譜](http://cdn-ak.f.st-hatena.com/images/fotolife/n/naraba/20171209/20171209141153.png?1512796620) 

前半に書いた"完全な"コードの例で`\header`ブロックを追加してタグラインを消す指定をした理由はここにある。

## ABC記法への対応
ここまで全く触れなかったが、`<score>`タグで属性に`lang="ABC"`を指定すると、[ABC記法](https://ja.wikipedia.org/wiki/ABC%E8%A8%98%E8%AD%9C%E6%B3%95)でも楽譜を記述できる。
このとき、Scoreの内部ではABCによるコードを`abc2ly`でLilyPondのコードに変換して楽譜の画像を生成している。
ただ残念ながら？LilyPondの[公式マニュアル](http://lilypond.org/doc/v2.18/Documentation/usage/invoking-abc2ly.ja.html)によると
>Note: このプログラムはサポートされていません。LilyPond 将来のバージョンからは削除される可能性があります。

とのことなので、Scoreを使って楽譜を埋め込むならLilyPond一択かと。