Processing用OSCユーティリティ

一昨日がなんでSound&Visionなのか、っていうと、まあ、昨日のsoftpadのライブに向けて"i'm waiting for a gift of sound and vision."状態だったわけです。。。
今回のライブはほぼP5。FullScreenがうまくいかない、とか、Alpha版つかってたら閉じるときに保存の警告がでなくて、リハ直前にコードが吹っ飛ぶとかトラブルはあった訳ですが、乗り切りました! 多分。
で、それにあたってちょっと便利なコード書いたので必要な方どうぞー。


Processingの場合、パラメータかえるのにもいちいちコンパイルし直さなきゃ行けなかったりでVJなんかで使うのはなかなか大変。Maxからコントロールできれば、その辺現場でもインプロできるので便利。で、OSCを使ってProcessingをMaxからコントロールするのに、oscEventでif else if else ifなんて書いて行くのはしんどい。plugでマッピングしてくのも同様。そんなんでpublicフィ−ルドをごりごりとMaxから変更できると便利だな、と。

まず、javaのutilパッケージとlang.reflectパッケージをimport。oscなので、oscP5のパッケージも。

import java.util.*;
import java.lang.reflect.*;

import oscP5.*;
import netP5.*;

で、ここから表示用クラスの親クラスとしてOscControlledを定義

class OscControlled{

  private Map fields;

  public OscControlled(String pattern, OscP5 oscP5){
    initFields();
    bindOsc(pattern, oscP5);
  }

  private void initFields(){
    fields = new HashMap();
    Field[] f = this.getClass().getFields();
    for(int i=0; i<f.length; i++){
      fields.put(f[i].getName(), f[i]);
    }
  }

  private void bindOsc(String pattern, OscP5 oscP5){
    oscP5.plug(this, "setParams", pattern);
  }

  public void setParams(String name, float value){
    Field f = (Field)fields.get(name);
    if(f != null){
      try{
        f.setFloat(this, value);
      }
      catch(Exception e){
        e.printStackTrace();
      }
    }
  }
}

reflectするコストを考えてあらかじめフィールドをMapにキャッシュしてるんだけど必要ないかも。


で、それを継承した表示用クラス

class Circle extends OscControlled{
  public float alpha;
  public float size;
  
  public Circle(OscP5 oscP5){
    super("/Circle", oscP5);
  }
  public void setParams(String name, float value){
    super.setParams(name, value);
  }
  public void draw(){
    if(alpha <= 0){
      return;
    }
    noStroke();
    fill(255, alpha);
    ellipseMode(CENTER);
    ellipse(width/2, height/2, size, size)
  }
}

なんか、plugするメソッドをサブクラスでもオーバーライドしてあげないとうまくplugさせられなかったので、ちょっと冗長ですがそのまんまsetParamsメソッドをオーバーライド。

で、setup、draw

OscP5 oscP5;
Circle circle;

void setup(){
  size(1024, 768);

  oscP5 = new OscP5(this, 12000);
  circle = new Circle(oscP5);
}
void draw(){
  background(0);
  circle.draw();
}

で、Maxからは

で、OKです。MaxからCircleクラスのpublicフィールドをがりがり変更できます。
とりあえず、floatが送れればいいやー、と思ってfloatのpublicフィールドにしか対応してません。その辺の型チェックも合った方がもちろんいいんだろうけど。とか、既存のものに組み込むことも考えて継承スタイルではなくてHelperクラスにした方がいいのかも、だけど。


この例の場合はCircleクラスにフィールドが2つしかないからどうってことないけども、8つとか10とか数多くパラメータがある場合とか、表示用のクラスを沢山管理しなきゃ行けない、とかの場合には便利。