Skip to content

Instantly share code, notes, and snippets.

@imorrish
Created December 29, 2018 18:25
Show Gist options
  • Save imorrish/60968e122b90444971623886f996eb59 to your computer and use it in GitHub Desktop.
Save imorrish/60968e122b90444971623886f996eb59 to your computer and use it in GitHub Desktop.
Animate Blackmagic ATEM Supersource box layouts using Windows PowerShell
# 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