WebMidiLinkをiOSでも動かしたいのでいろいろ試した

Vocacidwml ブラウザで楽しめるシーケンサーVOCACIDの話、続き。外部音源がない状態でもある程度シーケンサーで遊べるようにとWebMidiLinkという仕組みを使ってサンプル的なWebアプリを作った(→VOCACID – WebMidiLink ver. はてなブックマーク - VOCACID - WebMidiLink ver.)。前のエントリで書いたとおり、iOSでは動かない状態。その後いろいろ調べたら、なんとか動いた。でも、やっぱりむずかしいなあ、という話。

WebMidiLinkという選択

 せっかく作ったシーケンサーをいろんな環境で使えるようにしたい。もともとはポケット・ミクという外部MIDI音源を鳴らすことだけを考えて作ったのだけど、もっとカジュアルにPCやスマホ単体でも遊べるようにしたい。そんな感じでいろいろ調べる。そこで行き着いたのがWebMidiLink。


 WebMidiLinkというのは、ブラウザ上で動作する複数のWebシンセサイザーを連携動作させるための規格。2012年に発表され、対応シンセも数多く出ている。これらはウェブブラウザで単体で動作するシンセで、WebMidiLinkを使えば、別のドメインにあるWebアプリからもコントロールが可能。
 シンセをプログラミングすることは無理でも、自前のシーケンサーでこれらをコントロールできれば、外部MIDI音源使うのと変わらないんじゃね? ということに。
 そんなこんなでプログラミングを始めると、シーケンサー側のWebMidiLinkへの対応は驚くほど簡単。ドキュメントがちゃんと存在するというのもあり、音を鳴らすだけならすぐできた。最初はWeb MIDI APIで送ってたデータの配列をちょっと整形するだけでOK。すばらしい! 
 WebMidiLinkが登場した当時はなんのことやらわからなかったけど、ある程度知識がついて、ちゃんと読んでみると、なんともすごい規格だったのだな、とあらためて感動した次第。
 このへんが詳しい。
 ブラウザ上でソフトシンセを鳴らして遊ぼうよ! : 藤本健の“DTMステーション”
 WebMidiLinkがわずか40行でなしとげたとてつもないブレイクスルー – aikeの日記
 音楽方丈記 – Webアプリ間でMIDIデータの送受信を可能にする WebMidiLink
 とよしま語録: WebMidiLinkで遊んでみた

iOSで鳴らないんだけど

 で、ここまではWindowsでの話。その後、LinuxとAndroidでも試したのだけど、Windowsで動いたのがそのままこれらの環境でも動く。すげー!
 しかし、iOSではうまくいかない。というのが冒頭の話。で、いろいろ調べる。以下、調べたこと、わかったことをメモ。例によって勘違いなどもあると思われるので、なんかあれば指摘いただけるとありがたいです。
 まず、iOSのブラウザは、PCと違って複数のページが開けない(タブで開けるけど裏側のページは音が出ない)ので、iframeを使う。Androidではこれで問題ない。ちゃんとWebMidiLinkが動作する(CPUパワーの話は置いておく)。しかし、iOSではこれだけではダメ。
 iOSでWeb Audio APIを叩く場合には「タッチ制約」というのが問題になる模様。ユーザーの操作によって最初の音をstartしないとだめらしい。すなわち、WebMidiLinkを使って、iframeにロードしたシンセアプリにデータを送信するだけではだめ。いったんシンセアプリでタッチ操作で音を出す、というのが必要になる。
 しかし、WebMidiLinkのリストに挙がっているシンセアプリの多くはiOSでの操作に対応していないっぽい。
 できれば、Windowsで動いたプログラムで使っている「GMPlayer」をiOSでも使いたい。これが目標。
 他のシンセアプリをいくつか試してみると、「Web FM synthesizer made with HTML5」はiOSのタッチ操作に対応している。まずはこれをロード。最初は、MIDI信号をWebMidiLinkで送っても音は鳴らないのだけど、iframeにロードしたFMシンセの画面上の鍵盤を叩くと音が鳴り、その後はVOCACIDから送ったMIDI信号も鳴ってくれる。ナイス!
うちのiPad 2だとCPUパワーが足りないので、正常に鳴ってるとは言えない状態だけど、WebMidiLinkがiOSでもちゃんと動作することがわかった(これがわかるまでは無理なのかと思ってた)。
 とはいえ、このFMシンセはシングルティンバーなので、3パートを使うVOCACIDではちゃん鳴ってくれない(当たり前だけど。ドラムパートもないわけだし)。

