mirror of
https://github.com/staxrip/staxrip.git
synced 2026-10-19 06:59:04 +08:00
2139 lines
73 KiB
VB.net
2139 lines
73 KiB
VB.net
|
|
Imports System.Text.RegularExpressions
|
|
Imports System.Text
|
|
|
|
Imports StaxRip.UI
|
|
|
|
<Serializable()>
|
|
Public MustInherit Class AudioProfile
|
|
Inherits Profile
|
|
|
|
Property Language As New Language
|
|
Property Delay As Integer
|
|
Property StreamName As String = ""
|
|
Property Gain As Single
|
|
Property Streams As List(Of AudioStream) = New List(Of AudioStream)
|
|
Property [Default] As Boolean
|
|
Property Forced As Boolean
|
|
Property Commentary As Boolean
|
|
Property ExtractDTSCore As Boolean
|
|
Property Decoder As AudioDecoderMode
|
|
Property DecodingMode As AudioDecodingMode
|
|
|
|
Overridable Property Channels As Integer = 6
|
|
Overridable Property OutputFileType As String = "unknown"
|
|
Overridable Property Bitrate As Double
|
|
Overridable Property SupportedInput As String()
|
|
|
|
Overridable Property CommandLines As String
|
|
|
|
Sub New(name As String)
|
|
MyBase.New(name)
|
|
End Sub
|
|
|
|
Sub New(name As String,
|
|
bitrate As Integer,
|
|
input As String(),
|
|
fileType As String,
|
|
channels As Integer)
|
|
|
|
MyBase.New(name)
|
|
|
|
Me.Channels = channels
|
|
Me.Bitrate = bitrate
|
|
SupportedInput = input
|
|
OutputFileType = fileType
|
|
End Sub
|
|
|
|
ReadOnly Property AudioCodec As AudioCodec
|
|
Get
|
|
If TypeOf Me Is GUIAudioProfile Then
|
|
Return DirectCast(Me, GUIAudioProfile).Params.Codec
|
|
End If
|
|
|
|
For Each i As AudioCodec In System.Enum.GetValues(GetType(AudioCodec))
|
|
If i.ToString.ToLowerInvariant = OutputFileType Then
|
|
Return i
|
|
End If
|
|
Next
|
|
|
|
Return AudioCodec.None
|
|
End Get
|
|
End Property
|
|
|
|
Private FileValue As String = ""
|
|
|
|
Property File As String
|
|
Get
|
|
Return FileValue
|
|
End Get
|
|
Set(value As String)
|
|
If FileValue <> value Then
|
|
FileValue = value
|
|
Stream = Nothing
|
|
If p.TakeOverAudioDefault Then [Default] = value.Contains("[Default]")
|
|
If p.TakeOverAudioForced Then Forced = value.Contains("[Forced]")
|
|
OnFileChanged()
|
|
End If
|
|
End Set
|
|
End Property
|
|
|
|
Private StreamValue As AudioStream
|
|
|
|
Property Stream As AudioStream
|
|
Get
|
|
Return StreamValue
|
|
End Get
|
|
Set(value As AudioStream)
|
|
If Not value Is StreamValue Then
|
|
StreamValue = value
|
|
|
|
If Not Stream Is Nothing Then
|
|
If Not p.Script.GetFilter("Source").Script.Contains("DirectShowSource") Then
|
|
Delay = Stream.Delay
|
|
End If
|
|
|
|
Language = Stream.Language
|
|
Commentary = Stream.Commentary
|
|
|
|
If p.TakeOverAudioDefault Then Me.Default = Stream.Default
|
|
If p.TakeOverAudioForced Then Forced = Stream.Forced
|
|
If p.TakeOverAudioName Then
|
|
If StreamName = "" AndAlso Stream.Title <> "" Then
|
|
StreamName = Stream.Title
|
|
End If
|
|
End If
|
|
End If
|
|
|
|
OnStreamChanged()
|
|
End If
|
|
End Set
|
|
End Property
|
|
|
|
Property DisplayName As String
|
|
Get
|
|
Dim ret As String
|
|
|
|
If File?.FileExists() Then
|
|
If Stream Is Nothing Then
|
|
Dim streams = MediaInfo.GetAudioStreams(File)
|
|
|
|
If streams.Count > 0 Then
|
|
Dim firstStream = streams(0)
|
|
|
|
If firstStream.Bitrate = 0 AndAlso firstStream.Bitrate2 = 0 Then
|
|
firstStream.Bitrate = CInt(Calc.GetBitrateFromFile(File, p.SourceSeconds))
|
|
End If
|
|
|
|
ret = GetAudioText(firstStream, File)
|
|
Else
|
|
ret = File.FileName
|
|
End If
|
|
Else
|
|
ret = $"{Stream.Name} ({File?.Ext()})"
|
|
End If
|
|
Else
|
|
If Stream IsNot Nothing Then
|
|
ret = $"{Stream.Name} ({p.SourceFile?.Ext()})"
|
|
End If
|
|
End If
|
|
|
|
Return ret
|
|
End Get
|
|
Set(value As String)
|
|
End Set
|
|
End Property
|
|
|
|
<NonSerialized>
|
|
Private SourceSamplingRateValue As Integer
|
|
|
|
ReadOnly Property SourceSamplingRate As Integer
|
|
Get
|
|
If SourceSamplingRateValue = 0 Then
|
|
If Stream Is Nothing Then
|
|
If File <> "" AndAlso IO.File.Exists(File) Then
|
|
SourceSamplingRateValue = MediaInfo.GetAudio(File, "SamplingRate").ToInt
|
|
End If
|
|
Else
|
|
SourceSamplingRateValue = Stream.SamplingRate
|
|
End If
|
|
End If
|
|
|
|
If SourceSamplingRateValue = 0 Then
|
|
SourceSamplingRateValue = 48000
|
|
End If
|
|
|
|
Return SourceSamplingRateValue
|
|
End Get
|
|
End Property
|
|
|
|
<NonSerialized>
|
|
Private SourceBitDepthValue As Integer = 0
|
|
|
|
ReadOnly Property SourceBitDepth As Integer
|
|
Get
|
|
If SourceBitDepthValue = 0 Then
|
|
If Stream Is Nothing Then
|
|
If File <> "" AndAlso IO.File.Exists(File) Then
|
|
SourceBitDepthValue = MediaInfo.GetAudio(File, "BitDepth").ToInt
|
|
End If
|
|
Else
|
|
SourceBitDepthValue = Stream.BitDepth
|
|
End If
|
|
End If
|
|
|
|
Return SourceBitDepthValue
|
|
End Get
|
|
End Property
|
|
|
|
<NonSerialized>
|
|
Private SourceChannelsValue As Integer = 0
|
|
|
|
ReadOnly Property SourceChannels As Integer
|
|
Get
|
|
If SourceChannelsValue = 0 Then
|
|
If Stream Is Nothing Then
|
|
If File <> "" AndAlso IO.File.Exists(File) Then
|
|
SourceChannelsValue = MediaInfo.GetChannels(File)
|
|
End If
|
|
Else
|
|
If Stream.Channels > Stream.Channels2 Then
|
|
SourceChannelsValue = Stream.Channels
|
|
Else
|
|
SourceChannelsValue = Stream.Channels2
|
|
End If
|
|
End If
|
|
End If
|
|
|
|
Return SourceChannelsValue
|
|
End Get
|
|
End Property
|
|
|
|
ReadOnly Property HasStream As Boolean
|
|
Get
|
|
Return Stream IsNot Nothing
|
|
End Get
|
|
End Property
|
|
|
|
Public Overrides Sub Clean()
|
|
MyBase.Clean()
|
|
CommandLines = ""
|
|
DisplayName = ""
|
|
File = ""
|
|
Stream = Nothing
|
|
Streams.Clear()
|
|
End Sub
|
|
|
|
Overridable Sub Reset()
|
|
File = ""
|
|
Language = New Language()
|
|
SourceSamplingRateValue = 0
|
|
Stream = Nothing
|
|
End Sub
|
|
|
|
Overridable Sub Reset(trackIndex As Integer)
|
|
Reset()
|
|
|
|
If trackIndex >= 0 AndAlso g.LastModifiedTemplate.AudioTracks.Count > trackIndex Then
|
|
Dim ap = g.LastModifiedTemplate.AudioTracks(trackIndex).AudioProfile
|
|
|
|
StreamName = ap.StreamName
|
|
Else
|
|
StreamName = ""
|
|
End If
|
|
End Sub
|
|
|
|
Overridable Sub Migrate()
|
|
End Sub
|
|
|
|
ReadOnly Property ConvertExt As String
|
|
Get
|
|
Dim ret As String
|
|
|
|
Select Case DecodingMode
|
|
Case AudioDecodingMode.WAVE
|
|
ret = "wav"
|
|
Case AudioDecodingMode.W64
|
|
ret = "w64"
|
|
Case Else
|
|
ret = "flac"
|
|
End Select
|
|
|
|
If Not SupportedInput.Contains(ret) Then
|
|
ret = "flac"
|
|
End If
|
|
|
|
If Not SupportedInput.Contains(ret) Then
|
|
ret = "w64"
|
|
End If
|
|
|
|
If Not SupportedInput.Contains(ret) Then
|
|
ret = "wav"
|
|
End If
|
|
|
|
Return ret
|
|
End Get
|
|
End Property
|
|
|
|
Overridable Sub OnFileChanged()
|
|
End Sub
|
|
|
|
Overridable Sub OnStreamChanged()
|
|
End Sub
|
|
|
|
Function ContainsCommand(value As String) As Boolean
|
|
Return CommandLines.ContainsEx(value)
|
|
End Function
|
|
|
|
Function IsUsedAndContainsCommand(value As String) As Boolean
|
|
Return File <> "" AndAlso CommandLines.ContainsEx(value)
|
|
End Function
|
|
|
|
Function GetDuration() As TimeSpan
|
|
If IO.File.Exists(File) Then
|
|
If Stream Is Nothing Then
|
|
Return TimeSpan.FromMilliseconds(MediaInfo.GetAudio(File, "Duration").ToDouble)
|
|
Else
|
|
Using mi As New MediaInfo(File)
|
|
Return TimeSpan.FromMilliseconds(mi.GetAudio(Stream.Index, "Duration").ToDouble)
|
|
End Using
|
|
End If
|
|
End If
|
|
End Function
|
|
|
|
Function GetAudioText(stream As AudioStream, path As String) As String
|
|
For Each i In Language.Languages
|
|
If path.Contains(i.CultureInfo.EnglishName) Then
|
|
stream.Language = i
|
|
Exit For
|
|
End If
|
|
Next
|
|
|
|
Dim matchDelay = Regex.Match(path, " (-?\d+)ms")
|
|
|
|
If matchDelay.Success Then
|
|
stream.Delay = matchDelay.Groups(1).Value.ToInt
|
|
End If
|
|
|
|
Dim matchID = Regex.Match(path, " ID(\d+)")
|
|
Dim name As String
|
|
name = stream.Name.Substring(3)
|
|
|
|
If File.Base = p.SourceFile.Base Then
|
|
Return name + " (" + File.Ext + ")"
|
|
Else
|
|
Return name + " (" + File.FileName + ")"
|
|
End If
|
|
End Function
|
|
|
|
Sub SetStreamOrLanguage()
|
|
If File = "" Then Exit Sub
|
|
|
|
If File <> p.LastOriginalSourceFile Then
|
|
Language = g.ExtractLanguageFromPath(File)
|
|
Else
|
|
If Streams IsNot Nothing Then
|
|
For Each i In Streams
|
|
If FileTypes.AudioHQ.Contains(i.Ext) AndAlso i.Language.Equals(Language) Then
|
|
Stream = i
|
|
Exit For
|
|
End If
|
|
Next
|
|
|
|
If Stream Is Nothing Then
|
|
For Each i In Streams
|
|
If Not FileTypes.AudioHQ.Contains(i.Ext) AndAlso i.Language.Equals(Language) Then
|
|
Stream = i
|
|
Exit For
|
|
End If
|
|
Next
|
|
End If
|
|
|
|
If Stream Is Nothing AndAlso Streams.Count > 0 Then
|
|
Stream = Streams(0)
|
|
End If
|
|
End If
|
|
End If
|
|
End Sub
|
|
|
|
Function IsInputSupported() As Boolean
|
|
Return SupportedInput.NothingOrEmpty OrElse SupportedInput.Contains(File.Ext)
|
|
End Function
|
|
|
|
Function IsMuxProfile() As Boolean
|
|
Return TypeOf Me Is MuxAudioProfile
|
|
End Function
|
|
|
|
Overridable Function HandlesDelay() As Boolean
|
|
End Function
|
|
|
|
Overridable ReadOnly Property NeedConvert As Boolean
|
|
Get
|
|
Return False
|
|
End Get
|
|
End Property
|
|
|
|
Overridable Sub Encode()
|
|
End Sub
|
|
|
|
Overridable Sub EditProject()
|
|
End Sub
|
|
|
|
Function GetTrackIndex() As Integer
|
|
If Not p.AudioTracks.NothingOrEmpty() Then
|
|
For index = 0 To p.AudioTracks.Count - 1
|
|
If Me Is p.AudioTracks.ElementAt(index).AudioProfile Then Return index
|
|
Next
|
|
End If
|
|
|
|
For x = 0 To p.AudioFiles.Count - 1
|
|
If Me Is p.AudioFiles(x) Then
|
|
Return x + If(p.AudioTracks?.Count, 0)
|
|
End If
|
|
Next
|
|
End Function
|
|
|
|
Function GetTrackID() As String
|
|
Return "_" & (CRC32.GetChecksum(p.TargetFile) + GetTrackIndex())
|
|
End Function
|
|
|
|
Function GetOutputFile() As String
|
|
Dim base As String
|
|
|
|
If HasStream Then
|
|
base = Audio.GetBaseNameForStream(File, Stream)
|
|
ElseIf Not String.IsNullOrWhiteSpace(p.TempDir) AndAlso New DirectoryInfo(p.TempDir).Name.EndsWith("_temp") AndAlso File.Base.StartsWithEx(p.SourceFile.Base) Then
|
|
base = File.Base.Substring(p.SourceFile.Base.Length).Trim
|
|
Else
|
|
base = File.Base
|
|
End If
|
|
|
|
If base = "" Then
|
|
base = "temp"
|
|
End If
|
|
|
|
If Not base.Contains(GetTrackID) Then
|
|
base += GetTrackID()
|
|
End If
|
|
|
|
If Delay <> 0 Then
|
|
If HandlesDelay() Then
|
|
If base.Contains("ms") Then
|
|
Dim re As New Regex(" (-?\d+)ms")
|
|
|
|
If re.IsMatch(base) Then
|
|
base = re.Replace(base, "")
|
|
End If
|
|
End If
|
|
Else
|
|
If Not base.Contains("ms") Then
|
|
base += " " & Delay & "ms"
|
|
End If
|
|
End If
|
|
End If
|
|
|
|
Dim outfile = Path.Combine(p.TempDir, base + "." + OutputFileType.ToLowerInvariant)
|
|
|
|
If File = outfile Then
|
|
outfile = Path.Combine(p.TempDir, outfile.Base + "_new." + OutputFileType.ToLowerInvariant)
|
|
End If
|
|
|
|
Return outfile
|
|
End Function
|
|
|
|
Shared Function GetProfiles() As IEnumerable(Of AudioProfile)
|
|
Dim ret As New List(Of AudioProfile)
|
|
|
|
If Not p.AudioTracks.NothingOrEmpty() Then ret.AddRange(p.AudioTracks.Select(Function(x) x.AudioProfile))
|
|
If Not p.AudioFiles.NothingOrEmpty() Then ret.AddRange(p.AudioFiles)
|
|
|
|
Return ret
|
|
End Function
|
|
|
|
Function ExpandMacros(value As String) As String
|
|
Return ExpandMacros(value, True)
|
|
End Function
|
|
|
|
Function ExpandMacros(value As String, silent As Boolean) As String
|
|
If value = "" Then Return ""
|
|
If value.Contains("%input%") Then value = value.Replace("%input%", File.Escape)
|
|
If value.Contains("%output%") Then value = value.Replace("%output%", GetOutputFile.Escape)
|
|
If value.Contains("%bitrate%") Then value = value.Replace("%bitrate%", Bitrate.ToString)
|
|
If value.Contains("%channels%") Then value = value.Replace("%channels%", Channels.ToString)
|
|
If value.Contains("%delay%") Then value = value.Replace("%delay%", Delay.ToString)
|
|
If value.Contains("%language%") Then value = value.Replace("%language%", Language.Name)
|
|
If value.Contains("%language_english%") Then value = value.Replace("%language_english%", Language.EnglishName)
|
|
If value.Contains("%language_native%") Then value = value.Replace("%language_native%", Language.CultureInfo.NativeName)
|
|
If value.Contains("%streamid0%") AndAlso Stream IsNot Nothing Then value = value.Replace("%streamid0%", (Stream?.ID - 1)?.ToString)
|
|
If value.Contains("%streamid1%") Then value = value.Replace("%streamid1%", Stream?.ID.ToString)
|
|
|
|
Return Macro.Expand(value)
|
|
End Function
|
|
|
|
Shared Function GetDefaults() As List(Of AudioProfile)
|
|
Dim ret As New List(Of AudioProfile)
|
|
|
|
ret.Add(New GUIAudioProfile(AudioCodec.AAC, 50))
|
|
ret.Add(New GUIAudioProfile(AudioCodec.AC3, 1.0) With {.Channels = 6, .Bitrate = 640})
|
|
ret.Add(New GUIAudioProfile(AudioCodec.EAC3, 1.0) With {.Channels = 6, .Bitrate = 640})
|
|
ret.Add(New GUIAudioProfile(AudioCodec.FLAC, 0.3))
|
|
ret.Add(New GUIAudioProfile(AudioCodec.MP3, 4))
|
|
ret.Add(New GUIAudioProfile(AudioCodec.Opus, 1) With {.Bitrate = 250})
|
|
ret.Add(New GUIAudioProfile(AudioCodec.Vorbis, 1))
|
|
ret.Add(New BatchAudioProfile(640, {}, "ac3", 6, """%app_path:ffmpeg%"" -i %input% -b:a %bitrate%k -y -hide_banner %output%"))
|
|
ret.Add(New MuxAudioProfile())
|
|
ret.Add(New NullAudioProfile())
|
|
|
|
Return ret
|
|
End Function
|
|
End Class
|
|
|
|
<Serializable()>
|
|
Public Class BatchAudioProfile
|
|
Inherits AudioProfile
|
|
|
|
Sub New(bitrate As Integer,
|
|
input As String(),
|
|
fileType As String,
|
|
channels As Integer,
|
|
commandLines As String)
|
|
|
|
MyBase.New("Command Line", bitrate, input, fileType, channels)
|
|
Me.CommandLines = commandLines
|
|
CanEditValue = True
|
|
End Sub
|
|
|
|
Overrides Function Edit() As DialogResult
|
|
Using form As New CommandLineAudioEncoderForm(Me)
|
|
form.mbLanguage.Enabled = False
|
|
form.lLanguage.Enabled = False
|
|
form.tbDelay.Enabled = False
|
|
form.lDelay.Enabled = False
|
|
Return form.ShowDialog()
|
|
End Using
|
|
End Function
|
|
|
|
Function GetCode() As String
|
|
Return ExpandMacros(CommandLines).Trim
|
|
End Function
|
|
|
|
Overrides Sub Encode()
|
|
If File <> "" Then
|
|
Dim bitrateBefore = p.VideoBitrate
|
|
Dim targetPath = GetOutputFile()
|
|
|
|
For Each line In Macro.Expand(GetCode).SplitLinesNoEmpty
|
|
Using proc As New Proc
|
|
proc.Header = "Audio Encoding: " + Name
|
|
proc.SkipStrings = Proc.GetSkipStrings(CommandLines)
|
|
proc.File = "cmd.exe"
|
|
proc.Arguments = "/S /C """ + line + """"
|
|
|
|
Try
|
|
proc.Start()
|
|
Catch ex As AbortException
|
|
Throw ex
|
|
Catch ex As Exception
|
|
g.ShowException(ex)
|
|
Throw New AbortException
|
|
End Try
|
|
End Using
|
|
Next
|
|
|
|
If g.FileExists(targetPath) Then
|
|
If Not p.BitrateIsFixed Then
|
|
Dim bitrateFromFile = Calc.GetBitrateFromFile(targetPath, p.TargetSeconds)
|
|
p.VideoBitrate = p.VideoBitrate + CInt(Calc.GetAudioBitrateFromAudioProfile(Me)) - CInt(bitrateFromFile)
|
|
Bitrate = bitrateFromFile
|
|
|
|
If Not p.VideoEncoder.QualityMode Then
|
|
Log.WriteLine("Video Bitrate Adjustment: " + bitrateBefore.ToString() + " -> " & p.VideoBitrate & BR2)
|
|
End If
|
|
End If
|
|
|
|
File = targetPath
|
|
Log.WriteLine(MediaInfo.GetSummary(File))
|
|
Else
|
|
Log.Write("Error", "no output found")
|
|
|
|
If Not File.Ext = "wav" Then
|
|
Audio.Convert(Me)
|
|
|
|
If File.Ext = "wav" Then
|
|
Encode()
|
|
End If
|
|
End If
|
|
End If
|
|
End If
|
|
End Sub
|
|
|
|
Overrides Sub EditProject()
|
|
Using f As New CommandLineAudioEncoderForm(Me)
|
|
f.ShowDialog()
|
|
End Using
|
|
End Sub
|
|
|
|
Overrides Function HandlesDelay() As Boolean
|
|
Return CommandLines.Contains("%delay%")
|
|
End Function
|
|
End Class
|
|
|
|
<Serializable()>
|
|
Public Class NullAudioProfile
|
|
Inherits AudioProfile
|
|
|
|
Sub New()
|
|
MyBase.New("No Audio", 0, {}, "ignore", 0)
|
|
End Sub
|
|
|
|
Overrides Function HandlesDelay() As Boolean
|
|
End Function
|
|
|
|
Overrides Sub EditProject()
|
|
Using form As New SimpleSettingsForm("Null Audio Profile Options")
|
|
form.ScaleClientSize(20, 10)
|
|
Dim ui = form.SimpleUI
|
|
ui.Store = Me
|
|
|
|
Dim n = ui.AddNum()
|
|
n.Text = "Reserved Bitrate:"
|
|
n.Config = {0, Integer.MaxValue, 8}
|
|
n.Property = NameOf(Bitrate)
|
|
|
|
If form.ShowDialog() = DialogResult.OK Then
|
|
ui.Save()
|
|
End If
|
|
End Using
|
|
End Sub
|
|
|
|
Public Overrides Property OutputFileType As String
|
|
Get
|
|
Return "ignore"
|
|
End Get
|
|
Set(value As String)
|
|
End Set
|
|
End Property
|
|
|
|
Public Overrides Sub Encode()
|
|
End Sub
|
|
End Class
|
|
|
|
<Serializable()>
|
|
Public Class MuxAudioProfile
|
|
Inherits AudioProfile
|
|
|
|
Sub New()
|
|
MyBase.New("Copy/Mux", 0, Nothing, "ignore", 2)
|
|
CanEditValue = True
|
|
End Sub
|
|
|
|
Private ChannelsValue As Integer = 0
|
|
|
|
Public Overrides Property Channels As Integer
|
|
Get
|
|
If Stream IsNot Nothing Then
|
|
Return If(Stream.Channels > Stream.Channels2, Stream.Channels, Stream.Channels2)
|
|
ElseIf IO.File.Exists(File) Then
|
|
|
|
If ChannelsValue = 0 Then
|
|
ChannelsValue = MediaInfo.GetChannels(File)
|
|
End If
|
|
|
|
Return ChannelsValue
|
|
Else
|
|
Return 6
|
|
End If
|
|
End Get
|
|
Set(value As Integer)
|
|
End Set
|
|
End Property
|
|
|
|
Public Overrides Property OutputFileType As String
|
|
Get
|
|
Return If(Stream Is Nothing, File.Ext, Stream.Ext)
|
|
End Get
|
|
Set(value As String)
|
|
End Set
|
|
End Property
|
|
|
|
Overrides Property SupportedInput As String()
|
|
Get
|
|
Return {}
|
|
End Get
|
|
Set(value As String())
|
|
End Set
|
|
End Property
|
|
|
|
Overrides Function Edit() As DialogResult
|
|
Return Edit(False)
|
|
End Function
|
|
|
|
Overrides Sub EditProject()
|
|
Edit(True)
|
|
End Sub
|
|
|
|
Overrides Sub Encode()
|
|
End Sub
|
|
|
|
Overrides Sub OnFileChanged()
|
|
MyBase.OnFileChanged()
|
|
SetBitrate()
|
|
End Sub
|
|
|
|
Overrides Sub OnStreamChanged()
|
|
MyBase.OnStreamChanged()
|
|
SetBitrate()
|
|
End Sub
|
|
|
|
Sub SetBitrate()
|
|
If Stream Is Nothing Then
|
|
Dim temp = CInt(MediaInfo.GetAudio(File, "BitRate").ToInt / 1000)
|
|
|
|
If temp > 0 Then
|
|
Bitrate = temp
|
|
Else
|
|
Bitrate = Calc.GetBitrateFromFile(File, p.SourceSeconds)
|
|
End If
|
|
Else
|
|
Bitrate = Stream.Bitrate + Stream.Bitrate2
|
|
End If
|
|
End Sub
|
|
|
|
Private Overloads Function Edit(showProjectSettings As Boolean) As DialogResult
|
|
Using form As New SimpleSettingsForm("Audio Mux Options",
|
|
"The Audio Mux options allow to add an audio file without reencoding.")
|
|
|
|
form.ScaleClientSize(30, 15)
|
|
|
|
Dim ui = form.SimpleUI
|
|
Dim page = ui.CreateFlowPage("main page")
|
|
page.SuspendLayout()
|
|
|
|
Dim tbb = ui.AddTextButton(page)
|
|
tbb.Label.Text = "Track Name:"
|
|
tbb.Label.Help = "Track name used by the muxer. The track name may contain macros."
|
|
tbb.Edit.Expand = True
|
|
tbb.Edit.Text = StreamName
|
|
tbb.Edit.SaveAction = Sub(value) StreamName = value
|
|
tbb.Button.Text = "Macro Editor..."
|
|
tbb.Button.ClickAction = AddressOf tbb.Edit.EditMacro
|
|
|
|
Dim mbi = ui.AddMenu(Of Language)(page)
|
|
mbi.Label.Text = "Language:"
|
|
mbi.Label.Help = "Language of the audio track."
|
|
mbi.Expanded = True
|
|
mbi.Button.Value = Language
|
|
mbi.Button.Text = g.GetExtendedLanguageName(Language)
|
|
mbi.Button.SaveAction = Sub(value) Language = value
|
|
|
|
g.PopulateLanguagesAsync(mbi.Button)
|
|
|
|
Dim nb = ui.AddNum(page)
|
|
nb.Label.Text = "Delay:"
|
|
nb.Label.Help = "Delay used by the muxer."
|
|
nb.NumEdit.Config = {Integer.MinValue, Integer.MaxValue, 1}
|
|
nb.NumEdit.Value = Delay
|
|
nb.NumEdit.SaveAction = Sub(value) Delay = CInt(value)
|
|
|
|
Dim cb = ui.AddBool(page)
|
|
cb.Text = "Default"
|
|
cb.Help = "Flaged as default."
|
|
cb.Checked = [Default]
|
|
cb.SaveAction = Sub(value) [Default] = value
|
|
|
|
If TypeOf p.VideoEncoder.Muxer Is MkvMuxer Then
|
|
cb = ui.AddBool(page)
|
|
cb.Text = "Forced"
|
|
cb.Help = "Flaged as forced in MKV."
|
|
cb.Checked = Forced
|
|
cb.SaveAction = Sub(value) Forced = value
|
|
|
|
cb = ui.AddBool(page)
|
|
cb.Text = "Commentary"
|
|
cb.Help = "Flaged as commentary in MKV."
|
|
cb.Checked = Commentary
|
|
cb.SaveAction = Sub(value) Commentary = value
|
|
End If
|
|
|
|
cb = ui.AddBool(page)
|
|
cb.Text = "Extract DTS Core"
|
|
cb.Help = "Only include DTS core using mkvmerge."
|
|
cb.Checked = ExtractDTSCore
|
|
cb.SaveAction = Sub(value) ExtractDTSCore = value
|
|
|
|
page.ResumeLayout()
|
|
|
|
Dim ret = form.ShowDialog()
|
|
|
|
If ret = DialogResult.OK Then
|
|
ui.Save()
|
|
End If
|
|
|
|
Return ret
|
|
End Using
|
|
End Function
|
|
|
|
|
|
End Class
|
|
|
|
<Serializable()>
|
|
Public Class GUIAudioProfile
|
|
Inherits AudioProfile
|
|
|
|
Property Params As New Parameters
|
|
|
|
Sub New(codec As AudioCodec, quality As Single)
|
|
MyBase.New(Nothing)
|
|
|
|
Params.Codec = codec
|
|
Params.Quality = quality
|
|
|
|
Select Case codec
|
|
Case AudioCodec.DTS, AudioCodec.AC3, AudioCodec.AC4, AudioCodec.EAC3
|
|
Params.RateMode = AudioRateMode.CBR
|
|
Case Else
|
|
Params.RateMode = AudioRateMode.VBR
|
|
End Select
|
|
|
|
Bitrate = GetBitrate()
|
|
End Sub
|
|
|
|
Private ChannelsValue As Integer
|
|
|
|
Public Overrides Property Channels As Integer
|
|
Get
|
|
Select Case Params.ChannelsMode
|
|
Case ChannelsMode.Original
|
|
If Not Stream Is Nothing Then
|
|
If Stream.Channels > Stream.Channels2 Then
|
|
Return Stream.Channels
|
|
Else
|
|
Return Stream.Channels2
|
|
End If
|
|
ElseIf IO.File.Exists(File) Then
|
|
If ChannelsValue = 0 Then
|
|
ChannelsValue = MediaInfo.GetChannels(File)
|
|
End If
|
|
|
|
Return ChannelsValue
|
|
Else
|
|
Return 6
|
|
End If
|
|
Case ChannelsMode._1
|
|
Return 1
|
|
Case ChannelsMode._2
|
|
Return 2
|
|
Case ChannelsMode._6
|
|
Return 6
|
|
Case ChannelsMode._7
|
|
Return 7
|
|
Case ChannelsMode._8
|
|
Return 8
|
|
Case Else
|
|
Throw New NotImplementedException
|
|
End Select
|
|
End Get
|
|
Set(value As Integer)
|
|
End Set
|
|
End Property
|
|
|
|
ReadOnly Property TargetSamplingRate As Integer
|
|
Get
|
|
Return If(Params.SamplingRate <> 0, Params.SamplingRate, SourceSamplingRate)
|
|
End Get
|
|
End Property
|
|
|
|
Public Overrides Sub Reset()
|
|
MyBase.Reset()
|
|
ChannelsValue = 0
|
|
End Sub
|
|
|
|
Public Overrides Sub Reset(trackIndex As Integer)
|
|
MyBase.Reset(trackIndex)
|
|
ChannelsValue = 0
|
|
End Sub
|
|
|
|
Public Overrides Sub Migrate()
|
|
MyBase.Migrate()
|
|
Params.Migrate()
|
|
End Sub
|
|
|
|
Public Function GetBitrate() As Integer
|
|
If Params.RateMode = AudioRateMode.VBR Then
|
|
Select Case Params.Codec
|
|
Case AudioCodec.AAC
|
|
Select Case Params.Encoder
|
|
Case GuiAudioEncoder.qaac, GuiAudioEncoder.Automatic
|
|
Return Calc.GetYFromTwoPointForm(0, CInt(50 / 8 * Channels), 127, CInt(1000 / 8 * Channels), Params.Quality)
|
|
Case GuiAudioEncoder.eac3to
|
|
Return Calc.GetYFromTwoPointForm(0.01, CInt(50 / 8 * Channels), 1, CInt(1000 / 8 * Channels), Params.Quality)
|
|
Case Else
|
|
Return Calc.GetYFromTwoPointForm(1, CInt(50 / 8 * Channels), 5, CInt(900 / 8 * Channels), Params.Quality)
|
|
End Select
|
|
Case AudioCodec.MP3
|
|
Return Calc.GetYFromTwoPointForm(9, 65, 0, 245, Params.Quality)
|
|
Case AudioCodec.Vorbis
|
|
If Channels >= 6 Then
|
|
Return Calc.GetYFromTwoPointForm(0, 120, 10, 1440, Params.Quality)
|
|
Else
|
|
Return Calc.GetYFromTwoPointForm(0, 64, 10, 500, Params.Quality)
|
|
End If
|
|
Case AudioCodec.Opus
|
|
Return CInt(Bitrate)
|
|
End Select
|
|
End If
|
|
|
|
Select Case Params.Codec
|
|
Case AudioCodec.FLAC
|
|
Dim bd = If(Params.ffmpegFlacBitDepth > 0, Params.ffmpegFlacBitDepth, SourceBitDepth)
|
|
If {TargetSamplingRate, bd, Channels}.Contains(0) Then
|
|
Return CInt(((48000 * 16 * 6) / 1000) * 0.55)
|
|
Else
|
|
Return CInt(((TargetSamplingRate * bd * Channels) / 1000) * 0.55)
|
|
End If
|
|
Case AudioCodec.W64, AudioCodec.WAV
|
|
Dim bd = If(Params.ffmpegWaveBitDepth > 0, Params.ffmpegWaveBitDepth, SourceBitDepth)
|
|
If {TargetSamplingRate, bd, Channels}.Contains(0) Then
|
|
Return CInt((48000 * 16 * 6) / 1000)
|
|
Else
|
|
Return CInt((TargetSamplingRate * bd * Channels) / 1000)
|
|
End If
|
|
End Select
|
|
|
|
Return CInt(Bitrate)
|
|
End Function
|
|
|
|
Public Overrides Sub Encode()
|
|
If File <> "" Then
|
|
Dim bitrateBefore = p.VideoBitrate
|
|
Dim targetPath = GetOutputFile()
|
|
Dim cl = GetCommandLine(True)
|
|
|
|
Using proc As New Proc
|
|
proc.Header = "Audio Encoding " & (GetTrackIndex() + 1)
|
|
|
|
If cl.Contains("|") Then
|
|
proc.File = "cmd.exe"
|
|
proc.Arguments = "/S /C """ + cl + """"
|
|
Else
|
|
proc.CommandLine = cl
|
|
End If
|
|
|
|
If cl.Contains("qaac64") Then
|
|
proc.Package = Package.qaac
|
|
proc.SkipStrings = {", ETA ", "x)", "Optimizing..."}
|
|
proc.AddToPath(Package.AppleApplicationSupport.Directory)
|
|
ElseIf cl.Contains("fdkaac") Then
|
|
proc.Package = Package.fdkaac
|
|
proc.SkipStrings = {"%]", "x)"}
|
|
ElseIf cl.Contains("eac3to") Then
|
|
proc.Package = Package.eac3to
|
|
proc.SkipStrings = {"process: ", "analyze: "}
|
|
proc.TrimChars = {"-"c, " "c}
|
|
proc.AddToPath(Package.NeroAAC.Directory)
|
|
ElseIf cl.Contains("ffmpeg") Then
|
|
proc.Package = If(cl.Contains("libfdk_aac"), Package.ffmpeg_non_free, Package.ffmpeg)
|
|
proc.SkipStrings = {"frame=", "size="}
|
|
proc.Encoding = Encoding.UTF8
|
|
proc.Duration = GetDuration()
|
|
ElseIf cl.Contains("opusenc") Then
|
|
proc.Package = Package.OpusEnc
|
|
proc.SkipStrings = {"%"}
|
|
ElseIf cl.Contains("deezy") Then
|
|
proc.Package = Package.DeeZy
|
|
proc.SkipStrings = {"%", "frame=", "size="}
|
|
End If
|
|
|
|
proc.Start()
|
|
End Using
|
|
|
|
If g.FileExists(targetPath) Then
|
|
If Not p.BitrateIsFixed Then
|
|
Dim bitrateFromFile = Calc.GetBitrateFromFile(targetPath, p.TargetSeconds)
|
|
p.VideoBitrate = p.VideoBitrate + CInt(Calc.GetAudioBitrateFromAudioProfile(Me)) - CInt(bitrateFromFile)
|
|
Bitrate = bitrateFromFile
|
|
|
|
If Not p.VideoEncoder.QualityMode Then
|
|
Log.WriteLine("Video Bitrate Adjustment: " + bitrateBefore.ToString() + " -> " & p.VideoBitrate & BR2)
|
|
End If
|
|
End If
|
|
|
|
File = targetPath
|
|
Log.WriteLine(MediaInfo.GetSummary(File))
|
|
Else
|
|
Throw New ErrorAbortException("Error audio encoding", "The output file is missing")
|
|
End If
|
|
End If
|
|
End Sub
|
|
|
|
Function NormalizeFF() As Boolean
|
|
If Not Params.Normalize OrElse ExtractCore OrElse Params.Encoder = GuiAudioEncoder.deezy OrElse Not {ffmpegNormalizeMode.loudnorm, ffmpegNormalizeMode.volumedetect}.Contains(Params.ffmpegNormalizeMode) Then Return False
|
|
|
|
Dim args = "-i " + File.Escape
|
|
|
|
If Stream IsNot Nothing AndAlso Streams.Count > 1 Then
|
|
args += " -map 0:a:" & Stream.Index
|
|
End If
|
|
|
|
args += " -sn -vn -hide_banner"
|
|
|
|
If Params.ffmpegNormalizeMode = ffmpegNormalizeMode.volumedetect Then
|
|
args += " -af volumedetect"
|
|
ElseIf Params.ffmpegNormalizeMode = ffmpegNormalizeMode.loudnorm Then
|
|
args += " -af loudnorm=I=" & Params.ffmpegLoudnormIntegrated.ToInvariantString +
|
|
":TP=" & Params.ffmpegLoudnormTruePeak.ToInvariantString + ":LRA=" &
|
|
Params.ffmpegLoudnormLRA.ToInvariantString + ":print_format=summary"
|
|
End If
|
|
|
|
args += " -f null NUL"
|
|
|
|
Using proc As New Proc
|
|
proc.Header = "Find Gain " & (GetTrackIndex() + 1)
|
|
proc.SkipStrings = {"frame=", "size="}
|
|
proc.Encoding = Encoding.UTF8
|
|
proc.Package = Package.ffmpeg
|
|
proc.Arguments = args
|
|
proc.Start()
|
|
|
|
Dim match = Regex.Match(proc.Log.ToString, "max_volume: -(\d+\.\d+) dB")
|
|
If match.Success Then
|
|
Gain += match.Groups(1).Value.ToSingle()
|
|
Params.Normalize = False
|
|
End If
|
|
|
|
match = Regex.Match(proc.Log.ToString, "Input Integrated:\s*([-\.0-9]+)")
|
|
If match.Success Then Params.ffmpegLoudnormIntegratedMeasured = match.Groups(1).Value.ToDouble
|
|
|
|
match = Regex.Match(proc.Log.ToString, "Input True Peak:\s*([-\.0-9]+)")
|
|
If match.Success Then Params.ffmpegLoudnormTruePeakMeasured = match.Groups(1).Value.ToDouble
|
|
|
|
match = Regex.Match(proc.Log.ToString, "Input LRA:\s*([-\.0-9]+)")
|
|
If match.Success Then Params.ffmpegLoudnormLraMeasured = match.Groups(1).Value.ToDouble
|
|
|
|
match = Regex.Match(proc.Log.ToString, "Input Threshold:\s*([-\.0-9]+)")
|
|
If match.Success Then Params.ffmpegLoudnormThresholdMeasured = match.Groups(1).Value.ToDouble
|
|
End Using
|
|
|
|
Return True
|
|
End Function
|
|
|
|
Overrides Function Edit() As DialogResult
|
|
Using form As New AudioForm()
|
|
form.LoadProfile(Me)
|
|
form.mbLanguage.Enabled = False
|
|
form.numDelay.Enabled = False
|
|
form.numGain.Enabled = False
|
|
Return form.ShowDialog()
|
|
End Using
|
|
End Function
|
|
|
|
Overrides Sub EditProject()
|
|
Using form As New AudioForm()
|
|
form.LoadProfile(Me)
|
|
form.ShowDialog()
|
|
End Using
|
|
End Sub
|
|
|
|
Public Overrides Property OutputFileType As String
|
|
Get
|
|
Select Case Params.Codec
|
|
Case AudioCodec.AAC
|
|
Return "m4a"
|
|
Case AudioCodec.Vorbis
|
|
Return "ogg"
|
|
Case Else
|
|
Return Params.Codec.ToString.ToLowerInvariant
|
|
End Select
|
|
End Get
|
|
Set(value As String)
|
|
End Set
|
|
End Property
|
|
|
|
Function GetEncoder() As GuiAudioEncoder
|
|
Return GetEncoder(Params.Encoder)
|
|
End Function
|
|
|
|
Function GetEncoder(gae As GuiAudioEncoder) As GuiAudioEncoder
|
|
Select Case gae
|
|
Case GuiAudioEncoder.deezy
|
|
If {AudioCodec.AC3, AudioCodec.AC4, AudioCodec.EAC3}.Contains(Params.Codec) Then
|
|
Return GuiAudioEncoder.deezy
|
|
End If
|
|
Case GuiAudioEncoder.eac3to
|
|
If {AudioCodec.AAC, AudioCodec.AC3, AudioCodec.DTS, AudioCodec.FLAC, AudioCodec.W64, AudioCodec.WAV}.Contains(Params.Codec) Then
|
|
Return GuiAudioEncoder.eac3to
|
|
End If
|
|
Case GuiAudioEncoder.fdkaac
|
|
If Params.Codec = AudioCodec.AAC Then
|
|
Return GuiAudioEncoder.fdkaac
|
|
End If
|
|
Case GuiAudioEncoder.opusenc
|
|
If Params.Codec = AudioCodec.Opus Then
|
|
Return GuiAudioEncoder.opusenc
|
|
End If
|
|
Case GuiAudioEncoder.qaac
|
|
If Params.Codec = AudioCodec.AAC Then
|
|
Return GuiAudioEncoder.qaac
|
|
End If
|
|
Case GuiAudioEncoder.Automatic
|
|
If Params.Codec = AudioCodec.AAC Then
|
|
Return GuiAudioEncoder.qaac
|
|
ElseIf Params.Codec = AudioCodec.AC4 Then
|
|
Return GuiAudioEncoder.deezy
|
|
ElseIf Params.Codec = AudioCodec.Opus Then
|
|
Return GuiAudioEncoder.opusenc
|
|
End If
|
|
End Select
|
|
|
|
Return GuiAudioEncoder.ffmpeg
|
|
End Function
|
|
|
|
Function GetCommandLine(includePaths As Boolean, Optional useCrcSuffix As Boolean = False) As String
|
|
Select Case GetEncoder()
|
|
Case GuiAudioEncoder.deezy
|
|
Return GetDeezyCommandLine(includePaths)
|
|
Case GuiAudioEncoder.eac3to
|
|
Return GetEac3toCommandLine(includePaths)
|
|
Case GuiAudioEncoder.fdkaac
|
|
Return GetfdkaacCommandLine(includePaths)
|
|
Case GuiAudioEncoder.opusenc
|
|
Return GetOpusencCommandLine(includePaths)
|
|
Case GuiAudioEncoder.qaac
|
|
Return GetQaacCommandLine(includePaths)
|
|
Case Else
|
|
Return GetffmpegCommandLine(includePaths)
|
|
End Select
|
|
End Function
|
|
|
|
Function GetDeezyCommandLine(includePaths As Boolean) As String
|
|
Dim sb As New StringBuilder
|
|
'includePaths = includePaths And File <> ""
|
|
|
|
If includePaths Then
|
|
sb.Append(Package.DeeZy.Path.Escape)
|
|
sb.Append(" --no-progress-bars")
|
|
Else
|
|
sb.Append(Package.DeeZy.Filename.Base)
|
|
End If
|
|
|
|
Select Case Params.Codec
|
|
Case AudioCodec.AC3
|
|
sb.Append(" encode dd")
|
|
Case AudioCodec.AC4
|
|
sb.Append(" encode ac4")
|
|
Case AudioCodec.EAC3
|
|
Select Case Params.DeezyDdpMode
|
|
Case DeezyDdpMode.Ddp
|
|
sb.Append(" encode ddp")
|
|
Case DeezyDdpMode.DdpBluray
|
|
sb.Append(" encode ddp-bluray")
|
|
Case DeezyDdpMode.Atmos
|
|
sb.Append(" encode atmos")
|
|
Case Else
|
|
Throw New NotImplementedException("GetDeezyCommandLine-Encode")
|
|
End Select
|
|
Case Else
|
|
Throw New NotImplementedException("GetDeezyCommandLine")
|
|
End Select
|
|
|
|
If Stream IsNot Nothing Then sb.Append($" --track-index={Stream.Index}")
|
|
sb.Append($" --bitrate={CInt(Bitrate)}")
|
|
If Delay <> 0 Then sb.Append($" --delay={Delay}ms")
|
|
If Params.DeezyKeeptemp Then sb.Append(" --keep-temp")
|
|
If Params.Codec = AudioCodec.AC3 AndAlso Params.DeezyChannelsDd <> DeezyChannelsDd.Auto Then sb.Append($" --channels={Params.DeezyChannelsDd.ToString().TrimStart("_"c)}")
|
|
If Params.Codec = AudioCodec.EAC3 AndAlso Params.DeezyDdpMode = DeezyDdpMode.Ddp AndAlso Params.DeezyChannelsDdp <> DeezyChannelsDdp.Auto Then sb.Append($" --channels={Params.DeezyChannelsDdp.ToString().TrimStart("_"c)}")
|
|
If Params.Codec = AudioCodec.EAC3 AndAlso Params.DeezyDdpMode = DeezyDdpMode.DdpBluray Then sb.Append($" --channels={Params.DeezyChannelsDdpBluray.ToString().TrimStart("_"c)}")
|
|
If Params.Codec = AudioCodec.EAC3 AndAlso Params.DeezyDdpMode = DeezyDdpMode.Atmos AndAlso Params.DeezyChannelsAtmos = DeezyChannelsAtmos._6 Then sb.Append($" --atmos-mode streaming")
|
|
If Params.Codec = AudioCodec.EAC3 AndAlso Params.DeezyDdpMode = DeezyDdpMode.Atmos AndAlso Params.DeezyChannelsAtmos = DeezyChannelsAtmos._8 Then sb.Append($" --atmos-mode bluray")
|
|
If ((Params.Codec = AudioCodec.AC3 AndAlso Params.DeezyChannelsDd = DeezyChannelsDd._2) OrElse (Params.Codec = AudioCodec.EAC3 AndAlso Params.DeezyDdpMode = DeezyDdpMode.Ddp AndAlso Params.DeezyChannelsDdp = DeezyChannelsDdp._2)) AndAlso Params.DeezyStereodownmix <> DeezyStereodownmix.Auto Then sb.Append($" --stereo-down-mix={Params.DeezyStereodownmix.ToString().ToLower()}")
|
|
If Params.Codec <> AudioCodec.AC4 AndAlso Params.DeezyDynamicrangecompression <> DeezyDrcLineMode.Music_Light Then sb.Append($" --drc-line-mode={Params.DeezyDynamicrangecompression.ToString().ToLower()}")
|
|
If Params.CustomSwitches <> "" Then sb.Append(" " + Params.CustomSwitches)
|
|
If includePaths Then sb.Append($" --overwrite --output={GetOutputFile.LongPathPrefix.Escape} {File.Escape}")
|
|
|
|
Return sb.ToString()
|
|
End Function
|
|
|
|
Function GetEac3toCommandLine(includePaths As Boolean) As String
|
|
Dim id = ""
|
|
Dim sb As New StringBuilder()
|
|
|
|
If File.Ext.EqualsAny("ts", "m2ts", "mkv") AndAlso Stream IsNot Nothing Then
|
|
id = (Stream.StreamOrder + 1) & ": "
|
|
End If
|
|
|
|
If includePaths Then
|
|
sb.Append(Package.eac3to.Path.Escape + " " + id + File.LongPathPrefix.Escape +
|
|
" " + GetOutputFile.LongPathPrefix.Escape)
|
|
Else
|
|
sb.Append(Package.eac3to.Filename.Base)
|
|
End If
|
|
|
|
If Not (Params.Codec = AudioCodec.DTS AndAlso ExtractDTSCore) Then
|
|
Select Case Params.Codec
|
|
Case AudioCodec.AAC
|
|
sb.Append(" -quality=" & Params.Quality.ToInvariantString)
|
|
Case AudioCodec.AC3
|
|
sb.Append(" -" & Bitrate)
|
|
Case AudioCodec.DTS
|
|
sb.Append(" -" & Bitrate)
|
|
End Select
|
|
|
|
If Params.Normalize Then
|
|
sb.Append(" -normalize")
|
|
End If
|
|
|
|
If Params.eac3toDown16 Then
|
|
sb.Append(" -down16")
|
|
End If
|
|
|
|
If Params.SamplingRate <> 0 Then
|
|
sb.Append(" -resampleTo" & Params.SamplingRate)
|
|
End If
|
|
|
|
If Params.FrameRateMode = AudioFrameRateMode.Speedup Then
|
|
sb.Append(" -speedup")
|
|
End If
|
|
|
|
If Params.FrameRateMode = AudioFrameRateMode.Slowdown Then
|
|
sb.Append(" -slowdown")
|
|
End If
|
|
|
|
If Delay <> 0 Then
|
|
sb.Append(" " + If(Delay > 0, "+", "") & Delay & "ms")
|
|
End If
|
|
|
|
If Gain < 0 Then
|
|
sb.Append(" " & CInt(Gain) & "dB")
|
|
End If
|
|
|
|
If Gain > 0 Then
|
|
sb.Append(" +" & CInt(Gain) & "dB")
|
|
End If
|
|
|
|
Select Case Channels
|
|
Case 6
|
|
If Params.ChannelsMode <> ChannelsMode.Original Then
|
|
sb.Append(" -down6")
|
|
End If
|
|
Case 2
|
|
If Not Params.CenterOptimizedStereo AndAlso ((Params.Codec <> AudioCodec.Opus AndAlso Params.ChannelsMode = ChannelsMode._2) OrElse (Params.Codec = AudioCodec.Opus AndAlso Params.OpusencDownmix = OpusDownmix.Stereo)) Then
|
|
If Params.eac3toStereoDownmixMode = 0 Then
|
|
If Params.ChannelsMode <> ChannelsMode.Original Then
|
|
sb.Append(" -downStereo")
|
|
End If
|
|
Else
|
|
sb.Append(" -downDpl")
|
|
End If
|
|
End If
|
|
End Select
|
|
|
|
If Params.CustomSwitches <> "" Then
|
|
sb.Append(" " + Params.CustomSwitches)
|
|
End If
|
|
ElseIf ExtractDTSCore Then
|
|
sb.Append(" -core")
|
|
End If
|
|
|
|
If includePaths Then
|
|
sb.Append(" -progressnumbers")
|
|
End If
|
|
|
|
Return sb.ToString
|
|
End Function
|
|
|
|
Function GetfdkaacCommandLine(includePaths As Boolean) As String
|
|
Dim sb As New StringBuilder
|
|
includePaths = includePaths And File <> ""
|
|
|
|
If DecodingMode = AudioDecodingMode.Pipe Then
|
|
sb.Append(GetPipeCommandLine(includePaths))
|
|
End If
|
|
|
|
If includePaths Then
|
|
sb.Append(Package.fdkaac.Path.Escape)
|
|
Else
|
|
sb.Clear()
|
|
sb.Append(Package.fdkaac.Filename.Base)
|
|
End If
|
|
|
|
If Params.fdkaacProfile <> 2 Then
|
|
sb.Append(" --profile " & Params.fdkaacProfile)
|
|
End If
|
|
|
|
If Params.SimpleRateMode = SimpleAudioRateMode.CBR Then
|
|
sb.Append(" --bitrate " & CInt(Bitrate))
|
|
Else
|
|
sb.Append(" --bitrate-mode " & Params.Quality)
|
|
End If
|
|
|
|
If Params.fdkaacGaplessMode <> 0 Then sb.Append(" --gapless-mode " & Params.fdkaacGaplessMode)
|
|
If Params.fdkaacBandwidth <> 0 Then sb.Append(" --bandwidth " & Params.fdkaacBandwidth)
|
|
If Not Params.fdkaacAfterburner Then sb.Append(" --afterburner 0")
|
|
If Params.fdkaacAdtsCrcCheck Then sb.Append(" --adts-crc-check")
|
|
If Params.fdkaacMoovBeforeMdat Then sb.Append(" --moov-before-mdat")
|
|
If Params.fdkaacIncludeSbrDelay Then sb.Append(" --include-sbr-delay")
|
|
If Params.fdkaacHeaderPeriod Then sb.Append(" --header-period")
|
|
If Params.fdkaacLowDelaySBR <> 0 Then sb.Append(" --lowdelay-sbr " & Params.fdkaacLowDelaySBR)
|
|
If Params.fdkaacSbrRatio <> 0 Then sb.Append(" --sbr-ratio " & Params.fdkaacSbrRatio)
|
|
If Params.fdkaacTransportFormat <> 0 Then sb.Append(" --transport-format " & Params.fdkaacTransportFormat)
|
|
If Params.CustomSwitches <> "" Then sb.Append(" " + Params.CustomSwitches)
|
|
|
|
Dim input = If(DecodingMode = AudioDecodingMode.Pipe, "-", File.LongPathPrefix.Escape)
|
|
|
|
If includePaths Then
|
|
sb.Append(" --ignorelength -o " + GetOutputFile.LongPathPrefix.Escape + " " + input)
|
|
End If
|
|
|
|
Return sb.ToString
|
|
End Function
|
|
|
|
Function GetOpusencCommandLine(includePaths As Boolean) As String
|
|
Dim usePipe = DecodingMode = AudioDecodingMode.Pipe OrElse (Params.ChannelsMode <> ChannelsMode.Original AndAlso SupportedInput.Contains(File.Ext))
|
|
Dim sb As New StringBuilder
|
|
|
|
If usePipe Then
|
|
sb.Append(GetPipeCommandLine(includePaths))
|
|
End If
|
|
|
|
If includePaths Then
|
|
sb.Append(Package.OpusEnc.Path.Escape)
|
|
Else
|
|
sb.Clear()
|
|
sb.Append(Package.OpusEnc.Filename.Base)
|
|
End If
|
|
|
|
Select Case Params.OpusencOpusRateMode
|
|
Case OpusRateMode.VBR
|
|
sb.Append(" --vbr")
|
|
Case OpusRateMode.CVBR
|
|
sb.Append(" --cvbr")
|
|
Case OpusRateMode.CBR
|
|
sb.Append(" --hard-cbr")
|
|
End Select
|
|
|
|
sb.Append(" --bitrate " & CInt(Bitrate))
|
|
|
|
Select Case Params.OpusencTune
|
|
Case OpusTune.Music
|
|
sb.Append(" --music")
|
|
Case OpusTune.Speech
|
|
sb.Append(" --speech")
|
|
End Select
|
|
|
|
If Params.OpusencComp >= 0 AndAlso Params.OpusencComp < 10 Then
|
|
sb.Append(" --comp " & Params.OpusencComp)
|
|
End If
|
|
|
|
If Params.OpusencFramesize <> OpusFramesize._20 Then
|
|
sb.Append(" --framesize " & Params.OpusencFramesize.ToString().TrimStart("_"c).Replace("_", "."))
|
|
End If
|
|
|
|
If Params.OpusencExpectloss > 0 AndAlso Params.OpusencExpectloss <= 100 Then
|
|
sb.Append(" --expect-loss " & Params.OpusencExpectloss)
|
|
End If
|
|
|
|
Select Case Params.OpusencDownmix
|
|
Case OpusDownmix.Mono
|
|
sb.Append(" --downmix-mono")
|
|
Case OpusDownmix.Stereo
|
|
If Not Params.CenterOptimizedStereo AndAlso ((Params.Codec <> AudioCodec.Opus AndAlso Params.ChannelsMode = ChannelsMode._2) OrElse (Params.Codec = AudioCodec.Opus AndAlso Params.OpusencDownmix = OpusDownmix.Stereo)) Then
|
|
sb.Append(" --downmix-stereo")
|
|
End If
|
|
End Select
|
|
|
|
If Not Params.OpusencPhaseinversion Then
|
|
sb.Append(" --no-phase-inv")
|
|
End If
|
|
|
|
If Params.OpusencMaxdelay >= 0 AndAlso Params.OpusencMaxdelay < 1000 Then
|
|
sb.Append(" --max-delay " & Params.OpusencMaxdelay)
|
|
End If
|
|
|
|
If Params.CustomSwitches <> "" Then
|
|
sb.Append(" " + Params.CustomSwitches)
|
|
End If
|
|
|
|
Dim input = If(usePipe, "-", File.Escape)
|
|
|
|
If includePaths Then
|
|
sb.Append(" " + input + " " + GetOutputFile.LongPathPrefix.Escape)
|
|
End If
|
|
|
|
Return sb.ToString()
|
|
End Function
|
|
|
|
Function GetQaacCommandLine(includePaths As Boolean) As String
|
|
Dim usePipe = DecodingMode = AudioDecodingMode.Pipe OrElse (Params.ChannelsMode <> ChannelsMode.Original AndAlso SupportedInput.Contains(File.Ext))
|
|
Dim sb As New StringBuilder
|
|
includePaths = includePaths And File <> ""
|
|
|
|
If usePipe Then
|
|
sb.Append(GetPipeCommandLine(includePaths))
|
|
End If
|
|
|
|
If includePaths Then
|
|
sb.Append(Package.qaac.Path.Escape)
|
|
Else
|
|
sb.Clear()
|
|
sb.Append(Package.qaac.Filename.Base)
|
|
End If
|
|
|
|
Select Case Params.qaacRateMode
|
|
Case 0
|
|
sb.Append(" --tvbr " & CInt(Params.Quality))
|
|
Case 1
|
|
sb.Append(" --cvbr " & CInt(Bitrate))
|
|
Case 2
|
|
sb.Append(" --abr " & CInt(Bitrate))
|
|
Case 3
|
|
sb.Append(" --cbr " & CInt(Bitrate))
|
|
End Select
|
|
|
|
If Params.qaacHE AndAlso {1, 2, 3}.Contains(Params.qaacRateMode) Then
|
|
sb.Append(" --he")
|
|
End If
|
|
|
|
If Delay <> 0 Then
|
|
sb.Append(" --delay " + (Delay / 1000).ToInvariantString)
|
|
End If
|
|
|
|
If Gain <> 0 Then
|
|
sb.Append(" --gain " & Gain.ToInvariantString)
|
|
End If
|
|
|
|
If Params.Normalize AndAlso Gain = 0 Then
|
|
sb.Append(" --normalize")
|
|
End If
|
|
|
|
If Params.qaacQuality <> 2 Then
|
|
sb.Append(" --quality " & Params.qaacQuality)
|
|
End If
|
|
|
|
If Params.SamplingRate <> 0 Then
|
|
sb.Append(" --rate " & Params.SamplingRate)
|
|
End If
|
|
|
|
If Params.qaacLowpass <> 0 Then
|
|
sb.Append(" --lowpass " & Params.qaacLowpass)
|
|
End If
|
|
|
|
If Params.qaacNoDither Then
|
|
sb.Append(" --no-dither")
|
|
End If
|
|
|
|
If Params.qaacNoDelay Then
|
|
sb.Append(" --no-delay")
|
|
End If
|
|
|
|
If Params.CustomSwitches <> "" Then
|
|
sb.Append(" " + Params.CustomSwitches)
|
|
End If
|
|
|
|
Dim input = If(usePipe, "-", File.Escape)
|
|
|
|
If includePaths Then
|
|
sb.Append(" " + input + " -o " + GetOutputFile.Escape)
|
|
End If
|
|
|
|
Return sb.ToString
|
|
End Function
|
|
|
|
Function GetPipeCommandLine(includePaths As Boolean) As String
|
|
Dim sb As New StringBuilder
|
|
|
|
If includePaths AndAlso File <> "" Then
|
|
sb.Append(Package.ffmpeg.Path.Escape + " -i " + File.Escape)
|
|
Else
|
|
sb.Append(Package.ffmpeg.Filename.Base)
|
|
End If
|
|
|
|
If Stream IsNot Nothing AndAlso Streams.Count > 1 Then
|
|
sb.Append(" -map 0:a:" & Stream.Index)
|
|
End If
|
|
|
|
If Params.ChannelsMode <> ChannelsMode.Original OrElse Params.Codec = AudioCodec.Opus Then
|
|
If Params.CenterOptimizedStereo AndAlso ((Params.Codec <> AudioCodec.Opus AndAlso Params.ChannelsMode = ChannelsMode._2) OrElse (Params.Codec = AudioCodec.Opus AndAlso Params.OpusencDownmix = OpusDownmix.Stereo)) Then
|
|
If SourceChannels = 8 Then
|
|
sb.Append(" -af pan=stereo|c0=c2+0.30c0+0.30c4+0.30c6|c1=c2+0.30c1+0.30c5+0.30c7")
|
|
Else
|
|
sb.Append(" -af pan=stereo|c0=c2+0.30*c0+0.30*c4|c1=c2+0.30*c1+0.30*c5")
|
|
End If
|
|
Else
|
|
sb.Append(" -ac " & Channels)
|
|
End If
|
|
End If
|
|
|
|
If Params.Normalize Then
|
|
If Params.ffmpegNormalizeMode = ffmpegNormalizeMode.dynaudnorm Then
|
|
sb.Append(" " + Audio.GetDynAudNormArgs(Params))
|
|
ElseIf Params.ffmpegNormalizeMode = ffmpegNormalizeMode.loudnorm Then
|
|
sb.Append(" " + Audio.GetLoudNormArgs(Params))
|
|
End If
|
|
End If
|
|
|
|
If includePaths AndAlso File <> "" Then
|
|
sb.Append(" -loglevel fatal -hide_banner -f wav - | ")
|
|
End If
|
|
|
|
Return sb.ToString
|
|
End Function
|
|
|
|
Function GetffmpegCommandLine(includePaths As Boolean) As String
|
|
Dim sb As New StringBuilder
|
|
Dim pack = If(Params.Codec = AudioCodec.AAC AndAlso Params.ffmpegLibFdkAAC, Package.ffmpeg_non_free, Package.ffmpeg)
|
|
|
|
If includePaths AndAlso File <> "" Then
|
|
sb.Append(pack.Path.Escape)
|
|
|
|
If Params.ProbeSize <> 5 Then
|
|
sb.Append($" -probesize {Params.ProbeSize}M")
|
|
End If
|
|
|
|
If Params.AnalyzeDuration <> 5 Then
|
|
sb.Append($" -analyzeduration {Params.AnalyzeDuration}M")
|
|
End If
|
|
|
|
If File.Ext.EqualsAny("avs", "vpy") Then
|
|
sb.Append(" -vn")
|
|
End If
|
|
|
|
sb.Append(" -i " + File.Escape)
|
|
Else
|
|
sb.Append(pack.Filename.Base)
|
|
End If
|
|
|
|
If Not Stream Is Nothing Then
|
|
sb.Append(" -map 0:a:" & Stream.Index)
|
|
End If
|
|
|
|
Select Case Params.Codec
|
|
Case AudioCodec.MP3
|
|
If Not Params.CustomSwitches.Contains("-c:a ") Then
|
|
sb.Append(" -c:a libmp3lame")
|
|
End If
|
|
|
|
Select Case Params.RateMode
|
|
Case AudioRateMode.ABR
|
|
sb.Append(" -b:a " & CInt(Bitrate) & "k -abr 1")
|
|
Case AudioRateMode.CBR
|
|
sb.Append(" -b:a " & CInt(Bitrate) & "k")
|
|
Case AudioRateMode.VBR
|
|
sb.Append(" -q:a " & CInt(Params.Quality))
|
|
End Select
|
|
Case AudioCodec.AC3
|
|
If Not Params.CustomSwitches.Contains("-c:a ") Then
|
|
sb.Append(" -c:a ac3")
|
|
End If
|
|
|
|
sb.Append(" -b:a " & CInt(Bitrate) & "k")
|
|
Case AudioCodec.EAC3
|
|
If Not Params.CustomSwitches.Contains("-c:a ") Then
|
|
sb.Append(" -c:a eac3")
|
|
End If
|
|
|
|
Dim br = Bitrate
|
|
Select Params.ffmpegSamplesPerFrame
|
|
Case SamplesPerFrame.Auto
|
|
br = If(Bitrate > 960, CInt(Bitrate) + 0.1, CInt(Bitrate))
|
|
Case SamplesPerFrame._768
|
|
br = CInt(Bitrate) + 0.1
|
|
Case SamplesPerFrame._1536
|
|
br = CInt(Bitrate)
|
|
End Select
|
|
|
|
sb.Append(" -b:a " & br.ToInvariantString() & "k")
|
|
Case AudioCodec.DTS
|
|
If ExtractDTSCore Then
|
|
sb.Append(" -bsf:a dca_core -c:a copy")
|
|
Else
|
|
sb.Append(" -strict -2 -b:a " & CInt(Bitrate) & "k")
|
|
End If
|
|
Case AudioCodec.Vorbis
|
|
If Not Params.CustomSwitches.Contains("-c:a ") Then
|
|
sb.Append(" -c:a libvorbis")
|
|
End If
|
|
|
|
If Params.RateMode = AudioRateMode.VBR Then
|
|
sb.Append(" -q:a " & CInt(Params.Quality))
|
|
Else
|
|
sb.Append(" -b:a " & CInt(Bitrate) & "k")
|
|
End If
|
|
Case AudioCodec.Opus
|
|
If Not Params.CustomSwitches.Contains("-c:a ") Then
|
|
sb.Append(" -c:a libopus")
|
|
End If
|
|
|
|
Select Case Params.ffmpegOpusRateMode
|
|
Case OpusRateMode.CBR
|
|
sb.Append(" -vbr off")
|
|
Case OpusRateMode.CVBR
|
|
sb.Append(" -vbr constrained")
|
|
End Select
|
|
|
|
sb.Append(" -b:a " & CInt(Bitrate) & "k")
|
|
|
|
Select Case Params.ffmpegOpusApp
|
|
Case OpusApp.voip
|
|
sb.Append(" -application voip")
|
|
Case OpusApp.lowdelay
|
|
sb.Append(" -application lowdelay")
|
|
End Select
|
|
|
|
If Params.ffmpegOpusFrame <> 20 Then
|
|
sb.Append(" -frame_duration " & Params.ffmpegOpusFrame.ToInvariantString)
|
|
End If
|
|
|
|
If Params.ffmpegOpusMap <> -1 Then
|
|
sb.Append(" -mapping_family " & CInt(Params.ffmpegOpusMap))
|
|
End If
|
|
|
|
If Params.ffmpegOpusCompress <> 10 Then
|
|
sb.Append(" -compression_level " & CInt(Params.ffmpegOpusCompress))
|
|
End If
|
|
|
|
If Params.ffmpegOpusPacket <> 0 Then
|
|
sb.Append(" -packet_loss " & CInt(Params.ffmpegOpusPacket))
|
|
End If
|
|
Case AudioCodec.AAC
|
|
If Params.ffmpegLibFdkAAC Then
|
|
sb.Append(" -c:a libfdk_aac")
|
|
|
|
If Params.RateMode = SimpleAudioRateMode.CBR Then
|
|
sb.Append(" -b:a " & CInt(Bitrate) & "k")
|
|
Else
|
|
sb.Append(" -vbr " & CInt(Params.Quality))
|
|
End If
|
|
Else
|
|
sb.Append(" -c:a aac")
|
|
|
|
If Params.RateMode = SimpleAudioRateMode.CBR Then
|
|
sb.Append(" -b:a " & CInt(Bitrate) & "k")
|
|
Else
|
|
sb.Append(" -q:a " & CInt(Params.Quality))
|
|
End If
|
|
End If
|
|
Case AudioCodec.FLAC
|
|
Dim bd = If(Params.ffmpegFlacBitDepth > 0, Params.ffmpegFlacBitDepth, SourceBitDepth)
|
|
|
|
If Not Params.CustomSwitches.Contains("-c:a ") Then
|
|
sb.Append(" -c:a flac")
|
|
End If
|
|
|
|
If bd = 16 Then
|
|
sb.Append(" -sample_fmt s16")
|
|
ElseIf bd = 24 Then
|
|
sb.Append(" -sample_fmt s32 -bits_per_raw_sample 24")
|
|
End If
|
|
Case AudioCodec.W64, AudioCodec.WAV
|
|
If Not Params.CustomSwitches.Contains("-c:a ") Then
|
|
Select Case Params.ffmpegWaveBitDepth
|
|
Case WaveBitDepth.s16
|
|
sb.Append(" -c:a pcm_s16le")
|
|
Case WaveBitDepth.s24
|
|
sb.Append(" -c:a pcm_s24le")
|
|
Case WaveBitDepth.s32
|
|
sb.Append(" -c:a pcm_s32le")
|
|
Case WaveBitDepth.f32
|
|
sb.Append(" -c:a pcm_f32le")
|
|
Case Else
|
|
If SourceBitDepth > 0 Then sb.Append($" -c:a pcm_s{SourceBitDepth}le")
|
|
End Select
|
|
End If
|
|
End Select
|
|
|
|
If Gain <> 0 Then
|
|
sb.Append(" -af volume=" + Gain.ToInvariantString + "dB")
|
|
End If
|
|
|
|
If Params.Normalize Then
|
|
If Params.ffmpegNormalizeMode = ffmpegNormalizeMode.loudnorm Then
|
|
sb.Append(" " + Audio.GetLoudNormArgs(Params))
|
|
ElseIf Params.ffmpegNormalizeMode = ffmpegNormalizeMode.dynaudnorm Then
|
|
sb.Append(" " + Audio.GetDynAudNormArgs(Params))
|
|
End If
|
|
End If
|
|
|
|
If Params.ChannelsMode <> ChannelsMode.Original OrElse Params.Codec = AudioCodec.Opus Then
|
|
If Params.CenterOptimizedStereo AndAlso ((Params.Codec <> AudioCodec.Opus AndAlso Params.ChannelsMode = ChannelsMode._2) OrElse (Params.Codec = AudioCodec.Opus AndAlso Params.OpusencDownmix = OpusDownmix.Stereo)) Then
|
|
If SourceChannels = 8 Then
|
|
sb.Append(" -af pan=stereo|c0=c2+0.30c0+0.30c4+0.30c6|c1=c2+0.30c1+0.30c5+0.30c7")
|
|
Else
|
|
sb.Append(" -af pan=stereo|c0=c2+0.30*c0+0.30*c4|c1=c2+0.30*c1+0.30*c5")
|
|
End If
|
|
Else
|
|
sb.Append(" -ac " & Channels)
|
|
End If
|
|
End If
|
|
|
|
If Params.SamplingRate <> 0 Then
|
|
sb.Append(" -ar " & Params.SamplingRate)
|
|
End If
|
|
|
|
If Params.CustomSwitches <> "" Then
|
|
sb.Append(" " + Params.CustomSwitches)
|
|
End If
|
|
|
|
If includePaths AndAlso File <> "" Then
|
|
sb.Append(" -y -hide_banner")
|
|
sb.Append(" " + GetOutputFile.Escape)
|
|
End If
|
|
|
|
Dim ret = sb.ToString
|
|
Dim matches = Regex.Matches(ret, " -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}"
|
|
ret = ret.Remove(match.Index, match.Length)
|
|
Next
|
|
concated = " -af " + concated.Trim(","c)
|
|
ret = ret.Insert(matches(0).Index, concated)
|
|
End If
|
|
|
|
ret = Regex.Replace(ret, " -af ([^ ]+)", " -af ""$1""")
|
|
|
|
Return ret
|
|
End Function
|
|
|
|
Function SupportsNormalize() As Boolean
|
|
Return (GetEncoder() = GuiAudioEncoder.deezy AndAlso Params.Codec = AudioCodec.EAC3) OrElse GetEncoder() = GuiAudioEncoder.eac3to OrElse GetEncoder() = GuiAudioEncoder.qaac
|
|
End Function
|
|
|
|
Public Overrides ReadOnly Property DefaultName As String
|
|
Get
|
|
If Params Is Nothing Then
|
|
Exit Property
|
|
End If
|
|
|
|
Dim ch = ""
|
|
|
|
Select Case Params.ChannelsMode
|
|
Case ChannelsMode._8
|
|
ch += " 7.1"
|
|
Case ChannelsMode._7
|
|
ch += " 6.1"
|
|
Case ChannelsMode._6
|
|
ch += " 5.1"
|
|
Case ChannelsMode._2
|
|
ch += " 2.0"
|
|
Case ChannelsMode._1
|
|
ch += " Mono"
|
|
End Select
|
|
|
|
Dim circa = If(Params.RateMode = AudioRateMode.VBR OrElse Params.Codec = AudioCodec.FLAC, "~", "")
|
|
Dim bitrate = If(Params.RateMode = AudioRateMode.VBR, GetBitrate(), Me.Bitrate)
|
|
|
|
If ExtractCore Then
|
|
Return "Extract DTS Core"
|
|
Else
|
|
Return Params.Codec.ToString + ch & " " & circa & bitrate & " Kbps"
|
|
End If
|
|
End Get
|
|
End Property
|
|
|
|
ReadOnly Property ExtractCore As Boolean
|
|
Get
|
|
Dim enc = GetEncoder()
|
|
|
|
If Params.Codec = AudioCodec.DTS AndAlso ExtractDTSCore AndAlso
|
|
(enc = GuiAudioEncoder.eac3to OrElse enc = GuiAudioEncoder.ffmpeg) Then
|
|
|
|
Return True
|
|
End If
|
|
End Get
|
|
End Property
|
|
|
|
Overrides Property CommandLines() As String
|
|
Get
|
|
Return GetCommandLine(True)
|
|
End Get
|
|
Set(Value As String)
|
|
End Set
|
|
End Property
|
|
|
|
Overrides Property CanEdit() As Boolean
|
|
Get
|
|
Return True
|
|
End Get
|
|
Set(value As Boolean)
|
|
End Set
|
|
End Property
|
|
|
|
Overrides Function HandlesDelay() As Boolean
|
|
Return {GuiAudioEncoder.deezy, GuiAudioEncoder.eac3to, GuiAudioEncoder.qaac}.Contains(GetEncoder())
|
|
End Function
|
|
|
|
Public Overrides ReadOnly Property NeedConvert As Boolean
|
|
Get
|
|
Dim enc = GetEncoder()
|
|
|
|
If Not IsInputSupported() Then Return True
|
|
If enc = GuiAudioEncoder.opusenc AndAlso (Params.Normalize OrElse Gain <> 0) Then Return True
|
|
Return False
|
|
End Get
|
|
End Property
|
|
|
|
Function GetSupportedInput(gap As GuiAudioEncoder) As String()
|
|
Select Case gap
|
|
Case GuiAudioEncoder.deezy
|
|
Return FileTypes.DeezyInput
|
|
Case GuiAudioEncoder.eac3to
|
|
Return FileTypes.eac3toInput
|
|
Case GuiAudioEncoder.opusenc
|
|
Return FileTypes.OpusencInput
|
|
Case GuiAudioEncoder.qaac
|
|
If DecodingMode <> AudioDecodingMode.Pipe Then
|
|
Return If(p.Ranges.Count > 0, {"wav", "w64"}, {"wav", "flac", "w64"})
|
|
End If
|
|
Case GuiAudioEncoder.fdkaac
|
|
If DecodingMode <> AudioDecodingMode.Pipe Then
|
|
Return {"wav"}
|
|
End If
|
|
End Select
|
|
|
|
Return {}
|
|
End Function
|
|
|
|
Overrides Property SupportedInput As String()
|
|
Get
|
|
Return GetSupportedInput(GetEncoder())
|
|
End Get
|
|
Set(value As String())
|
|
End Set
|
|
End Property
|
|
|
|
<Serializable()>
|
|
Public Class Parameters
|
|
Property AnalyzeDuration As Integer = 5
|
|
Property ChannelsMode As ChannelsMode
|
|
Property Codec As AudioCodec
|
|
Property CustomSwitches As String = ""
|
|
Property eac3toStereoDownmixMode As Integer
|
|
Property eac3toDown16 As Boolean = False
|
|
Property Encoder As GuiAudioEncoder
|
|
Property FrameRateMode As AudioFrameRateMode
|
|
Property Normalize As Boolean = True
|
|
Property CenterOptimizedStereo As Boolean = False
|
|
Property ProbeSize As Integer = 5
|
|
Property Quality As Single = 0.3
|
|
Property RateMode As AudioRateMode
|
|
Property SamplingRate As Integer
|
|
|
|
Property Migrate1 As Boolean = True
|
|
Property MigrateffNormalizeMode As Boolean = True
|
|
|
|
Property DeezyKeeptemp As Boolean = False
|
|
Property DeezyChannelsAtmos As DeezyChannelsAtmos = DeezyChannelsAtmos._6
|
|
Property DeezyChannelsAc4 As DeezyChannelsAc4 = DeezyChannelsAc4._2
|
|
Property DeezyChannelsDd As DeezyChannelsDd = DeezyChannelsDd.Auto
|
|
Property DeezyChannelsDdp As DeezyChannelsDdp = DeezyChannelsDdp.Auto
|
|
Property DeezyChannelsDdpBluray As DeezyChannelsDdpBluray = DeezyChannelsDdpBluray._8
|
|
Property DeezyDdpMode As DeezyDdpMode = DeezyDdpMode.Ddp
|
|
Property DeezyStereodownmix As DeezyStereodownmix = DeezyStereodownmix.Auto
|
|
Property DeezyDynamicrangecompression As DeezyDrcLineMode = DeezyDrcLineMode.Music_Light
|
|
|
|
Property OpusencOpusRateMode As OpusRateMode = OpusRateMode.VBR
|
|
Property OpusencTune As OpusTune = OpusTune.Auto
|
|
Property OpusencComp As Integer = 10
|
|
Property OpusencFramesize As OpusFramesize = OpusencFramesize._20
|
|
Property OpusencExpectloss As Integer = 0
|
|
Property OpusencDownmix As OpusDownmix = OpusDownmix.Original
|
|
Property OpusencPhaseinversion As Boolean = True
|
|
Property OpusencMaxdelay As Integer = 1000
|
|
|
|
Property qaacHE As Boolean
|
|
Property qaacLowpass As Integer
|
|
Property qaacNoDelay As Boolean
|
|
Property qaacNoDither As Boolean
|
|
Property qaacQuality As Integer = 2
|
|
Property qaacRateMode As Integer
|
|
|
|
Property fdkaacProfile As Integer = 2
|
|
Property fdkaacBandwidth As Integer
|
|
Property fdkaacAfterburner As Boolean = True
|
|
Property fdkaacLowDelaySBR As Integer
|
|
Property fdkaacSbrRatio As Integer
|
|
Property fdkaacTransportFormat As Integer
|
|
Property fdkaacGaplessMode As Integer
|
|
Property fdkaacAdtsCrcCheck As Boolean
|
|
Property fdkaacHeaderPeriod As Boolean
|
|
Property fdkaacIncludeSbrDelay As Boolean
|
|
Property fdkaacMoovBeforeMdat As Boolean
|
|
|
|
Property ffNormalizeMode As ffNormalizeMode
|
|
Property ffmpegNormalizeMode As ffmpegNormalizeMode
|
|
|
|
Property ffmpegLibFdkAAC As Boolean
|
|
|
|
Property ffmpegLoudnormIntegrated As Double = -24
|
|
Property ffmpegLoudnormIntegratedMeasured As Double
|
|
Property ffmpegLoudnormLRA As Double = 7
|
|
Property ffmpegLoudnormLraMeasured As Double
|
|
Property ffmpegLoudnormThresholdMeasured As Double
|
|
Property ffmpegLoudnormTruePeak As Double = -2
|
|
Property ffmpegLoudnormTruePeakMeasured As Double
|
|
|
|
Property ffmpegDynaudnormF As Integer = 500
|
|
Property ffmpegDynaudnormG As Integer = 31
|
|
Property ffmpegDynaudnormP As Double = 0.95
|
|
Property ffmpegDynaudnormM As Double = 10
|
|
Property ffmpegDynaudnormR As Double
|
|
Property ffmpegDynaudnormN As Boolean = True
|
|
Property ffmpegDynaudnormC As Boolean
|
|
Property ffmpegDynaudnormB As Boolean
|
|
Property ffmpegDynaudnormS As Double
|
|
|
|
Property ffmpegFlacBitDepth As FlacBitDepth = FlacBitDepth.Original
|
|
Property ffmpegWaveBitDepth As WaveBitDepth = WaveBitDepth.Original
|
|
|
|
Property ffmpegOpusApp As OpusApp = OpusApp.audio
|
|
Property ffmpegOpusCompress As Integer = 10
|
|
Property ffmpegOpusFrame As Double = 20
|
|
Property ffmpegOpusMap As Integer = -1
|
|
Property ffmpegOpusPacket As Integer
|
|
Property ffmpegOpusRateMode As OpusRateMode = OpusRateMode.VBR
|
|
Property ffmpegOpusMigrate As Integer = 1
|
|
|
|
Property ffmpegSamplesPerFrame As SamplesPerFrame = SamplesPerFrame.Auto
|
|
|
|
Property SimpleRateMode As SimpleAudioRateMode
|
|
Get
|
|
If RateMode = AudioRateMode.CBR Then
|
|
Return SimpleAudioRateMode.CBR
|
|
Else
|
|
Return SimpleAudioRateMode.VBR
|
|
End If
|
|
End Get
|
|
Set(value As SimpleAudioRateMode)
|
|
If value = SimpleAudioRateMode.CBR Then
|
|
RateMode = AudioRateMode.CBR
|
|
Else
|
|
RateMode = AudioRateMode.VBR
|
|
End If
|
|
End Set
|
|
End Property
|
|
|
|
'legacy/obsolete
|
|
Sub Migrate()
|
|
'2019
|
|
If fdkaacProfile = 0 Then
|
|
fdkaacProfile = 2
|
|
SimpleRateMode = SimpleAudioRateMode.VBR
|
|
fdkaacAfterburner = True
|
|
End If
|
|
|
|
'2019
|
|
If Not Migrate1 Then
|
|
Normalize = True
|
|
|
|
ffmpegLoudnormIntegrated = -24
|
|
ffmpegLoudnormLRA = 7
|
|
ffmpegLoudnormTruePeak = -2
|
|
|
|
ffmpegDynaudnormF = 500
|
|
ffmpegDynaudnormG = 31
|
|
ffmpegDynaudnormP = 0.95
|
|
ffmpegDynaudnormM = 10
|
|
ffmpegDynaudnormN = True
|
|
|
|
Migrate1 = True
|
|
End If
|
|
|
|
'2020
|
|
If Not MigrateffNormalizeMode Then
|
|
ffmpegNormalizeMode = CType(ffNormalizeMode, ffmpegNormalizeMode)
|
|
MigrateffNormalizeMode = True
|
|
End If
|
|
|
|
'2020
|
|
If ffmpegOpusMigrate <> 1 Then
|
|
ffmpegOpusMigrate = 1
|
|
ffmpegOpusApp = OpusApp.audio
|
|
ffmpegOpusCompress = 10
|
|
ffmpegOpusFrame = 20
|
|
ffmpegOpusMap = -1
|
|
ffmpegOpusRateMode = OpusRateMode.VBR
|
|
End If
|
|
|
|
'2020
|
|
If ProbeSize = 0 AndAlso AnalyzeDuration = 0 Then
|
|
ProbeSize = 5
|
|
AnalyzeDuration = 5
|
|
End If
|
|
End Sub
|
|
End Class
|
|
End Class
|
|
|
|
Public Enum AudioCodec
|
|
AAC
|
|
AC3
|
|
AC4
|
|
EAC3
|
|
DTS
|
|
FLAC
|
|
MP3
|
|
Opus
|
|
Vorbis
|
|
W64
|
|
WAV
|
|
None
|
|
End Enum
|
|
|
|
Public Enum AudioRateMode
|
|
CBR
|
|
ABR
|
|
VBR
|
|
End Enum
|
|
|
|
Public Enum DeezyChannelsAc4
|
|
<DispName("Stereo (default)")> _2
|
|
End Enum
|
|
|
|
Public Enum DeezyChannelsDd
|
|
<DispName("Auto (default)")> Auto
|
|
<DispName("Mono")> _1
|
|
<DispName("Stereo")> _2
|
|
<DispName("Surround (5.1)")> _6
|
|
End Enum
|
|
|
|
Public Enum DeezyChannelsDdp
|
|
<DispName("Auto (default)")> Auto
|
|
<DispName("Mono")> _1
|
|
<DispName("Stereo")> _2
|
|
<DispName("Surround (5.1)")> _6
|
|
<DispName("SurroundEX (7.1)")> _8
|
|
End Enum
|
|
|
|
Public Enum DeezyChannelsDdpBluray
|
|
<DispName("SurroundEX (7.1)")> _8
|
|
End Enum
|
|
|
|
Public Enum DeezyChannelsAtmos
|
|
<DispName("Streaming (5.1)")> _6
|
|
<DispName("Bluray (7.1)")> _8
|
|
End Enum
|
|
|
|
Public Enum DeezyDdpMode
|
|
<DispName("Dolby Digital Plus (default)")> Ddp
|
|
<DispName("Dolby Digital Plus Bluray")> DdpBluray
|
|
<DispName("Atmos")> Atmos
|
|
End Enum
|
|
|
|
Public Enum DeezyStereodownmix
|
|
<DispName("Auto (default)")> Auto
|
|
<DispName("Loro")> Loro
|
|
<DispName("Ltrt")> Ltrt
|
|
<DispName("Dpl2")> Dplii
|
|
End Enum
|
|
|
|
Public Enum DeezyDrcLineMode
|
|
<DispName("Film Standard")> Film_Standard
|
|
<DispName("Film Light")> Film_Light
|
|
<DispName("Music Standard")> Music_Standard
|
|
<DispName("Music Light (default)")> Music_Light
|
|
<DispName("Speech")> Speech
|
|
End Enum
|
|
|
|
Public Enum IntermediateWaveBitDepth
|
|
<DispName("24-bit (single)")> s24 = 24
|
|
<DispName("32-bit (single)")> s32 = 32
|
|
<DispName("32-bit (float)")> f32 = 33
|
|
End Enum
|
|
|
|
Public Enum WaveBitDepth
|
|
<DispName("Original (default)")> Original = 0
|
|
<DispName("16-bit (single)")> s16 = 16
|
|
<DispName("24-bit (single)")> s24 = 24
|
|
<DispName("32-bit (single)")> s32 = 32
|
|
<DispName("32-bit (float)")> f32 = 33
|
|
End Enum
|
|
|
|
Public Enum FlacBitDepth
|
|
<DispName("Original (default)")> Original = 0
|
|
<DispName("16-bit")> _16 = 16
|
|
<DispName("24-bit")> _24 = 24
|
|
End Enum
|
|
|
|
Public Enum OpusDownmix
|
|
<DispName("Original (default)")> Original
|
|
<DispName("Mono")> Mono
|
|
<DispName("Stereo")> Stereo
|
|
End Enum
|
|
|
|
Public Enum SamplesPerFrame
|
|
<DispName("Automatic (default)")> Auto
|
|
<DispName("768")> _768
|
|
<DispName("1536")> _1536
|
|
End Enum
|
|
|
|
Public Enum OpusFramesize
|
|
<DispName("2.5")> _2_5
|
|
<DispName("5")> _5
|
|
<DispName("10")> _10
|
|
<DispName("20 (default)")> _20
|
|
<DispName("40")> _40
|
|
<DispName("60")> _60
|
|
End Enum
|
|
|
|
Public Enum OpusRateMode
|
|
<DispName("VBR (default)")> VBR
|
|
<DispName("CVBR")> CVBR
|
|
<DispName("CBR")> CBR
|
|
End Enum
|
|
|
|
Public Enum OpusTune
|
|
<DispName("Automatic (default)")> Auto
|
|
<DispName("Music")> Music
|
|
<DispName("Speech")> Speech
|
|
End Enum
|
|
|
|
Public Enum OpusApp
|
|
voip
|
|
audio
|
|
lowdelay
|
|
End Enum
|
|
|
|
Public Enum SimpleAudioRateMode
|
|
CBR
|
|
VBR
|
|
End Enum
|
|
|
|
Public Enum AudioAacProfile
|
|
Automatic
|
|
LC
|
|
SBR
|
|
<DispName("SBR+PS")> SBRPS = 300
|
|
End Enum
|
|
|
|
Public Enum GuiAudioEncoder
|
|
Automatic
|
|
deezy
|
|
eac3to
|
|
fdkaac
|
|
ffmpeg
|
|
opusenc
|
|
qaac
|
|
End Enum
|
|
|
|
Public Enum AudioFrameRateMode
|
|
Keep
|
|
<DispName("Apply PAL speedup")> Speedup
|
|
<DispName("Reverse PAL speedup")> Slowdown
|
|
End Enum
|
|
|
|
Public Enum AudioDownMixMode
|
|
<DispName("Simple")> Stereo
|
|
<DispName("Dolby Surround")> Surround
|
|
<DispName("Dolby Surround 2")> Surround2
|
|
End Enum
|
|
|
|
Public Enum ChannelsMode
|
|
Original = 0
|
|
<DispName("1 (Mono)")> _1 = 1
|
|
<DispName("2 (Stereo)")> _2 = 2
|
|
<DispName("5.1")> _6 = 6
|
|
<DispName("6.1")> _7 = 7
|
|
<DispName("7.1")> _8 = 8
|
|
End Enum
|