久しぶりに LilyPond を引っ張り出して、昔の自作曲の清書をしています。久しぶりに使うと、いろいろ問題が発生します。
1. Point and Click が効かない
以前 Emacs で ly
ファイルを編集していた時、"Point-and-Click" を実装しました。スコアの PDF に埋め込まれた textedit://...
というリンクをクリックすると、対応するエディタが開く、という便利なものです。その後、mi での編集に移行しました。拙作 "LilyRunner" で、"Script to respond to click on PDF" のボックスに下のように記述します。
#!/bin/sh
# $1 = file, $2 = line, $3 = column
/usr/bin/osascript <<EOF
tell application "mi"
open ("$1" as POSIX file)
activate
tell paragraph $2 of document 1 to select character $3
end tell
EOF
これで mi で Lilypond ファイルを編集して、たいへん快適に使っていたはずなのですが、今回久しぶりに引っ張り出すと、クリックで mi を立ち上げる機能が効かない。わりと直近に編集してたはずだけど、どうやってたんだっけ? いろいろ試行錯誤して、PDF をプレビュー.app ではなくて Safari で開けばよい、ということを思い出しました。
2. 違うバージョンの LilyPond って共存できるんか?
ずっと LilyPond 2.12.3 という超古いバージョンを使っていたのですが、最近のバージョンと共存できるんかな? 実は、2.12.3 は MIDI 出力の時にアーティキュレーション(スタッカートなど)をサポートしてない、という問題点があって、その時だけでも新しいバージョンを使いたいな、と思っていたのです。
最新の 2.24 は 10.14 Mojave では動かないため、2.22 をダウンロードして、試してみました。LilyRunner で 2.22 のアプリケーションパッケージを指定すると、ちゃんと動いた! 微妙に縦方向のスペーシングが違うのがおわかりでしょうか。
これで、「ガチガチに 2.12 で最適化した既存のコード」は 2.12 で、新しく書くコードは 2.22 で、と使い分けることができるようになりました。
3. Scheme コードの修正
LilyPond 2.22 を使うと、2.12 で作成した ly ファイルは修正なしでもおおむね解釈してくれます(出力結果のレイアウトはかなり変わる)。しかし、Scheme コードでカスタマイズしていると、ちょっと厄介です。例えば、「スラーを調整する」というテクニックで、下のコードを使うのですが、これが 2.22 で動かない。
shapeSlur =
#(define-music-function (parser location offsets) (list?)
#{ \once \override Slur #'control-points = #(alter-curve $offsets) #})
#(define ((alter-curve offsets) grob)
(let ((coords (ly:slur::calc-control-points grob)))
(define (add-offsets coords offsets)
(if (null? coords)
'()
(cons
(cons (+ (caar coords) (car offsets))
(+ (cdar coords) (cadr offsets)))
(add-offsets (cdr coords) (cddr offsets)))))
(add-offsets coords offsets)))
これの修正は簡単で、$offset
を offset
と書き直せばよいのですが、できれば 2.12 でも 2.22 でもコンパイルできるようにしておきたい。ちょっと試行錯誤しました。
- LilyPond のマニュアル Usage の 2.6 に "Writing code to support multiple versions" という記述があります。
ly:version?
という関数を使えばよい、とあるのですが、その下に "This function has been introduced in LilyPond 2.21.80" と書いてあります。つまり、2.12 では使えない! - Internals Reference の 4. Scheme functions を探してみると、
ly:version
というのがあります。"Return the current lilypond version as a list, e.g., (1 3 127 uu1)." ということなので、これを使えばよさそう。この関数は 2.12 にもあります。 - コンパイル中にメッセージを出して、いろいろ試してみたい。
ly:message
というのがあるのですが、説明が "A Scheme callable function to issue the message str. The message is formatted withformat
and rest." とあるだけで、なんだかよくわかりません。 - LilyPond のアプリケーションパッケージの中を探索します。
ly:message
で grep したら何か手がかりが見つからんかな? いろいろ出てきました。
試しに入力ファイルに$ cd /Applications/LilyPond.app/Contents/Resources/share $ grep ly:message `find . -name '*.scm'` ./lilypond/current/scm/documentation-lib.scm: (ly:message (_ "Processing ~S...") name)) ./lilypond/current/scm/documentation-lib.scm: (ly:message (_ "Writing ~S...") x)) ./lilypond/current/scm/stencil.scm: (ly:message "Writing ~a" outname) ./lilypond/current/scm/layout-page-dump.scm: (ly:message "Writing page layout to ~a" name) ...
#(ly:message "ly:version is ~a" (ly:version))
と書いてみると、LilyPond の出力に "ly:version is (2 22 2)" と表示されました。これでよさそうです。
いろいろお試しコードを書いて試してみた結果、下のようになりました。これで、2.12 と 2.22 のどちらでも通ります。"2022" のところは、本来は文法が変更されたバージョンを特定して書くべきですが、手元には 2.12 と 2.22 しかないので、「2.22 以上」と指定しておけば事足ります。
shapeSlur =
#(define-music-function (parser location offsets) (list?)
(if (>= (+ (* (car (ly:version)) 1000) (cadr (ly:version))) 2022)
#{ \once \override Slur #'control-points = #(alter-curve offsets) #}
#{ \once \override Slur #'control-points = #(alter-curve $offsets) #}))