オーディオ・映像用プログラミング言語・Extemporeの紹介

「音楽ツール・ライブラリ・技術 Advent Calendar 2019」16日目の記事になります。
https://adventar.org/calendars/3997

MachiaWorx(まきゃわーくす)と申します。
趣味で簡単な言語自体の組み込み+実装・ゲーム・シンセサイザー・メガデモ等のプログラムを書いてます。

今回はちょっと毛色の違うアプローチとして
ライブコーディング言語・Extemporeについて書いてみます。

元々簡単にシンセサイザーやシーケンスを作れる環境は存在しないものだろうか?と考え
色々調べているのですが、その中で見つかったものとして記載しています。

Extemporeとは

オーディオとビジュアルについて、Schemeベースの言語でライブコーディングが可能な環境です。

ライブコーディングとは
https://en.wikipedia.org/wiki/Live_coding

オススメの環境構築

まずはここの「download a binary」からバイナリを落としてきます。
https://extemporelang.github.io/

自分の場合は、以下ページの「VSCode」をベースに構築済みです。
https://extemporelang.github.io/docs/overview/editor-support/

試しに音を鳴らしてみる

サンプル QuickStartより
https://extemporelang.github.io/docs/overview/quickstart/

「Extempore start」「Extempore connect」で接続したあと、
解釈したいカッコ区切りの「末尾以外」にカーソルを合わせてCtrl+Enterでソースコードの解釈が始まります。
もしくは範囲選択を行いCtrl+Enterで解釈が可能です。

あと参考資料をベースに音をそれっぽく鳴らしてみました。

参考資料:
http://youz.hatenablog.com/entry/20121224/1356365175

;; instruments定義ファイルを読み込み
(sys:load "libs/core/instruments.xtm")
;; 音色定義
(make-instrument synth fmsynth)
;; 出力用のDSP処理を定義
(bind-func dsp:DSP
   (lambda (in time chan dat)
     (synth in time chan dat)))
;; 出力音色を登録
(dsp:set! dsp)
;; ===========================================
;; こっから参考資料のコピペ
;; 音階
(define (scale n base)
  (let ((m (modulo n 7)))
    (+ base
       (* 12 (/ (- n m) 7))
       (list-ref '(0 2 4 5 7 9 11) m))))
;; tak関数
(define (tak x y z next)
  (let* ((len (* 2 44100))   ; 2秒ずつ鳴らす
         (t (+ (now) len)))  ; 次の音へ移る時刻
    (print "[" x y z "]\n")
    ; 和音発声
    (map (lambda (n) (play-note (now) synth (scale n 60) 70 len))
         (list x y z))
    ; 次の音へ
    (if (<= x y)
        (callback t next y)
      (callback t tak (- x 1) y z
                (lambda (nx)
                  (tak (- y 1) z x
                       (lambda (ny)
                         (tak (- z 1) x y
                              (lambda (nz)
                                (tak nx ny nz next))))))))))
;; 起動
(tak 10 5 1 println)
;; 停止
(define (tak x y z next) )

使い勝手

  • 他のソフトをいっぱい起動しなくてもいいので、ソフト管理が楽

  • Schemeベースの環境なのもあって、文法がわりと単純に書ける

  • あとScheme処理系の入門にもなる

  • 変数はExtemporeを起動している間は保存されるので、
    一度クリアしたい場合は今の所Extemporeの再起動が早い。
    (他にリセット方法があるんだろか)

  • VSCode上だとキーボードで起動→終了の処理が全部制御可能

参考資料

Documents
https://extemporelang.github.io/

まずは上記ページをメインに見つつ試してみるのが早い。

うまくサンプルが動かない場合

  • libs/aot-cacheあたりを眺める。
    どうもここにプリコンパイルされたデータが格納されているらしく、
    事前定義と重複するときがあったりする。

  • ライブラリを修正する。これは、「instruments.xtm」がおかしいとか
    言ってくるケースがあるので、エラーを修正する必要があるかも。
    (原因が特定できなかったけど、古い書き方を参照したせいかもしれない)
    あとLLVMで出力されたソースコードの関係上ダメなケースもある?
    とりあえず現状の環境では再コンパイルしてみて問題なくなったが・・・原因が絞りきれない。

  • 日本語の資料が古すぎるケースがある。
    1年前後に記載された記事を確認するか公式のDocを確認して動かしてみるのが確実

  • 変数を間違えて定義してるケースがある。
    Extemporeを再起動するのが早い。

他のライブコーディング環境

ある程度限定で。

  • TidalCycles
    SuperColliderベースの環境。リズムメインで作るならこっちが早いと思われる。

  • FoxDot
    Tidalsとほぼ特徴は同じ?(未検証)

  • Max8(Max/MSP)
    商用ソフト。
    即興でパッチ作るのはマウスで操作することになるので色々辛いのでは?と思うものの、
    ライブ用の仕込みするならかなり有効かと。

  • PureData
    フリーソフト。
    Maxと同じような特徴。
    個人的には事前作り込みしたい。

  • AbletonLive(Max for Liveでライブコーディングできる環境が存在する)
    https://reallyusefulplugins.tumblr.com/livecode

面白そうな要素(ハックともいう)

  • libs/aot-cacheのバイナリ(というかstaticライブラリ?)のハック
    上記の通りstaticライブラリの定義がいっぱい入ってる+プリコンパイル済み?なので
    これを弄ってみるのも面白い。
    ただ定義に差異が出るとエラー扱いなので気をつける事。(これ何が原因でエラーが出るのかよくわからん)

  • Schemeとxtm文法の違い
    どうもExtemporeは、内部で2系統の言語が存在するらしく、命令等で分岐を行う。
    Schemeはクロージャーを定義するときに入力引数または戻り値のデータ型を指定する必要はなくてちょい低速、
    xtlangの方が変数等の制約がある代わりに高速という位置づけらしい。
    参考資料:
    https://extemporelang.github.io/docs/reference/scheme-xtlang-interop/

    文法が似通っているので混乱するところがあると思うけど、
    「Schemeとxtlangの書き換えが容易」というのはメリットと思う。
    Cとかで高速化しようとすると面倒ですものね。

  • ちなみにFFIを経由してC言語とも連携ができるとの事。
    https://extemporelang.github.io/docs/reference/c-xtlang-interop/

  • OpenGLサンプルをワンステップずつ実装していくことが可能
    OpenGLのサンプルをいくつか試してみたところ、
    どうもウィンドウ生成→三角形描画をワンステップずつ実行可能みたい(オンザフライ書いてあるものね)
    これを利用して、それぞれの機能を1ステップずつ説明みたいなのも可能と思料。
    ただし、その間は出力したウィンドウが「応答なし」扱いなので、
    割とソフトの状態としてはあかんことになってるのに注意。

  • 一気にファイルを読み込む
    これは「sys:load」という命令を使って可能。
    ただ、コンパイル+関数の定義を行う形なので、トータルの実行速度は遅めなのに注意。
    前述のプリコンパイルじみたほうに組み込むこともできそうだけど、まだそこまでは未確認。

まとめ

言語としてはSchemeベースではあるものの、
シンセサイザーの音色を作ってみたり、シーケンスをランダムや数式で作り込んでみたり、というのが
プログラムから簡単に書けそうです。