Pitch Canvasを使ったピッチの変更とその制限
200 msで11 kHzから50 Hzに落ちるカーブを、Phase PlantとSurge XTで鳴らして比べた。バッファサイズやピッチベンドの更新間隔で音がどう変わるのか、REAPERで試している対策とあわせて書いた。
Pitch Canvasを開発しては自分で使う、ということを繰り返す中で、気になる現象を見つけた。聴いた限りではおおむね意図したピッチが鳴っているものの、再生速度を下げてスペクトログラムを見ると、描いたカーブがうまく再現されていないことがあった。
この問題を調べる中でいろいろと発見があったので、この記事にまとめておこうと思う。
Pitch Canvasで描いたカーブに沿ってピッチを動かすには、カーブをピッチベンド情報に変換し、DAWを経由してシンセサイザーに渡す。制限が出るのは、大きく分けて次の2つだ。
- ピッチベンド情報を更新する周期
- DAWのバッファサイズとシンセサイザー側の処理
1. ピッチベンド情報を更新する周期
1つ目は、ピッチベンド情報の時間的な解像度だ。
Pitch Canvasでカーブをピッチベンド情報へと変換する際には、この情報をどのくらいの周期で更新するかを決めなくてはならない。
例えば100 msごとに値を送る場合、その間のピッチ変化を示す情報はない。シンセプラグイン側で補間が行われなければ、100 msごとにピッチが変わる階段状のカーブになってしまう。
Pitch Canvasでは、サイン波のピッチを急なカーブで変化させ、キックのような音を作ることも想定している。短い時間でピッチが大きく変化するときに、ピッチが階段状になってしまうのはかなり問題がある。
一方、滑らかにしようとして更新頻度を上げすぎると、DAWによってはピッチベンド情報がうまく反映されず、ピッチがほとんど変わらないことがあった。
実際に更新頻度を上げて試したときには、急な変化を狙ったのに、もっとゆっくりした別のカーブになった。この問題には対処したものの、実験した範囲では、正常に再生できる更新頻度の上限がDAWによって異なっていた。
そのため、各DAWで検証を行い、正常に扱える範囲に更新頻度を収める必要があった。
2. DAWのバッファサイズとシンセサイザー側の処理
DAWで正常に扱える更新頻度でピッチベンド情報を送れたとする。次に立ちはだかるのは、シンセサイザーがその情報をどう受け取り、音に反映するかという問題だ。
DAWは音声をサンプルのまとまり(ブロック)に分けて処理する。オーディオデバイスのバッファサイズは、通常の再生時に使う処理ブロックの大きさに影響する。例えば48 kHzで1ブロックが1024サンプルなら、約21.3 ms分の音声をまとめて処理することになる。
ここで問題になるのが、処理ブロックの大きさとシンセプラグインの組み合わせだ。
ワーストケースでは、ブロック内に複数のピッチベンド値があっても、最後の値しか音に反映されない。こうなると、いくらピッチベンドを細かく送っても、1024サンプルのブロックなら1024サンプルにつき1つの値しか使われない。シンセ側で補間が行われていればピッチは滑らかに変化するが、それでも当初想定していたカーブが再現されるとは限らない。
VST3やCLAPには、ブロック内のパラメーター変更をサンプル単位の位置情報とともに受け渡す仕組みがある。そのため、実装によってはピッチの変更をサンプル単位で受け取って音に反映できる。ただ、受け取った情報をいつ、どう適用するかは音源ごとの実装に依存する。その処理が公開されているとは限らない。
例えば、2022年当時のJUCEのVST3実装には、MIDIのピッチベンドなどをパラメーター変更から復元する際に、ブロック内の最後の値しか使わない問題があった。JUCEの開発ブランチには2022年9月に修正が入った。修正前の実装を使う音源では、独自に対処していない限り、ブロックサイズによってピッチカーブが変わることがある。
ここは音源の開発者がどう実装したかに依存する部分で、MIDIデータを生成する側だけではどうにもできない。
実際にどのくらい違うのか
Pitch Canvasで、200 msで11 kHzから50 Hzへと落ちるカーブを描き、バッファサイズによって結果がどう変わるかを比較した。
48 kHz環境で、Phase PlantとSurge XTのそれぞれを使用して検証した。バッファサイズを次の順番で変更し、Pitch CanvasのLive出力で音を再生している。
32 → 64 → 128 → 256 → 512 → 1024 → 2048サンプル
Phase Plantでは、バッファサイズが大きくなるにつれてピッチ変化が滑らかでなくなり、後半では目も当てられないような音に変わっていく。
一方、Surge XTでは、1024サンプルでも32サンプルと同等の滑らかなピッチ変化を確認できた。
この比較からも、バッファサイズが同じでも、ピッチの変化がどこまで再現されるかはシンセサイザー側の実装によって変わることが分かる。
MIDIを出力するところまでしか制御できないPitch Canvasにとっては、ここが限界となる。
急激なピッチ変化を含むカーブを正確に鳴らしたい場合は、細かなピッチベンド情報を処理できるシンセサイザーを選ぶか、バッファサイズを小さくして、実際の音を確認してもらう必要がある。
REAPERでの解決に向けた取り組み
多くのDAWでは、こうした問題を回避するにはシンセサイザーを変更するか、バッファサイズを小さくしてレンダリングする必要がある。一方、REAPERでは、オーディオデバイスのバッファサイズとは別に、オフラインレンダリング時の処理ブロックサイズを指定できる。Pitch Canvasでは、REAPER専用の機能として、ステレオのApply Take FXを実行するときに処理ブロックサイズを一時的に4サンプルに切り替え、レンダリング後に元に戻すオプションを追加している。ただし、これはレンダリング時の対応であり、通常の再生中に発生する問題を解決するものではない。
そこで現在は、より抜本的な解決に向けて、REAPER用の拡張機能「Adaptive Precision」を開発している。
これは、REAPERがVST3シンセサイザーに渡す処理ブロックを途中で受け取り、パラメーターの変化量に応じて細かく分割してからシンセサイザーに渡す仕組みだ。例えば、ピッチがほとんど変化しない部分は大きなブロックのまま処理し、急激に変化する部分は64サンプル以下の細かなブロックに分ける。必要に応じて1サンプル単位まで細分化することもできる。
分割したブロックは同じシンセサイザーのインスタンスで連続して処理する。オシレーターやエンベロープなどの内部状態を維持したまま処理するためだ。こうすれば、ブロック内の最後のピッチベンド値しか使わないシンセサイザーでも、ピッチ変化をより正確に再現できる可能性がある。
今のところ、変化量に応じてブロックを分割するところまでは実装できている。VST3の処理に介入する実験的な方式なので、音源ごとの互換性やCPU負荷など、まだ検証すべき課題は多い。音源内部の制御周期やスムージングまでは変更できないため、あらゆる音源で精度が上がるとも限らない。
うまく実用化できるかどうかはまだ分からないが、Pitch Canvasで描いたカーブを、音源側の制限にできるだけ左右されずに再現できるようにしたい。
実用化の目処が立ったら、こちらもリリースしたいと思ってます。
