Extension/SilenceDetect.RoughDraft.Extension.ps1

<#
.Synopsis
    Detects silence in an audio stream
.Description
    Detects silence in an audio stream, using the silencedetect filter.
.Link
    https://ffmpeg.org/ffmpeg-filters.html#silencedetect
#>

# It's an extension
[Runtime.CompilerServices.Extension()]
# that extends Get-Media
[Management.Automation.Cmdlet("Get","Media")]
param(
    # If set, will find silences within an audio.
    [Parameter(Mandatory,ValueFromPipelineByPropertyName)]
    [switch]
    $SilenceDetect,

    # The duration of quiet that is considered silence. By default a half second.
    [Parameter(ValueFromPipelineByPropertyName)]    
    [Timespan]
    $SilenceDuration = "00:00:00.5",

    # The noise tolerance (by default 0.1%)
    # If this is a number between 0 and 1 it will be treated as an amplitude ratio.
    # Otherwise, it will be treated as a decibal value.
    [Parameter(ValueFromPipelineByPropertyName)]
    [Alias('Noise','Tolerance')]    
    [double]
    $NoiseThreshold = 0.001,
    
    # If set, will find silence within any channel of audio
    # (this passes the ironically named mono parameter to the silencedetect filter of FFMPEG).
    [Parameter(ValueFromPipelineByPropertyName)]
    [Alias('Mono','M')]
    [ComponentModel.AmbientValue({"m=true"})]
    [switch]
    $AnyChannel
)

$filterArgs = 
    "d=$($SilenceDuration.TotalSeconds)",
    "n=$(if ($NoiseThreshold -ge 0 -and $NoiseThreshold -le 1){$NoiseThreshold} else {"${NoiseThreshold}dB"})",
    "$(if ($AnyChannel) {'m=true'})" -join ":"

$ffArgs = @(
    '-i', "`"$ri`"", "-af", "silencedetect=$filterArgs", '-f', 'null', '-'
)

Use-FFMpeg -FFMpegPath $ffMpegPath -FFMpegArgument $ffArgs |
. {
    param([Parameter(Mandatory,ValueFromPipeline)][string]$line)

    process {
        $theSilence = @([Regex]::Matches($line, "(?<Key>silence_\S{1,})\s{0,}:\s{0,}(?<Value>[^\s]{1,})"))
        if ($theSilence) {
            foreach ($foundSilence in $theSilence) {
                $theKey = $foundSilence.Groups["Key"].Value
                $theValue = $foundSilence.Groups["Value"].Value
                if ($theKey -eq 'silence_start') {
                    $silenceStart = [Timespan]::FromSeconds($theValue)
                }
                if ($theKey -eq 'silence_end' -and $silenceStart) {
                    $SilenceEnd = [Timespan]::FromSeconds($theValue)
                    [PSCustomObject][Ordered]@{
                        InputPath = "$ri"
                        FilterName = 'silencedetect'
                        Start    = $silenceStart
                        End      = $silenceEnd
                        SilenceDuration = ($silenceEnd - $silenceStart)
                    }               
                    $silenceStart = $null

                    if ($theDuration -and $progId) {
                        $perc = $silenceEnd.TotalMilliseconds * 100 / $theDuration.TotalMilliseconds
                        Write-Progress "$ri - $filterName" " " -PercentComplete $perc -Id $ProgId
                    }
                }
            }
        }
    }

}