ssaw08 0624

45
SSAW08 第9回 SuperCollider入門 SCとMax、SCとProcessingの連携 2008年6月24日

Upload: atsushi-tadokoro

Post on 15-May-2015

1.570 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Ssaw08 0624

SSAW08 第9回

SuperCollider入門SCとMax、SCとProcessingの連携2008年6月24日

Page 2: Ssaw08 0624

今日の内容

• SuperColliderはじめの一歩• SuperColliderの簡単な導入• SuperColliderとOSCの関わり

• SuperColliderとMax/MSPの連携• Maxをコントローラーにして、SCで音響生成する

• SuperColliderとProcessig (+ OscP5) の連携• Processingのアニメーションをトリガーにして、SCで音響生成する

Page 3: Ssaw08 0624

SuperColliderとは

• 音響合成のためのプログラミング環境およびプログラミング言語• 1996にJames McCartneyにより開発・リリースされた• 2002年にはGNU General Public Licenseの元フリーウエアに• 2008年7月現在のバージョンは、ver. 3.2

Page 4: Ssaw08 0624

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/

Page 5: Ssaw08 0624

最初の一歩、"Hello World"

// Hello Worldの文字列を表示する"Hello World!".postln;

上の文字列を選択して、enterキー (returnキーではない) を押す

// ( ) で囲むとコードのブロックになる( "Hello World!".postln; "Hello SuperCollider".postln;)

Page 6: Ssaw08 0624

sclang (クライアント) と scsynth (サーバー)

• SuperColliderの特徴• 音響合成をするサーバー部と、言語の部分(クライアント)が明確に分離している

• sclang• クライアント部分• インタプリタ言語

• scsynth• サーバー部分• 音響合成エンジン

Page 7: Ssaw08 0624

sclang (クライアント) と scsynth (サーバー)

(1)オーディオサーバー(2)音響合成言語(3)言語のインタープリタ (ソースを逐次解釈しながら実行する)(4)サーバーへのインタプリタ (ソースを逐次解釈しながら実行する)(5)アプリケーション全体

Page 8: Ssaw08 0624

sclang (クライアント) と scsynth (サーバー)

• SCは、クライアント/サーバー方式• 両者はOSCメッセージをやりとりすることでコミュニケーションしている

Page 9: Ssaw08 0624

sclang (クライアント) と scsynth (サーバー)

• SCサーバーは、SuperColliderの言語部だけでなく、OSCを利用することのできる外部のアプリケーションからでも利用可能である

Page 10: Ssaw08 0624

SCサーバーを起動する

• 音を生成するためには、SCサーバーを起動 (boot) する必要がある• 2種類のサーバーが存在する• internal server:• クライアント内部に組みこまれているサーバー

• localhost server:• クライアントアプリとは別に切り離されて存在するサーバー

Page 11: Ssaw08 0624

SCサーバーを起動する

• internal server、localhost serverどちらかの"Boot"ボタンを押すと、サーバーが起動する• 音響合成の準備完了

Page 12: Ssaw08 0624

いろいろな括弧

• SCのプログラムで、最初にとまどう部分• 括弧がやたらと多い、しかもいろいろな種類がある• 括弧の意味の理解がSC理解のキーとなる

• それぞれの括弧には意味がある• ダブルクオーテーション " "• 文字列をあらわす

• 中括弧 { } • 関数の定義をあらわす

• 小括弧 ( )• 関数の引数、クラスの引数をあらわす• 計算順位をあらわす

• 大括弧 [ ]• 集合をあらわす• 出力チャンネルをあらわす

Page 13: Ssaw08 0624

いろいろな括弧

// 文字列"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;

Page 14: Ssaw08 0624

関数の定義

• SCで音響合成する一番楽な方法は、関数を利用するやりかた• 音響合成の方法を定義した関数を作成• SCでは関数は { } で囲むことで表現する

• 作成した関数に対して、".play" というメソッド(手続)を与えると、音響を生成する

Page 15: Ssaw08 0624

関数の定義

// 関数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

Page 16: Ssaw08 0624

関数の定義

// 440HZ、音量0.2の音を生成する関数{ SinOsc.ar(440, 0, 0.2) }.play;

// この関数を分解すると、以下のような意味合いになる({ // 関数の開始 SinOsc.ar( // サイン波をオーディオレイト(.ar)で生成する 440, // 周波数は 440HZ 0, // 位相は 0 0.2) // 音量は 0.2} // 関数を終了.play; // 'play'の命令を関数に与える)

Page 17: Ssaw08 0624

関数の定義

// 関数を変数に代入することも可能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;

