Whisper系のモデルは16 kHzの音声を前提としています。一方、多くのMacのオーディオハードウェアは48 kHzで動作します。その間のどこかでレート変換が必要になりますが、フィルタなしで行うと、あなたの声が生み出していない成分がモデルの入力に混入します。
要点
- ローパスフィルタなしで48 kHzから16 kHzへ間引くと、8 kHzを超える成分すべてが音声帯域に折り返されます。
- 帯域制限変換では、まず8 kHzでローパスフィルタをかけ、その後3対1で間引きます。
- Voice TypeはCore Audioに16 kHzの入力ストリームを直接要求するため、通常、変換はアプリではなくオーディオドライバ内で行われます。
- デバイスが16 kHzを提供できない場合、アプリは各バッチのコンディショニングチェーンの最後で
AVAudioConverterを使って変換します。
単純な方法には問題がある
単純な間引き、つまり3サンプルのうち2サンプルを捨てる方法では、エイリアシングが発生します。48 kHzのキャプチャには24 kHzまでの成分が含まれています。8 kHzを超える成分は16 kHzのストリームでは表現できないため、音声帯域に折り返されます。10 kHzのトーンは6 kHzに現れます。モデルは、話者が発していない音を聞くことになります。
安価なリサンプリングは、阻止帯域の減衰ではなく速度を優先して最適化されています。着信音ならそれで構いませんが、音声認識では問題です。「s」「f」「th」の違いは、まさにフィルタが守るべき高周波領域にあるからです。
帯域制限リサンプリング
帯域制限変換とは、目標レートのナイキスト周波数(16 kHz出力なら8 kHz)でローパスフィルタをかけてから間引くことです。エイリアシングを起こす周波数は、折り返される前に取り除かれます。
エンジニアリング上の肝はフィルタです。強すぎると、摩擦音を区別する高周波成分が失われます。弱すぎると、エイリアシングがすり抜けます。
Voice Typeがこれを行う場所
推測されるような場所ではなく、このページの以前のバージョンに書かれていた場所でもありません。
アプリは48 kHzでキャプチャして最後に変換するのではありません。最初から入力のAudio Queueに16 kHzのストリームを要求するため、アプリがサンプルを受け取る前に、キャプチャ経路でCore Audioがレート変換を行います。音声区間検出器、バッチャー、認識器はすべて16 kHzで動作します。ライブのパイプラインに48 kHzの段階はありません。
ただし、要求はあくまで要求であって保証ではないため、アプリ内で変換を行う箇所が2つ残っています。
- 選択されたデバイスが16 kHz以外のレートを報告した場合、音声区間検出器の入力が最初に変換されます。ゲートは16 kHzの512サンプルのフレームだけを前提に作られているためです。
- フラッシュされた各バッチは、16 kHzへのリサンプリングで終わるコンディショニングチェーンを通ります。キャプチャがすでに16 kHzだった場合、この手順は何もしません。そうでない場合は
AVAudioConverterが処理し、短いクリップが前のクリップからのプライミングアーティファクトを拾わないよう、コンバータは呼び出しごとにステートレスとして扱われます。
その周囲のコンディショニングチェーンの順序は、DCオフセットの除去、フィルタとラウドネス制御の適用、そしてリサンプリングです。ハイパスのカットオフはHzで指定され、フィルタ係数は動作するサンプルレートに依存するため、レート変更の前にフィルタをかけるのが正しい順序です。
48 kHzで録音して後から変換すればよいのでは?
それも可能で、多くのパイプラインがそうしています。モデルのレートをキャプチャ層で要求するほうが、3つの点で効率的です。バッファが必要以上に3倍大きくならないこと、一般的な経路では音声区間検出器の前に変換が不要なこと、そして行われる変換がアプリによる繰り返しではなく、オーディオドライバによって一度だけ行われることです。
トレードオフは、自前のコンバータではなくCore Audioのコンバータを信頼することです。私たちはこのトレードオフに満足しています。ドライバレベルのサンプルレートコンバータは十分にテストされたコードであり、代替案はAppleがすでに解決した問題のために自前のものを保守することだからです。
あなたにとっての意味
ほとんど何もありません。それが要点です。レート変換は調整つまみではなく、正しさの問題です。正しく行われれば目に見えず、誤って行われると、どれだけモデルを大きくしても直らない、子音が微妙に間違った文字起こしとして現れます。
似たものを作る場合は、帯域制限コンバータで変換し、一度だけ行い、フィルタの前ではなく後に行ってください。
