芸大 – メディアアート・プログラミング 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);
}
}
