Zenn
🔥

Beatrice VST の遅延を実測した話

2025/03/06に公開

こんにちは。GokRackこと極落にんじんです。
某社で主にリアルタイムの音響信号処理の技術開発をやってます。
先日、プライベートでAI声質変換 Beatrice v2 を使って十全に遊ぶために、VST版のBeatriceに話者モデルのマージ機能 (Voice Morphing Mode)を(勝手に)実装させて頂きました。

この間、Beatrice の公式の作者(prj_beatrice)さんが処理遅延の話をしている記事を見かけました。
https://zenn.dev/prj_beatrice/articles/40b122b8de6472

私これでも一応リアルタイム音響信号処理で10年以上禄を食んできた身。こういう話を見ると実測でどうなっているのかを自分でも確認してみたくなります。

というわけでこの記事は、手持ちの機材で Beatrice v2 VST版の遅延時間の測定をやってみたよ、そしたら(私の環境では)ほぼ公称値通りの0.05秒で動いていたよ、という話となります。

遅延の測定対象について

今回、遅延を測定したいシステムとしては軽く図で表すと下記のようになります。
要するに、マイクで入力した音が、オーディオインタフェースやPC内部の処理を通じてスピーカーに出力されるまでの時間差が知りたいわけです。

測定したい遅延について

一応注意点として、Beatrice VSTの処理だけでなくこのオーディオインタフェースとオーディオAPIでも無視できない遅延が生じるため、今回測定した遅延というのはあくまで私の環境・設定での遅延というものとなります。
異なるオーディオインタフェースや異なるAPIを使用している場合、これとは違った遅延となることをご承知おきください。

なお、今回の測定に使用した機材やその設定については下記の通りとなります。

サンプリング周波数は、後述する通り Beatrice の内部処理で一度 48kHz にサンプリング周波数変換(SRC)を行うようになっているため、特別な理由がない限りは無駄な処理を省くという意味で 48kHz に揃えておいたほうが良いと思います。

フレームサイズについては小さいほど遅延は少なくなりますが、その分安定性が下がり音切れを起こしやすくなりますので、使用しているPCや同時起動するほかのソフトの負荷などを鑑みて適切な値を探ってみてください。[2]
私の環境だと128サンプルがちょうど良さそうでした。

VST を動かすホストアプリとしては、大体何使っても良いんですが、自分はJUCEのSDKに含まれているサンプルアプリの AudioPluginHost を使いました。[3]
exeではなくソースコードの形式で配布されているものなので自分でビルドする必要があること、さらにオーディオAPIとしてASIOを使えるようにするためには別途 ASIO SDKをダウンロードして適切に設定してからビルドする必要があるなど、ソフトウェア開発者以外には少々敷居が高いですが、それらを乗り越えればGUIが直観的で動作も軽いため、個人的には使いやすくてオススメです。

遅延の測定方法

遅延を測定するため、もう一台のPCとオーディオインタフェースを用意して下図のように接続しました。

遅延測定系(Beatrice VST)

図の左側のPCからは同じ信号をオーディオインタフェースの左右両方のチャンネルから出力し、左チャンネルはそのまま自分自身の入力の左チャンネルに繋いでループバックさせ、右チャンネルは遅延測定対象の処理を通してから右チャンネルに戻し、その入力の左右チャンネルを同時に録音してwavファイルに保存します。
この録音されたwavの左右の信号の時間差を計測することで、実際の使用時の遅延時間を正確に測ることが出来ます。

また、ついでに比較のために Beatrice VST の処理を行わず、そのまま音声信号をパススルーさせた場合についても測定しておきます。

遅延測定系(passthrough)

これで、オーディオインタフェースとASIOのみの遅延を確認することが出来、その値からBeatrici VST単体の遅延も計算することが出来ます。

計測された信号と遅延時間の評価

Audio I/F と ASIO の部分の遅延の評価

まず先に、オーディオインタフェースとASIOのみの遅延の方から確認しましょう。
測定された信号の波形は下図のようになりました。

録音信号(passthrough)

上がループバックさせた左チャンネル、下が処理後の音になる右チャンネルです。
この波形の時間差を目視で測ってそれをもって遅延時間としても良いのですが、一応ちゃんと真面目に信号処理で遅延量を計算しましょう。

こういった信号同士の遅延時間を評価するためには、信号同士の相互相関を計算してそのピーク位置を確認するのが常套手段かと思います。
そこで、相互相関を計算してみた所、下図のようになりました。

相互相関(passthrough)

これだとちょっと見づらいので、最大値付近を拡大して見てみます。なお、図中の数字は各極大値のx座標です。

相互相関のピーク周辺(passthrough)

660サンプルのところに強く鋭いピークを持っているため、遅延量としては約14ms (660サンプル/48kHz = 13.75ms)といったところでしょうか。

なお、今回使用した UR12 は、ASIOの設定画面で推定遅延量を確認できます
今回の設定値であるサンプリング周波数48kHz&フレームサイズ128サンプルの場合、入力が 6.458 ms、出力が 7.438 ms の計 13.896 ms でした。サンプル数にして 667 サンプル……なんか微妙に違うな?
仕事だったらちゃんと違いの原因を深堀りしてみても良さそうなズレですが、まぁ概ね一致しているということで良いでしょう。

