読者です 読者をやめる 読者になる 読者になる

測地線 on Canvas と ABCjs on HasteFFI


また一ヶ月がたってしまった。

1.Haste

 ちょこちょこHaskellを触ったりしていますが、Atcoder Begginerで遊ぶだけでなく、
何か作ってみないとなぁという気持ちがありました。そこで調べてみるとHasteとかいうのを見つけます。

haste-lang.org


 HasteはHaskellからJavaScriptへのコンパイラで、どういう訳かHaskellの基本機能が全部使えます。
で、それだけではJavaScriptの代替にはならないので、CanvasやDOM操作用のモジュールが定義されています。

haste-compiler-0.5.5.0: Haskell To ECMAScript compiler


 ごいすー。ところでHaskellのドキュメント、型から大体の情報が得られる良さがありますね。とにかく型がよいということがわかります。
 このHaste、hastec hogehoge.hsで生成される同名jsファイルをHTMLから読むようにすれば終了です。なんということだ。
JavaScriptまったく触ったことがないし、JavaScript1行も書かなくてもJavaScriptが書けます(?)。

 ほいで、やっぱりモチベーション維持のためには、視覚に訴える物を作りたくなります。まるちめでぃあという奴です。
 そこでHaste.Graphics.Canvasを見てみると、簡単な図形・画像描画関数があります。全部モナドっぽい。
なるほどなるほど。しかし表示するだけじゃなくていんたらくてぶなことをしたいなと思えてきます。我々はわがままなので。
 そこでHaste.Eventsを見てみると、たくさんのイベント型が定義されており、コールバック登録関数onEventがあります。
なるほどなるほどなるほど。しかしどんな感じで何を使うか一から試して考えるのは辛いので何か例が欲しくなります。
 そこで公式のExampleからサンプルを落としてコンパイルしてみます。とっても小さなサンプルもあるのでこのくらいなら読めます。大体要素をIDで探してそれに対するアクションをする感じとわかります。
なるほどなるほどなるほどなるほど。

豊かなわかりが得られる事がわかります。Wakari is God.

 で、前から試してみたいと思ってた非ユークリッド平面を作ってみることにしました。二次元リーマン多様体ですが、2次元だと次元が小さいので、曲率テンソルの有意な成分は実質一つになることが知られています。ということで、すくなくとも局所的には曲率が正か負かゼロかという話で尽きます。
 じゃぁ曲率が正、負、ゼロで一定の面とは何かというので、それぞれ球面、双曲面、普通のユークリッド平面が代表的なものとして出てきます。これらにはそれぞれいい感じに自己等長変換リー群が作用できます。SO(3),PSL(2),SO(2)\ltimes \mathbb{R}^2です。
これらの群は全部3次元で、回転と平行移動がいい感じに混ざっていると考えることができます。仮にこうした平面上で「移動」に相当する概念があるとしたら、それが単位元近傍の等長変換であると考えるのは理に適っているでしょう。
 そこでこれらのリー群の指数写像を作用できるようにしましょう。それから、「移動」するならそもそもこの平面に何か物を置かないといけません。これはもう直線にしておきましょう。もちろん測地線のことです。

ここでハッピーなことが3つあります。

  • こうした3「平」面は、簡単な非ユークリッド計量をもった平面として表現できる。

ポアンカレ上半面:ポアンカレ計量、立体射影:フビニ=スタディ計量)

  • それからそこでの測地線が全て見かけ上は円弧か直線である。
  • そしてHaste.Graphics.Canvas円弧が定義されている

大勝利である事がわかります(低級グラフィックだと円弧が無かったりする)。

結果です。

http://www.asahi-net.or.jp/~fu5k-mths/hyper_line.html
http://www.asahi-net.or.jp/~fu5k-mths/sphere_line.html



 良さがありました。しかしこれを書くにあたってHasteモジュール中CanvasとEventsばかり触ることになり、いまだDOMやSocketの操作が全くわからないままであるので、
HasteでJavaScriptライフを満喫するにまだ課題がある事がわかります。ソースは、何処に貼ればいいんだっけ...Canvasの描画、どのくらいまで速度がでるのかわかりません。ミニゲームくらいは作れるのだろうか。

 ところでPSL(2,\mathbb{R})リー代数なのですが、当初計算しやすいからと次の基底でとっていました。

