前回の番外編MIDI編① で、MIDIは音の波形ではなく「いつ・どの高さを・どの強さで弾け」という数バイトの指示を送る規格だ、という話をしました。ただ、指示は受け取り手がいて初めて意味を持ちます。届いた3バイトを解釈して、鳴らして、覚えて、並べ替える。その受け取り手の主役が、コンピューターです。

そして今は、専用ソフトを買ってこなくても、この受け取り手を自分で書けます。ブラウザのJavaScriptには、USBでつないだMIDIキーボードと直接会話するためのWeb MIDI APIがあり、届いたバイト列は前回デモで眺めたものとまったく同じ形をしています。MIDIは特別な機材の中だけの話ではなく、コードから触れる身近な信号なのです。

楽器から90 3C 64のようなバイト列がコンピューターに届き、3方向に活かされる図。音源に渡して鳴らす、時刻を付けて並べて記録する(シーケンサー)、数値を書き換えて作り変える(編集・移調)。DAWのピアノロールはこの3つの組み合わせ

コンピューターが指示に対してできることは、突き詰めるとこの図の3つです。鳴らす、記録する、作り変える。今回はこの3つを、ブラウザの上で実際に組み立てていきます。

ブラウザが楽器とつながるまで

Web MIDI APIの流れは、カメラやマイクを使うWebアプリとよく似ています。ページがAPIを呼ぶと、ブラウザがユーザーに「このサイトにMIDIデバイスの使用を許可しますか?」と確認し、許可されて初めてポートの一覧が手に入ります。

Web MIDI APIの流れ。ページがnavigator.requestMIDIAccess()を呼ぶと、ブラウザがユーザーに接続許可を求める。許可されるとMIDIAccessオブジェクトが得られ、その中に入力ポート(楽器からブラウザへ)と出力ポート(ブラウザから楽器へ)の一覧がある。入力ポートのonmidimessageに関数を登録すると、弾くたびにバイト列が届く

入り口はnavigator.requestMIDIAccess()のひとつだけ。返ってくるMIDIAccessオブジェクトの中に、入力ポート(楽器からブラウザへ)と出力ポート(ブラウザから楽器へ)が並んでいます。入力ポートのonmidimessageに関数を登録すれば、鍵盤を弾くたびにその関数へバイト列が届きます。

const access = await navigator.requestMIDIAccess();
for (const input of access.inputs.values()) {
  input.onmidimessage = (ev) => {
    const [status, note, velocity] = ev.data;  // 例: [0x90, 0x3C, 0x64]
    if ((status & 0xF0) === 0x90 && velocity > 0) {
      playNote(note, velocity);                // あとは前回の知識で読める
    }
  };
}

ev.dataの中身は、前回解剖した3バイトそのものです。ステータスの上位4ビットで命令を見分け、ノート番号とベロシティを取り出す。規格が40年変わっていないおかげで、1980年代のシンセをUSB-MIDIインターフェイス経由でつないでも、この数行がそのまま動きます。

対応状況は正直に書いておきます。ChromeとEdge、Firefox(バージョン108以降)では使えますが、SafariはmacOSでもiPhoneでも対応していません。AppleのWebKitチームが、MIDI機器の固有IDがユーザーの追跡(フィンガープリント)に使われることを懸念して実装を見送り続けているためです。接続が許可制なのも同じ理由です。スマートフォンでこの記事を読んでいる方が実機接続を試せないのは心苦しいところですが、この後のデモは実機なしでも最後まで動くように作ってあります。

時刻を付ければ、それはもうシーケンサー

届いたバイト列を鳴らすだけなら、コンピューターは高級なMIDIケーブルにすぎません。面白いのはここからで、届いたイベントに受け取った時刻を添えて配列に積んでいくと、それだけで演奏の記録になります。

const events = [];
function record(bytes) {
  events.push({ t: (performance.now() - recStart) / 1000, bytes });
}

再生は逆再生ならぬ逆過程で、時計を走らせて、時刻が来たイベントから順に「鳴らす」処理へ流し込むだけです。これがシーケンサーの最小形で、DAWのピアノロールで音符をつまんで動かす操作は、この配列のtやノート番号を書き換えているにすぎません。

録音した音声データと決定的に違うのは、時間と音程が別々の数値として持たれていることです。Tape Stopの回 で、テープやサンプルは再生速度を変えると音程まで一緒に変わる、という物理を確かめました。指示の列にはそれがありません。

上段は録音(波形)を2倍速にした場合:波形が半分の時間に押し縮められ、振動そのものが速くなるので音程が1オクターブ上がる。下段はMIDI(指示の列)を2倍速にした場合:ピアノロール上の音符の間隔が半分になるだけで、ノート番号は変わらないので音程はそのまま