Beatrice VST 処理音の遅延の評価

次に、本命の Beatrice VST の処理を行った場合の遅延量を確認しましょう。
録音された音声はこのようになっています(生声注意)。

https://www.youtube.com/watch?v=HOct7W3sxkc

左チャンネルが私の肉声を収録したもの、右チャンネルは(確か)東北きりたん歌唱データベースを用いて私の手元で学習して作った Beatrice v2 のモデルを通した音声となります。[4]
実際に使うときもこれくらいの遅延で聞こえるんだなーと思って聞いてみてください。
なお、セリフの内容は職場の先輩がいつもマイクテスト用のテスト音として毎回そらんじていて耳タコになってしまったセリフです。由来については自分もあまり詳しくは知りません。

この音声信号に対して相互相関を計算したところ、下図のようになり、最大ピーク位置は2317サンプルと出ました。

相互相関(Beatrice)

最初、このピーク位置を見てあぁ大体50msを少し下回るくらいなのかーとか思っていたのですが、しかしながらよくよく考えるとこの値を遅延量として採用するのはちょっとマズそうです。現にピーク位置周辺を拡大すると下図のようになり、最大ピークと同等のピークが多数確認出来ます。

相互相関のピーク周辺(Beatrice)

これは Beatrice の処理の際にピッチを変更しているため、基本周波数が全く異なる音声同士で相互相関を計算してしまったためでしょう。
正確に遅延量を評価するためにはもうちょっと信号の形を揃えてから比較する必要性がありそうです。

そこで、ヒルベルト変換の絶対値を取ることで信号の包絡線を計算し、さらにその包絡線に対して適当にローパスフィルタ(LPF)をかけて下図のような信号を得ました。

包絡線(Beatrice)

青線が元信号、橙色の線が包絡線、緑線が包絡線にLPFをかけたものです。
緑線が概ねその時点その時点の音声の大きさに追従する感じの信号になっていることがわかります。

この緑線同士の相互相関を計算した図が下記の通りとなります。

包絡線の相互相関(Beatrice)

包絡線の相互相関のピーク周辺(Beatrice)

LPFの影響でピークの鋭さがだいぶなだらかになっていて多少正確性に欠けるかも知れませんが、これならピーク位置を遅延量として採用しても良さそうです。
ピーク位置としては2435サンプルという値を得ることが出来ましたので、時間に直すと約 50.7 msでしょうか。
VST単体としては差し引き 37ms 程度の遅延ということになりますね。
図らずしも、Beatrice公称の約0.05秒という遅延量にほぼ完璧に一致する値が得られました。

Beatrice VSTの内部処理から推測される遅延量との比較

Beatrice VST に話者マージ機能を追加した際に内部処理について把握したので、折角ですから、今回の遅延の実測値と Beatrice VST の内部処理から推測される遅延量とを比較してみます。
Beatrice VST のソースコードを読み解いた感じ、処理ブロック図としては概ね下記のようになります。

Beatrice VST 処理ブロック図

Beatrice 本体の推論処理(⑥)は、入力としてサンプリング周波数16kHz・フレームサイズ160サンプルの信号を受け取って、サンプリング周波数24kHz・フレームサイズ240サンプルの信号を出力するという形式になっています。
しかしながらオーディオインタフェースは Beatrice が期待するサンプリング周波数やフレームサイズで動いているとは限らない(というか、普通は入出力で違うサンプリング周波数・フレームサイズを選ぶことは出来ない)ので、それらの差異を吸収するために、

  • ③と⑨のSRC(サンプリング周波数変換)とLPF(ローパスフィルタ)でサンプリング周波数を48kHzに揃え(るとともに③のデシメーションと⑦のゼロ補間で生じるエイリアシングを除去し)
  • ④と⑧のバッファリング処理でフレームサイズを480サンプルに揃え
  • ⑤のデシメーションと⑦のゼロ補間によって所望の入出力のサンプリング周波数・フレームサイズに揃える

という処理になっています。

これらの処理で遅延が生じるブロックとその遅延量は大きく分けて下記のようになると考えられます。

  • オーディオインタフェース & ASIO の遅延 (①、②、⑩、⑪): 約14ms弱
    • 詳細は上で述べた通り。
  • SRC & LPF のフィルタ遅延 (③、⑨): 1ms未満
    • 今回の場合、オーディオインタフェースも48kHzで動作しており、SRCは実質的に動作しないため、SRCの影響についてはあまり考えなくて良いと思います。
    • LPFについては、ソースコードを見ると今回の場合はサンプリング周波数48kHz・タップ数32の線形位相FIRフィルタとなるようです。
    • そのため、入出力合わせてフィルタ遅延の合計は 約0.65ms(15.5サンプル@fs=48kHzの遅延が2回かかるため)となります。ほぼ無視していい程度ですね。
  • バッファリング処理による遅延(④、⑧): 10ms (480サンプル@fs=48kHz)
    • 480サンプル貯まるまで処理を遅延することに相当するため、ピッタリ10msとなります。
  • Beatrice の推論処理によるアルゴリズム遅延(⑥): 恐らく 25ms 程度?
    • こちらの内部処理についてはLibファイルの形式で与えられておりソースコード内部は見ていないため、学習用のスクリプト(Beatrice trainer)を軽く眺めた推測値となります。
      • ピッチ推論の所を見るに、サンプリング周波数 16kHz でフレームサイズ 560、ホップサイズ 160 の STFT となっているようなので、全体もその調子で動いているとして遅延量を 25ms (400サンプル@fs=16kHz)と推測しました。
      • と思ってXで呟いたらprj_beatriceさん曰くもうちょっと大きくなっているはずとのこと。ふーむ。

