ブラウザ上でmidiファイルを再生する手段の1つとしてhtml-midi-playerがあり、以下のページに沿ってmidiファイルのURLをsrcに指定するとmidiファイルが再生されます。
html-midi-player
https://cifkao.github.io/html-midi-player/
上記ページではsrcがhttpsで始まるURLとなっていますが、これをjavascriptでメモリ上に作成した任意のmidiデータにできないか?と思ったので処理を追ってみました。
html-midi-playerのsrcで指定したmidiファイルの取得方法を追ってみる
html-midi-playerのgithub上のソースコードを読んでみると、srcで指定したmidiファイルは以下の箇所で urlToNoteSequence
なる関数に this.src
として渡されています。
try {
let ns: INoteSequence = null;
if (initNs) {
if (this.src) {
this.ns = null;
this.ns = await mm.urlToNoteSequence(this.src);
}
この urlToNoteSequence
は上記 src/player.ts
に書かれている @magenta/music/esm/core.js
ですが、これはローカルで npm i -S @magenta/music@1.23.1
を実行してnode_modulesの中身を確認してみると見れます。
※ネット上で似たようなファイルが出てきますし、core.jsのgithubのリポジトリのコードを読んでも midi_io.ts
内の urlToBlob
を呼び出していることに変わりありませんでした。
※冒頭のhtml-midi-playerのページではscriptタグのsrcに npm/@magenta/music@1.23.1/es6/core.js
と書いてありますが、 urlToBlob
を呼び出しているのは同じでした。
export function urlToNoteSequence(url) {
return urlToBlob(url).then(blobToNoteSequence);
}
関数内で呼ばれている urlToBlob
は同ファイル内のもので、引数のURLに指定されたものをfetchで取得しています。
export function urlToBlob(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then((response) => {
return response.blob();
})
.then((blob) => {
resolve(blob);
})
.catch((error) => reject(error));
});
}
fetchした結果をresponse.blob()しており、レスポンスのblob()の結果が同じであれば、httpsで始まるもの以外がurlToBlobの引数urlに渡ってきても問題ないことになります。
httpsで始まるもの以外をmidiとしてsrcに渡す方法
上記よりレスポンスをblob()した結果が同じであれば良いので、これはjavascriptで独自に作ったメモリ上のデータをbase64エンコードして渡したものでもOKということになります。
例えば以下のライブラリの writeMidi
関数を使って生成されるデータをbase64エンコードしてhtml-midi-playerのsrcに渡すとmidiが再生されます。
長くなるので詳細は別記事に書きますが、writeMidiした結果をArrayBufferに変換し、それをbase64にエンコードして data:audio/midi;base64,
の後にくっつけてURLとして渡せば正常に再生されます。