Created
December 29, 2018 18:25
-
-
Save imorrish/60968e122b90444971623886f996eb59 to your computer and use it in GitHub Desktop.
Animate Blackmagic ATEM Supersource box layouts using Windows PowerShell
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# See https://ianmorrish.wordpress.com for more info and prerequisites | |
# Tranlated from LUA code provided by Doug Johnson https://djp.li/supersource | |
function ConnectToATEM() | |
{ | |
Try{ | |
$ATEMipAddress = (Get-ItemProperty -path 'HKCU:\Software\Blackmagic Design\ATEM Software Control').ipAddress | |
$DocumentsPath = [Environment]::GetFolderPath("MyDocuments") + '\windowspowershell\SwitcherLib.dll' | |
add-type -path $DocumentsPath #'SwitcherLib.dll' | |
$Global:atem = New-Object SwitcherLib.Switcher($ATEMipAddress) | |
$atem.Connect() | |
} | |
catch{ | |
write-host "Can't connect to ATEM on $($ATEMipAddrss)." | |
Write-Host "ATEM controle software must be installed and have connected to switcher at least one time" | |
exit | |
} | |
} | |
ConnectToATEM | |
$MEs = $atem.GetMEs() | |
$me1 = $MEs[0] | |
$Global:curpvw = $me1.preview | |
$SSBoxes=$Atem.GetSuperSourceBox() | |
$Global:boxcount = $SSBoxes.Capacity | |
$Global:delay = 10 | |
$Global:easefactor = 1.5; | |
function SaveSuperSourceData(){ | |
for ($i=0;$i -lt $Global:boxcount; $i++){ | |
$Global:size[0,$i] = $SSBoxes[$i].Size | |
$Global:size[1,$i] = $SSBoxes[$i].Size | |
$Global:xpos[0,$i] = $SSBoxes[$i].PositionX | |
$Global:xpos[1,$i] = $SSBoxes[$i].PositionX | |
$Global:ypos[0,$i] = $SSBoxes[$i].PositionY | |
$Global:ypos[1,$i] = $SSBoxes[$i].Positiony | |
$Global:cropl[0,$i] = $SSBoxes[$i].CropLeft | |
$Global:cropl[1,$i] = $SSBoxes[$i].CropLeft | |
$Global:cropt[0,$i] = $SSBoxes[$i].CropTop | |
$Global:cropt[1,$i] = $SSBoxes[$i].CropTop | |
$Global:cropr[0,$i] = $SSBoxes[$i].CropRight | |
$Global:cropr[1,$i] = $SSBoxes[$i].CropRight | |
$Global:cropb[0,$i] = $SSBoxes[$i].CropBottom | |
$Global:cropb[1,$i] = $SSBoxes[$i].CropBottom | |
$Global:cropped[0,$i] = $SSBoxes[$i].Cropped | |
$Global:cropped[1,$i] = $SSBoxes[$i].Cropped | |
$Global:enabled[0,$i] = $SSBoxes[$i].enabled | |
$Global:enabled[1,$i] = $SSBoxes[$i].enabled | |
} | |
} | |
function printdata(){ | |
for ($i=0; $i -lt $Global:boxcount;$i++){ | |
Write-Host "Box:$($i) Size:$($Global:size[1,$i]) Pos:$($Global:xpos[1,$i]) $($Global:ypos[1,$i]) Enabled:$($Global:enabled[1,$i])" | |
} | |
} | |
function InitSuperSourceArrays(){ | |
#-- startpos = 0, endpos = 1 | |
$Global:xpos=New-Object 'double[,]' 2,4 | |
$Global:ypos=New-Object 'double[,]' 2,4 | |
$Global:size=New-Object 'double[,]' 2,4 | |
$Global:cropl=New-Object 'double[,]' 2,4 | |
$Global:cropr=New-Object 'double[,]' 2,4 | |
$Global:cropt=New-Object 'double[,]' 2,4 | |
$Global:cropb=New-Object 'double[,]' 2,4 | |
$Global:cropped=New-Object 'bool[,]' 2,4 | |
$Global:enabled=New-Object 'bool[,]' 2,4 | |
SaveSuperSourceData | |
} | |
function SetSuperSourceLayout($layout){ | |
for ($i=0;$i -lt 4;$i++){ | |
$Global:enabled[1,$i] = $false; | |
} | |
switch($layout){ | |
0{ | |
$Global:layoutname = "Two side-by-side" | |
$Global:numbox = 2; | |
$sz = 0.80; | |
$xp = 7.2; | |
$yp = 0.0; | |
$hc = 7.5; | |
$vc = 0; | |
SetBox 0 $sz -$xp $yp $hc $hc $vc $vc | |
SetBox 1 $sz $xp $yp $hc $hc $vc $vc | |
} | |
1{ | |
$Global:layoutname = "Tiny 1 + 2"; | |
$Global:numbox = 2; | |
SetBox 1 0.80 2 -1 0 0 0 0 | |
SetBox 0 0.30 -10 5 0 0 0 0 | |
} | |
2{ | |
$Global:layoutname = "Small 1 + 2"; | |
$Global:numbox = 2; | |
$Global:boxno = 2; | |
SetBox 1 0.80 1.6 0 0 0 0 0 | |
SetBox 0 0.60 -10.4 0 10 10 0 0 | |
} | |
3{ | |
$Global:layoutname = "Half & Half"; | |
$Global:numbox = 2; | |
SetBox 0 1.0 -8 0 8 7.95 0 0 | |
SetBox 1 1.0 8 0 8 8 0 0 | |
} | |
4{ | |
$Global:layoutname = "1 2 3"; | |
$Global:numbox = 3; | |
SetBox 0 0.8 -9.25 0 10.5 10.5 0 0 | |
SetBox 1 0.8 0, 0 10.5 10.5 0 0 | |
SetBox 2 0.80 9.25 0 10.5 10.5 0 0 | |
} | |
5{ | |
$Global:layoutname = "1 + 2/3"; | |
$Global:numbox = 3; | |
SetBox 0 0.80 -7 0 7 7 0 0 | |
SetBox 1 0.40 7.5 3.7 0 0 0.15 0.15 | |
SetBox 2 0.40 7.5 -3.7 0 0 0.15 0.15 | |
} | |
6{ | |
$Global:layoutname = "2/3 + 1"; | |
$Global:numbox = 3; | |
SetBox 0 0.80 7 0 7 7 0 0 | |
SetBox 1 0.40 -7.5 3.7 0 0 0.15 0.15 | |
SetBox 2 0.40 -7.5 -3.7 0 0 0.15 0.15 | |
} | |
7{ | |
$Global:layoutname = "1 2 3 4"; | |
$Global:numbox = 4; | |
$Global:boxno = 1; | |
$sz = 0.80; | |
$x1 = 10.75; | |
$x2 = 3.6; | |
$hc = 11.75; | |
$vc = 0; | |
SetBox 0 $sz -$x1 0 $hc $hc $vc $vc | |
SetBox 1 $sz -$x2 0 $hc $hc $vc $vc | |
SetBox 2 $sz $x2 0 $hc $hc $vc $vc | |
SetBox 3 $sz $x1 0 $hc $hc $vc $vc | |
} | |
8{ | |
$Global:layoutname = "1/2 + 3/4"; | |
$Global:numbox = 4; | |
$Global:boxno = 1; | |
$sz = 0.42; | |
$xp = 7.2; | |
$yp = 4.2; | |
$hc = 0.0; | |
$vc = 0.0; | |
SetBox 0 $sz -$xp $yp $hc $hc $vc $vc | |
SetBox 1 $sz -$xp -$yp $hc $hc $vc $vc | |
SetBox 2 $sz $xp $yp $hc $hc $vc $vc | |
SetBox 3 $sz $xp -$yp $hc $hc $vc $vc | |
} | |
10{ | |
$Global:layoutname = "1 Full"; | |
$Global:numbox = 1; | |
SetBox 0 1.0 0 0 0 0 0 0 | |
} | |
11{ | |
$Global:layoutname = "1 Full"; | |
$Global:numbox = 1; | |
SetBox 1 1.0 0 0 0 0 0 0 | |
} | |
12{ | |
$Global:layoutname = "1 Full"; | |
$Global:numbox = 1; | |
SetBox 2 1.0 0 0 0 0 0 0 | |
} | |
13{ | |
$Global:layoutname = "1 Full"; | |
$Global:numbox = 1; | |
SetBox 3 1.0 0 0 0 0 0 0 | |
} | |
14{ | |
$Global:layoutname = "All off screen"; | |
$Global:numbox = 0; | |
SetBox 0 1.0 -40 18 0 0 0 0 | |
SetBox 1 1.0 -40 -18 0 0 0 0 | |
SetBox 2 1.0 40 18 0 0 0 0 | |
SetBox 3 1.0 40 -18 0 0 0 0 | |
} | |
default{ | |
$Global:layoutname = "1 Full"; | |
$Global:numbox = 1; | |
SetBox 1 1.0 0 0 0 0 0 0 | |
} | |
} | |
} | |
# Set box destination values | |
function SetBox([int]$box, [double]$sz, [double]$xp, [double]$yp, [double]$cl, [double]$cr, [double]$ct, [double]$cb){ | |
#$box=$bn.value | |
$Global:enabled[1,$box] = $true | |
$Global:cropped[1,$box] = $true | |
$Global:size[1,$box] = $sz | |
$Global:xpos[1,$box] = $xp | |
$Global:ypos[1,$box] = $yp | |
$Global:cropl[1,$box] = $cl | |
$Global:cropr[1,$box] = $cr | |
$Global:cropt[1,$box] = $ct | |
$Global:cropb[1,$box] = $cb | |
} | |
# SSource annimation | |
function DoSuperSourceTransition($steps, $delay){ | |
$easefactor = 1.5 | |
for ($i=0; $i -lt $Global:boxcount;$i++){ | |
#write-host "Moving box $($i)" | |
if (($Global:enabled[0,$i] -eq $false) -AND $Global:enabled[1,$i] -eq $true){ | |
#write-host "1. Enabled" | |
if ($Global:xpos[1,$i] -lt -7){ | |
$Global:xpos[0,$i] = -40; | |
$Global:ypos[0,$i] = $Global:ypos[1,$i]; | |
} | |
elseif ($Global:xpos[1,$i] -lt -2){ | |
if ($Global:ypos[1,$i] -lt -5){ | |
$Global:xpos[0,$i] = $Global:xpos[1,$i]; | |
$Global:ypos[0,$i] = -18; | |
} | |
elseif ($ypos[1,$i] -gt 5){ | |
$Global:xpos[0,$i] = $Global:xpos[1,$i]; | |
$Global:ypos[0,$i] = 18; | |
} | |
else{ | |
$Global:xpos[0,$i] = -40; | |
$Global:ypos[0,$i] = $Global:ypos[1,$i]; | |
} | |
} | |
elseif ($Global:xpos[1,$i] -gt 7){ | |
$Global:xpos[0,$i] = 40; | |
$Global:ypos[0,$i] = $Global:ypos[1,$i]; | |
} | |
elseif ($Global:xpos[1,$i] -gt 2){ | |
if ($Global:ypos[1][$i] -lt -5){ | |
$Global:xpos[0,$i] = $Global:xpos[1,$i]; | |
$Global:ypos[0,$i] = -18; | |
} | |
elseif ($Global:ypos[1,$i] -gt 5){ | |
$Global:xpos[0,$i] = $Global:xpos[1,$i]; | |
$Global:ypos[0,$i] = 18; | |
} | |
else{ | |
$Global:xpos[0,$i] = 40; | |
$Global:ypos[0,$i] = $Global:ypos[1,$i] | |
} | |
} | |
else{ | |
#write-host "2 - not enabled" | |
if ($Global:ypos[1,$i] -lt 0){ | |
$Global:xpos[0,$i] = $Global:xpos[1,$i]; | |
$Global:ypos[0,$i] = -18; | |
} | |
else{ | |
$Global:xpos[0,$i] = $Global:xpos[1,$i]; | |
$Global:ypos[0,$i] = 18; | |
} | |
} | |
} | |
if ($Global:enabled[0,$i] -eq $true -AND ($Global:enabled[1,$i] -eq $false)){ | |
#write-host "2 - not enabled" | |
if ($Global:xpos[0,$i] -lt -7){ | |
$Global:xpos[1,$i] = -40; | |
$Global:ypos[1,$i] = $Global:ypos[0,$i]; | |
} | |
elseif ($Global:xpos[0,$i] -lt -2){ | |
if ($Global:ypos[0,$i] -lt -5){ | |
$Global:xpos[1,$i] = $Global:xpos[0,$i]; | |
$Global:ypos[1,$i] = -18; | |
} | |
elseif ($Global:ypos[1,$i] -gt 5){ | |
$Global:xpos[1,$i] = $Global:xpos[0,$i]; | |
$Global:ypos[1,$i] = 16; | |
} | |
else{ | |
$Global:xpos[1,$i] = -40; | |
$Global:ypos[1,$i] = $Global:ypos[0,$i]; | |
} | |
} | |
elseif ($Global:xpos[0,$i] -gt 7){ | |
$Global:xpos[1,$i] = 40; | |
$Global:ypos[1,$i] = $Global:ypos[0,$i]; | |
} | |
elseif ($Global:xpos[0,$i] -gt 2){ | |
if ($Global:ypos[0,$i] -lt -5){ | |
$Global:xpos[1,$i] = $Global:xpos[0,$i]; | |
$Global:ypos[1,$i] = -18; | |
} | |
elseif ($ypos[1,$i] -gt 5){ | |
$Global:xpos[1,$i] = $Global:xpos[0,$i]; | |
$Global:ypos[1,$i] = 18; | |
} | |
else{ | |
$Global:xpos[1,$i] = 40; | |
$Global:ypos[1,$i] = $Global:ypos[0,$i]; | |
} | |
} | |
else{ | |
if ($Global:ypos[0,$i] -lt 0) { | |
$Global:xpos[1,$i] = $Global:xpos[0,$i]; # changed from 1 to 0 | |
$Global:ypos[1,$i] = -18; | |
} | |
else{ | |
$Global:xpos[1,$i] = $Global:xpos[0,$i]; | |
$Global:ypos[1,$i] = 18; | |
} | |
} | |
} | |
if($Global:enabled[1,$i] -eq $true -OR $Global:enabled[0,$i] -eq $True){$en=$true}else{$en=$false} #check last value, may need to be true | |
#write-host "Updating box $($i) to off screen position to $($Global:xpos[0,$i]) $($Global:ypos[0,$i])" | |
$SSBoxes[$i].PositionX = $Global:xpos[0,$i] | |
$SSBoxes[$i].PositionY = $Global:ypos[0,$i] | |
$SSBoxes[$i].Enabled = $en | |
} | |
for ($j=1; $j -le $steps;$j++){ | |
#write-host "Step $($j)" | |
$newpos = $j/$steps | |
if ($newpos -le 0.5){ | |
$newpos = (^ $newpos $easefactor) / (^ 0.5 $easefactor) * 0.5 | |
} | |
else{ | |
$newpos = 1 - ((^(1-$newpos) $easefactor) / (^ 0.5 $easefactor)) * 0.5 | |
} | |
for ($i=0; $i -lt $Global:boxcount;$i++){ | |
$SSBoxes[$i].Size = ScaleNum $Global:size[0,$i] $Global:size[1,$i] $newpos | |
$SSBoxes[$i].PositionX = ScaleNum $Global:xpos[0,$i] $Global:xpos[1,$i] $newpos | |
$SSBoxes[$i].PositionY = ScaleNum $Global:ypos[0,$i] $Global:ypos[1,$i] $newpos | |
$SSBoxes[$i].CropLeft = ScaleNum $Global:cropl[0,$i] $Global:cropl[1,$i] $newpos | |
$SSBoxes[$i].CropRight = ScaleNum $Global:cropr[0,$i] $Global:cropr[1,$i] $newpos | |
$SSBoxes[$i].CropTop = ScaleNum $Global:cropt[0,$i] $Global:cropt[1,$i] $newpos | |
$SSBoxes[$i].CropBottom = ScaleNum $Global:cropb[0,$i] $Global:cropb[1,$i] $newpos | |
$SSBoxes[$i].Cropped = $true | |
#write-host "Updating box $($i) position to $(ScaleNum $Global:xpos[0,$i] $Global:xpos[1,$i] $newpos) $(ScaleNum $Global:ypos[0,$i] $Global:ypos[1,$i] $newpos) size to $(ScaleNum $Global:size[0,$i] $Global:size[1,$i] $newpos)" | |
} | |
start-sleep -m $delay | |
#write-host $newpos | |
} | |
for ($x=0; $x -lt $Global:boxcount; $x++){ | |
if( $Global:enabled[1,$x] = $true){ | |
$SSBoxes[$x].Enabled = 1 | |
} | |
Else{ | |
$SSBoxes[$x].Enabled = 0 | |
} | |
} | |
} | |
function power ($num1, $num2) { [Math]::Pow($num1, $num2) } | |
set-alias ^ power | |
function ScaleNum($val1, $val2, $scale){ | |
$result = (($val2-$val1) *$scale) + $val1 | |
return $result; | |
} | |
# Call this from a macro or button command, spcify the layout number you want | |
function selectlayout($layoutno){ | |
SaveSuperSourceData #save current box positions | |
SetSuperSourceLayout $layoutno | |
DoSuperSourceTransition 100 1 | |
} | |
# Initialize one time | |
InitSuperSourceArrays | |
#Example use | |
# selectlayout 8 | |
# start-sleep 5 | |
# selectlayout 14 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment