音の鳴るブログ

鳴らないこともある

ウェブオーディオが使われているライブの様子を見てきた

楽×学(ラクガク)2014~私の「やる!」を興すために~ を開催します/浜松市

浜松で「楽×学 2014~私の「やる!」を興すために~」というイベントが開催されて、その最期を飾る SjQ ライブパフォーマンスでウェブオーディオが使われていたので様子を見に行った。

SjQというのはこういう感じ。

【SjQ++】生演奏とコンピュータを組み合わせ、新しい即興音楽を生み出すバンド - PICK UP | KAKEHASHI

前回 、Cell というインスタレーションを手伝った流れで、そのシステムをライブ仕様に調整して使用することになった。インスタレーションでは、Cell という人工生命デバイスが環境と自身に反応しながらドローンを生成、その合間合間に音の素材をドロップする構造で、現地の音響空間を楽しむ他に、その生成された音をブラウザ経由で聴けるようになっていたのだけど、今回のライブは人工生命デバイスと人間の演奏が相互に反応しながら、生成された音の素材をお客さんのスマートフォンに送信して、演奏に合わせて光り、そして音が鳴るという仕組みを構築した。

仕組み

おおまかな構成はこういう感じ。

+-----+          +--------------+           +------------------+
| SjQ | - OSC -> | SocketServer | - WiFi -> | MobileDevice * N |
+-----+          +--------------+           +------------------+

僕は SocketServer と MobileDevice のプログラムを書いた。SocketServer は SjQ のシステムから受信したOSCメッセージをJSONに変換してブラウザに送るだけで、ブラウザは受信したメッセージに応じて、音を出したり(Web Audio API)、画面を光らせたりする(Canvas)。 音を出す部分は以前に書いたものを使用したので、実際にライブの仕様に合わせて書いたのはサーバー側、クライアント側あわせて 500 行程度。前日のスタジオ練習で雰囲気を確認していったん寝た翌朝、当日の朝に全部書き直す開発手法(development in sleeping)を採用した。

以下は抜粋したコード。

// server.js
var express = require("express");
var oscmin = require("osc-min");
var udp = require("dgram");
var http = require("http");
var socketIO = require("socket.io");

var app = express();
var server = http.createServer(app);
var io = socketIO(server);

app.use(express.static(__dirname + "/public"));

server.listen(SERVER_PORT, function() {
  console.log("Listening on port %d", server.address().port);
});

var numUsers = 0;
var prevOsc = {};

// お客さんの端末とのソケット接続
io.on("connection", function(socket) {
  numUsers += 1;
  console.log("connected: " + numUsers);
  
  // 接続数に応じて制御の調整を行う
  io.emit("numUsers", {
    count: numUsers, osc: prevOsc
  });

  socket.on("disconnect", function() {
    numUsers -= 1;
    console.log("disconnected: " + numUsers);

    io.emit("numUsers", {
      count: numUsers, osc: prevOsc
    });
  });

  // お客さんの全端末を強制的に音を鳴らす
  socket.on("fire", function(data) {
    io.emit("fire", data);
    console.log("fire!");
  });

});

// SjQのシステムからOSCを受信
udp.createSocket("udp4", function(data) {
  var osc = oscmin.fromBuffer(data);

  osc.args = osc.args.map(function(x) {
    return x.value;
  });

  // お客さんの端末に送信
  io.emit("osc", osc);

  prevOsc = osc;

  console.log(JSON.stringify(osc));
}).bind(OSC_PORT);
// client.js
var socket = io();
var app = new CellLiveApp();

socket.on("osc", function(osc) {
  app.onReceiveOsc(osc);
});

socket.on("numUsers", function(data) {
  app.numUsers = data.count;
  app.setOsc(data.osc);
});

socket.on("fire", function() {
  app.fire();
});

ライブの様子

50分弱のパフォーマンスの間、サーバーに接続があったのは最大時で50台、平均して35台程度で演奏やプロジェクターで投影している映像に合わせて周りを取り囲むお客さんの端末がチカチカ光る。演奏がスパースになった瞬間にスマートフォンからの音が入り込むなど絶妙な融合ができて、パフォーマンスとそれを鑑賞するお客さんという区別が溶けて全員が当事者であるみたいな一体感というか緊張感があった。自分のiPhoneもサーバーに接続していたのだけど、自分の所有物である端末に演奏のフィードバックがダイレクトに伝わってくる感覚は非常に刺激的だった。当初、お客さん全員の端末が一気に爆発したらどうしようみたいな心配をしていたのだけど、爆発した端末がなかったのもよかった。

ウェブオーディオとアート/音楽

以前、自分で書いた内容の引用だけど。目の前で確認したことで、より強く感じた。

現地で生成される音をネットを介して体験することができるのはかなり面白くて、応用方法を色々考えるとアートや音楽と体験者との距離感の新しい選択肢になりえそう。 音楽系のメディアアートだとMax/MSPとかSuperColliderとかが良く使わていて、そういう蓄積のある技術に比べると Web Audio API はまだまだ見劣りする感じだけど、ブラウザがあれば*1専用のアプリケーションやデバイスを用意することなく誰でも手軽に体験を共有できるという点で重要なポジションを担えるんじゃないかなと思います。

今後の課題

いくつか反省点もあったのだけど、書くのが面倒になってきたので箇条書き。

  • 非対応端末(Androidとか)の扱いを雑にしてしまった
    • 非対応な旨を表示するとか対応可能な範囲で動作させるとかすればよかった
  • 端末スペックに応じた処理の切り替え
    • 端末に応じた最高の動作をさせたい (今回は iPhone 4s を目安に調整した)
  • WiFiネットワークの構築
    • もっと大きな規模になった場合にどうしたら良いのかさっぱり分からない