音の鳴るブログ

鳴らないこともある

OSC in the browser

openFrameworks や Max/MSP, SuperCollider などで良く使われるメッセージングプロトコルOSC (Open Sound Control) というのがあって、どんなものかについては この辺 を参照して欲しいのだけど、node-osc-min というライブラリを使えば OSC のメッセージを JavaScript でも解釈できるのでそれで遊ぶ話です。

名前に node と付いているけどバージョン 0.2.0 からブラウザにも対応していて、以下のコマンドでブラウザバージョンをビルドできます。

$ git clone https://github.com/russellmcc/node-osc-min.git
$ cd node-osc-min
$ npm install --dev
$ npm run-script browserify
$ ls build
  osc-min.js  osc-min.min.js

簡単な使い方

osc.toBuffer(json)JSONからOSC形式のバイナリ(Uint8Array)に変換。

uint8 = osc.toBuffer({ address: "/message", args: [ "hello, world" ] });

osc.fromBuffer(uint8) でバイナリからJSONに変換。

JSON.stringify(osc.fromBuffer(uint8), null, 2)
// {
//   "address": "/message",
//   "args": [
//     {
//       "type": "string",
//       "value": "hello, world"
//     }
//   ],
//   "oscType": "message"
// }

こういう感じで OSC形式のバイナリデータとJSONを相互変換できる。JSONの形式はちょっと癖があるのでリポジトリのドキュメントを要参照です。

WebSocketでブラウザと接続

OSC が使えて何が嬉しいのかというと、最初にあげた openFrameworks なんかとブラウザで連携させたいときに便利です。もうちょっと具体的に言うと、いつもは openFrameworks や Max/MSP を使って作品制作をしているんだけど、その出力先として iPhone とかモバイル端末を使ってみたい。でも、JavaScript はあまり良く分からんので、お前ちょっとやってくれや。と言われたときに便利です。 ただし、直接通信させるのは困難なので、今回は WebSocket を介して openFrameworks とブラウザを socket.io 経由で接続する簡単な例を紹介します。順番に openFrameworks, サーバー(CoffeeScript), クライアント(JavaScript) のコードです。

// ofApp.h
#include "ofxOsc.h"

class ofApp : public ofBaseApp {
  // 省略
private:
  ofxOscSender sender;
}

// ofApp.cpp
void ofApp::setup(){
    sender.setup("127.0.0.1", 57120);
}

void ofApp::mousePressed(int x, int y, int button){
    ofxOscMessage m;

    m.setAddress("/synth/note");
    m.addFloatArg(440.0f);
    m.addFloatArg(0.8f);
    m.addFloatArg(2.1f);

    sender.sendMessage(m); // (1) マウスのボタンを押したらメッセージ送信
}
# server.coffee
udp = require("dgram").createSocket("udp4")
app = require("express")();
io  = require("socket.io")(app)
emitter = new require("events").EventEmitter()

sock = udp.createSocket "udp4", (msg, rinfo)->
  emitter.emit "osc", msg # (2) oFからメッセージを受信
sock.bind 57120

app.get "/", (req, res)->
  res.sendFile "index.html"

io.on "connection", (socket)->
  emitter.on "osc", (msg)->
    socket.emit "osc", msg # (3) ブラウザにメッセージを送信
app.listen 3000
// client.js in index.html
var socket = io();

socket.on("osc", function(msg) {
  emitter.emit("osc", osc.fromBuffer(msg)); // (4) メッセージを受信
});

emitter.on("osc", function(msg) {
  var val0 = msg.args[0].value;
  var val1 = msg.args[1].value;
  var val2 = msg.args[1].value;
  // (5) ここで何かする
});

クライアントの部分だけ jsFiddle で書いてみた。

neume.js example - receive osc message - JSFiddle

このサンプルは実際にソケットサーバーからOSCメッセージを受け取っているわけではなく、サンプル内で擬似的にOSCメッセージを生成して送信→受信しているけど、こういう感じのことが簡単にできる。openFrameworks や Max/MSP、それらに接続した Arduino からのデータで制御していて、しかも iPhone なんかで簡単に見たり聴いたり出来ると思えば色々と夢が広がるのではないでしょうか。

他にこういうこともやりたい

あまり良く分かってないけど、WebRTC を使って直接接続できるともっと良さそう。誰か分かる人おしえてください。

他の事例

この記事とは逆で iOS -> WebSocket -> Max/MSP のパターン。