波形の2倍速は振動そのものの2倍速なので、音程が1オクターブ上がります。指示の列の2倍速は、イベントの間隔を半分にするだけ。各イベントが運ぶノート番号は手つかずなので、音程はそのままです。テンポと音程を独立に扱えるこの性質こそ、打ち込みという制作スタイルの土台になっています。

表情のコントロールも同じ言葉で書けます。ピッチベンドはE0で始まる3バイト(値だけ14ビットに拡張されています)、ビブラートなどに使うモジュレーションホイールはB0 01 xxというコントロールチェンジ。鍵盤のオンオフと同じただのメッセージなので、シーケンサーは区別なく記録・再生できます。前回「指示の缶詰」として紹介したSMF(.midファイル)は、まさにこの時刻付きイベント列をファイルに書き出したものです。

弾いて、記録して、倍速で聴く

ここまでの部品を全部つないだデモです。USBのMIDIキーボードがあれば「MIDI機器に接続する」から実機で、なければ画面の鍵盤で、同じように遊べます。

うまく表示されないときは、デモを別タブで開く

おすすめの手順は、記録開始を押してから鍵盤で短いフレーズを弾き、停止してピアノロールに音符が並ぶのを見ることです。それから再生速度を2倍にして再生してみてください。忙しくなるのはタイミングだけで、音の高さは1ミリも動きません。逆に0.5倍にすると、自分の演奏のヨレがゆっくり引き伸ばされて聴こえてきます。ピッチベンドやモジュレーションを動かしながら弾くと、その操作もイベントとして記録され、再生時にスライダーがひとりでに動きます。

どう実現するか

デモの中心は、入力源がなんであれ同じ関数に流し込む、という一本道の設計です。実機から届いたバイト列も、画面鍵盤が作ったバイト列も、再生機が吐き出したバイト列も、すべて同じhandleMessage(bytes)を通って解釈されます。

function handleMessage(bytes, source) {
  const status = bytes[0] & 0xF0;
  if (status === 0x90 && bytes[2] > 0) synthOn(bytes[1], bytes[2]);
  else if (status === 0x80 || status === 0x90) synthOff(bytes[1]);
  else if (status === 0xB0 && bytes[1] === 1) setVibrato(bytes[2]);
  else if (status === 0xE0) setBend(((bytes[2] << 7) | bytes[1]) - 8192);
  if (recording) events.push({ t: now() - recStart, bytes });
}

再生側は、15ミリ秒ごとに時計を見て、再生位置を追い越したイベントを順にhandleMessageへ渡すループです。再生速度のスライダーは、この時計の進み方に掛け算しているだけです。入力と再生が同じ道を通るので、「実機で弾いても画面で弾いても同じ音がして、同じように記録される」が自然に成立します。MIDIという規格の設計思想、つまりどこから来たメッセージも同じ言葉で読める、という性質をそのまま設計に写した形です。

指示で組み立てられた音楽を聴く

締めくくりに、「演奏を指示の列として組み立てる」やり方がそのまま作品になった2枚を紹介します。時代も場所も違いますが、どちらも巨大なスタジオではなく、機材を指示でつないだ小さな部屋から生まれた音楽です。

Daft Punk『Homework』のアルバムジャケット

Daft Punk / 1997

Homework

タイトルどおり、パリの自宅の寝室でRolandのシンセやドラムマシンをつないで作られたデビュー作。世界を踊らせたトラックの正体が、寝室に積まれた機材へ流れる指示の列だったという事実は、何度思い出しても痛快です。

Perfume『GAME』のアルバムジャケット

Perfume / 2008

GAME

中田ヤスタカのプロデュースによる、日本のポップスを塗り替えた打ち込みアルバム。歌声まで楽器のように編集して音符の網目に織り込むスタイルは、コンピューターの中で音楽を組み立てる時代の到来をお茶の間にまで知らせました。

ジャケット画像はMusicBrainz / Cover Art Archive由来の画像を記事内に同梱して配信しています。

余談ですが、このデモで音を出している「受け手の音源」のような、波形を発生させる道具そのものをアプリにしたものを個人開発で公開しています。音を鳴らしながら波形も確認できるiPhone向けのオシレーターです。

前回と今回で、MIDIの言葉を読むところから、ブラウザで受け取り、記録して作り変えるところまでたどり着きました。鍵盤とスピーカーの間に流れているのが、波形ではなくたった3バイトの指示だと知ってしまうと、DAWのピアノロールも、ゲーム音楽も、駅の発車メロディの打ち込みも、少し違って見えてくるはずです。

参考文献