OSC通信

Author: mucho

こんにちは。muchoです。もうすぐお花見のシーズンですね。

さてさて、cinderにはフルスクリーンになる機能があるんですが、
プロジェクターや別のモニターでフルスクリーンにして、
手元のPCでフルスクリーン画面の方をコントロールしたい!
ということでアプリが2個になってしまうのですが、
描画プログラムとパラメーターを制御するプログラムと分割してみました。

OSCはデフォルトのままでは動かないので、blocks以下にライブラリを入れてください。
ライブラリはこちらから
https://github.com/cinder/Cinder/tree/master/blocks/osc

追加リンカファイル
$(CINDER_PATH)/blocks/osc/lib/macosx/osc.a

追加インクルード
$(CINDER_PATH)/blocks/osc/include

OSCでの通信は以下のデータを使います。
・送信先(IPアドレス)
・ポート
・アドレス(変数名のようなもの)
・値の型(int,float,stringのいずれか)
・値

以下の抜粋サンプルではアドレスをプログラムの固有IDと変数名から生成するような
形にしてます。

[code lang="cpp"]

//-----------------------------------------------------
// senderApp

#include "OscSender.h"

class senderAPP : public AppBasic {
  public:
	void setup();
	void update();
	
	void sendString(string address, vector arg);
	void sendInt(string address, vector arg);
	void sendFloat(string address, vector arg);

	osc::Sender	sender;
	std::string	host;
	std::string	prefix;
	int		port;
};

void senderAPP::setup()
{
	host = "localhost";
	prefix = "/devjam_osc";
	port = 3000;
	sender.setup(host, port);
}

void senderApp::update()
{
	sendFloat("quat", wxyz);
	sendFloat("colora", rgba);
	sendFloat("position", xyz);
}

void senderApp::sendString(string address, vector arg)
{
	osc::Message message;
	message.setRemoteEndpoint(host, port);
	message.setAddress(prefix + "/" + address);
	for(int i = 0; i < arg.size(); i++){
		message.addStringArg(arg[i]);
	}
	sender.sendMessage(message);
}

void senderApp::sendInt(string address, vector arg)
{
	osc::Message message;
	message.setRemoteEndpoint(host, port);
	message.setAddress(prefix + "/" + address);
	for(int i = 0; i < arg.size(); i++){
		message.addIntArg(arg[i]);
	}
	sender.sendMessage(message);
}

void senderApp::sendFloat(string address, vector arg)
{
	osc::Message message;
	message.setRemoteEndpoint(host, port);
	message.setAddress(prefix + "/" + address);
	for(int i = 0; i < arg.size(); i++){
		message.addFloatArg(arg[i]);
	}
	sender.sendMessage(message);
}

//-----------------------------------------------------
// listenerApp

#include "OscListener.h"

class listenerApp : public AppBasic {
  public:
	void prepareSettings( Settings *settings );
	void setup();
	void update();

	osc::Listener	listener;
	std::string	prefix;
};

void listenerApp::prepareSettings( Settings *settings )
{
	settings->enableSecondaryDisplayBlanking( false );
}

void listenerApp::setup()
{
	prefix = "devjam_osc";
	listener.setup(3000);
}

void listenerApp::update()
{
	while (listener.hasWaitingMessages()) {
		osc::Message message;
		listener.getNextMessage(&message);
		string adr = message.getAddress();
		vector substrings = split(adr, "/");
		if(substrings[0] == prefix){

			if(substrings[1] == "quat") {
				float qw = message.getArgAsFloat(0);
				float qx = message.getArgAsFloat(1);
				float qy = message.getArgAsFloat(2);
				float qz = message.getArgAsFloat(3);
				Quaternion oscQuat = Quaternion(qw, qx, qy, qz);
			}
			
			if(substrings[1] == "colora") {
				float vr = message.getArgAsFloat(0);
				float vg = message.getArgAsFloat(1);
				float vb = message.getArgAsFloat(2);
				float va = message.getArgAsFloat(3);
				ColorA oscColor = ColorA(vr, vg, vb, va);
			}
			
			if(substrings[1] == "position") {
				float px = message.getArgAsFloat(0);
				float py = message.getArgAsFloat(1);
				float pz = message.getArgAsFloat(2);
				Vec3f oscPos = Vec3f(px, py, pz);
			}
		}
	}
}

[/code]

そして・・・できたサンプルがこちら左が送信側プログラム、右が受信側です。

にしてもインターフェースを作るにはcinderは不向きなので、
コントローラー側はflashで作ろうと思います。