\begin{bmatrix}
1&0\\
0&-1
\end{bmatrix},\begin{bmatrix}
0&1\\
0&0
\end{bmatrix},\begin{bmatrix}
0&0\\
1&0
\end{bmatrix}

 しかしこれ、あんまり自然じゃないんですね。2次元平面のアナロジーで行けば、ある点周りの回転と平行移動が欲しいところですが、このうち、1つめは上半面モデルで垂直方向の移動ですが、残り2つは何物でもない。
 パウリ行列もどきですが、結局次の基底のほうがより素直な変換になる事がわかります。場の量子論ポアンカレ群いじりしていたときを思い出す。

\begin{bmatrix}
1&0\\
0&-1
\end{bmatrix},\begin{bmatrix}
0&-1\\
1&0
\end{bmatrix},\begin{bmatrix}
0&1\\
1&0
\end{bmatrix}


ちなみに2つ目が回転で3つ目が平行移動です。

2.ABCjsとそもそものABC記法

またwebがらみですが、僕は音楽に関してスコア厨ですから、webで楽譜を弄れたら良さみが深まるなぁと思うわけです。
そこでまた調べてみると、ABCjsなるJavaScriptライブラリがあることがわかります。

abcjs.net


 JavaScriptライブラリ以前にそもそもJavaScriptをよく知らないのでどのような位置付けなのかもわかりませんが、とにかくブラウザはHTMLを表示するし、その中でJavaScriptが起動するわけで、
ドキュメント自体がJavaScriptから見える実行環境と思うことにしました。そんなわけで、ドキュメントの先のほうでjsファイルをロードしておけばライブラリとしてはそれで配置終了っぽいというわかりを得ます。
 ABCjsのうちBasicなるライブラリでは、文字列でABC記法(後述)自体と、それを表示する要素IDを投げると、そこで楽譜を描画してくれる関数renderAbcがあり、これで大体用が終わることがわかります。

 Hasteを触ったのですからJavaScriptを回避してみたくなります。HasteはFFIをもっており、js関数をインポートしたり、Haskell関数をjs関数としてエクスポートできます。どういう原理なんだ。
そしてその関数はシンプルにも

ffi::(FFI a)=> JSString -> a

で、JavaScriptの生コードを適当な何者かとして受け付けます。
得られる型aは実質なんでもよく、生コードに期待する型をこっちでつけてしまってよいのです。どういう原理なんだ。
とにかくFFIは謎です。そこで試しに

renderABC::String -> String -> IO()
renderABC = do ((ffi.toJSStr) "(function(a,b){ABCJS.renderAbc(a,b);})")

などとし、

renderABC "note" dat

とかしてやると、なんと表示されてしまう事がわかります。お試しください。どういう原理なんだ。
("note"はHTMLに書いた要素ID、datは別に定義したABC記法のString)

 既にABC記法のスコアがページにある場合は、勝手にその続きに譜面を描画するPluginもあり、簡単な楽譜表示には困らないことがわかります。
 しかしどうもABC記法の検出が雑っぽく、ページ内にごちゃごちゃしたものがあると誤認して変なものが出てくるのでこっちはやめました。

 結局Haskell内にABC譜文字列を埋め込み、ABCjsをFFIロードし、HasteでJavaScriptにするという埋め込み+FFIを行います。以下は去年書いた曲のメロ譜です。

http://www.asahi-net.or.jp/~fu5k-mths/cis_moll_ref.html

