Skip to content

Instantly share code, notes, and snippets.

@Aquei
Last active June 23, 2023 03:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Aquei/c463dafbd85999fe419fc7f8860a8292 to your computer and use it in GitHub Desktop.
Save Aquei/c463dafbd85999fe419fc7f8860a8292 to your computer and use it in GitHub Desktop.
#license CC0 - https://creativecommons.org/publicdomain/zero/1.0/deed.ja
$noise_max = "-30dB" #この音量未満を対象とする
$duration_min = "1" #この長さ(秒)以上を対象とする
$silent_start_min = 2.0 #開始からこの秒数以内に始まった無音をイントロ無音の対象とする
$silent_end_max = 2.0 #末尾からこの秒数以内に始まった無音をアウトロ無音の対象とする
if ($args.Length -eq 0){
throw "need at least one file path"
}
function Get-SCSilenceData{
param (
$start,
$end
)
$start_time = $start | select-string -Pattern 'silence_start: ([0-9.]+)' | %{ $_.Matches.Groups[1].value }
$end_time = $end | select-string -Pattern 'silence_end: ([0-9.]+)' | %{ $_.Matches.Groups[1].value }
[float] $start_time, [float] $end_time
}
function ConvertTo-SCDurationInt{
param(
$duration_str
)
$nums = $duration_str -Split ':'
[array]::Reverse($nums)
$duration = 0
0..($nums.Length -1) | foreach {
$co = [Math]::Pow(60, $_)
$duration = $duration + $co * $nums[$_]
}
return $duration
}
function Remove-SCSilence{
param(
$file,
$start = 0,
$end = 0
)
$orig_path = $file
$resolved_orig_path = $orig_path | %{ resolve-path -LiteralPath $_ }
$resolved_orig_parent = $resolved_orig_path | %{ split-path -LiteralPath $_ }
$ext = $orig_path -Split '\.' | select-object -Last 1
foreach($c in 0..1000){
$temp_filename = [string] (Get-Date|%{$_.Ticks}) + ".${ext}"
$temp = $resolved_orig_parent + '\' + $temp_filename
if (test-path -Path $temp) {
start-sleep -Milliseconds 10
continue
}
break
}
#元ファイルを一時的に名前に変更
rename-item -LiteralPath $resolved_orig_path -NewName $temp_filename
#cut
if ($start) {
$ss = "-ss", $start
} else {
$ss = $()
}
if ($end) {
$to = "-to", $end
}else{
$to = @()
}
ffmpeg "-hide_banner" "-loglevel" "error" "-i" $temp "-codec" "copy" @ss @to $resolved_orig_path
$result = $?
if($result -eq $true){
remove-item -Path $temp
}
}
function Get-SCTargetData{
param (
$file
)
try{
$rawdata = ffmpeg "-hide_banner" "-i" "$file" "-af" "silencedetect=noise=${noise_max}:duration=${duration_min}" "-f" "null" "-" 2>&1
} catch {
Write-Output $_
}
$duration_str = $rawdata | select-string -Pattern 'Duration: (\d{2}:\d{2}:\d{2}\.\d+)' | %{ $_.Matches.Groups[1].value }
$duration = ConvertTo-SCDurationInt $duration_str
$silences = $rawdata | select-string -Pattern '^\[silencedetect'
if ($silences.Length % 2 -ne 0){
throw "something weard"
}
#初期化
$remove_intro = $false
$remove_outro = $false
if ($silences.Length -ge 2) {
#少なくとも一つの無音がある
$silence_data = Get-SCSilenceData $silences[0].Line $silences[1].Line
$start_first_silence = $silence_data[0]
$end_first_silence = $silence_data[1]
if ($start_first_silence -le $silent_start_min){
#最初の無音がファイルの開始指定秒以内に始まっている場合
write-verbose "先頭の無音が${start_first_silence}に始まり、${end_first_silence}に終わりました"
$remove_intro = $end_first_silence
}
if ($silences.Length -ge 4){
#複数の無音がある
#最後の無音を調べる
$last_silence_data = Get-SCSilenceData $silences[-2].Line $silences[-1].Line
$start_last_silence = $last_silence_data[0]
$end_last_silence = $last_silence_data[1]
}else{
#無音は一つしかなかった場合
$start_last_silence = $start_first_silence
$end_last_silence = $end_first_silence
if (($start_last_silence -le $silent_start_min) -and (($duration - $start_last_silence) -ge $silent_end_max)){
#このファイルはほとんど無音?
}
}
if (($duration - $end_last_silence) -le $silent_end_max){
#最後の無音がファイルの終了から指定秒以前に終了した
write-verbose "末尾の無音が${start_last_silence}に始まり、${end_last_silence}に終わりました"
$remove_outro = $start_last_silence
}
return $remove_intro, $remove_outro
}
}
foreach ($target in $args){
if (test-path -LiteralPath $target){
$remove_intro, $remove_outro = Get-SCTargetData $target $end_first_silence
if ($remove_intro -or $remove_outro){
Remove-SCSilence $target $remove_intro $remove_outro
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment