2011年12月24日土曜日

NodeがつなぐMIDIシンセサイザーとGoogleマップ

JavaScript Advent Calendar 2011(Node.js/WebSocketsコース)に急遽参戦。24日分の投稿になります。

MIDI信号をNodeで読み取り、WebSocketでブラウザに送ることで、MIDIシンセサイザーをキーボードやトラックパッドにかわる入力デバイスにすることができます。過去にもやったネタなのですが、今回はGoogleマップをシンセで動かします。Nodeみたいなイベント駆動系とハードウェアって相性がいいに決まってるじゃないですか。

まずは動画で

要はこういうことなんです。つまみのぐりぐりに連動して、マップのズームが上下していますね。

MIDI信号をNodeで読むには

node-midiモジュールを使用します。インストールは次のコマンドで。

npm install midi

RtMidiという、MIDI信号をリアルタイムに読み取るC++のライブラリをつかっています。

サーバ側

https://github.com/niccolli/MidiMaps/blob/master/midi2socketio.js

input.on('message', function(deltaTime, message) {
 // ノブをいじった信号
 if(message[0]==176 && message[1]==99){
  if(message[2]==0){ // knob X
   state = 'X';
  }
  if(message[2]==2){ // knob Y
   state = 'Y';
  }
  if(message[2]==4){ // knob Z
   state = 'Z';
  }
 }
 if(message[0]==176 && message[1]==38){
  LSB = message[2];
  switch(state){
   case 'X':
    var temp = MSB*128 + LSB;
    value = (temp-500)/5000;
    break;
   case 'Y':
    if(MSB){
     value = LSB - 28;
    } else {
     value = 100 + LSB;
    }
    value = (value-200)/1000;
    break;
   case 'Z':
    value = LSB/100*20;
    break;
   default:
    break;
  }
  io.sockets.emit('message', { state: state, value: value });
 }
}

一部抜粋で。使用するMIDIシンセサイザーに依存した記述になっています。ここではALESISのMicronを使っています。input.onはMIDI信号の受信をトリガにして呼ばれるコールバックで、前半のifで3つあるノブのどれが回ったかを記録。後半は3つのノブそれぞれ最大最小値が違うので、なんとなくごまかす処理。最後のio.sockets.emitでブラウザに値を送ります。

クライアント側

https://github.com/niccolli/MidiMaps/blob/master/map.html

socket.on('message', function(data){
 switch(data.state){
  case 'Z':
   map.setZoom(Math.round(data.value));
   break;
  default:
   break;
 }
});

こちらも一部抜粋。GoogleマップのsetZoomにそのままつっこむと、上記の動画のようになるんですね。

やり残し

本当はノブが3つあるので、残り2つのノブで上下左右の移動を実装しようとしたのですが、「WebSocketを受け取る→マップの中心座標から次の中心を調整→setCenter」を受ける度に繰り返すと、中心座標がundefinedになりうまくうごかないんですね。setCenterの処理が終わる前に次のsetCenterが呼ばれるのがいけない気がするのですが、なかなかうまい解決法がみつけられず…。

加えて、node-midiモジュールはいまのところnodeの0.6に対応できていません。C++のコンパイルがあるので、node_events.hがなくなった状態に追いつけていない状態です。ここはなんとかしたいところ。

(追記 2011.12.26 )Nodeが0.5.2以上の場合、node-midiはこちらで。先を越されてた…。

0 件のコメント:

コメントを投稿