http://www.asahi-net.or.jp/~fu5k-mths/f_moll_ref.html


 いい感じですね。スペースを入れるかどうか、ハイフンをつけるかどうかで、スラー/タイの制御や、旗の接続制御ができるので、例えば八分三連や、八分シンコペなどはグルーヴに応じて調整できます。楽譜の整形ができるので見栄えします。


 ところでこのABC記法、構文は単純ではありますが、これ自体を楽譜、もとい演奏ファイルの抽象として考えると不自然な構文があります。一応、「音楽記述言語」を標榜しているのですが、ウーン?
 違和感の例として、音名と記譜が対応していないことがあります。ABCは名の通りABCDEFG(ラ~ソ)で音を書きますが、変化音(Cis,Ces,Dis,Desとか)はありません。
 それから調号をスケール呼称で指定して表示できますが、調号がかかっているときでも、変化なしのABCDEFGでそのスケールの音を指定します。つまりこの記号は音名ではなく、五線上の音符の位置のことです。
 さらに、調号がかかっている時に、変化音を付けた場合、勝手にナチュラルやダブルシャープダブルフラットに変換されるわけではありません。やはりこれも何の音を書いているかではなく、楽譜上その記号があるかどうかなのです。これでは音楽の記述言語ではなく、楽譜の記述言語です。音楽に対して二段離れている。すなわち、音楽にはこういう要素がこういう構造であるよね?というのを書く言語(楽譜とかMIDIとか)ではなく、楽譜にはこういう記号がこういう配置であるよね?というのを書く言語ということです。

 ちょっと音楽周りに関してやってみたい事があり、そのためにABCがいい感じかと思ったのですが、こういう調子だと微妙なことになりますね。僕は音楽それ自体の高級軽量抽象言語がほしいと思っているのですが、伝統的な楽譜はレガシーたっぷりで曖昧なところもあり、それに代替するものが何かないかと思っていましたが、ABC記法は楽譜がセマンティクスになってしまっているので同様の問題をはらんでしまいます。ここでの問題は、例えば意味論(音そのもの)がちゃんと定義されるのかどうかというのを含みます。

 もともと五線楽譜というのは微妙に冗長だったり曖昧だったりする記譜法ではあります。
例えば平均律ゆえの同音異名はその例です。良く書かれた楽譜では、同音異名のうちどれを取るか(調号で沢山シャープしてある音の半音下をナチュラルで書くか、一度下からダブルシャープするか等)
というのは幾つかの理由をもって選択されます。具体的には

  • 記譜上のメロディラインが滑らかかつ見やすくなるようにとる(半音階的メロディや刺繍音など)。
  • モーダルインターチェンジや局所転調で、旋法上の音順序を破壊しないように最近音から変化させる。

等です。このあたりはどういうニュアンスを込めるかは未定義な割にしばしそうしたニュアンスが意味を持ったりするので困りものです。

 旗を接続するかどうか、旗の切断を拍のどこで行うか、というのもそうで、これも慣習に基づきます。グルーヴによらす、4/4の曲は四音程度で旗を切断する傾向にあります。恐らく視認性のためでしょう。また付点8分付点8分8分というのは様々なところで聴くリズムですが、これも二回目の付点8分を16分8分のタイにすることが多いように思えます。不思議ですね。しかもこの場合4音以下でも途中の16分と8分の旗はつなぎません。

 こうしたものは慣習を守らなくても、楽譜として不正になることはありません。しかし見栄えは悪くなります。可読性も落ちます。
 DAWで五線編集機能が無いものが結構あるのですが、そもそも楽譜からMIDIへの変換は比較的曖昧さが無いが、MIDIから楽譜への変換はかなりの曖昧さがあるという問題によるように思います。昔そうしたGUIを触ったことがありますが、MIDIに保存してから立ち上げ直すと、楽譜が崩れていることに大変落胆した覚えがあります。しかしそのソフトは変化音処理や旗接続はかなり自然にできていたので、今思えば優秀な方だったのでしょう。

 ABCが音楽抽象、音楽記述言語というより、楽譜抽象、楽譜記述言語にあえてしたのは、やはり楽譜を取り巻く伝統的エコシステムに乗りたいというのと、新しい音楽抽象を策定して普及される事それ自体が極めて難しいからだろうという予測はできます。
 MIDIは楽器制御というつよい目的があったので、割と思い切った低レベル音楽抽象規格になりましたが、高レベル抽象で、楽譜並の表現力があり、楽譜以上の形式的厳格さを持つものを作れるかどうかというと、ウーン...
 こうした厳格かつ高級な策定自体が、なんらかの非自明な音楽観を反映してしまいざるを得ないことが想像できます。例えば「声部」概念が意味をもつかどうか、というのは例です。
また電子楽器の制御UIをどうするかというのも音源やDAWで微妙に異なる訳で、出来合いの記述変数自体に統一性がありません。
様々な面倒があります。面倒。面倒。面倒。

3.サピエンス全史たのしかった

これです。
www.amazon.co.jp


ジャパリパークの図書館に納め、フレンズが文字を学ぶことにより、かばんちゃんが容易にハブられることがわかる。