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座標の情報と、画面を押した場合と離した場合の情報が送られます。
![](https://r-dimension.xsrv.jp/classes_j/wp-content/uploads/2020/06/IMG_0001-2-225x300.png)
![](https://r-dimension.xsrv.jp/classes_j/wp-content/uploads/2020/06/IMG_0001-225x300.png)
受信側(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 );
}