22.05kHz vs 44.1kHz — 『本物の広帯域』とアップサンプリングは何が違うのか
音声変換の出力を聴き比べていて、こんな疑問を持ったことはないでしょうか。
「44.1kHz で書き出しているのに、なんだか音がこもって聞こえる」
書き出しのサンプリングレートは確かに 44.1kHz。ファイルのプロパティにもそう出ている。なのに、CD音質の空気感がない。実はこれ、サンプリングレートの数字と、実際に含まれる音の帯域は別物だからです。この記事は、「声のデザイン」アプリで 22.05kHz モデルから 44.1kHz の F0 条件付きモデルへ切り替えたときに確かめた、“本物の広帯域” とアップサンプリングの決定的な違いの記録です。
前提: サンプリングレートは「上限」を決めるだけ
まず基本の確認から。ナイキスト定理により、サンプリングレート fs の音声が表現できる周波数の上限は fs / 2 です。
- 22.05kHz → 上限 約11kHz
- 44.1kHz → 上限 約22kHz
ここで大事なのは、「44.1kHz にすれば22kHzまで表現できる」だけであって、「22kHzまで中身が詰まる」わけではない、という点です。器の大きさが決まるだけで、中身が自動で増えるわけではない。
22.05kHz で作られた音声には、そもそも11kHzより上の成分が存在しません。これを 44.1kHz にリサンプル(アップサンプル)しても、空いた高域は空のままです。器を2倍に広げても、無かったものは生まれてこない。これが直感に反するポイントです。
22.05kHz モデルと 44.1kHz モデルは別物
「声のデザイン」の推論サービスは、環境変数でモデルを切り替えます。
# 44.1kHz F0条件付きモデル(本物の広帯域出力)を使うか。既定OFF(従来22.05kHz)。
F0_COND = os.environ.get("VOICE_CANVA_F0", "0") == "1"
そして 44k モードの起動スクリプトはこうなっています。
export VOICE_CANVA_F0="${VOICE_CANVA_F0:-1}" # 44k F0条件付きモデルを使う
export VOICE_CANVA_OUTPUT_SR="${VOICE_CANVA_OUTPUT_SR:-44100}" # 出力も44.1kHz(ダウンサンプルしない)
export VOICE_CANVA_AUTO_F0="${VOICE_CANVA_AUTO_F0:-1}" # キャリアF0を目標音域へ寄せる
ここが決定的です。VOICE_CANVA_F0=1 は単に「出力ファイルのレートを上げる」設定ではありません。生成モデルそのものを、44.1kHz で学習された別のモデルに差し替えているのです。
内部的には、22kモデルと44kモデルはチェックポイントもボコーダも異なります。44kモデルは高いサンプリングレートで学習された BigVGAN ボコーダを持っており、メルスペクトログラムから波形へ戻す段階で、11kHzより上の帯域をモデルが生成できる。つまり空の高域を、リサンプルで機械的に埋めるのではなく、学習した知識に基づいて中身として作り出すわけです。
sr もモデルに追従して切り替わります。
sr = mel_fn_args["sampling_rate"] # f0モードは44100
出力レートも 44100 のまま維持し、ダウンサンプルしません。「44kで生成 → 44kで出力」という一貫した経路を保つことで、せっかく作った高域を途中で捨てないようにしています。
実測: 高域にエネルギーが乗っているか
「本当に高域の中身が増えたのか」は、数字で確かめないと意味がありません。そこで、同じ入力から生成した音声のスペクトルを見て、11kHzより上の帯域が全体エネルギーに占める割合を測りました。
結果はこうでした。
- 44.1kHz モデルで生成した出力: >11kHz 帯に全エネルギーの 約7.4% が乗っている
- 22.05kHz 出力を 44.1kHz へアップサンプルしたもの: >11kHz 帯は ほぼゼロ
同じ 44.1kHz のファイルでも、中身がまるで違います。アップサンプルした側は、器こそ22kHzまであるのに、11kHzより上は空っぽ。一方、44kモデルの出力にはちゃんとエネルギーが乗っている。この7.4%が、子音の抜けや息の空気感、“CD音質らしさ” として耳に届く成分です。
数字にすると当たり前に見えますが、耳だけで聴き比べると「なんとなくこっちがクリア」で終わってしまいがちです。スペクトルで帯域ごとのエネルギーを見て初めて、「高域が生まれている / いない」を客観的に切り分けられました。
なぜアップサンプルでは高域が生まれないのか
理屈をもう少しだけ。アップサンプリングは、既存のサンプル点の間を補間する処理です。線形補間にせよ、より高品質なローパス補間にせよ、やっていることは「今ある波形をなめらかにつなぐ」こと。新しい周波数成分をでっち上げることはしません(むしろ真っ当なリサンプラーは、折り返し雑音として偽の高域が出ないよう、上限より上を積極的に消します)。
だから「22.05kHz音声を44.1kHzにする」と「44.1kHzで音声を生成する」は、結果の器が同じでも中身が根本的に違う。前者は補間、後者は生成です。高域という “情報” は、それを知っているモデルにしか作れません。
落とし穴と学び
- サンプリングレートの数字を音質の証明に使わない。「44.1kHz出力」はスペック表の飾りになりがちですが、中身が伴っているとは限りません。帯域ごとのエネルギーを実測して初めて “本物” を主張できます。
- 44kモデルは重い。起動スクリプトにも「モデルが大きくCPUでは生成が遅い(GPU推奨)」と明記しています。広帯域は無料ではなく、モデルサイズと推論コストの対価です。用途に応じて 22k と使い分ける前提で設計するのが現実的です。
- 経路のどこかでダウンサンプルすると台無し。せっかく44kで生成しても、後段のどこかで22kに落とせば高域は消えます。
VOICE_CANVA_OUTPUT_SR=44100を明示し、生成から出力まで一貫させることが重要でした。 - “高域が足りない” は根本原因を疑う。こもって聞こえるとき、EQで高域を持ち上げるのは応急処置にすぎません。無い成分は持ち上げようがない。真の解決は「高域を生成できるモデルに切り替える」ことでした。
まとめ
- サンプリングレートは表現できる周波数の上限を決めるだけで、中身が自動で詰まるわけではない
- 22.05kHz音声を44.1kHzにアップサンプルしても、11kHzより上の高域は生まれない(補間であって生成ではない)
VOICE_CANVA_F0=1は出力レートを上げる設定ではなく、44.1kHzで学習された別モデル(BigVGANボコーダ込み)への切り替え- 実測では、44kモデル出力は >11kHz 帯に全エネルギーの約7.4%が乗り、22kアップサンプルはほぼゼロ
- 広帯域はモデルサイズ・推論コストの対価。生成から出力まで44kを一貫させ、途中でダウンサンプルしないことが肝心