SuperColliderの全体像について書きます。
SuperColliderとは
SuperColliderは、James McCartneyによって開発されたリアルタイム音響合成・アルゴリズム作曲のための環境です。1996年に発表され、2002年にGPLの下でオープンソース化されました(現在のバージョン系列はSuperCollider 3)。音響合成エンジンとプログラミング言語がクライアント/サーバーとして分離されている点が最大の特徴で、この設計により、ライブコーディングによる即興演奏から、非リアルタイムでの高品質なレンダリング、他言語からのリモート制御まで、幅広い用途に対応できます。
SuperColliderのコンポーネント構成
SuperColliderは3つのコンポーネントから構成されます。
- scsynth: リアルタイム音響合成サーバー
- sclang: scsynthクライアントとして動作するプログラミング言語とインタプリタ
- scIDE: GUIで提供される統合開発環境
SuperColliderのサーバー/クライアントはOSCプロトコルで通信します。 sclangはOSCメッセージをscsynthに送り、scsynthがそれを解釈して音響を生成します。
音響合成エンジン(scsynth)とその制御言語(sclang)が別プロセスとして独立している点がSuperColliderの設計上の核心です。両者はOSCという言語非依存のプロトコルでしか結びついていないため、sclangの代わりにPythonやHaskell、SuperColliderとは無関係な外部アプリケーションからscsynthを制御することも可能です(後述の「エコシステムと他クライアントとの連携」を参照)。逆に、sclangは音を出さずにscsynthへメッセージを送るだけのクライアントとして振る舞うこともできます。
クライアント/サーバー間通信: OSC
sclangとscsynthは、OSC (Open Sound Control) メッセージをUDP(既定)またはTCPで送受信することで通信します。scsynthはローカルホスト上のプロセスとして起動されるのが一般的ですが、OSCはネットワーク透過なプロトコルなので、原理上は別マシン上のscsynthをリモートから制御することもできます。
- 同期的コマンド(sync command):
/snew(Synth生成)や/nset(パラメータ変更)のように、送信するとサーバー内部の状態がすぐに変化するコマンド群です。 - 非同期的コマンド(async command):
/ballocRead(サウンドファイルの読み込み)や/drecv(SynthDefの登録)のように、ディスクI/Oなどを伴い完了までに時間がかかるコマンド群です。完了すると/doneメッセージが返されます。 - OSCバンドル(OSC Bundle): 複数のメッセージをタイムスタンプ付きでまとめて送ることで、サンプル精度に近い正確なタイミングで複数の操作(たとえば複数のSynthの同時生成)を実行できます。sclangの
Clock系クラス(SystemClockなど)はこの仕組みを使って、将来の時刻を指定したスケジューリングを実現しています。
scsynth側からsclang側へも、/n_go(ノード生成完了の通知)や/tr(トリガー通知)のようなメッセージが送られます。sclangはこれをOSCFunc/OSCdefで受信し、サーバー内部の状態変化に応じてクライアント側の処理を実行します。
scsynth: 音響合成サーバー
scsynthはC++で実装された、音を生成すること専任のリアルタイムオーディオエンジンです。GUIや言語処理系を一切持たず、OSCメッセージで指示された通りにオーディオグラフを構築・実行するだけの軽量なプロセスとして設計されています。内部状態は主に次の4種類のオブジェクトで構成されます。
ノード(Node): SynthとGroup
scsynthが管理する再生中の処理単位はNodeと呼ばれ、Synth(実際に音響を生成する単位)とGroup(複数のNodeをまとめるコンテナ)の2種類があります。すべてのNodeは木構造(ノードツリー)として管理されており、ルートには常にID 0のGroup(root node)が存在します。
- Synth: 後述のSynthDefから生成される、実行中のUGenグラフのインスタンスです。
/s_newメッセージで生成されます。 - Group: 複数のSynth/Groupをまとめて管理するコンテナです。GroupごとRunさせたりFreeさせたりできるほか、Groupに属するSynth全体へまとめてパラメータを送ることもできます。
ノードツリー内での並び順は単なる管理上の順序ではなく、実際の音響信号処理の順序を意味します。scsynthはツリーの先頭から末尾へ向かって各Nodeを順に実行するため、たとえばリバーブなどのエフェクトSynthを音源Synthより後ろ(ツリーの末尾側)に置くことで、前段の出力をBus経由で後段が受け取って処理する、という典型的なシグナルチェインが実現できます。/s_newではaddAction引数(addToHead・addToTail・addBefore・addAfter・addReplace)で、生成位置をツリー内のどこにするかを指定します。
バス(Bus)
Busはscsynth内部で信号やコントロール値をやり取りするための名前付きチャンネルで、audio bus(オーディオレート信号用)とcontrol bus(コントロールレート値用)の2種類があります。Synth同士がBusを介して信号を送受信することで、ノードツリーの順序と組み合わせたシグナルルーティングが可能になります。
audio busのうち、先頭のoptions.numOutputBusChannels個は物理出力(スピーカー)に、続くoptions.numInputBusChannels個は物理入力(マイクなど)に直結しています。それ以降のインデックスは内部的な信号受け渡し専用の「プライベートバス」として自由に使えます。
バッファ(Buffer)
Bufferはサンプルデータを保持するためのメモリ領域です。サウンドファイルの読み込み(/ballocRead)、波形テーブルの確保(/balloc)、録音先(/b_writeと組み合わせた録音)、FFT処理の中間データなど、単発の音響イベントを超えて保持しておきたいデータ全般に使われます。Busがリアルタイムのストリームであるのに対し、Bufferはランダムアクセス可能な配列データという位置づけです。
UGen(Unit Generator)
UGenはscsynthにおける最小のDSP処理単位で、正弦波発振器のSinOscやフィルタのLPFなど、個々の演算をC++プラグイン(.scxファイル)として実装したものです。scsynth起動時にプラグインディレクトリから動的に読み込まれるため、標準UGen以外にもサードパーティ製・自作のUGenを追加できます。
UGenにはそれぞれ計算レートがあり、用途に応じて使い分けます。
- audio rate(
.ar): サンプルごとに計算される、音声信号そのものを扱うレート。 - control rate(
.kr): 1コントロールブロック(既定で64サンプル)ごとに1回計算される、パラメータ制御用の軽量なレート。 - scalar rate(
.ir): Synth生成時に1回だけ計算され、以後変化しない値。 - demand rate(
.dr):Demand系UGenから明示的に「値を要求」された時にのみ次の値を計算する、プル型のレート。
SynthDef
scサーバーが音響合成をするために、SynthDefクラスでシンセ定義をします。 シンセ定義の構文は次の通りです。
SynthDef.new(\name, {UGens})
定義したSynthDefは.addメソッドでサーバーに送信されます。
SynthDefは、UGenをつなぎ合わせたグラフ(UGenグラフ)を、名前付きの再利用可能な設計図としてコンパイルしたものです。関数内でUGen同士をつなぐと、sclang側でその接続関係が解析され、scsynthが解釈できるバイナリ形式のSynthDefファイルに変換されます。主な特徴は次の通りです。
- 引数(Control): SynthDef関数の引数はコントロール値としてサーバーに登録され、生成後のSynthに対して
/n_setで名前付きに値を変更できます(例:SynthDef(\sine, {|freq=440, amp=0.1| Out.ar(0, SinOsc.ar(freq) * amp)}))。 - マルチチャンネル展開: UGenに配列を渡すと、そのUGen以降のグラフ全体が配列の要素数ぶん自動的に複製・並列化されます(例:
SinOsc.ar([440, 441])でステレオのわずかにデチューンした2音が得られます)。 - 送信方法:
.addはSynthDefをコンパイルしてサーバーに直接送信(/d_recv)します。.writeDefFileでディスク上に.scsyndefファイルとして書き出し、サーバー起動時に自動ロードさせることもできます。 .play: SynthDefを即座に.addしてSynthを生成するショートカットで、対話的な試行に便利です。
sclang: プログラミング言語とクラスライブラリ
sclangはSmalltalkの影響を受けたオブジェクト指向言語で、独自のインタプリタ(sclangプロセス)上で動作します。すべての値がオブジェクトであり、クラスライブラリ(標準で用意された.scファイル群)自体もsclangで書かれています。主な役割は次の通りです。
- scsynthへOSCメッセージを送るクライアントとして振る舞うこと。
- パターン(
PbindなどのPatternクラス群)による音楽的なイベントシーケンスの記述。 - スケジューリング(
Clockクラス群)による正確なタイミング制御。 - 対話的評価(REPL)によるライブコーディング。
クラスライブラリはユーザーが独自のクラスを追加・拡張することも前提とした設計になっており、コミュニティが開発した拡張ライブラリはQuark(パッケージ)という単位で配布され、Quarksクラスを通じてインストール・管理できます。
scIDEと開発環境
scIDEはQtベースのクロスプラットフォーム統合開発環境で、コードエディタ・ポストウィンドウ(実行結果やログの表示)・ヘルプブラウザなどを1つのアプリケーションにまとめたものです。内部的にはsclangプロセスをサブプロセスとして起動し、エディタ上で選択したコードをsclangへ送って評価する、という形でsclangと連携しています。
scIDEは公式に提供される標準の開発環境ですが、sclang自体はコマンドラインからも起動できるため、Emacs(scel)やVim、Atom/VS Code向けの拡張機能など、サードパーティ製のフロントエンドで開発することも可能です。いずれもscIDEと同様、内部ではsclangプロセスを起動してコードを送信するという同じ仕組みに依っています。
OSCメッセージ
scserverには組み込みのOSCメッセージがあります。 リファレンスはServer Command Reference。
代表的なメッセージには次のようなものがあります。
/snew・/nfree・/nset・/nmap: Synthの生成・解放・パラメータ変更・Busへのマッピング。/gnew・/ghead・/g_tail: Groupの生成とノードツリー内での配置。/drecv・/dload: SynthDefの登録(直接送信/ディスクからのロード)。/balloc・/ballocRead・/b_free: Bufferの確保・サウンドファイル読み込み・解放。/cset・/cget: グローバルなControl Busの値の設定・取得(Synthに紐づかない共有変数として使える)。/status・/dumpOSC: サーバーの負荷状況の取得、受信した全OSCメッセージのデバッグ出力。