ブラウザからWebSocketとOSCを使ってMAXを操作してみる

# ブラウザからWebSocketとOSCを使ってMAXを操作してみる

## モチベーション

- 久々にMax触りたいので、コントローラ募集中。うちにiPhone×2+iPod touch 5th×1がある！コレ使いたい。というか、iOSしかない！w
- [iOSC](http://recotana.com/iphone/iosc/ja/)は素晴らしいし大好きだが、自分でもUI作ってみたい
- でもiPhoneのネイティブアプリ作りたくないのでブラウザでやりたい。
- インターネットに出て行くなんて使い方はしないので、レイテンシーなんとかなるはず！
- ブラウザで作れるようにしとけば、iPhoneだけでなく、ブラウザ+Arduino+センサ、Web MIDIとか、WebRTCとか、いろいろと夢(妄想)が広がる！

というわけで、自分以外に誰も得な人が居ないと思われる記事ですw

## レイテンシー気にせず変換作戦！

↓こんな風に途中で変換すれば、なんとかなるはず！という作戦です。

![なんとかなって欲しい図](http://img.dfm.lrv.jp/osc/title.png)

MaxをWebSocketに対応させる方が良いのかもしれませんが、応用効かないのであまりやりたくないし。
レイテンシーは仕方ありませんので、ある程度は目をつぶる方針です。速さを求めるならOSCを組み込んだNativeアプリの方が良いです。

### 使ったもの

- MacとiPhone少々
- 比較的高速なWLAN環境
- [node.js](http://nodejs.org/)
- [Max6](http://cycling74.com/products/max/)
- [ws](https://github.com/einaros/ws)
- [omgosc](https://github.com/deanm/omgosc)

こんな感じです。

### 1) 「WebSocketを受けてOSCで送る君」をnode.jsで作る

まず、サーバから作ります。
Node.jsとnpmは入っている前提です。
wsとomgoscを入れましょう。

```
> npm install ws
> npm install omgosc
```

あとは「WebSocketを受けてOSCで送る君」を書くだけです。

```js
var hosturl = "0.0.0.0";
var wsport = 3100;
var oscport = 8000;

// WebSocket Serverを立ち上げる
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({host:hosturl, port:wsport});

// OSC Senderを立ち上げる
var oscsender = require('omgosc').UdpSender;
var sender = new oscsender(hosturl, oscport);

// WebSocketのイベントハンドラ
wss.on('connection', function (ws) {
    ws.on('message', function (message) {
        console.log(message);
        var mes = JSON.parse(message);
        if(mes.osc){    // チェック甘！
        		// OSCで送信
            sender.send(mes.path,mes.type,[mes.data]);
        }
    });
});
```

はい。できました。
これを、`server.js` など、適当な名前で保存して、コマンドラインから

```
> node server.js
```

と入力して実行します。

### 2) OSCを受け取る側(ここではMax)のパッチ

server.jsが、UDPに変換してくれるので、Max側ではOSC対応コントローラと繋ぐ時と同じ要領で普通にパッチが作れます。
念のため、server.jsに指定したOSC送信先ポート番号だけ間違わないようにしてください。

今回の例では、server.jsが8000番にOSCを送りつけてくるので、受け取るMax側も`udpreceive 8000` で受けとる必要があります。

![データが届いたことを確認するだけのパッチ](http://img.dfm.lrv.jp/osc/maxpatch.png)


### 3) コントローラとなるWebページを作る

最後にWebページです。
WebSocketをSever.jsに送りつけるところだけ紹介します。

```js
// server.jsは同じドメインに居る前提。
var url = window.document.location.host.replace(/:.*/, '');
var wsport = 3100;	// WebSocketのPort番号

// WebSocket開始
var wsOsc = {};
wsOsc.ws = new WebSocket('ws://' + url + ':'+wsport);
wsOsc.status = 0;		// 0: 送れる 1: 送れない
wsOsc.ws.onopen = function(){
	wsOsc.status = 1;	// 送れる
};
wsOsc.ws.onclose = function(){
	wsOsc.status = 0;	// 送れない
};
wsOsc.send = function(path,type,data){
	var jsonobj = {"osc":"WsOscSend","path":path,"type":type,"data":data};
	var json = JSON.stringify(jsonobj);

	// 送れれば送る
	if(wsOsc.status){
		wsOsc.ws.send(json);
	}
};

// 送るところ。(jQuery使ってます)
var toggle = 0;
$(function() {
  // iPhone用(てぬき)
	$('#bt1').bind('touchstart', function(event) {
		event.preventDefault();

		// ここで送信。
		wsOsc.send('/osc/button1','i',[toggle]);
		if(toggle == 0){
			toggle = 1;
		}else{
			toggle = 0;
		}
	});
});

```

。。。てきと〜なコードですいませんw
やってることは下記のようなことです。

- WebSocketのコネクションを貼る
- OSCメッセージは、一旦JSONにシリアライズする
- JSONシリアライズしたデータをWebSocketで送る

#### 通信じゃないところにもレイテンシーの原因があるので注意！

今回これを作ってて気付いたのですが、`onClick`とかを使うと反応がメチャメチャ悪くなります。
サンプルコードでは面倒くさがって`touchstart`にイベントを仕掛けましたが、クリック操作にしたい場合、[fastclick](https://github.com/ftlabs/fastclick)とかを使った方が良いと思いました。


### 動かしてみた感想

<a href="http://instagram.com/p/qGjjJ0nCuA/"><img src="http://img.dfm.lrv.jp/osc/movie.png"></a>

確かにレイテンシーありますけど、使い道はあるんじゃないかな〜？w


## まとめ

Node.js+WebSocket素晴らしいですね。

オマケ：[MIDIでやってる人](http://vimeo.com/38274225)も居ました。

## 2015.02.26 追記

パッケージを公開してる人が居ました！（仕組みは同じっぽい）
[osc-web](http://automata.cc/osc-web)
自分でいちから作るの面倒！という方は試してみよう！
さっそく試してみます！！←お前もか！！w