Darmowe skrypty do vMix
Ducking Audio inputa 1 i 2 wywoływany BUSEM F i G
Gotowy skrypt do vMix. Działa w pętli, sprawdza poziom audio na wybranych BUS-ach i płynnie przycisza wskazane inputy.
Dim engageThreshold As Double = 50.0
Dim releaseThreshold As Double = 35.0
Dim normalVolume1 As Double = 100.0
Dim normalVolume2 As Double = 100.0
Dim duckPercent As Double = 0.5
Dim fadeMs As Integer = 500
Dim releaseHoldMs As Integer = 700
Dim checkMs As Integer = 100
Dim ducked1 As Boolean = False
Dim lastSignalTime1 As DateTime = DateTime.Now
Dim ducked2 As Boolean = False
Dim lastSignalTime2 As DateTime = DateTime.Now
Do While True
Dim x As New System.Xml.XmlDocument
x.LoadXml(API.XML())
' BUS F -> INPUT 1
Dim busFNode = x.SelectSingleNode("//audio/busF")
If busFNode IsNot Nothing Then
Dim meterLF As Double = Double.Parse(busFNode.Attributes("meterF1").Value, Globalization.CultureInfo.InvariantCulture)
Dim meterRF As Double = Double.Parse(busFNode.Attributes("meterF2").Value, Globalization.CultureInfo.InvariantCulture)
Dim busLevelF As Double = Math.Max(Math.Pow(meterLF, 0.25) * 100.0, Math.Pow(meterRF, 0.25) * 100.0)
If busLevelF > engageThreshold Then
lastSignalTime1 = DateTime.Now
If ducked1 = False Then
API.Function("SetVolumeFade", Input:="1", Value:=CInt(normalVolume1 * duckPercent).ToString() & "," & fadeMs.ToString())
ducked1 = True
End If
End If
If busLevelF < releaseThreshold Then
If ducked1 = True AndAlso DateTime.Now.Subtract(lastSignalTime1).TotalMilliseconds > releaseHoldMs Then
API.Function("SetVolumeFade", Input:="1", Value:=CInt(normalVolume1).ToString() & "," & fadeMs.ToString())
ducked1 = False
End If
End If
End If
' BUS G -> INPUT 2
Dim busGNode = x.SelectSingleNode("//audio/busG")
If busGNode IsNot Nothing Then
If busGNode.Attributes("meterF1") IsNot Nothing AndAlso busGNode.Attributes("meterF2") IsNot Nothing Then
Dim meterLG As Double = Double.Parse(busGNode.Attributes("meterF1").Value, Globalization.CultureInfo.InvariantCulture)
Dim meterRG As Double = Double.Parse(busGNode.Attributes("meterF2").Value, Globalization.CultureInfo.InvariantCulture)
Dim busLevelG As Double = Math.Max(Math.Pow(meterLG, 0.25) * 100.0, Math.Pow(meterRG, 0.25) * 100.0)
If busLevelG > engageThreshold Then
lastSignalTime2 = DateTime.Now
If ducked2 = False Then
API.Function("SetVolumeFade", Input:="2", Value:=CInt(normalVolume2 * duckPercent).ToString() & "," & fadeMs.ToString())
ducked2 = True
End If
End If
If busLevelG < releaseThreshold Then
If ducked2 = True AndAlso DateTime.Now.Subtract(lastSignalTime2).TotalMilliseconds > releaseHoldMs Then
API.Function("SetVolumeFade", Input:="2", Value:=CInt(normalVolume2).ToString() & "," & fadeMs.ToString())
ducked2 = False
End If
End If
End If
End If
Sleep(checkMs)
Loop
Jak działa ten skrypt?
- Skrypt co 100 ms pobiera z vMix aktualny XML, czyli informacje o projekcie, inputach i poziomach audio.
- Następnie sprawdza poziom sygnału na BUS F. Jeżeli poziom przekroczy 50%, skrypt przycisza Input 1 do połowy głośności.
- Jeżeli poziom na BUS F spadnie poniżej 35% i minie krótki czas podtrzymania, Input 1 wraca płynnie do 100%.
- Analogicznie działa druga część: BUS G steruje przyciszeniem Input 2.
- Zmienna ducked1 i ducked2 pilnuje, żeby input nie był ściszany wielokrotnie coraz niżej. Dzięki temu poziom wraca do normalnej wartości.
Auto Cut by Audio — automatyczne przełączanie kamer
Gotowy skrypt do vMix, który na podstawie poziomów audio automatycznie przełącza ujęcia między planem szerokim a close-upami rozmówców.
' ==========================================
' AUTO CUT BY AUDIO - CLOSE-UP PRIORITY VERSION
' BUS A Left -> LEFT_CLOSE_INPUT
' BUS A Right OR BUS B Left -> RIGHT_CLOSE_INPUT
' Priorytet: trzymanie close-upów
' Szeroki: rzadko lub gdy mówią obie strony
' ==========================================
Dim WIDE_INPUT As String = "4"
Dim LEFT_CLOSE_INPUT As String = "5"
Dim RIGHT_CLOSE_INPUT As String = "6"
Dim THRESHOLD_SPEECH As Double = 0.060
Dim THRESHOLD_DOMINANCE As Double = 0.010
Dim THRESHOLD_BOTH_TALK As Double = 0.018
Dim MIN_SHOT_MS As Integer = 2600
Dim WIDE_INSERT_EVERY_MS As Integer = 60000
Dim WIDE_INSERT_DURATION_MS As Integer = 3000
Dim SPEAKER_HOLD_MS As Integer = 500
Dim PAUSE_HOLD_MS As Integer = 5000
Dim LOOP_MS As Integer = 150
Dim TRANSITION_NAME As String = "CutDirect"
Dim currentShot As String = WIDE_INPUT
Dim target As String = WIDE_INPUT
Dim lastCloseShot As String = LEFT_CLOSE_INPUT
Dim lastSwitchTime As Date = Date.Now
Dim lastWideInsertTime As Date = Date.Now
Dim leftCandidateSince As Date = Date.MinValue
Dim rightCandidateSince As Date = Date.MinValue
Dim wideCandidateSince As Date = Date.MinValue
Dim silenceSince As Date = Date.MinValue
Dim forceWideUntil As Date = Date.MinValue
Dim rnd As New Random()
API.Function(TRANSITION_NAME, Input:=WIDE_INPUT)
Do While True
Dim xml As String = API.XML()
Dim x As New System.Xml.XmlDocument()
x.LoadXml(xml)
Dim busALeftNode As System.Xml.XmlNode = x.SelectSingleNode(".//audio/busA/@meterF1")
If busALeftNode Is Nothing Then
busALeftNode = x.SelectSingleNode(".//audio/busa/@meterF1")
End If
Dim busARightNode As System.Xml.XmlNode = x.SelectSingleNode(".//audio/busA/@meterF2")
If busARightNode Is Nothing Then
busARightNode = x.SelectSingleNode(".//audio/busa/@meterF2")
End If
Dim busBLeftNode As System.Xml.XmlNode = x.SelectSingleNode(".//audio/busB/@meterF1")
If busBLeftNode Is Nothing Then
busBLeftNode = x.SelectSingleNode(".//audio/busb/@meterF1")
End If
Dim leftLevel As Double = 0.0
Dim busARightLevel As Double = 0.0
Dim busBLeftLevel As Double = 0.0
Dim rightLevel As Double = 0.0
If Not busALeftNode Is Nothing Then
Double.TryParse(busALeftNode.Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, leftLevel)
End If
If Not busARightNode Is Nothing Then
Double.TryParse(busARightNode.Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, busARightLevel)
End If
If Not busBLeftNode Is Nothing Then
Double.TryParse(busBLeftNode.Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, busBLeftLevel)
End If
rightLevel = Math.Max(busARightLevel, busBLeftLevel)
Dim nowTime As Date = Date.Now
Dim diff As Double = Math.Abs(leftLevel - rightLevel)
Dim leftSpeaking As Boolean = leftLevel >= THRESHOLD_SPEECH
Dim rightSpeaking As Boolean = rightLevel >= THRESHOLD_SPEECH
Dim bothSpeaking As Boolean = leftSpeaking And rightSpeaking
Dim silence As Boolean = (Not leftSpeaking And Not rightSpeaking)
target = currentShot
If nowTime < forceWideUntil Then
target = WIDE_INPUT
Else
' Rzadki szeroki "oddech"
If (nowTime - lastWideInsertTime).TotalMilliseconds >= WIDE_INSERT_EVERY_MS Then
If rnd.Next(0, 100) < 50 Then
forceWideUntil = nowTime.AddMilliseconds(WIDE_INSERT_DURATION_MS)
lastWideInsertTime = nowTime
target = WIDE_INPUT
End If
End If
If nowTime >= forceWideUntil Then
If bothSpeaking And diff <= THRESHOLD_BOTH_TALK Then
If wideCandidateSince = Date.MinValue Then
wideCandidateSince = nowTime
End If
leftCandidateSince = Date.MinValue
rightCandidateSince = Date.MinValue
silenceSince = Date.MinValue
If (nowTime - wideCandidateSince).TotalMilliseconds >= SPEAKER_HOLD_MS Then
target = WIDE_INPUT
End If
ElseIf leftSpeaking And (leftLevel - rightLevel) >= THRESHOLD_DOMINANCE Then
If leftCandidateSince = Date.MinValue Then
leftCandidateSince = nowTime
End If
rightCandidateSince = Date.MinValue
wideCandidateSince = Date.MinValue
silenceSince = Date.MinValue
If (nowTime - leftCandidateSince).TotalMilliseconds >= SPEAKER_HOLD_MS Then
target = LEFT_CLOSE_INPUT
lastCloseShot = LEFT_CLOSE_INPUT
End If
ElseIf rightSpeaking And (rightLevel - leftLevel) >= THRESHOLD_DOMINANCE Then
If rightCandidateSince = Date.MinValue Then
rightCandidateSince = nowTime
End If
leftCandidateSince = Date.MinValue
wideCandidateSince = Date.MinValue
silenceSince = Date.MinValue
If (nowTime - rightCandidateSince).TotalMilliseconds >= SPEAKER_HOLD_MS Then
target = RIGHT_CLOSE_INPUT
lastCloseShot = RIGHT_CLOSE_INPUT
End If
ElseIf silence Then
If silenceSince = Date.MinValue Then
silenceSince = nowTime
End If
leftCandidateSince = Date.MinValue
rightCandidateSince = Date.MinValue
wideCandidateSince = Date.MinValue
' Przy ciszy nie lecimy od razu na szeroki.
' Trzymamy ostatni close-up przez PAUSE_HOLD_MS.
If (nowTime - silenceSince).TotalMilliseconds <= PAUSE_HOLD_MS Then
target = lastCloseShot
Else
' Po dłuższej ciszy można dać szeroki
target = WIDE_INPUT
End If
Else
' Niejednoznacznie -> preferuj ostatni close-up, nie szeroki
leftCandidateSince = Date.MinValue
rightCandidateSince = Date.MinValue
wideCandidateSince = Date.MinValue
silenceSince = Date.MinValue
target = lastCloseShot
End If
End If
End If
If target <> currentShot Then
If (nowTime - lastSwitchTime).TotalMilliseconds >= MIN_SHOT_MS Then
API.Function(TRANSITION_NAME, Input:=target)
currentShot = target
lastSwitchTime = nowTime
If target = LEFT_CLOSE_INPUT Or target = RIGHT_CLOSE_INPUT Then
lastCloseShot = target
End If
End If
End If
Console.WriteLine("A_L=" & leftLevel.ToString("0.000") & " | A_R=" & busARightLevel.ToString("0.000") & " | B_L=" & busBLeftLevel.ToString("0.000") & " | RIGHT_USED=" & rightLevel.ToString("0.000") & " | LAST_CLOSE=" & lastCloseShot & " | CURRENT=" & currentShot)
Sleep(LOOP_MS)
Loop
Jak działa ten skrypt?
- Skrypt analizuje poziomy audio z BUS A oraz BUS B i na tej podstawie wykrywa, która strona aktualnie mówi.
- BUS A Left steruje lewym close-upem, czyli inputem ustawionym w zmiennej LEFT_CLOSE_INPUT.
- BUS A Right lub BUS B Left steruje prawym close-upem, czyli inputem ustawionym w zmiennej RIGHT_CLOSE_INPUT.
- Jeżeli mówi jedna osoba i jej poziom dominuje nad drugą stroną, skrypt przełącza obraz na odpowiedni close-up.
- Jeżeli mówią obie strony albo po dłuższej ciszy nie ma aktywnego rozmówcy, skrypt może przełączyć obraz na plan szeroki.
- Zmienne czasowe, takie jak MIN_SHOT_MS, SPEAKER_HOLD_MS i PAUSE_HOLD_MS, chronią przed zbyt szybkim i nerwowym przełączaniem kamer.
Jak dodać skrypt w vMix?
- Wejdź w Settings → Scripting.
- Kliknij Add i wybierz skrypt VB.NET.
- Wklej kod z tej strony.
- Dostosuj inputy, BUS-y i progi działania bezpośrednio w kodzie.
- Uruchom skrypt i przetestuj na kopii projektu przed realizacją live.
Ważne: skrypt działa w pętli, więc zatrzymujesz go ręcznie w panelu Scripting.
Pomogło?
Skrypty są darmowe. Jeśli chcesz docenić moją pracę, możesz postawić mi kawę BLIK-iem.
Odbiorca BLIK: Tomek Cedro
Tytuł: Kawa za skrypt vmix
Odbiorca BLIK: Tomek Cedro
Tytuł: Kawa za skrypt vmix
+48 536 800 099
cedrotomasz@gmail.com