SSブログ

サンプリング周波数の変換 [プログラム]

とある事情により、LPCMデータでサンプリング周波数を
   48kHz → 44.1kHz → 48kHz
に変換するという、バカな状況が起こってしまいました。
 テレビ放送を録画したもの(48kHz)からffmpegで音声を取り出しながらサンプリング周波数変換(48kHz->44.1kHz)を行ない、CD-Rに書き込んだのです(44.1kHz)が、それが多くなったのでCD-Rからffmepgを使ってサンプリング周波数変換(44.1kHz->48kHz)を行ない、DVD-R(DVDプレーヤーでDVDとして再生が可能なもの; 48kHz)に焼き直したのです(最後のものは、Roxio Toastで簡単にできます)。
 しかし、聞いてみると、どうも音が濁っています。CDプレーヤーの再生回路よりもDVDプレイヤーの音声再生回路が悪いのかとも思いましたが、それにしては、普通のDVDの音声がマトモ過ぎますから、DVDプレイヤーの音声再生回路は犯人ではなさそうです。
 となると、「音が汚なすぎるのは、もしかしたらffmpegのせいではないか?」と私が思ってもまったく不思議ではありませんでした。

 さて、ffmpeg以外にも、SoX(Sound eXchange)でもサンプリング周波数の変換ができます。ただ、コマンドラインのオプションの使い方がよくわからず、検索でヒットしたページのとおりに指定したら、そんなオプション知らん!と言われたり、とにかく使いこなすのが大変なので、遠ざかっていました。今回、SoXを使って、サンプリング周波数の変換などを試してみましょう。ついでに、AudacityやToast(Toast10; mac版 10.0.7)も試してみます。

 調査は次の手順で行ないます。
まず、基準となる音声ファイルを作ります(たとえば、10秒の1kHzの正弦波、48kHzと44.1kHzでサンプリング)。
次に、これをffmpegとsoxとaudaciy(Best Sinc Interpolator,Dither None)とToastでサンプリング周波数の変換をします。
さらに、サンプリング周波数の変換をした音声ファイルを、もう一度サンプリング周波数の変換をして、元のサンプリング周波数に戻したものを作ります。
 つまり、次の4つのファイルを作ります。

  • 基準(44.1kサンプリング) → 48kに変換
  • 基準(48kサンプリング) → 44.1kに変換
  • 基準(44.1kサンプリング) → 48kに変換 → 44.1kに変換
  • 基準(48kサンプリング) → 44.1kに変換 → 48kに変換
 あとは、サンプリング周波数ごとに、基準となる音声ファイルのデータの「値」と変換したもの、さらに再変換したものの「値」と差を比較します。
 今回、差の比較方法として、単純に、差の絶対値の合計としましたが、その結果だけで、soxやaudacityと、ffmpegは「十分なほどの差がありました」。

ところで、今回始めて知ったのですが、SoXやAudacityでは、設定により、変換の際にあえて「ノイズを加える」処理を行なうようになっていました。これは、SoXで生成したファイルが毎回値が異なっていたためわかったのですが、今回の調査では不要ですので、変換時には、-Dでoffしたり、-Rでrandom seedを固定したりしました。

 なお、バージョンは以下のとおりです。
  • sox: SoX v14.3.1
  • FFmpeg SVN-r23334
      libavutil     50.16. 0 / 50.16. 0
      libavcodec    52.70. 0 / 52.70. 0
      libavformat   52.66. 0 / 52.66. 0
      libavdevice   52. 2. 0 / 52. 2. 0
      libavfilter    1.20. 0 /  1.20. 0
      libswscale     0.10. 0 /  0.11. 0
      libpostproc   51. 2. 0 / 51. 2. 0
  • Audacity v1.3.10-beta (Unicode)
  • Toast10(10.0.7)
 また、soxでのサンプリングレートの変換は、rateでのデフォルトの
    -h     high      95%     125     16-bit mastering (use with dither)
と、
    -v   very high   95%     175     24-bit mastering
の両方を試してみました。なお、SoXのページのFAQにある
    dither -s
