ssaw08 0624
TRANSCRIPT
SSAW08 第9回
SuperCollider入門SCとMax、SCとProcessingの連携2008年6月24日
今日の内容
• SuperColliderはじめの一歩• SuperColliderの簡単な導入• SuperColliderとOSCの関わり
• SuperColliderとMax/MSPの連携• Maxをコントローラーにして、SCで音響生成する
• SuperColliderとProcessig (+ OscP5) の連携• Processingのアニメーションをトリガーにして、SCで音響生成する
SuperColliderとは
• 音響合成のためのプログラミング環境およびプログラミング言語• 1996にJames McCartneyにより開発・リリースされた• 2002年にはGNU General Public Licenseの元フリーウエアに• 2008年7月現在のバージョンは、ver. 3.2
SuperColliderの入手・インストール
• SourceForgeのプロジェクトページから最新版がダウンロードできる• http://supercollider.sourceforge.net/
• 参考サイト• SuperCollider Japan (日本のユーザーコミュニティ)• http://supercollider.jp/
• The SuperCollider Swiki• http://swiki.hfbk-hamburg.de:8888/MusicTechnology/6
• 旧ホームページ• http://www.audiosynth.com/
最初の一歩、"Hello World"
// Hello Worldの文字列を表示する"Hello World!".postln;
上の文字列を選択して、enterキー (returnキーではない) を押す
// ( ) で囲むとコードのブロックになる( "Hello World!".postln; "Hello SuperCollider".postln;)
sclang (クライアント) と scsynth (サーバー)
• SuperColliderの特徴• 音響合成をするサーバー部と、言語の部分(クライアント)が明確に分離している
• sclang• クライアント部分• インタプリタ言語
• scsynth• サーバー部分• 音響合成エンジン
sclang (クライアント) と scsynth (サーバー)
(1)オーディオサーバー(2)音響合成言語(3)言語のインタープリタ (ソースを逐次解釈しながら実行する)(4)サーバーへのインタプリタ (ソースを逐次解釈しながら実行する)(5)アプリケーション全体
sclang (クライアント) と scsynth (サーバー)
• SCは、クライアント/サーバー方式• 両者はOSCメッセージをやりとりすることでコミュニケーションしている
sclang (クライアント) と scsynth (サーバー)
• SCサーバーは、SuperColliderの言語部だけでなく、OSCを利用することのできる外部のアプリケーションからでも利用可能である
SCサーバーを起動する
• 音を生成するためには、SCサーバーを起動 (boot) する必要がある• 2種類のサーバーが存在する• internal server:• クライアント内部に組みこまれているサーバー
• localhost server:• クライアントアプリとは別に切り離されて存在するサーバー
SCサーバーを起動する
• internal server、localhost serverどちらかの"Boot"ボタンを押すと、サーバーが起動する• 音響合成の準備完了
いろいろな括弧
• SCのプログラムで、最初にとまどう部分• 括弧がやたらと多い、しかもいろいろな種類がある• 括弧の意味の理解がSC理解のキーとなる
• それぞれの括弧には意味がある• ダブルクオーテーション " "• 文字列をあらわす
• 中括弧 { } • 関数の定義をあらわす
• 小括弧 ( )• 関数の引数、クラスの引数をあらわす• 計算順位をあらわす
• 大括弧 [ ]• 集合をあらわす• 出力チャンネルをあらわす
いろいろな括弧
// 文字列"Hello World".postln;
//関数f = { 1 + 1 };f.value;
// 関数の引数f = { arg a, b; a + b; };f.value(2, 3);
// 配列x = [1, 2, 3];x.postln;
// チャンネル{ SinOsc.ar([440, 660], 0, 0.2) }.play;
関数の定義
• SCで音響合成する一番楽な方法は、関数を利用するやりかた• 音響合成の方法を定義した関数を作成• SCでは関数は { } で囲むことで表現する
• 作成した関数に対して、".play" というメソッド(手続)を与えると、音響を生成する
関数の定義
// 関数f = { 1 + 1 };f.value;
// 関数の引数f = { arg a, b; a + b; };f.value(2, 3);
// 変数を使うf = { arg a, b; var firstResult, finalResult; firstResult = a + b; finalResult = firstResult * 2; finalResult;};f.value(2, 3); // (2 + 3) * 2 = 10
関数の定義
// 440HZ、音量0.2の音を生成する関数{ SinOsc.ar(440, 0, 0.2) }.play;
// この関数を分解すると、以下のような意味合いになる({ // 関数の開始 SinOsc.ar( // サイン波をオーディオレイト(.ar)で生成する 440, // 周波数は 440HZ 0, // 位相は 0 0.2) // 音量は 0.2} // 関数を終了.play; // 'play'の命令を関数に与える)
関数の定義
// 関数を変数に代入することも可能f = { SinOsc.ar(440, 0, 0.2) };f.play;
// 関数に引数を渡すx = {arg freq=440; SinOsc.ar(freq, 0, 0.2)}.play;x.set(\freq, 880);x.free;
// ステレオ(左右2ch)で再生{ SinOsc.ar([440, 660], 0, 0.2) }.play;
x = {arg freq=440; SinOsc.ar([freq, freq+5], 0, 0.2)}.play;x.set(\freq, 880);x.set(\freq, 80);x.free;
楽器の定義:SynthDef
• 関数.play で音は生成できる• いちばん簡単な方法• しかし、あまり応用の効くやりかたではない• あくまでテストのための簡易的な手段と考えるべき
• 楽器を定義するクラスを作成する• SynthDef:楽器を定義するクラス• オブジェクト指向 (OOP) なプログラミング手法• 最終的な出力は、Outクラスに接続する• Out.ar(バス番号, オーディオシグナル);
楽器の定義:SynthDef
//関数による音響生成{ SinOsc.ar(440, 0, 0.2) }.play;//SynthDefを用いる方法で書き換えるSynthDef.new("SinOsc_test", { Out.ar(0, SinOsc.ar(440, 0, 0.2)) }).play;
//より複雑な例 変数を使用+2chに(SynthDef.new("SinOsc-stereo", { var outArray; outArray = [SinOsc.ar(440, 0, 0.2), SinOsc.ar(442, 0, 0.2)]; Out.ar(0, outArray) }).play;)
楽器の定義:SynthDef
//引数を使用Server.default = Server.internal;s = Server.default;s.boot;
(SynthDef.new("SinOsc-stereo-args", { arg freq=440, mul=0.2; var outArray; outArray = [SinOsc.ar(freq, 0, mul), SinOsc.ar(freq+2, 0, mul)]; Out.ar(0, outArray) }).send(s);)
x = Synth.new("SinOsc-stereo-args");x.set("freq", 660);x.set("mul", 0.2);x.set("freq", 100, "mul", 0.5);x.free;
OSCを介して、SCサーバーと通信
• OSCメッセージを用いて、SCサーバーと通信して、音響を生成する• OSCメッセージの種類によって、SCサーバーは挙動を決定している• 代表的なOSCメッセージ• /s_new• SynthDefを新規にインスタンス化しノードに追加する• つまり新規に音響を生成する
• /n_free:• ノードを切断する• つまり音を停止する
• /n_set:• ノードのSynthDefクラスで定義されている引数に値を渡す
OSCを介して、SCサーバーと通信
//サーバー "myServer" を IP:127.0.0.1 port:12000で起動s = Server("myServer", NetAddr("127.0.0.1", 12000)); s.boot;//OSCメッセージをダンプするs.dumpOSC(1);//SynthDefの定義(SynthDef.new("sine-stereo", { arg freq=440, mul=0.2; var outArray; outArray = [SinOsc.ar(freq, 0, mul), SinOsc.ar(freq+2, 0, mul)]; Out.ar(0, outArray) }).send(s);)//OSCを介して、新規に"sine-stereo"のSyhtDefクラスをインスタンス化s.sendMsg("s_new", "sine-stereo", s.nextNodeID, 0, 1);//音を停止s.sendMsg("/n_free", n);//サーバーを停止s.quit;
OSCを介して、SCサーバーと通信
• それぞれの操作のタイミングでのダンプされたOSCメッセージに注目
• SynthDef.newをした時a SynthDef[ "#bundle", 1, [ "/d_recv", DATA[234], 0 ]
]
• 状態の監視[ "/status", ]
• サウンドの開始myServer[ "s_new", "sine-stereo", 1000, 0, 1 ]
OSCを介して、SCサーバーと通信
• サウンドの停止myServer[ "/n_free", 1000 ]
• サーバーの停止/quit sent
[ "/quit", ][ 24, 0 ]myServer->SC_CoreAudioDriver::DriverStop<-SC_CoreAudioDriver::DriverStopRESULT = 0
• MaxをSuperColliderのコントロールのためのGUIとして活用してみる• OSCを利用して、コミュニケーションする
MaxとSuperClliderの連携
OSC
音響合成ユーザ操作
Max → SC:簡単な例
//SC側:ステレオのSin波を生成する sine-stereo を定義
//サーバー "myServer" を IP:127.0.0.1 port:12000で起動s = Server("myServer", NetAddr("127.0.0.1", 12000));s.boot;
//OSCメッセージをダンプするs.dumpOSC(1);
//SynthDefの定義(SynthDef.new("sine-stereo", { arg freq=440, mul=0.2; var outArray; outArray = [SinOsc.ar(freq, 0, mul), SinOsc.ar(freq+2, 0, mul)]; Out.ar(0, outArray) }).send(s);)
• Max側
Max → SC:簡単な例
Max → SC:応用例 - レゾナンスフィルタ
//サーバー "myServer" を IP:127.0.0.1 port:12000で起動s = Server("myServer", NetAddr("127.0.0.1", 12000));s.boot;
//OSCメッセージをダンプするs.dumpOSC(1);
//SynthDefの定義(SynthDef("resonance", { arg note = 36, fc = 1000, rq = 25, bal=0, amp= -20, gate = 1; var x; x = Mix.fill(4, { LFSaw.ar((note + {0.1.rand2}.dup).midicps, 0, 0.02) }); x = RLPF.ar(x, fc, rq/100).softclip; x = RLPF.ar(x, fc, rq/100, amp.dbamp).softclip; x = Balance2.ar(x[0], x[1], bal); x = x * EnvGen.kr(Env.cutoff, gate, doneAction: 2); Out.ar(0, x); }).load(s);)
Max → SC:応用例 - レゾナンスフィルタ
• Max側
• 送信側:Processing + OscP5• 受信側:SuperCollider
• Processingのアニメーションをトリガーにして、OSCを送信• その情報をもとにSCが音響合成
ProcessingとSuperClliderの連携
OSC
SCP5 + OscP5
• Processing側• 画面上でマウスをクリックすると、波紋状に円が拡がるプログラム
P5 → SC (1):波紋にあわせて音を生成
• Processing側• マウスからのインタラクションを以下の情報に変換• onPressedの際の• X座標 (mouseX):デチューン(左右の周波数のずれ)• Y座標 (mouseY):周波数• 円の数だけsynthDefを生成する• 常に新しいSynthIDを発行する
P5 → SC (1):波紋にあわせて音を生成
P5 → SC (1):波紋にあわせて音を生成
import oscP5.*;import netP5.*;
OscP5 oscP5;NetAddress myRemoteLocation;
Ring[] rings;int numRings = 50;int currentRing = 0;int synthId = 1;
void setup() { size(400, 400); colorMode(HSB, 360, 100, 100, 100); frameRate(30); oscP5 = new OscP5(this,12000); myRemoteLocation = new NetAddress("127.0.0.1",12000); colorMode(HSB, 360, 100, 100, 100); smooth(); rings = new Ring[numRings]; for(int i = 0; i < numRings; i++){ rings[i] = new Ring(); }}
P5 → SC (1):波紋にあわせて音を生成
void draw(){ background(0); for(int i = 0; i < numRings; i++){ rings[i].grow(); rings[i].display(); }}void mousePressed(){
//OSC送信部分 OscMessage myMessage = new OscMessage("/s_new"); myMessage.add("env-sine"); myMessage.add(synthId); myMessage.add(1); myMessage.add(0); myMessage.add("freq"); myMessage.add((height - mouseY) * 10); myMessage.add("detune"); myMessage.add(((width/2) - mouseX)/30); oscP5.send(myMessage, myRemoteLocation); synthId++;
rings[currentRing].start(mouseX, mouseY); currentRing++; if(currentRing >= numRings){ currentRing = 0; }}
P5 → SC (1):波紋にあわせて音を生成
class Ring { float x, y; float diameter; boolean on = false; color col; void start(float _x, float _y){ x = _x; y = _y; on = true; diameter = 1; col = color(random(360), 50, 100, 50); } void grow() { if(on) { diameter++; if(diameter > 1000){ on = false; } } }
P5 → SC (1):波紋にあわせて音を生成
void display(){ if(on){ noFill(); stroke(col); strokeWeight(4); ellipse(x, y, diameter, diameter); } }}
• SC側• エンベロープのついたSine波を生成する
P5 → SC (1):波紋にあわせて音を生成
//サーバー "myServer" を IP:127.0.0.1 port:12000で起動s = Server("myServer", NetAddr("127.0.0.1", 12000));s.boot;
//OSCメッセージをダンプするs.dumpOSC(1);
//エンベロープ付き sin波(SynthDef("env-sine", { arg freq = 880, amp=0.125, detune=0; var env, x; env = EnvGen.kr(Env.perc(0.001,20,1,-4), doneAction: 2); x = env * SinOsc.ar([freq, freq+detune],0, amp); Out.ar(0, x) }).send(s));
•
P5 → SC (1):波紋にあわせて音を生成
• Processing側• 上下に球が弾むプログラム
P5 → SC (2):バウンドにあわせて音を鳴らす
P5 → SC (2):バウンドにあわせて音を鳴らす
import oscP5.*;import netP5.*;
OscP5 oscP5;NetAddress myRemoteLocation;
int numSpots = 24;Spot [] spots = new Spot[numSpots];int synthId = 1;
void setup() { size(400, 400); frameRate(30);
oscP5 = new OscP5(this,12000); myRemoteLocation = new NetAddress("127.0.0.1",12000);
smooth(); noStroke(); colorMode(HSB, 360, 100, 100, 100); for(int i = 0; i < spots.length; i++){ float x = (width / numSpots) * i + width/numSpots/2; float rate = (i+1)/4.0; color col = color(360/numSpots*i, 80, 50); spots[i] = new Spot(i, x, height/2, width/numSpots, rate, col);
P5 → SC (2):バウンドにあわせて音を鳴らす
}}
void draw() { background(0); for(int i = 0; i < spots.length; i++){ spots[i].move(); spots[i].display(); }}
class Spot { int n; float x, y, diameter, speed; color spotColor; Spot(int _n,float _x,float _y,float _diameter,float _speed,color _spotColor) { n = _n; x = _x; y = _y; diameter = _diameter; speed = _speed; spotColor = _spotColor; }
P5 → SC (2):バウンドにあわせて音を鳴らす
void move() { y += speed; if(y > height-(diameter/2) || y < diameter/2){ speed *= -1; //Send OSC Message OscMessage myMessage = new OscMessage("/s_new"); myMessage.add("env-sine-note"); myMessage.add(synthId); myMessage.add(1); myMessage.add(0); myMessage.add("note"); if(y < diameter/2){ myMessage.add(n*4+36); } else { myMessage.add(n*4+12); } myMessage.add("detune"); myMessage.add(6); oscP5.send(myMessage, myRemoteLocation); synthId++; } } void display() { fill(spotColor);
P5 → SC (2):バウンドにあわせて音を鳴らす
ellipse(x, y, diameter, diameter); }}
• SC側• エンベロープのついたSine波を生成する
P5 → SC (2):バウンドにあわせて音を鳴らす
//サーバー "myServer" を IP:127.0.0.1 port:12000で起動s = Server("myServer", NetAddr("127.0.0.1", 12000));s.boot;
//OSCメッセージをダンプするs.dumpOSC(1);
//エンベロープ付き sin波(SynthDef("env-sine-note", { arg note = 10, amp=0.125, detune=6; var env, x; env = EnvGen.kr(Env.perc(0.001,6,1,-4), doneAction: 2); x = env * SinOsc.ar([note.midicps, note.midicps+detune],0, amp); Out.ar(0, x) }).send(s));
s.quit;
P5 → SC (1):波紋にあわせて音を生成