Files

851 lines
29 KiB
VB.net

Imports System.Text
Imports System.Globalization
Imports System.Text.RegularExpressions
Imports System.Runtime.Remoting
Public Class Audio
Shared Sub Process(ap As AudioProfile)
If Not File.Exists(ap.File) OrElse TypeOf ap Is NullAudioProfile Then
Exit Sub
End If
If Not Directory.Exists(p.TempDir) Then
p.TempDir = ap.File.Dir
End If
If ap.File <> p.SourceFile Then
Log.Write("Media Info Audio Source " & (ap.GetTrackIndex + 1), MediaInfo.GetSummary(ap.File))
End If
Dim normalized = False
Dim isGUIAP = TypeOf ap Is GUIAudioProfile
Dim gap = TryCast(ap, GUIAudioProfile)
If isGUIAP AndAlso gap.ContainsCommand("ffmpeg") Then
normalized = gap.NormalizeFF()
End If
Dim extractCore = isGUIAP AndAlso gap.ExtractCore
If ap.Decoder <> AudioDecoderMode.Automatic AndAlso Not extractCore Then
Convert(ap)
End If
If ap.HasStream Then
Dim cutting = p.Ranges.Count > 0
Dim directMux = TypeOf ap Is MuxAudioProfile AndAlso
p.VideoEncoder.Muxer.IsSupported(ap.Stream.Ext) AndAlso
p.VideoEncoder.Muxer.IsSupported(ap.File.Ext) AndAlso Not cutting
Dim trackIsSupportedButNotContainer = TypeOf ap Is MuxAudioProfile AndAlso
p.VideoEncoder.Muxer.IsSupported(ap.Stream.Ext) AndAlso
Not p.VideoEncoder.Muxer.IsSupported(ap.File.Ext)
If ((cutting OrElse Not ap.IsInputSupported) AndAlso Not directMux) OrElse
trackIsSupportedButNotContainer Then
Select Case ap.File.ExtFull
Case ".mkv", ".webm"
mkvDemuxer.Demux(ap.File, {ap.Stream}, Nothing, ap, p, False, False, True, "Demux MKV Audio " & (ap.GetTrackIndex + 1), True)
Case ".mp4"
MP4BoxDemuxer.DemuxAudio(ap.File, ap.Stream, ap, p, True)
Case Else
If p.Script.GetFilter("Source").Script.ToLowerInvariant.Contains("directshowsource") AndAlso TypeOf ap IsNot MuxAudioProfile Then
ConvertDirectShowSource(ap)
ElseIf Not ap.File.Ext = "m2ts" Then
ffmpegDemuxer.DemuxAudio(ap.File, ap.Stream, ap, p, True)
End If
End Select
End If
End If
Cut(ap)
If TypeOf ap IsNot MuxAudioProfile AndAlso ap.NeedConvert Then
Convert(ap, True)
End If
End Sub
Shared Function GetBaseNameForStream(filePath As String, stream As AudioStream) As String
Dim base = If(p.TempDir?.DirExists() AndAlso New DirectoryInfo(p.TempDir).Name.EndsWith("_temp") AndAlso filePath.Base.StartsWithEx(p.SourceFile.Base),
filePath.Base.Substring(p.SourceFile.Base.Length),
filePath.Base)
Dim ret = base + " ID" & (stream.Index + 1)
If stream.Language.TwoLetterCode <> "iv" Then
ret += $"_[{stream.Language.Name}] ({stream.Language.EnglishName})"
End If
If stream.Default Then
ret += " [Default]"
End If
If stream.Forced Then
ret += " [Forced]"
End If
If stream.SBR Then
ret += " [SBR]"
End If
If stream.Delay <> 0 Then
ret += " " & stream.Delay & "ms"
End If
If stream.Title <> "" Then
Dim pathLength = (p.TempDir + ret).Length
Dim leftLength = GlobalClass.MAX_PATH - 10 - pathLength
If leftLength > 3 Then
ret += " {" + stream.Title.Shorten(leftLength).EscapeIllegalFileSysChars + "}"
End If
End If
Return ret.Trim
End Function
Shared Sub Convert(ap As AudioProfile, Optional force As Boolean = False)
If Not force AndAlso ap.File.Ext = ap.ConvertExt Then Exit Sub
If ap.File.Ext = "avs" Then
Dim outPath = ap.File.DirAndBase + "." + ap.ConvertExt
Dim args = "-i " + ap.File.Escape + " -y -hide_banner " + outPath.Escape
Using proc As New Proc
proc.Header = "AVS to " + outPath.Ext.ToUpperInvariant
proc.SkipStrings = {"frame=", "size="}
proc.Encoding = Encoding.UTF8
proc.Package = Package.ffmpeg
proc.Arguments = args
proc.Start()
End Using
If g.FileExists(outPath) Then
ap.File = outPath
Exit Sub
End If
End If
Dim isGUIAP = TypeOf ap Is GUIAudioProfile
Dim gap = TryCast(ap, GUIAudioProfile)
Dim renormalize = isGUIAP AndAlso gap.Params.Normalize AndAlso gap.GetEncoder() <> GuiAudioEncoder.deezy AndAlso
(gap.Params.ffmpegNormalizeMode = ffmpegNormalizeMode.dynaudnorm OrElse
(gap.Params.ChannelsMode <> ChannelsMode.Original OrElse gap.GetEncoder() = GuiAudioEncoder.opusenc))
Select Case ap.Decoder
Case AudioDecoderMode.ffmpeg, AudioDecoderMode.Automatic
ConvertFF(ap)
Case AudioDecoderMode.FFAudioSource
ConvertFFAudioSource(ap)
Case AudioDecoderMode.eac3to
ConvertEac3to(ap)
Case AudioDecoderMode.NicAudio
ConvertNicAudio(ap)
Case AudioDecoderMode.DirectShow
ConvertDirectShowSource(ap)
End Select
If p.Script.GetFilter("Source").Script.ToLowerInvariant.Contains("directshowsource") Then
ConvertDirectShowSource(ap)
End If
gap.Params.Normalize = renormalize
gap.Params.ffmpegNormalizeMode = If(gap.Params.ffmpegNormalizeMode = ffmpegNormalizeMode.dynaudnorm, ffmpegNormalizeMode.volumedetect, gap.Params.ffmpegNormalizeMode)
ConvertFF(ap, renormalize)
ConvertEac3to(ap)
ConvertDirectShowSource(ap)
End Sub
Shared Sub CutNicAudio(ap As AudioProfile)
If ap.File.Contains("_cut_") Then
Exit Sub
End If
If Not FileTypes.NicAudioInput.Contains(ap.File.Ext) Then
Exit Sub
End If
If Not Package.AviSynth.VerifyOK(True) Then
Throw New AbortException
End If
ap.Delay = 0
Dim d As New VideoScript
d.Filters.AddRange(p.Script.Filters)
Dim wavPath = Path.Combine(p.TempDir, ap.File.Base + "_cut_na.wav")
d.Path = Path.Combine(p.TempDir, ap.File.Base + "_cut_na.avs")
d.Filters.Insert(1, New VideoFilter(GetNicAudioCode(ap)))
If ap.Channels = 2 Then
d.Filters.Add(New VideoFilter(GetDown2Code))
End If
d.Synchronize()
Dim args = "-i " + d.Path.Escape + " -y -hide_banner " + wavPath.Escape
Using proc As New Proc
proc.Header = "AVS to WAV"
proc.SkipStrings = {"frame=", "size="}
proc.WriteLog(Macro.Expand(d.GetScript) + BR)
proc.Encoding = Encoding.UTF8
proc.Package = Package.ffmpeg
proc.Arguments = args
proc.Start()
End Using
If g.FileExists(wavPath) Then
ap.File = wavPath
Log.WriteLine(MediaInfo.GetSummary(wavPath))
Else
Log.Write("Error", "no output found")
End If
End Sub
Shared Sub ConvertNicAudio(ap As AudioProfile)
If ap.File.Ext = ap.ConvertExt Then
Exit Sub
End If
If Not FileTypes.NicAudioInput.Contains(ap.File.Ext) Then
Exit Sub
End If
If Not Package.AviSynth.VerifyOK(True) Then
Throw New AbortException
End If
ap.Delay = 0
Dim d As New VideoScript
d.Filters.AddRange(p.Script.Filters)
d.RemoveFilter("Cutting")
Dim outPath = Path.Combine(p.TempDir, ap.File.Base + "_DecodeNicAudio." + ap.ConvertExt)
d.Path = Path.Combine(p.TempDir, ap.File.Base + "_DecodeNicAudio.avs")
d.Filters.Insert(1, New VideoFilter(GetNicAudioCode(ap)))
If ap.Channels = 2 Then
d.Filters.Add(New VideoFilter(GetDown2Code))
End If
d.Synchronize()
Dim args = "-i " + d.Path.Escape + " -y -hide_banner " + outPath.Escape
Using proc As New Proc
proc.Header = "AVS to WAV"
proc.SkipStrings = {"frame=", "size="}
proc.WriteLog(Macro.Expand(d.GetScript) + BR)
proc.Encoding = Encoding.UTF8
proc.Package = Package.ffmpeg
proc.Arguments = args
proc.Start()
End Using
If g.FileExists(outPath) Then
ap.File = outPath
Log.WriteLine(MediaInfo.GetSummary(outPath))
Else
Log.Write("Error", "no output found")
End If
End Sub
Shared Sub Cut(ap As AudioProfile)
If p.Ranges.Count = 0 OrElse
Not File.Exists(ap.File) OrElse
TypeOf p.VideoEncoder Is NullEncoder OrElse
ap.File.Contains("_cut_.") Then
Exit Sub
End If
Select Case p.CuttingMode
Case CuttingMode.mkvmerge
CutMkvmerge(ap)
Case CuttingMode.NicAudio
If FileTypes.NicAudioInput.Contains(ap.File.Ext) AndAlso TypeOf ap IsNot MuxAudioProfile Then
CutNicAudio(ap)
Else
CutMkvmerge(ap)
End If
Case CuttingMode.DirectShow
If TypeOf ap IsNot MuxAudioProfile Then
CutDirectShowSource(ap)
Else
CutMkvmerge(ap)
End If
End Select
End Sub
Shared Function GetNicAudioCode(ap As AudioProfile) As String
Select Case ap.File.Ext
Case "ac3"
Return "AudioDub(last, NicAC3Source(""" + ap.File + """, Channels = " & ap.Channels & "))"
Case "mpa", "mp2", "mp3"
Return "AudioDub(last, NicMPASource(""" + ap.File + """))"
Case "wav"
Return "AudioDub(last, RaWavSource(""" + ap.File + """, Channels = " & ap.Channels & "))"
End Select
End Function
Shared Sub ConvertEac3to(ap As AudioProfile)
If ap.File.Ext = ap.ConvertExt Then
Exit Sub
End If
If Not FileTypes.eac3toInput.Contains(ap.File.Ext) Then
Exit Sub
End If
Dim outPath = Path.Combine(p.TempDir, ap.File.Base + "." + ap.ConvertExt)
Dim args = ap.File.Escape + " " + outPath.Escape
If ap.Channels = 6 Then
args += " -down6"
ElseIf ap.Channels = 2 Then
args += " -down2"
End If
If TypeOf ap Is GUIAudioProfile Then
Dim gap = DirectCast(ap, GUIAudioProfile)
If gap.Params.Normalize Then
args += " -normalize"
gap.Params.Normalize = True
End If
End If
args += " -simple -progressnumbers"
Using proc As New Proc
proc.Header = "Convert " + ap.File.Ext.ToUpperInvariant + " to " + outPath.Ext.ToUpperInvariant + " " & (ap.GetTrackIndex + 1)
proc.Package = Package.eac3to
proc.Arguments = args
proc.TrimChars = {"-"c, " "c}
proc.SkipStrings = {"process:", "analyze:"}
proc.AllowedExitCodes = {0, 1}
proc.Start()
End Using
If g.FileExists(outPath) Then
ap.File = outPath
Log.WriteLine(MediaInfo.GetSummary(outPath))
Else
Log.Write("Error", "no output found")
End If
End Sub
Shared Sub ConvertFF(ap As AudioProfile, Optional force As Boolean = False)
If Not force AndAlso ap.File.Ext = ap.ConvertExt Then Exit Sub
Dim gap = TryCast(ap, GUIAudioProfile)
gap?.NormalizeFF()
Dim base = ap.File.Base
If Not base.Contains(ap.GetTrackID) Then
base += ap.GetTrackID
End If
Dim outPath = Path.Combine(p.TempDir, base + "." + ap.ConvertExt)
If ap.File = outPath Then
outPath += "." + ap.ConvertExt
End If
Dim cancel = True
Dim args = "-y -hide_banner -i " + ap.File.Escape
If ap.Stream IsNot Nothing Then
args += " -map 0:" & ap.Stream.StreamOrder
End If
If ap.Gain <> 0 Then
args += " -af volume=" + ap.Gain.ToInvariantString + "dB"
cancel = False
End If
If gap?.Params.Normalize Then
If gap.Params.ffmpegNormalizeMode = ffmpegNormalizeMode.dynaudnorm Then
args += " " + Audio.GetDynAudNormArgs(gap.Params)
cancel = False
ElseIf gap.Params.ffmpegNormalizeMode = ffmpegNormalizeMode.loudnorm Then
args += " " + Audio.GetLoudNormArgs(gap.Params)
cancel = False
End If
End If
If gap.Params.CenterOptimizedStereo AndAlso ((gap?.Params.Codec <> AudioCodec.Opus AndAlso gap?.Params.ChannelsMode = ChannelsMode._2) OrElse (gap?.Params.Codec = AudioCodec.Opus AndAlso gap?.Params.OpusencDownmix = OpusDownmix.Stereo)) Then
If gap.SourceChannels = 8 Then
args += " -af pan=stereo|c0=c2+0.30c0+0.30c4+0.30c6|c1=c2+0.30c1+0.30c5+0.30c7"
Else
args += " -af pan=stereo|c0=c2+0.30*c0+0.30*c4|c1=c2+0.30*c1+0.30*c5"
End If
gap.Params.ChannelsMode = ChannelsMode.Original
gap.Params.OpusencDownmix = OpusDownmix.Original
cancel = False
ElseIf gap.Params.ChannelsMode <> ChannelsMode.Original Then
args += " -ac " & CInt(gap.Params.ChannelsMode)
gap.Params.ChannelsMode = ChannelsMode.Original
gap.Params.OpusencDownmix = OpusDownmix.Original
ElseIf gap.Params.Codec = AudioCodec.Opus AndAlso gap.Params.OpusencDownmix <> OpusDownmix.Original Then
args += " -ac " & CInt(gap.Params.OpusencDownmix)
gap.Params.ChannelsMode = ChannelsMode.Original
gap.Params.OpusencDownmix = OpusDownmix.Original
Else
If Not force Then
args += " -ac " & ap.Channels
End If
gap.Params.ChannelsMode = ChannelsMode.Original
gap.Params.OpusencDownmix = OpusDownmix.Original
End If
If force AndAlso cancel Then Exit Sub
If ap.ConvertExt.EqualsAny("wav", "w64") Then
Select Case p.AudioIntermediateWaveBitDepth
Case IntermediateWaveBitDepth.s24
args += " -c:a pcm_s24le"
Case IntermediateWaveBitDepth.s32
args += " -c:a pcm_s32le"
Case IntermediateWaveBitDepth.f32
args += " -c:a pcm_f32le"
Case Else
args += " -c:a pcm_s32le"
End Select
End If
Dim matches = Regex.Matches(args, " -af ([^ ]+)")
If matches.Count > 1 Then
Dim concated = ""
For i = matches.Count - 1 To 0 Step -1
Dim match = matches(i)
concated = $"{match.Groups(1)},{concated}"
args = args.Remove(match.Index, match.Length)
Next
concated = " -af " + concated.Trim(","c)
args = args.Insert(matches(0).Index, concated)
End If
args = Regex.Replace(args, " -af ([^ ]+)", " -af ""$1""")
args += " " + outPath.Escape
Using proc As New Proc
proc.Header = "Convert " + ap.File.Ext.ToUpperInvariant + " to " + outPath.Ext.ToUpperInvariant + " " & (ap.GetTrackIndex + 1)
proc.SkipStrings = {"frame=", "size="}
proc.Encoding = Encoding.UTF8
proc.Package = Package.ffmpeg
proc.Arguments = args
proc.AllowedExitCodes = {0, 1}
proc.Start()
End Using
If g.FileExists(outPath) Then
If outPath.StartsWith("\\?\") Then
outPath = outPath.Substring(4)
End If
ap.Gain = 0
gap.Params.CenterOptimizedStereo = False
ap.File = outPath
Log.WriteLine(MediaInfo.GetSummary(outPath))
Else
Log.Write("Error", "no output found")
End If
End Sub
Shared Function GetLoudNormArgs(params As GUIAudioProfile.Parameters) As String
Return "-af loudnorm=" +
"I=" + params.ffmpegLoudnormIntegrated.ToInvariantString +
":TP=" + params.ffmpegLoudnormTruePeak.ToInvariantString +
":LRA=" + params.ffmpegLoudnormLRA.ToInvariantString +
":measured_I=" + params.ffmpegLoudnormIntegratedMeasured.ToInvariantString +
":measured_TP=" + params.ffmpegLoudnormTruePeakMeasured.ToInvariantString +
":measured_LRA=" + params.ffmpegLoudnormLraMeasured.ToInvariantString +
":measured_thresh=" + params.ffmpegLoudnormThresholdMeasured.ToInvariantString +
":print_format=summary"
End Function
Shared Function GetDynAudNormArgs(params As GUIAudioProfile.Parameters) As String
Dim ret = ""
If params.ffmpegDynaudnormF <> 500 Then ret += ":f=" + params.ffmpegDynaudnormF.ToInvariantString
If params.ffmpegDynaudnormG <> 31 Then ret += ":g=" + params.ffmpegDynaudnormG.ToInvariantString
If params.ffmpegDynaudnormP <> 0.95 Then ret += ":p=" + params.ffmpegDynaudnormP.ToInvariantString
If params.ffmpegDynaudnormM <> 10 Then ret += ":m=" + params.ffmpegDynaudnormM.ToInvariantString
If params.ffmpegDynaudnormR <> 0 Then ret += ":r=" + params.ffmpegDynaudnormR.ToInvariantString
If params.ffmpegDynaudnormS <> 0 Then ret += ":s=" + params.ffmpegDynaudnormS.ToInvariantString
If Not params.ffmpegDynaudnormN Then ret += ":n=false"
If params.ffmpegDynaudnormC Then ret += ":c=true"
If params.ffmpegDynaudnormB Then ret += ":b=true"
Return If(ret = "", "-af dynaudnorm", "-af dynaudnorm=" + ret.Trim(":"c))
End Function
Shared Sub ConvertDirectShowSource(ap As AudioProfile, Optional useFlac As Boolean = False)
If ap.File.Ext = ap.ConvertExt Then
Exit Sub
End If
If Not Package.AviSynth.VerifyOK(True) Then
Throw New AbortException
End If
ap.Delay = 0
Dim d As New VideoScript
d.Filters.AddRange(p.Script.Filters)
d.RemoveFilter("Cutting")
Dim outPath = Path.Combine(p.TempDir, ap.File.Base + "_convDSS." + ap.ConvertExt)
d.Path = Path.Combine(p.TempDir, ap.File.Base + "_DecDSS.avs")
d.Filters.Insert(1, New VideoFilter("AudioDub(last,DirectShowSource(""" + ap.File + """, video=false))"))
If ap.Channels = 2 Then
d.Filters.Add(New VideoFilter(GetDown2Code))
End If
d.Synchronize()
Dim args = "-i " + d.Path.Escape + " -y -hide_banner " + outPath.Escape
Using proc As New Proc
proc.Header = "AVS to WAV"
proc.SkipStrings = {"frame=", "size="}
proc.WriteLog(Macro.Expand(d.GetScript) + BR)
proc.Encoding = Encoding.UTF8
proc.Package = Package.ffmpeg
proc.Arguments = args
proc.Start()
End Using
If g.FileExists(outPath) Then
ap.File = outPath
Log.WriteLine(MediaInfo.GetSummary(outPath))
Else
Log.Write("Error", "no output found")
End If
End Sub
Shared Sub ConvertFFAudioSource(ap As AudioProfile)
If ap.File.Ext = ap.ConvertExt Then
Exit Sub
End If
If Not Package.AviSynth.VerifyOK(True) Then
Throw New AbortException
End If
ap.Delay = 0
Dim cachefile = Path.Combine(p.TempDir, ap.File.Base + ".ffindex")
g.ffmsindex(ap.File, cachefile)
Dim d As New VideoScript
d.Filters.AddRange(p.Script.Filters)
d.RemoveFilter("Cutting")
Dim outPath = Path.Combine(p.TempDir, ap.File.Base + "_convFFAudioSource." + ap.ConvertExt)
d.Path = Path.Combine(p.TempDir, ap.File.Base + "_DecodeFFAudioSource.avs")
d.Filters.Insert(1, New VideoFilter("AudioDub(last,FFAudioSource(""" + ap.File + """, cachefile=""" + cachefile + """))"))
If ap.Channels = 2 Then
d.Filters.Add(New VideoFilter(GetDown2Code))
End If
d.Synchronize()
Dim args = "-i " + d.Path.Escape + " -y -hide_banner " + outPath.Escape
Using proc As New Proc
proc.Header = "AVS to WAV"
proc.SkipStrings = {"frame=", "size="}
proc.WriteLog(Macro.Expand(d.GetScript) + BR)
proc.Encoding = Encoding.UTF8
proc.Package = Package.ffmpeg
proc.Arguments = args
proc.Start()
End Using
If g.FileExists(outPath) Then
ap.File = outPath
Log.WriteLine(MediaInfo.GetSummary(outPath))
Else
Log.Write("Error", "no output found")
End If
End Sub
Shared Sub CutDirectShowSource(ap As AudioProfile)
If ap.File.Contains("_cut_") Then
Exit Sub
End If
If Not Package.AviSynth.VerifyOK(True) Then
Throw New AbortException
End If
ap.Delay = 0
Dim d As New VideoScript
d.Filters.AddRange(p.Script.Filters)
Dim wavPath = Path.Combine(p.TempDir, ap.File.Base + "_cut_ds.wav")
d.Path = Path.Combine(p.TempDir, ap.File.Base + "_cut_ds.avs")
d.Filters.Insert(1, New VideoFilter("AudioDub(last,DirectShowSource(""" + ap.File + """, video=false))"))
If ap.Channels = 2 Then
d.Filters.Add(New VideoFilter(GetDown2Code))
End If
d.Synchronize()
Dim args = "-i " + d.Path.Escape + " -y -hide_banner " + wavPath.Escape
Using proc As New Proc
proc.Header = "AVS to WAV"
proc.SkipStrings = {"frame=", "size="}
proc.WriteLog(Macro.Expand(d.GetScript) + BR)
proc.Encoding = Encoding.UTF8
proc.Package = Package.ffmpeg
proc.Arguments = args
proc.Start()
End Using
If g.FileExists(wavPath) Then
ap.File = wavPath
Log.WriteLine(MediaInfo.GetSummary(wavPath))
Else
Log.Write("Error", "no output found")
End If
End Sub
Shared Sub CutFFAudioSource(ap As AudioProfile)
If ap.File.Contains("_cut_") Then
Exit Sub
End If
If Not Package.AviSynth.VerifyOK(True) Then
Throw New AbortException
End If
ap.Delay = 0
Dim cachefile = Path.Combine(p.TempDir, ap.File.Base + ".ffindex")
g.ffmsindex(ap.File, cachefile)
Dim d As New VideoScript
d.Filters.AddRange(p.Script.Filters)
Dim wavPath = Path.Combine(p.TempDir, ap.File.Base + "_cut_ff.wav")
d.Path = Path.Combine(p.TempDir, ap.File.Base + "_cut_ff.avs")
d.Filters.Insert(1, New VideoFilter("AudioDub(last,FFAudioSource(""" + ap.File + """, cachefile=""" + cachefile + """))"))
If ap.Channels = 2 Then
d.Filters.Add(New VideoFilter(GetDown2Code))
End If
d.Synchronize()
Dim args = "-i " + d.Path.Escape + " -y -hide_banner " + wavPath.Escape
Using proc As New Proc
proc.Header = "AVS to WAV"
proc.SkipStrings = {"frame=", "size="}
proc.WriteLog(Macro.Expand(d.GetScript) + BR)
proc.Encoding = Encoding.UTF8
proc.Package = Package.ffmpeg
proc.Arguments = args
proc.Start()
End Using
If g.FileExists(wavPath) Then
ap.File = wavPath
Log.WriteLine(MediaInfo.GetSummary(wavPath))
Else
Log.Write("Error", "no output found")
End If
End Sub
Shared Sub CutMkvmerge(ap As AudioProfile)
If ap.File.Contains("_cut_") Then
Exit Sub
End If
If Not Package.AviSynth.VerifyOK(True) Then
Throw New AbortException
End If
Dim base = ap.File.Base
If Not base.Contains(ap.GetTrackID) Then
base += ap.GetTrackID
End If
Dim aviPath = Path.Combine(p.TempDir, base + "_cut_.avi")
Dim d = (p.CutFrameCount / p.CutFrameRate).ToString("f9", CultureInfo.InvariantCulture)
Dim r = p.CutFrameRate.ToString("f9", CultureInfo.InvariantCulture)
Dim args = $"-f lavfi -i color=c=black:s=16x16:d={d}:r={r} -y -hide_banner -c:v ffv1 -g 1 " + aviPath.Escape
Using proc As New Proc
proc.Header = "Create avi file for audio cutting " & (ap.GetTrackIndex + 1)
proc.SkipStrings = {"frame=", "size="}
proc.WriteLog("mkvmerge cannot cut audio without video so an avi file has to be created" + BR2)
proc.Encoding = Encoding.UTF8
proc.Package = Package.ffmpeg
proc.Arguments = args
proc.Start()
End Using
If Not File.Exists(aviPath) Then
Throw New ErrorAbortException("Error", "Output file missing")
Else
Log.WriteLine(MediaInfo.GetSummary(aviPath))
End If
Dim mkvPath = Path.Combine(p.TempDir, base + "_cut_.mkv")
Dim args2 = "-o " + mkvPath.Escape + " " + aviPath.Escape + " " + ap.File.Escape
args2 += " --split parts-frames:" + p.Ranges.Select(Function(v) v.Start & "-" & (v.End + 1)).Join(",+")
args2 += " --engage append_and_split_flac --ui-language en"
Using proc As New Proc
proc.Header = "Cut Audio " & (ap.GetTrackIndex + 1)
proc.SkipString = "Progress: "
proc.Encoding = Encoding.UTF8
proc.Package = Package.mkvmerge
proc.Arguments = args2
proc.AllowedExitCodes = {0, 1}
proc.Start()
End Using
Dim fail As Boolean
If File.Exists(mkvPath) Then
Log.WriteLine(MediaInfo.GetSummary(mkvPath))
Dim streams = MediaInfo.GetAudioStreams(mkvPath)
If streams.Count > 0 Then
mkvDemuxer.Demux(mkvPath, {streams(0)}, Nothing, ap, p, False, False, True,
"Demux cutted MKV " & (ap.GetTrackIndex + 1), False)
Else
fail = True
End If
Else
fail = True
End If
If fail AndAlso TypeOf ap Is GUIAudioProfile AndAlso Not ap.File.Ext = "wav" Then
Log.Write("Error", "no output found")
Convert(ap)
If ap.File.Ext = "wav" Then
Cut(ap)
End If
End If
End Sub
Shared Function GetDown2Code() As String
Return "Audiochannels() >= 6 ? Down2(last) : last
function Down2(clip a)
{
a = ConvertAudioToFloat(a)
fl = GetChannel(a, 1)
fr = GetChannel(a, 2)
c = GetChannel(a, 3)
lfe = GetChannel(a, 4)
sl = GetChannel(a, 5)
sr = GetChannel(a, 6)
l_sl = MixAudio(fl, sl, 0.2929, 0.2929)
c_lfe = MixAudio(lfe, c, 0.2071, 0.2071)
r_sr = MixAudio(fr, sr, 0.2929, 0.2929)
l = MixAudio(l_sl, c_lfe, 1.0, 1.0)
r = MixAudio(r_sr, c_lfe, 1.0, 1.0)
return MergeChannels(l, r)
}"
End Function
Shared Function FileExist(fp As String) As Boolean
Return File.Exists(fp) AndAlso New FileInfo(fp).Length > 500
End Function
Shared Function IsEncoderUsed(encoder As GuiAudioEncoder) As Boolean
If Not p.AudioTracks.NothingOrEmpty() Then
For Each track In p.AudioTracks
If IsEncoderUsed(track.AudioProfile, encoder) Then
Return True
End If
Next
End If
If Not p.AudioFiles.NothingOrEmpty Then
For Each ap In p.AudioFiles
If IsEncoderUsed(ap, encoder) Then
Return True
End If
Next
End If
Return False
End Function
Shared Function IsEncoderUsed(ap As AudioProfile, encoder As GuiAudioEncoder) As Boolean
If TypeOf ap Is GUIAudioProfile AndAlso ap.File <> "" Then
Dim gap = DirectCast(ap, GUIAudioProfile)
If gap.GetEncoder = encoder Then
Return True
End If
End If
End Function
Shared Function CommandContains(find As String) As Boolean
If Not p.AudioTracks.NothingOrEmpty() Then
For Each track In p.AudioTracks
If track.AudioProfile.IsUsedAndContainsCommand(find) Then
Return True
End If
Next
End If
If Not p.AudioFiles.NothingOrEmpty Then
For Each ap In p.AudioFiles
If ap.IsUsedAndContainsCommand(find) Then
Return True
End If
Next
End If
Return False
End Function
End Class
Public Enum AudioDecoderMode
Automatic
ffmpeg
eac3to
NicAudio
DirectShow
FFAudioSource
End Enum
Public Enum AudioDecodingMode
FLAC
W64
WAVE
Pipe
End Enum
Public Enum CuttingMode
mkvmerge
DirectShow
NicAudio
End Enum
Public Enum ffNormalizeMode
volumedetect
loudnorm
dynaudnorm
End Enum
Public Enum ffmpegNormalizeMode
volumedetect
loudnorm
dynaudnorm
End Enum