これらを合計すると 50ms 前後となります。上記の実測値より少し小さいとはいえ、大きな齟齬はないですね。
今回の測定方法と遅延の推定値に大きな間違いは無さそうです。

他の環境だとどうなるか

ちなみに、設定を変えてみたり、放課後に職場の機材を借りて実験してみた所、同様に計算して得られた遅延量は下記のようになりました。
やっぱり使用機材や設定によってかなりの影響受けますね…。

  • Yamaha/Steinberg UR12

    • fs:48kHz、API:ASIO、 フレームサイズ:384の場合
      • 遅延量:約 63.5ms (3047サンプル)
    • fs:48kHz、API:WASAPI、 フレームサイズ:480の場合
      • 遅延量:約 126.6ms (6075サンプル)
    • fs:48kHz、API:WASAPI(排他モード)、 フレームサイズ:480の場合
      • 遅延量:約 80.7ms (3872サンプル)
    • fs:48kHz、API:WASAPI(LowLatency)、 フレームサイズ:480の場合
      • 遅延量:約 130.7ms (6273サンプル)
  • RME FirefaceUCX

    • fs:48kHz、API:ASIO、 フレームサイズ:256の場合
      • 遅延量:約 50.1ms (2405サンプル)
    • fs:48kHz、API:ASIO、 フレームサイズ:512の場合
      • 遅延量:約 60.8ms (2919サンプル)
    • fs:48kHz、API:WASAPI(排他モード)、 フレームサイズ:480の場合
      • 遅延量:約 112.0ms (5379サンプル)
    • 他のWASAPIモードや、ASIOのフレームサイズ 128 などは音切れしたりして正しく測定できず……。

なんか全体的に WASAPI での遅延がやたら大きい気がします。というか、LowLatencyモードが全然低遅延じゃないような…?
もしかしたら、WASAPI の遅延はデバイスの ASIO のフレームサイズ設定にも影響を受けるとか(各測定時にどの設定になっていたかは失念…)なんか気をつけないといけない点があるんじゃないかという気がしてきました。このWASAPIの値はちょっと正確じゃないかも知れません。
まぁ、ASIOが使えるオーディオインタフェースだったらASIOを使っておいたほうが安牌な気はします。

また、職場にあるかと思ったらちょっと見つけられなかったので試せていないのですが、 機会があったら Roland 製のオーディオインタフェースでも測定しておきたいところです。
昔一時期仕事で UA-101QUAD-CAPTURE を使ってたんですが、ASIOのフレームサイズとして 160の倍数を選ぶことが出来た記憶があるんですよね。[5]
オーディオインタフェースのサンプリング周波数とフレームサイズをBeatrice VSTが求める 48kHz・480サンプル に揃えられるので、音切れしにくく動作が安定するんじゃないかなと期待してます。

他のソフトウェアだとどうなるか

Beatrice を VCClientで動かした場合や、RVCなどの他の声質変換を用いた場合についても気になるところではありますが、環境構築が面倒なのでやるとしてもまた後日ですかね…。[6]

最後に

Beatrice v2 は聞いての通り遅延も少なくて品質もいいので、皆もっと使おうぜ!

脚注
  1. 人によってバッファサイズとかブロックサイズとか言ったりもしますね。自分の周りはフレームサイズ呼びが多いかな? ↩︎

  2. ただ、処理内容的に多分480サンプル前後までで十分で、それ以上大きくする意味はあまりないんじゃないかな…?という気はします。 ↩︎

  3. 他には UR12 を買ったときにオマケでライセンスが付いてきた Cubase AI や、フリーでも使える Reaper なんかをよく使っています。 ↩︎

  4. データベースの利用規約的にこの学習したモデルそのものを不用意に公開するのはマズそうですが、こうやって研究目的に使ったうえで出力音を公開するのは大丈夫なはず…多分。 ↩︎

  5. Fireface UCX で使うことを想定してフレームサイズが2の累乗数以外にならないことを前提に実験用アプリ書いたら QUAD-CAPTURE で使ったときに異常終了した苦い思い出が…。 ↩︎

  6. 以前 VCClient は v.1 の頃に Linux 上で docker 使って動かしてたので RVC ならすぐ試せるんですが、Beatrice v2 を VCClient で使おうと思ったら v.2 以降を Windows 上で動かさなきゃですよね多分。 ↩︎

Discussion

ログインするとコメントできます