利点1: 高速・軽量
js-synthesizer は libfluidsynth を内部の wasm で動かして MIDI を再生します。 それだけでなく AudioWorklet でメインドスレッドを使わずに再生していることが肝に見えます。 これまで作っていたアプリでは MIDI の再生に Magenta.js を使っていたのですが、 Magenta.js は同時に鳴らす音が増えると再生の負荷が大きくなる課題があります。 しょぼ PC で開発しているので、複雑な曲は若干のラグが発生することを確認していました。 理由は正確にわかっていませんが、おそらく Tone.js がメインスレッドのイベントで実装していることが問題です。 3つの解決案があり、(1) Tone.js の進化待ち、(2) on the fly encoding、 (3) 非メインスレッドの再生と思っています。 すでに PR も来ているので 1 も期待できますが、on the fly encoding にも興味はあります。 ただ 2 は大変だし遅そうなので AudioWorklet でイベントを管理する 3 の js-synthesizer が、 解決案としては一番良さそうです。 js-synthesizer を使えば、Magenta.js だとラグが発生する MIDI でもまったくラグが発生しません。 ちなみにライセンスも libfluidsynth は LGPL、js-synthesizer は BSD3 なので、とても使いやすいです。欠点: 実装がやや面倒
欠点としては、処理が MIDI と FluidSynth の仕様に強く依存することになるので、複雑なことをするのは大変そうなところです。 イベント処理も AudioWorklet に依存したものになるので難しいです。やったことないし、やることもほとんどないし…。 そこで私は MIDI そのものは Magenta.js で扱い、再生だけを任せる実装にしました。 これなら気楽に MIDI の中身を弄れて、高速に再生ができます。実装の面倒な例としては、たとえば seekbar の実装は面倒で、libfluidsynth にそのような機能はありません。 特定の tick に seek する機能しかないので、Magenta.js でテンポ情報を読み取って、tick を推定する実装をしています。 他にも tick=0 へ seek して再生するとわずかなラグが発生して音が消えるので 0.1秒ずらして再生しています。 また音符を再生したときにその音符に対する callback もできないと思うので、再生時間から推定して疑似 callback を実現しています。 細かいところは適当に調整すればどうにでもなります。 まだ全然使いこなせていないので、もっと色々遊んでみるつもりです。
利点2: サウンドフォントで再生できる
js-synthesizer は sf2, sf3 形式のサウンドフォントをロードして MIDI を再生します。 サウンドフォントを利用した再生に対応できる利点もあります。 気分に応じて音色を変えられるようになるのは、地味に良いことです。ちなみにこれまでも Web 上でサウンドフォントを再生するライブラリがいくつかあったのですが、安定的に再生できるライブラリがありませんでした。 どれも独自実装でメンテに不安があるものばかりだったのですよね。 しかし js-synthesizer の中身は libfluidsynth なので一切の不安がありません。 libfluidsynth は意外と活発に実装されており、今後にも期待しています。 個人的には、低遅延・低ビットレートの品質・ライブラリの軽量性の三拍子が揃った Opus 形式のサポートに一番期待しています。 ちなみに議論はされているみたいです。
0 件のコメント:
コメントを投稿