非エンジニアが音響知識だけでffmpegのコードサンプル作ってみた

 


この記事はVoicy Advent Calendar 2021 7日目の記事です。

初めまして、Voicyのプロダクトマネージャーのエモジマです。

同時並行で走るVoicyの開発のプロジェクトにおいて、リソースが効率的に配分され、レビュー漏れがなく、コンフリクトせず、最速で高品質のアプトプットをするというような ”無理ゲーパズル” をミッションとして課せられています。

ボクはPMなので業務上コードを書いたりすることはありません。(見え張った、できません。)
しかし、レコーディング・ミックス技術者としてのキャリアがあり、音声処理において基本的な知見を持っています。
音声に対する理解が深いからこそ、Voicyの音声処理について何かコミットできることはないかと思い、ffmpegくらいは触ってみたところ、これがまぁ面白い。

というわけで、非エンジニアがffmpeg触って、ちょっとした音声処理のテンプレを作ってみたのでご紹介します。

※ 以下は社内ハッカソンの際に、アプリエンジニアに渡した設計書が元になっています。コントロール に記載されたパラメータをフロントで入力する想定です。
また、サンプルの音源は変化がわかりやすいように極端な設定にしています。

 

1. Gain調整

音量を調節する機能。設定したdBだけ音量を増減させる。
家庭用オーディオの音量つまみを上げるのと同じようなやつ。

   f:id:a-fridge-on-heatisland:20211206193226p:plain

$ffmpeg -i input.mp3 -af volume=10dB output.wav
//増加の場合単位なし、低減の場合-10dBを指定する。0dBを超える増幅の場合、0dBになる。

・元ファイル

・音量上げ済 (+5dB)

参考: https://www.ffmpeg.org/ffmpeg-filters.html#volume

2. コンプレッサー

音量を圧縮して音圧を調整する機能。 thresholdで閾値を決め、指定したdb以上の音を圧縮する。

ratioで超えた音の圧縮率を決める1:2の場合、4dB超えると2dBに圧縮される。1:20になるとリミッターと呼ばれ、そこ以上は絶対に超えないようにするアプローチ。

makeupで圧縮された後に全体の音量を増減させる。大きい音を圧縮した後、全体の音量を上げると、相対的に音量の小さい部分が大きくなり音量のバラツキを調整できる。

コントール:

  • threshold = -20dB
  • ratio = 1:4、1:8、1:20
  • makeup = 3dB

以下デフォルト設定値

  • attack = 5ms
  • release = 100ms

   

$ffmpeg -i input.mp3 -af acompressor=threshold=-21dB:ratio=20:makeup=3:attack=5:release=100 output.wav 
//thresholdは数値を{-〇}dBで入れ、ratioは1:◯側の数値を入れる。 

・元ファイル

・コンプ済 (threshold -30dB, ratio 1:20, makeup 5dB)

参考: https://www.ffmpeg.org/ffmpeg-filters.html#acompressor

3. フィルター

指定した周波数以下の音を除去(ハイパス)、もしくは指定した周波数以上の音を除去(ローパス)する。
軽くハイパスかけておくと部屋のブォーンっていうノイズ低減になり、ローパスをかけておくと高周波のノイズが消える。かけ過ぎると声質に影響する。

コントール:

  • highpass = 200Hz
  • lowpass = 3000Hz

 

$ffmpeg -i input.mp3 -af highpass=f=200,lowpass=f=3000 output.wav

・元ファイル

・ハイパス (500Hz)

・ローパス (1000Hz)

・ハイパス&ローパス (highpass 500Hz, lowpass 1000Hz)

参考: https://www.ffmpeg.org/ffmpeg-filters.html#highpass

4. ノイズ除去

ホワイトノイズを除去する機能。 ノイズフロアで除去の感度を決める(通常、ホワイトノイズは音が小さく何dB以下をノイズとするかの閾値を決める)
ノイズリダクションで何dB分ノイズ音を低減させるか決める。かけ過ぎると変な変化をする。

コントール:

  • ノイズリダクション = 12dB
  • ノイズフロア = -50dB

以下デフォルト設定値

  • ノイズタイプ = ホワイトノイズ
  • 出力モード = ノイズを除去する

 

$ffmpeg -i input.mp3 -af afftdn=nr=12:nf=-50:nt=w:om=o output.wav
//ノイズフロア(nf)は{-◯}dBの形で入力する。

・元ファイル

・ホワイトノイズ除去済 (リダクション 12dB, ノイズフロア -50dB, タイプ ホワイトノイズ)

参考: https://www.ffmpeg.org/ffmpeg-filters.html#afftdn

5. 音量レベル測定

現在の音量を測定する機能。
オーディオファイルを読み込ませて、以下の数値を表示させたい

  • 音量("max_volume" dB)
  • ラウドネス値("input_i" / LUFS)
  • True Peak("input_tp" / dB)

 

$ffmpeg -i input.mp3 -af volumedetect -f null -
結果
[Parsed_volumedetect_0 @ 0x7fb450004180] n_samples: 441000
[Parsed_volumedetect_0 @ 0x7fb450004180] mean_volume: -21.1 dB 
[Parsed_volumedetect_0 @ 0x7fb450004180] max_volume: -18.1 dB ←これ
[Parsed_volumedetect_0 @ 0x7fb450004180] histogram_18db: 128000
$ffmpeg -i input.wav -af loudnorm=print_format=json -f null -
結果

[Parsed_loudnorm_0 @ 0x7fec77104080] 
{
	"input_i" : "-20.91",←これ
	"input_tp" : "-0.98",←これ
	"input_lra" : "12.40",
	"input_thresh" : "-32.76",
	"output_i" : "-25.16",
	"output_tp" : "-2.86",
	"output_lra" : "4.90",
	"output_thresh" : "-36.36",
	"normalization_type" : "dynamic",
	"
target_offset" : "1.16"
}

参考: https://www.ffmpeg.org/ffmpeg-filters.html#afftdn

 

まとめ

実用化とか全然考えず、とりあえずコマンド叩くと音が変わるってことが確認できただけでも、ボクとしては長〜いウィニングランが出来るほど豪快なゴール達成なわけで。

ffmpegPythonなんかを習得、音声エンジニアになって、早いとこプロダクトマネージャー卒業したいです(嘘)