ofxOscを使ったネットワーク上のデータ送受信

      ofxOscを使ったネットワーク上のデータ送受信 はコメントを受け付けていません

OSC(Open Sound Control)とは

OSC(Open Sound Control)とは、ネットワークを通してデータの送受信を行うプロトコルです。つぎのようなデータを送るための仕組みです。仕組みがシンプルなので、様々なプラットフォーム間のデータの送受信につかわれており、代表的なものだけでも以下の環境があります。

  • Max
  • openFrameworks
  • Pure Data
  • TouchDesigner
  • Processing

アドレスパターン

データの送受信を行う際には、アドレスパターンをまず設定して、その次に値(引数)を送るという、二段階のステップを踏みます。アドレスパターンは以下のようにURLと同じようなパスで区切られる階層構造をしています。そして、この階層は自由に増やすことができます。例えば以下のような階層が考えられるでしょう。

  • /mouse/position
  • /mouse/button
  • /sensors/arduino/a
  • /sensors/arduino/b

引数

送信側から受信側に渡す引数は、型を明示する必要があります。例えば、以下のメソッドがあります。とりあえず4つ覚えておけば問題ないでしょう。

  • addIntArg(int)
  • addFloatArg(float)
  • addStringArg(string)
  • addBoolArg(bool)

ofxOscをプロジェクトに追加(インクルード)する

ofxOscは標準でaddonフォルダの中に入っていますが、新しくプロジェクトを作る時には追加(インクルード)する必要があります。送信側、受信側双方のプログラムにofxOscを追加してください。以下はofxGuiという、別のaddon追加の解説ですが、ofxOscも同じ手順で追加してみましょう。

https://r-dimension.xsrv.jp/classes_j/of_addons/

送信側(Sender)のプログラム【iOS】

まずはofApp.hで送信先のIPアドレス(host)とポートを設定します。送信先のiOSデバイスのIPアドレスは以下の記事を参考にして調べてみましょう。このレジュメでは「10.0.1.7」にしています。

https://www.akakagemaru.info/port/ipad.html

注意!)受信側がPCになる場合には、PCのIPアドレスを調べて、送信側のプログラムに登録してください。以下のサイトが参考になります。

https://pc-karuma.net/mac-ip-address/

ofApp.h

#pragma once

#include "ofxiOS.h"
#include "ofxOsc.h"

#define HOST "10.0.1.7"  //送信先のiOSデバイスのIPアドレス
#define PORT 12345

class ofApp : public ofxiOSApp {

	public:
		void setup();
		void update();
		void draw();
		void exit();
		
		void touchDown(ofTouchEventArgs & touch);
		void touchMoved(ofTouchEventArgs & touch);
		void touchUp(ofTouchEventArgs & touch);
		void touchDoubleTap(ofTouchEventArgs & touch);
		void touchCancelled(ofTouchEventArgs & touch);

		void lostFocus();
		void gotFocus();
		void gotMemoryWarning();
		void deviceOrientationChanged(int newOrientation);

		ofxOscSender sender;
        int cX, cY; //円のx, y座標
};

次に、ofApp.mmのsetup()で、ポートの使用開始を宣言します。

ofApp.mm

void ofApp::setup(){
    
    //画面の向きを左に90度回転
	ofSetOrientation(OF_ORIENTATION_90_LEFT);
    
	// ポートを開く
	sender.setup( HOST, PORT );
}

draw()で、円を描画します。

void ofApp::draw(){
    ofBackground( 40, 100, 40 );
    
    ofSetColor(255);
    ofDrawCircle(cX, cY, 50);   //円を描画
}

touchDown()で、アドレスパターンの”/mouse/button”を送り、その次に値である”down”を送ります。

void ofApp::touchDown(ofTouchEventArgs & touch){
	ofxOscMessage m;
	m.setAddress( "/mouse/button" );
    //receiverに"down"を渡す
	m.addStringArg( "down" );   //文字列を渡すときはaddStringArgを使う
	sender.sendMessage( m );
}

touchMoved()では、画面を触っている箇所のx, y座標を送ります。

void ofApp::touchMoved(ofTouchEventArgs & touch){
	ofxOscMessage m;
	m.setAddress( "/mouse/position" );
	m.addIntArg( touch.x ); //int型の値を渡すときはaddIntArgを使う
	m.addIntArg( touch.y );
	sender.sendMessage( m );
    
    cX = touch.x;
    cY = touch.y;
}

