logo

Live Production Software Forums


Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

Options
Go to last post Go to first unread
DerhamProductions  
#1 Posted : Friday, July 18, 2025 7:01:13 PM(UTC)
DerhamProductions

Rank: Newbie

Groups: Registered
Joined: 7/18/2025(UTC)
Posts: 1
United Kingdom
Location: Birmingham

Hey fellow vMixers,

Long time reader, but first time posting here. Hoping to share some knowledge others might find useful.

Background, our vMix studio has been having a bit of an overhaul this summer ready for a busy autumn of events. With enhancements to the control surfaces (extra stream decks and some old akai midi interfaces replaced with behringer X-Touch controllers) we started from scratch tidying up all scripts and updating to companion v4.
However we've regularly wanted to have an easy way of controlling audio status (Live/Green room) that is automated to what's actually in program. With lots of corporate panel discussions, with people coming and going, and opening and closing calls to get the next presenters ready, doing this manually sometimes leads to mistakes.

After some serious trial and error we've created the below script, that checks if inputs 101-108 are live on Mix 1 or if the input live on Mix 1 has these inputs active on a layer, it then fires "CallerX Live" the script that changes audio routing for that caller (removes from green room bus, adds to live bus) and actives the onair toggle in the green room and changes the video return feed to the live output.

The 'database' about which caller is live is stored in a blank title input, this allows the script to check for changes between live / green room and then trigger "CallerX GR" script that does the reverse. Using the title gets around the fact there's no variable storage when working strictly within the vMix scripting engine.

I hope this script can help others with automating their productions and minimising errors in live production.
Usual caveat of test, test, TEST and REALLY TEST! this code before using it in your production.

Code:

' vMix VB.NET script: Detect live vMixCall inputs 101–108 on Mix 1 (even in layers), update title 50, and run trigger scripts

' CONFIGURATION
Dim callerInputs = New Integer() {101, 102, 103, 104, 105, 106, 107, 108}
Dim callerScriptsLive = New String() {"Caller1 Live", "Caller2 Live", "Caller3 Live", "Caller4 Live", "Caller5 Live", "Caller6 Live", "Caller7 Live", "Caller8 Live"}
Dim callerScriptsGone = New String() {"Caller1 GR", "Caller2 GR", "Caller3 GR", "Caller4 GR", "Caller5 GR", "Caller6 GR", "Caller7 GR", "Caller8 GR"}
Dim titleInput As String = "50"
Dim titleField As String = "Message.Text"

' LOAD XML
Dim xml As String = API.XML()
Dim doc As New System.Xml.XmlDocument()
doc.LoadXml(xml)

' GET CURRENT STATE FROM TITLE (Input 50)
Dim titleNode As Xml.XmlNode = doc.SelectSingleNode("//input[@number='" & titleInput & "']/text")
Dim lastStateRaw As String = If(titleNode IsNot Nothing, titleNode.InnerText, "")
Dim stateTagIndex As Integer = lastStateRaw.IndexOf("[state:")
Dim lastVisibleCallers As New System.Collections.Generic.List(Of Integer)

If stateTagIndex >= 0 Then
    Dim stateData As String = lastStateRaw.Substring(stateTagIndex + 7).TrimEnd("]"c)
    For Each part As String In stateData.Split(","c)
        Dim num As Integer
        If Integer.TryParse(part.Trim(), num) Then
            lastVisibleCallers.Add(num)
        End If
    Next
    ' Optional: strip out the tag from visible display message
    lastStateRaw = lastStateRaw.Substring(0, stateTagIndex).Trim()
End If

' GET MIX 1 ACTIVE INPUT
Dim mix1InputNumNode As Xml.XmlNode = doc.SelectSingleNode("//active")
Dim mix1InputNum As String = If(mix1InputNumNode IsNot Nothing, mix1InputNumNode.InnerText, "")
If mix1InputNum = "" Then
    API.Function("SetText", Input:=titleInput, SelectedName:=titleField, Value:="Mix 1 not found")
    Return
End If

Dim mix1Input As Xml.XmlNode = doc.SelectSingleNode("//input[@number='" & mix1InputNum & "']")
If mix1Input Is Nothing Then
    API.Function("SetText", Input:=titleInput, SelectedName:=titleField, Value:="Mix 1 input not found")
    Return
End If

' SCAN FOR CALLERS (including nested layers)
Dim visibleCallers As New System.Collections.Generic.List(Of Integer)
Dim inputStack As New System.Collections.Generic.Stack(Of Xml.XmlNode)
Dim visitedKeys As New System.Collections.Generic.List(Of String)

inputStack.Push(mix1Input)

Do While inputStack.Count > 0
    Dim currentInput As Xml.XmlNode = inputStack.Pop()
    If currentInput.Attributes("key") Is Nothing Then Continue Do

    Dim key As String = currentInput.Attributes("key").Value
    If visitedKeys.Contains(key) Then Continue Do
    visitedKeys.Add(key)

    Dim numAttr = currentInput.Attributes("number")
    If numAttr IsNot Nothing Then
        Dim num As Integer = Integer.Parse(numAttr.Value)
        If Array.IndexOf(callerInputs, num) >= 0 AndAlso Not visibleCallers.Contains(num) Then
            visibleCallers.Add(num)
        End If
    End If

    For Each overlay As Xml.XmlNode In currentInput.SelectNodes("overlay")
        Dim layerKey As String = If(overlay.Attributes("key") IsNot Nothing, overlay.Attributes("key").Value, overlay.InnerText)
        If layerKey <> "" AndAlso Not visitedKeys.Contains(layerKey) Then
            Dim layeredInput As Xml.XmlNode = doc.SelectSingleNode("//input[@key='" & layerKey & "']")
            If layeredInput IsNot Nothing Then inputStack.Push(layeredInput)
        End If
    Next
Loop

' TRIGGER SCRIPTS
For i As Integer = 0 To callerInputs.Length - 1
    Dim num As Integer = callerInputs(i)
    Dim nowVisible As Boolean = visibleCallers.Contains(num)
    Dim wasVisible As Boolean = lastVisibleCallers.Contains(num)

    If nowVisible And Not wasVisible Then
        API.Function("ScriptStart", Value:=callerScriptsLive(i))
    ElseIf Not nowVisible And wasVisible Then
        API.Function("ScriptStart", Value:=callerScriptsGone(i))
    End If
Next

' BUILD NEW DISPLAY MESSAGE
Dim displayText As String = If(visibleCallers.Count > 0, "Callers: " & String.Join(", ", visibleCallers), "No callers live")
Dim stateTag As String = "[state:" & String.Join(",", visibleCallers) & "]"
API.Function("SetText", Input:=titleInput, SelectedName:=titleField, Value:=displayText & " " & stateTag)


Users browsing this topic
Guest (2)
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.