Web MIDI API と WebSocket を利用した遠隔 MIDI ライブ演奏のサンプルウェブアプリを作りました。イメージ図は次の通りです。WebSocket には Node.js の Socket.IO を利用しました。
クライアントがアプリと MIDI 楽器を繋ぎ演奏すると、同じアプリに繋がれた他のクライアントにも Node.js サーバーを通して、リアルタイムに MIDI メッセージが送られます。メッセージを受信した各クライアントは自身と接続された MIDI 楽器を鳴らします。複数クライアントが同時に演奏すれば、同時に情報が送られ、遠隔演奏セッションが実現できます。
サーバーコード
app.js
まずは node.js のフロント部のコードです。midi.listen(io)
を呼び出し、MIDI を送受信する WebSocket のイベントハンドラーを設定しています。
var fs = require('fs');
var http = require('http');
var midi = require('./sockets/midi');
var server = http.createServer();
var io = require('socket.io').listen(server);
// MIDI socket 通信設定
midi.listen(io);
server.listen(8080);
sockets/midi.js
受信した MIDI メッセージを他クライアントに配布するmidi.listion(io)
を定義します。
var clients = {};
exports.listen = function (io) {
io.sockets.on('connection', function (socket) {
socket.emit('connected', {});
socket.on('join', function (client) {
// 接続クライアント情報を格納する
socket.set('client', client, function () {
clients[client.name] = socket;
console.log('join: ' + client.name);
});
socket.emit('joined', {});
// 受信した MIDI message を全クライアントに送る
socket.on('play', function (data) {
console.log('play: ' + data);
socket.broadcast.emit('play', data);
});
});
});
};
play
イベントにより MIDI メッセージを受信したら、受け取った data を socket.broadcast.emit
メソッドでそのまま他クライアントに配信しています。名前は midi.js
ですが、MIDI に特化した処理は何もしてません。
クライアントコード
クライアントは接続確立後、requestMIDIAccess
API を用いて端末に接続されている MIDI 機器を認識します。MIDI 機器から MIDI メッセージを受信したら、それをサーバーに送信します。逆にサーバーから play
イベントにより MIDI メッセージを受信したら、それを MIDI 機器に送信します。
index.html
<script src="//code.jquery.com/jquery.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
var input;
var output;
var socket;
var session = {
name: Math.round(Math.random() * 1000)
};
$(document).ready(function () {
socket = io.connect();
socket.on('connected', function (data) {
socket.emit('join', session);
});
socket.on('joined', function (data) {
navigator.requestMIDIAccess({sysex:true})
.then(scb, ecb);
function scb (access) {
input = access.inputs()[0];
console.log(input);
output = access.outputs()[0];
console.log(output);
// MIDI 機器から受信した message をサーバーに送る
input.onmidimessage = function (event) {
console.log(event.data);
socket.emit('play', event.data);
};
// サーバーから受信した message を MIDI 機器に送る
socket.on('play', function (data) {
var data = [data[0], data[1], data[2]];
console.log('play: ' + data);
output.send(data);
});
}
function ecb (error) {
console.log(error);
}
});
});
</script>
ネットワーク遅延
Node.js をさくら VPS の東京リージョンのサーバーにデプロイし、実験してみました。クライアントも東京にあり、サーバー・クライアント間の物理的な距離は23区内に収まっていると思われますが、若干演奏の遅延が感じられました。
遅延の程度に幅があり、リズム・テンポが受信側で時々不安定になります。 ただ、体感的には遅延時間は遅くとも 0.5 秒未満には収まっている感じで、ほとんど遅延を感じないタイミングもあります。むしろ全体的には意外に遅延しないなーという感想です。
一方通行の遠隔ライブは大丈夫そうですが、複数クライアントによるセッションは、お互いでタイミングを合わせられないので、ちょっと難しそうです。すっごいテンポゆっくりな曲なら大丈夫かもしれません。