yoppa.org


芸大 – メディアアート・プログラミング 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クラスのリスト
ArrayList ringList = 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);
  }
}