touchUp()では、アドレスパターンの”/mouse/button”を送り、その次に値である”up”を送ります。

void ofApp::touchUp(ofTouchEventArgs & touch){
	ofxOscMessage m;
	m.setAddress( "/mouse/button" );
	m.addStringArg( "up" );
	sender.sendMessage( m );
}

ofApp.mmは最終的に以下になります。

//--------------------------------------------------------------
void ofApp::setup(){
    
    //画面の向きを左に90度回転
	ofSetOrientation(OF_ORIENTATION_90_LEFT);
    
	// ポートを開く
	sender.setup( HOST, PORT );
}

//--------------------------------------------------------------
void ofApp::update(){

}

//--------------------------------------------------------------
void ofApp::draw(){
    ofBackground( 40, 100, 40 );
    
    ofSetColor(255);
    ofDrawCircle(cX, cY, 50);   //円を描画
}

//--------------------------------------------------------------
void ofApp::exit(){

}

//--------------------------------------------------------------
void ofApp::touchDown(ofTouchEventArgs & touch){
	ofxOscMessage m;
	m.setAddress( "/mouse/button" );
    //receiverに"down"を渡す
	m.addStringArg( "down" );   //文字列を渡すときはaddStringArgを使う
	sender.sendMessage( m );
}

//--------------------------------------------------------------
void ofApp::touchMoved(ofTouchEventArgs & touch){
	ofxOscMessage m;
	m.setAddress( "/mouse/position" );
	m.addIntArg( touch.x ); //int型の値を渡すときはaddIntArgを使う
	m.addIntArg( touch.y );
	sender.sendMessage( m );
    
    cX = touch.x;
    cY = touch.y;
}

//--------------------------------------------------------------
void ofApp::touchUp(ofTouchEventArgs & touch){
	ofxOscMessage m;
	m.setAddress( "/mouse/button" );
	m.addStringArg( "up" );
	sender.sendMessage( m );
}

受信側(Receiver)のプログラム【iOS】

ここでは、iOSデバイス同士を接続します。ofApp.hでは、受信用のreceiver、円のx, y座標であるcX、cY、マウスボタンの状態を格納するmouseButtonStateを宣言します。

ofApp.h

#pragma once

#include "ofxiOS.h"
#include "ofxOsc.h"

//受信ポートは12345
#define PORT 12345

class ofApp : public ofxiOSApp {

	public:
		void setup();
		void update();
		void draw();
		void exit();
		
		void touchDown(ofTouchEventArgs & touch);
		void touchMoved(ofTouchEventArgs & touch);
		void touchUp(ofTouchEventArgs & touch);
		void touchDoubleTap(ofTouchEventArgs & touch);
		void touchCancelled(ofTouchEventArgs & touch);

		void lostFocus();
		void gotFocus();
		void gotMemoryWarning();
		void deviceOrientationChanged(int newOrientation);

		ofxOscReceiver receiver;

        int cX; //円のx, y座標
        int cY;
		string mouseButtonState;    //ボタンのON/OFF
};

次に、ofApp.mmのsetup()の中を書きます。ここでは、受信の設定を行います。

ofApp.mm

void ofApp::setup(){
    
    //画面の向きを左に90度回転
	ofSetOrientation(OF_ORIENTATION_90_LEFT);

	// 設定されたポートを設定
	cout << "listening for osc messages on port " << PORT << "\n";
	receiver.setup( PORT );

	//変数の初期化
    cX = 0;
	cY = 0;
	mouseButtonState = "";
}

update()では、送信側からデータが送られてくるのを待ち、受信したらアドレスパターンを読んで、それぞれの変数に格納します。

void ofApp::update(){
    
	//senderからメッセージが送られてくるまで待機
	while( receiver.hasWaitingMessages() ){
		// 次のメッセージを取得
		ofxOscMessage m;
		receiver.getNextMessage(m);

		// マウスが動いたかをチェック
		if( m.getAddress() == "/mouse/position" ){
			// both the arguments are int32's
			cX = m.getArgAsInt32( 0 );
			cY = m.getArgAsInt32( 1 );
		}
		// マウスのON/OFFをチェック
		else if( m.getAddress() == "/mouse/button" ){
			// the single argument is a string
			mouseButtonState = m.getArgAsString( 0 ) ;
		}
	}	
}

draw()で描画します。

