ofxPubSubOscの使い方 (ofxSubscribeOsc編)

[ofxPubSubOsc](https://github.com/2bbb/ofxPubSubOsc) というoFのaddonを書いてまして, 最近やっとver0.3.0もリリースしたし, 今更ながら紹介記事を書いてみようと.

## もう `if(m.getAddress() == "/hoge")` って書きたくない

```cpp
// int hoge, fuga, piyo;
// receiver.setup(port);
void update() {
    ...

    ofxOscMessage m;
    while(receiver.hasWaitingMessages()) {
        receiver.getNextMessage(m);
        if(m.getAddress() == "/hoge") {
            hoge = m.getArgAsInt32(0);
        }
        else if(m.getAddress() == "/fuga") {
            fuga = m.getArgAsInt32(0);
        }
        else if(m.getAddress() == "/piyo") {
            piyo = m.getArgAsInt32(0);
        }
        ...
    }

    ...
}
```

こんなコード書いてますか？書いてますよね？
ofxPubSubOscを使うと

```cpp
// int hoge, fuga, piyo;
void setup() {
    ...

    ofxSubScribeOsc(port, "/hoge", hoge);
    ofxSubScribeOsc(port, "/fuga", fuga);
    ofxSubScribeOsc(port, "/piyo", piyo);
    ...
}
```

すっきり.

## 値が変更されたときに何か処理したい

```cpp
// int hoge;
ofxOscMessage m;
while(receiver.hasWaitingMessages()) {
    receiver.getNextMessage(m);
    if(m.getAddress() == "/hoge") {
        hoge = m.getArgAsInt32(0);
        doHoge(hoge);
    }
}
```

こういうときは無名関数を使って

```cpp
// int hoge;
ofxSubscribeOsc(port, "/hoge", [=](int val) {
    hoge = val;
    doHoge(hoge);
});
```

## OSC引数が複数ある場合

```cpp
// int hoge1;
// std::string hoge2;
// bool hoge3;
if(m.getAddress() == "/hoge") {
    hoge1 = m.getArgAsInt32(0);
    hoge2 = m.getArgAsString(1);
    hoge3 = m.getArgAsBool(2);
}
```

複数引数にも対応.

```cpp
// int hoge1;
// std::string hoge2;
// bool hoge3;
ofxSubscribeOsc(port, "/hoge", hoge1, hoge2, hoge3);
```

## `std::vector<float>` とか

### `std::vector<float>`

```cpp
// std::vector<float> xs;
if(m.getAddress() == "/xs") {
    xs.resize(m.getNumArgs());
    for(std::size_t i = 0; i < xs.size(); i++) {
        xs[i] = m.getArgAsFloat(i);
    }
}
```

```cpp
// std::vector<float> xs;
ofxSubscribeOsc(port, "/xs", xs);
```

### `ofVec4f`

```cpp
// ofVec4f v4;
if(m.getAddress() == "/vec") {
    for(std::size_t i = 0; i < 4; i++) {
        v4[i] = m.getArgAsFloat(i);
    }
}
```

そのまま渡すと

```cpp
// ofVec4f v4;
ofxSubscribeOsc(port, "/vec", v4);
```

## もっと複雑な使い方

### 受信時に追加で処理したいときは

```cpp
// int hoge1;
// std::string hoge2;
// bool hoge3;
ofxSubscribeOsc(port, "/hoge", [=](int x, std::string y, bool z) {
    hoge1 = x;
    hoge2 = y;
    hoge3 = z;
    doHogehoge();
});
```

もっとスマートに

```cpp
// int hoge1;
// std::string hoge2;
// bool hoge3;
ofxSubscribeOsc(port, "/hoge", hoge1, hoge2, hoge3, [=]{ doHogehoge(); });
```

### 前処理もしたい

受信時に追加で処理したいときは

```cpp
// int hoge1;
// std::string hoge2;
// bool hoge3;
ofxSubscribeOsc(port, "/hoge", [=](int x, std::string y, bool z) {
    wilHogeHoge();
    hoge1 = x;
    hoge2 = y;
    hoge3 = z;
    doHogehoge();
});
```

もっとスマートに

```cpp
// int hoge1;
// std::string hoge2;
// bool hoge3;
ofxSubscribeOsc(port, "/hoge", [=]{ willHogehoge(); }, hoge1, hoge2, hoge3, [=] { doHogehoge(); });
```

## 例

こんなコードが

```cpp
class ofApp : public ofBaseApp {
	ofxOscReceiver receiver;
	ofVec3f position;
	ofColor bgColor;
	ofColor fgColor;

public:
	void setup() {
		receiver.setup(26666);
	}
	void update() {
		while(receiver.hasWaitingMessages()) {
			ofxOscMessage m;
			receiver.getNextMessage(m);

			std::string address = m.getAddress();
			if(address == "/position") {
				position.x = m.getArgAsFloat(0);
				position.y = m.getArgAsFloat(1);
				position.z = m.getArgAsFloat(2);
			}
			else if(address == "/bg_color") {
				bgColor.r = m.getArgAsInt32(0);
				bgColor.g = m.getArgAsInt32(1);
				bgColor.b = m.getArgAsInt32(2);
			}
			else if(address == "/fg_color") {
				fgColor.r = m.getArgAsInt32(0);
				fgColor.g = m.getArgAsInt32(1);
				fgColor.b = m.getArgAsInt32(2);
			}
			else if(address == "/bg_auto") {
				bool b = m.getArgAsBool(0);
				ofSetBackgroundAuto(b);
			}
		}
	}
};
```

こんな感じに

```cpp
class ofApp : public ofBaseApp {
	ofxOscReceiver receiver;
	ofVec3f position;
	ofColor bgColor;
	ofColor fgColor;
	std::uint16_t port{26666};
public:
	void setup() {
		ofxSubscribeOsc(port, "/position", position);
		ofxSubscribeOsc(port, "/bg_color", bgColor);
		ofxSubscribeOsc(port, "/fg_color", fgColor);
		ofxSubscribeOsc(port, "/bg_auto", ofSetBackgroundAuto);
	}
	void update() {
	}
};
```

スマートでしょ？

## 飽きてきた

質問等のコメント付いたら答えます.

気が向いたら次は `ofxPublishOsc` について書きます.
といってももっぱら `ofxSubscribeOsc` の方がニーズがある気がするので書かないかも.