Abstract
動画や音声ファイルの音量(ゲイン)を ffmpeg で調整するときのメモをPowerShellで一つのコマンドにしたかったが、当時(約1年前)苦労したので備忘録。
環境
- Windows 10
- PoweShell v7.4.0
- ffmpeg version 6.1-full_build-www.gyan.dev
目的
mp3とかの音楽ファイルのmax_volume
を0dB位になるように調整すること。
0以外にもできるように引数を生やしたりして、次のようにコマンドで変換できるようにする。
Set-MaxVolume -InputFile hoge.mp3 -OutputFile fuga.mp3 -TargetVolume 0.0
方針
- ffmepgのログ出力から、max_volumeを抽出
- ゲインを上げたら
$TargetVolume
になるように、上げるゲインX
[dB]を計算 -
ffmpeg -i input -af volume=XdB output
で調整
簡単ですね!
完成したもの
function Select-ffmpegLog([parameter(mandatory=$true)][string]$File, [string]$Pattern = "max_volume:") {
# ffmpegは標準エラーに出力されてしまうので、標準出力に渡しなおす
ffmpeg -i $File -vn -af volumedetect -f null - 2>&1 | Select-String $Pattern;
}
function Find-MaxVolume([parameter(mandatory=$true)][string]$File) {
<#
.SYNOPSIS
対象ファイルのmax_volumeを'10 dB'の形式で取得して返す
#>
$pattern = "max_volume:";
$raw = Select-ffmpegLog $File $pattern;
$raw.Tostring().Substring($raw.Matches.Index + $pattern.Length);
}
function Remove-dB([parameter(mandatory=$true)][string]$dBString) {
<#
.SYNOPSIS
'10 dB' -> '10'のように取り出す
#>
$dBString = $dBString.Replace(' ', '');
$dBString -replace "(\d+)dB", "`$1";
}
function Get-VolumeGain([parameter(mandatory=$true)][string]$File, [float]$TargetVolume = 0.0) {
$max_volume = [float](Remove-dB (Find-MaxVolume $File));
$gain = [Math]::Truncate($TargetVolume - $max_volume * 10) / 10; # 小数点第1位で切り捨て
"${gain}dB";
}
function Set-MaxVolume([parameter(mandatory=$true)][string]$InputFile, [parameter(mandatory=$true)][string]$OutputFile, [float]$TargetVolume = 0.0) {
$gain = Get-VolumeGain $InputFile $TargetVolume;
ffmpeg -i $InputFile -af volume=$gain $OutputFile;
}
ハマりどころと解説
ffmpegのログ出力を受け取れない
A. ffmpegのログ出力は標準エラーに出るから。
初心者殺し。当時沼った。
ということで、次のようにしてログを得て、max_volumeの行をSelect-String
で抽出します。
function Select-ffmpegLog([parameter(mandatory=$true)][string]$file, [string]$pattern = "max_volume:") {
# ffmpegのログ出力は標準エラーに出力されてしまうので、標準出力に渡しなおす
ffmpeg -i $file -vn -af volumedetect -f null - 2>&1 | Select-String $pattern;
}
取得したログからmax_volumeを抽出
Select-String
の返り値から、Matchオブジェクトを取り出して、ゲインを取り出す。
function Find-MaxVolume([parameter(mandatory=$true)][string]$file) {
<#
.SYNOPSIS
対象ファイルのmax_volumeを'10 dB'の形式で取得して返す
#>
$pattern = "max_volume:";
$raw = Select-ffmpegLog $file $pattern;
$raw.Tostring().Substring($raw.Matches.Index + $pattern.Length);
}
上げるゲインを計算する
得られたmax_volume'10 dB'
から10を取り出して、上げるゲインを計算して、'2dB'
みたいな形式で得る。
つまり文字列 -> float -> 計算 -> 文字列という処理が必要。
次のように[float]
でキャストしたりして処理する。
ちなみにReplace
メソッドでは正規表現による置換ができない。
function Remove-dB([parameter(mandatory=$true)][string]$dBString) {
<#
.SYNOPSIS
'10 dB' -> '10'のように取り出す
#>
$dBString = $dBString.Replace(' ', '');
$dBString -replace "(\d+)dB", "`$1";
}
function Get-VolumeGain([parameter(mandatory=$true)][string]$File, [float]$TargetVolume = 0.0) {
$max_volume = [float](Remove-dB (Find-MaxVolume $File));
$gain = [Math]::Truncate($TargetVolume - $max_volume * 10) / 10; # 小数点第1位で切り捨て
"${gain}dB";
}