芸大 – メディアアート・プログラミング I 2017
第9回 作品への応用2: oscP5 – OSCによるアプリケーション間通信
今回は、ネットワークを活用したサンプルを紹介します。Open Sound Control(OSC)というプロトコルを使用して、アプリケーション同士をネットワークを介して通信する方法について解説します。これにより、Processingのスケッチ間で通信したり、複数のユーザが1つのスケッチを遠隔操作することが可能となります。またProessingのスケッチを他のアプリケーション、例えば、Sonic Pi、Max/MSPやPd、SuperColliderなどの音楽アプリケーション、さらにはTouchOSCといったiPhoneアプリなどからコントロールすることが出来るようになります。
Sonic Piのダウンロードは下記のURLから行ってください。
スライド資料
サンプルプログラム
01 OSC基本、送信側
//OSC関連のライブラリーをインポート import oscP5.*; import netP5.*; //OSCP5クラスのインスタンス OscP5 oscP5; //OSC送出先のネットアドレス NetAddress myRemoteLocation; void setup() { size(800,600); frameRate(60); //ポートを12000に設定して新規にOSCP5のインスタンスを生成 oscP5 = new OscP5(this,12000); //OSC送信先のIPアドレスとポートを指定 myRemoteLocation = new NetAddress("127.0.0.1",12000); } void draw() { if(mousePressed){ background(255, 0, 0); } else { background(0); } //マウスの場所に円を描く noFill(); stroke(255); ellipse(mouseX, mouseY, 10, 10); //現在のマウスの位置をOSCで送出 //新規にメッセージ作成 OscMessage msg = new OscMessage("/mouse/position"); msg.add(mouseX); //X座標の位置を追加 msg.add(mouseY); //Y座標の位置を追加 //OSCメッセージ送信 oscP5.send(msg, myRemoteLocation); } //マウスボタンを押した時にメッセージを送信 void mousePressed(){ OscMessage msg = new OscMessage("/mouse/cliked"); msg.add(1); //1を送信 //OSCメッセージ送信 oscP5.send(msg, myRemoteLocation); } //マウスボタンを離した時にメッセージを送信 void mouseReleased(){ OscMessage msg = new OscMessage("/mouse/cliked"); msg.add(0); //0を送信 //OSCメッセージ送信 oscP5.send(msg, myRemoteLocation); }
02 OSC基本、受信側
import oscP5.*; import netP5.*; //OSCP5クラスのインスタンス OscP5 oscP5; //マウスの位置ベクトル PVector mouseLoc; //マウスのクリック検知 int clicked; void setup() { size(800,600); frameRate(60); //ポートを12000に設定して新規にOSCP5のインスタンスを生成 oscP5 = new OscP5(this,12000); //マウスの位置ベクトルを初期化 mouseLoc = new PVector(width/2, height/2); //マウスのクリック状態を初期化 clicked = 0; } void draw() { if(clicked == 1){ background(255, 0, 0); } else { background(0); } //OSCで指定された座標に円を描く noFill(); stroke(255); ellipse(mouseLoc.x, mouseLoc.y, 10, 10); } //OSCメッセージを受信した際に実行するイベント void oscEvent(OscMessage msg) { //もしOSCメッセージが /mouse/position だったら if(msg.checkAddrPattern("/mouse/position")==true) { //最初の値をint方としてX座標に mouseLoc.x = msg.get(0).intValue(); //次の値をint方としてY座標に mouseLoc.y = msg.get(1).intValue(); } if(msg.checkAddrPattern("/mouse/cliked")==true) { //Bool値を読み込み clicked = msg.get(0).intValue(); println("msg = " + clicked); print("*"); } }
03 OSC受信応用 – 拡がる波紋
import oscP5.*; import netP5.*; //OSCP5クラスのインスタンス OscP5 oscP5; //マウスの位置ベクトル PVector mouseLoc; //Ringクラスのリスト ArrayListringList = new ArrayList (); void setup() { size(800, 600); frameRate(60); //ポートを12000に設定して新規にOSCP5のインスタンスを生成 oscP5 = new OscP5(this,12000); //マウスの位置ベクトルを初期化 mouseLoc = new PVector(width/2, height/2); } void draw() { background(0); noFill(); stroke(255); strokeWeight(1); ellipse(mouseLoc.x, mouseLoc.y, 10, 10); //リストに格納されたマウスの位置を全て描画する strokeWeight(2); for (int i = 0; i < ringList.size(); i++) { ringList.get(i).draw(); } } //OSCメッセージを受信した際に実行するイベント void oscEvent(OscMessage msg) { //もしOSCメッセージが /mouse/position だったら if (msg.checkAddrPattern("/mouse/position")==true) { //最初の値をint方としてX座標に mouseLoc.x = msg.get(0).intValue(); //次の値をint方としてY座標に mouseLoc.y = msg.get(1).intValue(); } if (msg.checkAddrPattern("/mouse/cliked")==true) { //もしマウスがクリックされたメッセージを受けとったら if (msg.get(0).intValue() == 1) { //マウスの位置のリストに新規に現在の位置を追加する ringList.add(new Ring(mouseLoc.x, mouseLoc.y)); } } } class Ring { PVector location; float radius; float speed; float alpha; float alphaSpeed; float release; Ring(PVector _location) { location = new PVector(); location = _location; radius = 20; speed = 1.0; alpha = 255; alphaSpeed = 1.0; } void draw() { alphaSpeed = 255.0/(release*frameRate); fill(63, 127, 255, alpha); noStroke(); pushMatrix(); translate(location.x, location.y); ellipse(0, 0, radius, radius); popMatrix(); radius += speed; alpha -= alphaSpeed; strokeWeight(1.0); } }
04 Sonic PiへOSCを送信 - 基本
import oscP5.*; import netP5.*; OscP5 oscP5; NetAddress location; void setup() { size(400, 400); frameRate(60); //OSCのセットアップ oscP5 = new OscP5(this, 12000); //SonicPiの受信ポート4557に送信 location = new NetAddress("127.0.0.1", 4557); } void draw() { } void mousePressed() { //ド(C)の音を演奏させる OscMessage msg = new OscMessage("/run-code"); msg.add("fromP5"); msg.add("play 60"); oscP5.send(msg, location); println(msg); }
05 Sonic PiへOSC送信 - マウスで音程とパンを操作
import oscP5.*; import netP5.*; OscP5 oscP5; NetAddress location; void setup() { size(640, 480); //OSCのセットアップ oscP5 = new OscP5(this, 12000); //SonicPiの受信ポート4557に送信 location = new NetAddress("127.0.0.1", 4557); background(0); } void draw() { } void mousePressed() { //マウスのX座標で定位(パン)を決定 float pan = map(mouseX, 0, width, -1, 1); //マウスのY座標でノートナンバーを決定 float note = map(mouseY, 0, width, 80, 50); //OSCメッセージを送信 OscMessage msg = new OscMessage("/run-code"); msg.add("fromP5"); msg.add("play "+ note + ", pan: "+ pan); oscP5.send(msg, location); }
06 Sonic PiへOSC送信 - 表示の工夫
import oscP5.*; import netP5.*; OscP5 oscP5; NetAddress location; float note; //ノート番号 float pan; //パン void setup() { size(640, 480); oscP5 = new OscP5(this, 12000); location = new NetAddress("127.0.0.1", 4557); } void draw() { background(0); stroke(255); //マウスの位置を表示 line(mouseX, 0, mouseX, height); line(0, mouseY, width, mouseY); ellipse(mouseX, mouseY, 10, 10); //マウスの位置から、ノート番号とパンを決定 note = map(mouseY, 0, width, 80, 50); pan = map(mouseX, 0, width, -1, 1); //テキストで表示 text("note = " + note + ", pan = " + pan, mouseX + 10, mouseY-10); } void mousePressed() { //OSCを送信 OscMessage msg = new OscMessage("/run-code"); msg.add("fromP5"); msg.add("play "+ note + ", pan: "+ pan); oscP5.send(msg, location); println(msg); }
07 Sonic PiへOSC送信 - 自動演奏
import oscP5.*; import netP5.*; OscP5 oscP5; NetAddress location; float note; float pan; void setup() { size(640, 480); frameRate(60); oscP5 = new OscP5(this, 12000); location = new NetAddress("127.0.0.1", 4557); } void draw() { background(0); int speed = 8; //8フレームに一度実行 if (frameCount % speed == 0) { //ランダムなノート番号とパンを設定 note = random(50, 80); pan = random(-1, 1); //OSCを送信 OscMessage msg = new OscMessage("/run-code"); msg.add("fromP5"+frameCount); msg.add("play "+ note + ", pan: "+ pan); oscP5.send(msg, location); println(msg); } }
08 Sonic PiへOSC送信 - 自動演奏 + ビジュアライズ
import oscP5.*; import netP5.*; OscP5 oscP5; NetAddress location; float note; float pan; ArrayList< Ring > rings; int MAX = 16; void setup() { size(800, 600); frameRate(60); oscP5 = new OscP5(this, 12000); location = new NetAddress("127.0.0.1", 4557); rings = new ArrayList< Ring >(); } void draw() { background(0); int speed = 8; if (frameCount % speed == 0) { note = int(random(50, 80)); pan = random(-1, 1); OscMessage msg = new OscMessage("/run-code"); msg.add("fromP5"+frameCount); msg.add("play "+ note + ", pan: "+ pan); oscP5.send(msg, location); println(msg); float x = map(pan, -1, 1, width/4, width/4*3); float y = map(note, 40, 90, height, 0); PVector location = new PVector(x, y); Ring r = new Ring(location); r.release = 3.0; rings.add(r); } for (int i = 0; i < rings.size(); i++) { rings.get(i).draw(); } if (rings.size() > MAX) { rings.remove(0); } } class Ring { PVector location; float radius; float speed; float alpha; float alphaSpeed; float release; Ring(PVector _location) { location = new PVector(); location = _location; radius = 20; speed = 1.0; alpha = 255; alphaSpeed = 1.0; } void draw() { alphaSpeed = 255.0/(release*frameRate); fill(63, 127, 255, alpha); noStroke(); pushMatrix(); translate(location.x, location.y); ellipse(0, 0, radius, radius); popMatrix(); radius += speed; alpha -= alphaSpeed; strokeWeight(1.0); } }