既存のシンセでいろいろ試す

 で、GMPlayerに戻る。マルチティンバーで、音色配列もGM。ポケット・ミクの仕様に近いので、ベストだと思われ。しかし、これ。ページを単独で開いた状態で、iOSで画面をタッチしても音が鳴らない。マウスでの操作が前提なようだ(追記:これ、間違い。鍵盤の下をタップしてもノートオン的な処理は走っている模様)。
 いったんローカルに保存してソースを書き換え、画面上にNote Onするボタンを1つ配置、それを押して鳴るようにしてみる。いったん、音が鳴ればWebMidiLinkでも鳴るだろう。
Vocacidwmlgmadd
 そんな目論見もあえなく失敗。
 Windowsならこちらで追加したボタンで音が鳴った。しかし、iOSではこれが鳴ってくれない。
 GMPlayerでは、音が鳴ると画面上の鍵盤みたいなやつの上に、ノートの高さを示す赤い目印が出る。これで信号が来ていることが判断できる。iOSでも、この赤い目印がちゃんと動くのだけど、音は鳴らない。むー。
 ソースを見ても、むずしくてわからない。
 自分でもWeb Audio APIのテストをしていて、iOSだとうまいことしないとAudio Contextのタイマーが進まない、ということがあったので、そのへんなのかなあ? とも思うのだけど。今の自分の知識と理解力ではこれが限界。
 このほか、マルチティンバーのWebMidiLink対応のシンセアプリとして、SoundFontを使った「SoundFont: Yamaha XG Sound Set.sf2」と「sftsynth.js」というのがあり、これらは一応、iOSでも鳴る。
 iframeにロードしてから、画面の右側の鍵盤っぽいところをタップすると音が鳴り、WebMidiLink経由の信号も鳴ってくれる。GM配列でマルチティンバーだし、これがちゃんと鳴ってくれれば問題ない気もする。
 しかし、ものすごく重い。ウチのiPad 2だとCPUパワーが足りずひいひい言う感じ。Windowsマシンでもちょっと重く、テンポがよたったりする。Chromeの開発ツール見ると、なんらかのエラーも盛大に出ている。これはWeb Audio APIの仕様変更とかChromeのバージョンアップによるものだろうか? このへんもいろいろむずかしそうだ。
 そもそも、WebMidiLinkが登場して、多くの対応シンセアプリが出たのが2012年。その間にChromeもかなりバージョンアップしたので、リストにあるシンセの一部は動いていないものもいくつかある。これもWebMidiLinkをいまさら始めようとしている自分にはまたややこしい。
 さて、どうしたものだろうか。

iframeへのロードではまったところ

 あと、Web MIDI APIを使ってないので、Safariでもいけそうな気がしたので試す。シンセのロードはできるけど、Web MIDI Browserのほうがだいぶ安定してる様子。
 でもって、はまったのがChrome。iframeにロードしてるつもりが、なぜか別タブに出る。
 WebMidiLinkのドキュメントにあるようにwindow.openでやろうとすると、iframe内に出ない。別タブにシンセがロードされてしまう。
 iframeにロードしてるデモがあったなあ、と思い、「WebMidiLinkで遊んでみた」をもう一度よく読む。なるほど。window.openじゃなくて、srcを変えるのか。というわけで、こうした。

document.getElementById(handler).src = url;
this.sy = document.getElementById(handler).contentWindow;

 こんなことでもつまいづいてしまうんだなあ。
 で、一応Safari、Chromeでも鳴ったのだけど、テンポがおかしかったり音が割れてしまったり。まあ、iOSはWeb MIDI Browserをメインに作業していくということで、深くはつっこまないことにする。

これからやりたいこと

 そんなこんなで、WebMidiLinkで鳴らすのをいったん保留。Web Audio APIを使って自分で音が鳴るやつを作ろう。
 ドラムを含めて3パート分なるやつができればそれでいい。
 そんな感じでプログラミングを始めるも、やっぱりむずかしい。
 音は鳴るようになったのだけど、しょぼい。音を出すまでのプログラミングと、音色を作るプログラミングの間には大きな隔たりがあるのだよなあ。うすうす気づいてたのだけど。やっぱり本とか買うかなあ。あんのかなあ。
 というのが今の状態。
 例によって、iOSでのテストで使っているのはWeb MIDI Browser。あらためてリンク。

Web Audio APIWeb Audio API

コメント