は、-hと-vでの両方で試してみましたが、結果(誤差とFFT)をみる限りにおいて「使うべきでない」と判断しました。誤差が多く、FFTでは20kHzのまわりに波形がでていました。さらに、SoXでは-Dと-Rオプションを指定し、ノイズを追加しないようにしました。

 結果は以下のとおりです。


ffmpeg
sox
sox -v
  誤差合計 最大誤差 誤差合計 最大誤差 誤差合計 最大誤差
48k->44.1k
1kHz 605,294 493 220,620 164 220,718 164
5kHz 2,368,239 2,588 226,804 844 227,157 845
10kHz 4,740,763 6,168 234,503 1,813 235,218 1,816
15kHz 740,473,840 15,374 248,212 3,033 249,627 3,078
20kHz 6,419,425,028 22,868 333,519 6,353 339,598 6,164

44.1k->48k
1kHz 740,226 334 246,558 178 246,649 178
5kHz 2,387,836 1,738 256,104 906 255,722 903
10kHz 4,682,808 3,974 265,215 1,957 265,982 1,951
15kHz 190,046,717 8,711 290,234 3,476 288,278 3,464
20kHz 5,014,488,725 17,389 7,858,724 7,779 963,641 7,746
 
44.1k->48k->44.1k
1kHz 1,097,677 448 35,959 235 36,072 236
5kHz 4,482,480 2,356 45,839 1,200 45,820 1,200
10kHz 9,065,992 5,743 58,468 2,560 59,331 2,560
15kHz 898,376,184 15,565 86,089 4,270 247,523 4,309
20kHz 7,020,275,885 25,009 7,402,131 8,651 913,698 8,431
 
48k->44.1k->48k
1kHz 1,198,943 541 66,332 269 66,503 269
5kHz 4,892,888 2,835 76,336 1,374 76,462 1,372
10kHz 9,947,555 6,793 90,257 2,947 91,257 2,941
15kHz 967,383,206 17,418 125,734 5,033 119,265 5,048
20kHz 7,467,202,670 25,039 7,874,228 10,623 974,258 10,528


audacity
toast10
  誤差合計 最大誤差 誤差合計 最大誤差
48k->44.1k
1kHz 221,073 97 1,387,077 155
5kHz 226,880 508 6,434,139 796
10kHz 234,233 1,154 14,760,306 1,819
15kHz 247,930 2,292 31,593,019 3,732
20kHz 330,915 6,780 4,556,636,932 23,212

44.1k->48k
1kHz 246,892 97 239,668 147
5kHz 254,867 503 243,641 764
10kHz 263,383 1,136 244,574 1,731
15kHz 283,170 2,209 255,127 3,465
20kHz 376,568 5,992 4,877,475,407 25,451

44.1k->48k->44.1k
1kHz 34,529 81 1,241,147 156
5kHz 43,033 424 6,293,410 813
10kHz 55,394 972 14,621,993 1,887
15kHz 78,547 1,982 31,461,050 4,029
20kHz 201,524 6,712 6,303,307,517 26,320

48k->44.1k->48k
1kHz 66,762 438 1,120,589 215
5kHz 80,077 1,949 5,606,065 1,118
10kHz 90,302 2,497 13,055,018 2,571
15kHz 98,336 2,759 28,513,225 5,349
20kHz 215,840 8,736 6,717,687,514 26,929

 まず第一に最大誤差を見ますと、明らかにffmpegは酷すぎます。サンプリング周波数変換のためには使うべきではありません。特に20kHzでの変換結果は異常です。波形を見ると振幅が非常に小さくなってしまっています。採用しているサンプリング周波数変換のアルゴリズムに問題がありそうです(ひょっとするとオプションで選択できたりするのでしょうか?)。

 SoXは、良い方です。なお、48kHzに変換する場合には-vオプションを使うとよいでしょう。

 Audacityは全体的に優秀です。

 Toastは、低中音域ではSoXと同程度の良さなのですが、ffmpegと同じく致命的な欠点があります。ffmpegほどではありませんが、20kHzの振幅が半分程度に小さくなってしまうのです。これですべてが台無しです。これも採用しているサンプリング周波数変換のアルゴリズムに問題がありそうです。

 また、変換結果をAudacityで開いて、plot spectrumを使って3〜6秒の間の周波数成分をみますと、SoXやAudacityは鋭いピークのみですが、ffmpegはそれ以外のところ数ヶ所にピークが出ていたり、toastではピーク以外に全体的に変な形になっていたりと、明らかに問題のある変換結果でした。問題のあるものだけ示します。