void ofApp::draw(){
    ofBackground( 30, 30, 130 );

    ofSetColor(255);
    ofDrawCircle(cX, cY, 50);

    ofSetColor(255, 0, 0);
	ofDrawBitmapString( mouseButtonState, 580, 20 );
}

ofApp.mmの最終的なコードは以下です。

//--------------------------------------------------------------
void ofApp::setup(){
    
    //画面の向きを左に90度回転
	ofSetOrientation(OF_ORIENTATION_90_LEFT);

	// 設定されたポートを設定
	cout << "listening for osc messages on port " << PORT << "\n";
	receiver.setup( PORT );

	//変数の初期化
    cX = 0;
	cY = 0;
	mouseButtonState = "";
}

//--------------------------------------------------------------
void ofApp::update(){
    
	//senderからメッセージが送られてくるまで待機
	while( receiver.hasWaitingMessages() ){
		// 次のメッセージを取得
		ofxOscMessage m;
		receiver.getNextMessage(m);

		// マウスが動いたかをチェック
		if( m.getAddress() == "/mouse/position" ){
			// both the arguments are int32's
			cX = m.getArgAsInt32( 0 );
			cY = m.getArgAsInt32( 1 );
		}
		// マウスのON/OFFをチェック
		else if( m.getAddress() == "/mouse/button" ){
			// the single argument is a string
			mouseButtonState = m.getArgAsString( 0 ) ;
		}
	}	
}

//--------------------------------------------------------------
void ofApp::draw(){
    ofBackground( 30, 30, 130 );

    ofSetColor(255);
    ofDrawCircle(cX, cY, 50);

    ofSetColor(255, 0, 0);
	ofDrawBitmapString( mouseButtonState, 580, 20 );
}

送信側のiOSデバイス画面に触れると、x, y座標の情報と、画面を押した場合と離した場合の情報が送られます。

送信側(Sender)
受信側(Receiver)

受信側(Receiver)のプログラム【macOS】

ここでは、iOSデバイスを送信側とした場合に、受信側をmacOSにする場合のプログラムを考えてみます。実は、iOSデバイス同士を使う場合とコードはほとんど一緒になります。

ofApp.h

#pragma once

#include "ofMain.h"
#include "ofxOsc.h"

//受信ポートは12345
#define PORT 12345

class ofApp : public ofBaseApp{
	public:

		void setup();
		void update();
		void draw();

		void keyPressed(int key);
		void keyReleased(int key);
		void mouseMoved(int x, int y);
		void mouseDragged(int x, int y, int button);
		void mousePressed(int x, int y, int button);
		void mouseReleased(int x, int y, int button);
		void mouseEntered(int x, int y);
		void mouseExited(int x, int y);
		void windowResized(int w, int h);
		void dragEvent(ofDragInfo dragInfo);
		void gotMessage(ofMessage msg);

		ofTrueTypeFont font;
		ofxOscReceiver receiver;

		int cX = 0; //円のx, y座標
		int cY = 0;
		string mouseButtonState = "";    //ボタンのON/OFF
};

ofApp.cpp

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
	ofSetWindowTitle("oscReceiveExample");
	ofSetVerticalSync(true);

    // 設定されたポートを表示
	ofLog() << "listening for osc messages on port " << PORT;
	receiver.setup(PORT);
    
    //変数の初期化
    cX = 0;
    cY = 0;
    mouseButtonState = "";
}

//--------------------------------------------------------------
void ofApp::update(){

    //senderからメッセージが送られてくるまで待機
	while(receiver.hasWaitingMessages()){

        // 次のメッセージを取得
		ofxOscMessage m;
		receiver.getNextMessage(m);

        // マウスが動いたかをチェック
		if(m.getAddress() == "/mouse/position"){

            // int型の値が送られてくる
			cX = m.getArgAsInt32(0);
			cY = m.getArgAsInt32(1);
		}
        // マウスが押されたか押されていないかをチェック
		else if(m.getAddress() == "/mouse/button"){

            // string型の値が送られてくる
			mouseButtonState = m.getArgAsString(0);
		}
	}
}

//--------------------------------------------------------------
void ofApp::draw(){
    ofBackground( 30, 30, 130 );
    
    ofSetColor(255);
    ofDrawCircle(cX, cY, 50);   //円を描画

    //マウスの状態を表示
    ofSetColor(255, 0, 0);
    ofDrawBitmapString( mouseButtonState, ofGetWidth()/2, ofGetHeight()/2 );
}