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

音の鳴るブログ

鳴らないこともある

SuperCollider の SynthDefBinary を JSON にするやつ

最近 SuperCollider がどんな感じなのか調べている。

その流れで SynthDef したときのバイナリをJSONで可視化するツールをつくった。

SuperColliderはクライアントサーバー構成をとっていて、クライアントでプログラムを書いてサーバーに送信して音を出すみたいな感じで動作する。SynthDefっていうのはクライアント側でつくる音色仕様書みたいなもので、それをサーバーに送信して使い回している。そのときのフォーマットは Synth Definition File Format で説明されている。

音を出すときはこの定義と与えられた引数に応じて Unit のリストを作成してひたすら順番に処理をしていくだけで良い。

SynthDef("test", { |freq=440, amp=0.5|
  Out.ar(0, SinOsc.ar(freq+[-2,2], 0, amp))
}).writeDefFile

// SynthDef.synthDefDir に test.scsyndef が保存される

こういう感じでバイナリ保存したファイルをドラッグすると以下の雰囲気で表示される。

{
  "version": 2,
  "defs": [
    {
      "name": "test",
      // 定数
      "consts": [ -2, 2, 0 ],
      // 引数
      "params": {
        // 引数の値
        "values": [ 440, 0.5 ],
        // 引数の名前と値のインデックス
        // コントロールの種類に応じて values の値がソートされるのでインデックスが必要
        "names": [ "freq", 0, "amp", 1 ]
      },
      "specs": [
        // Name, Rate, SpecialIndex, InputSpec, OutputSpec
        // Rate (0=scalar, 1=control, 2=audio)
        // SpecialIndex は UGenごとに意味を持つ
        //   BinaryOpUGenなら演算子の種類とか
        //   Controlなら対応する params.values のインデックスとか
        // InputSpec は 2つ1組のデータ. 
        //   入力UGenのインデックスとそのアウトプットのインデックス
        //   入力UGenのインデックスが -1 のときは定数のインデックス
        // OutputSpec はアウトプットの Rate 
        //   マルチチャネルのUGenで異なるRateを出すときがあるらしい
        [ "Control"     , 1, 0, [                   ], [ 1, 1 ] ],
        [ "BinaryOpUGen", 1, 0, [ 0, 0, -1, 0       ], [ 1    ] ],
        [ "SinOsc"      , 2, 0, [ 1, 0, -1, 2       ], [ 2    ] ],
        [ "BinaryOpUGen", 2, 2, [ 2, 0, 0, 1        ], [ 2    ] ],
        [ "BinaryOpUGen", 1, 0, [ 0, 0, -1, 1       ], [ 1    ] ],
        [ "SinOsc"      , 2, 0, [ 4, 0, -1, 2       ], [ 2    ] ],
        [ "BinaryOpUGen", 2, 2, [ 5, 0, 0, 1        ], [ 2    ] ],
        [ "Out"         , 2, 0, [ -1, 2, 3, 0, 6, 0 ], [      ] ]
      ],
      // 引数辞書
      "variants": {
      }
    }
  ]
}