ffmpeg-20kHz-44.1k.pngffmpeg-20kHz-48k.png まず、ffmpegの20kHzでの、サンプリング周波数48kHz→44.1kHzと44.1kHz→48kHzへの変換の結果のスペクトラムです。48kHzは明らかですが、44.1kHzの場合も450Hzと4600Hzあたりに小さなピークが出ています。



















toast-1kHz-44.1k.pngtoast-20kHz-44.1k.png

 次にToast10です。ffmpegよりもすごいことになっています。1kHzと20kHzでの、サンプリング周波数48kHz→44.1kHzへの変換の結果のスペクトラムです。


 

 

 

 

 

 

 

 

 

 

 

toast-20kHz-44.1k-sound.png

  また、Toastでは、次のように振幅が半分程度に小さくなってしまっています(この現象はffmpegでも見られました)。20kHzでの、サンプリング周波数48kHz→44.1kHzへの変換の結果のデータです。

 

 

 

 

 簡単にまとめますと、私の結論としては

  • サンプリング周波数の変換には、Audacityを持ちいること。Audacityが使えないときはSoXを使うこと。
  • SoXのdither -sオプションは使わない方がよさそうだ。デフォルトか、-vオプションを使うこと。-vの方が高域の誤差が少ない。
  • ffmpegでは音声データの変換を行なわないこと。ffmpegではフォーマット変換のみを行なうこと。
  • Toastでは音声データの変換を行なわないこと。
となりました。

 さて、Audacityではサンプリング周波数の変換のためのバッチ処理はできません。エフェクトのバッチ処理はできるのですが、そこにサンプリング周波数の変換はないのです。全部手作業となると、非常に面倒です。一方、SoXはバッチ処理ができます。以上のことから、私としては、可能な限りaudacityを用い、バッチ処理が必要なほど多いときにはSoX -vで処理する、という方針にしました。ただし、この決定は、各ソフトのバージョンが変わったときに変更される可能性があります。なにしろ、過去には「SoXの変換は音が悪い」と言われていたこともあるのですから。

 なお、今回は、ノイズの追加処理を行なわないようにして調査しましたが、調査を主目的とするのでなければ、デフォルトやdither -sオプションによるノイズの追加処理を使う方がよいかもしれません。自分の耳で確認してください。


 というわけで、soxでサンプリング周波数の変換をするためのオプションは次のとおり。
sox 元の音声ファイル 変換後の音声ファイル rate -v 44.1k
48kHzにするなら、44.1kのところを48kにします。また、very highにしないのならば-vをとります。音声ファイルのフォーマットは、各ファイルの拡張子で判断されます。なお、SoXのFAQページによるCDのためのマスタリングは次のオプションを指定しろとかかれています。
sox 元の音声ファイル 変換後の音声ファイル rate -v 44.1k dither -s

 参考までに、テストで使ったコマンドとオプションの例です。
基準となる音声ファイルの作成(10秒の1kHzの正弦波、-1.938db、44.1kHz)
    sox -n 基準となる音声ファイル synth 10 sine 1000 gain -1.938
サンプリング周波数の変換
    ffmpeg -i 基準となる音声ファイル -ar 48000 変換後の音声ファイル
    sox 基準となる音声ファイル -D -R 変換後の音声ファイル rate -v 48k
RAW(LPCM)への変換(16bit LPCM、BigEndian)
    ffmpeg -i 音声ファイル -f s16be LPCM音声ファイル
    sox 音声ファイル -B LPCM音声ファイル.s16


共通テーマ:パソコン・インターネット

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。