Page 18: Ssaw08 0624

楽器の定義:SynthDef

• 関数.play で音は生成できる• いちばん簡単な方法• しかし、あまり応用の効くやりかたではない• あくまでテストのための簡易的な手段と考えるべき

• 楽器を定義するクラスを作成する• SynthDef:楽器を定義するクラス• オブジェクト指向 (OOP) なプログラミング手法• 最終的な出力は、Outクラスに接続する• Out.ar(バス番号, オーディオシグナル);

Page 19: Ssaw08 0624

楽器の定義: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;)

Page 20: Ssaw08 0624

楽器の定義: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;

Page 21: Ssaw08 0624

OSCを介して、SCサーバーと通信

• OSCメッセージを用いて、SCサーバーと通信して、音響を生成する• OSCメッセージの種類によって、SCサーバーは挙動を決定している• 代表的なOSCメッセージ• /s_new• SynthDefを新規にインスタンス化しノードに追加する• つまり新規に音響を生成する

• /n_free:• ノードを切断する• つまり音を停止する

• /n_set:• ノードのSynthDefクラスで定義されている引数に値を渡す

Page 22: Ssaw08 0624

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;

Page 23: Ssaw08 0624

OSCを介して、SCサーバーと通信

• それぞれの操作のタイミングでのダンプされたOSCメッセージに注目

• SynthDef.newをした時a SynthDef[ "#bundle", 1, [ "/d_recv", DATA[234], 0 ]

]

• 状態の監視[ "/status", ]

• サウンドの開始myServer[ "s_new", "sine-stereo", 1000, 0, 1 ]

Page 24: Ssaw08 0624

OSCを介して、SCサーバーと通信

• サウンドの停止myServer[ "/n_free", 1000 ]

• サーバーの停止/quit sent

[ "/quit", ][ 24, 0 ]myServer->SC_CoreAudioDriver::DriverStop<-SC_CoreAudioDriver::DriverStopRESULT = 0

Page 25: Ssaw08 0624

• MaxをSuperColliderのコントロールのためのGUIとして活用してみる• OSCを利用して、コミュニケーションする

MaxとSuperClliderの連携

OSC

音響合成ユーザ操作

Page 26: Ssaw08 0624

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);)

Page 27: Ssaw08 0624

• Max側

Max → SC:簡単な例

Page 28: Ssaw08 0624

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);)

Page 29: Ssaw08 0624

Max → SC:応用例 - レゾナンスフィルタ

• Max側

Page 30: Ssaw08 0624

• 送信側:Processing + OscP5• 受信側:SuperCollider

• Processingのアニメーションをトリガーにして、OSCを送信• その情報をもとにSCが音響合成

ProcessingとSuperClliderの連携

OSC

SCP5 + OscP5

Page 31: Ssaw08 0624

• Processing側• 画面上でマウスをクリックすると、波紋状に円が拡がるプログラム

P5 → SC (1):波紋にあわせて音を生成

Page 32: Ssaw08 0624

• Processing側• マウスからのインタラクションを以下の情報に変換• onPressedの際の• X座標 (mouseX):デチューン(左右の周波数のずれ)• Y座標 (mouseY):周波数• 円の数だけsynthDefを生成する• 常に新しいSynthIDを発行する

P5 → SC (1):波紋にあわせて音を生成

Page 33: Ssaw08 0624

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(); }}

Page 34: Ssaw08 0624

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; }}

Page 35: Ssaw08 0624

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; } } }

Page 36: Ssaw08 0624

P5 → SC (1):波紋にあわせて音を生成

void display(){ if(on){ noFill(); stroke(col); strokeWeight(4); ellipse(x, y, diameter, diameter); } }}

Page 37: Ssaw08 0624

• SC側• エンベロープのついたSine波を生成する

P5 → SC (1):波紋にあわせて音を生成

Page 38: Ssaw08 0624

//サーバー "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):波紋にあわせて音を生成

Page 39: Ssaw08 0624

• Processing側• 上下に球が弾むプログラム

P5 → SC (2):バウンドにあわせて音を鳴らす

Page 40: Ssaw08 0624

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);

Page 41: Ssaw08 0624

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; }

Page 42: Ssaw08 0624

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);

Page 43: Ssaw08 0624

P5 → SC (2):バウンドにあわせて音を鳴らす

ellipse(x, y, diameter, diameter); }}

Page 44: Ssaw08 0624

• SC側• エンベロープのついたSine波を生成する

P5 → SC (2):バウンドにあわせて音を鳴らす

Page 45: Ssaw08 0624

//サーバー "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):波紋にあわせて音を生成