Skip to content

Instantly share code, notes, and snippets.

@Jamie0
Last active January 3, 2018 16:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Jamie0/7fbe9c0b117ac954ca743c716490998c to your computer and use it in GitHub Desktop.
Save Jamie0/7fbe9c0b117ac954ca743c716490998c to your computer and use it in GitHub Desktop.
SEE https://github.com/InsanityRadio/automix ; Automatic Vision Mixer. Licensed under CC-BY-NC - contact me for commercial opportunities.
#!/bin/env ruby
require 'rjoystick'
require 'atem'
require 'mysql2'
$AUDIO_THRESHOLD = 858803 * 2
$IP = "10.0.0.1"
$JOYSTICK = "/dev/input/js0"
# CREATE TABLE link_history (`id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT, `start_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `end_date` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00');
$DATABASE = Mysql2::Client.new(:host => '10.0.0.0', :username => 'root', :password => 'toor', :databae => 'mic', :reconnect => true)
class Inputs
def initialize mapping, mixer
@mapping = mapping
@mixer = mixer
@k = Rjoystick::Device.new($JOYSTICK)
Thread.new do
loop do
begin
e = @k.event
handle_event e
rescue
STDERR.puts "Error in Joystick thread"
STDERR.p $!
@k.close rescue nil
@k = Rjoystick::Device.new($JOYSTICK)
end
end
end
end
def handle_event e
return unless e.type == Rjoystick::Event::JSBUTTON
return unless @mapping[e.number] != nil
e.value == 1 ? @mixer.enable(@mapping[e.number]) : @mixer.disable(@mapping[e.number])
end
end
class VisionMixer
attr_accessor :close, :wide
def initialize ip, close, wide, slate
@ip = ip
@close = close
@wide = wide
@break = true
@current_camera = wide[0]
connect!
@close.map! { | w | @atem.inputs[w] }
@wide.map! { | w | @atem.inputs[w] }
@slate = @atem.inputs[slate]
end
def loop!
sleep 0
loop do
select_camera
sleep 0
# Make the camera live then start immediately gathering data again
live_camera
reset_peaks
sleep 2
end
end
def connect!
@atem = ATEM.connect(@ip)
@atem.use_audio_levels = true
@atem.inputs[@current_camera].program
end
def enable camera
debug "Enabling #{camera}"
camera = @atem.inputs[camera]
@close << camera unless @close.include? camera
reload
end
def reload
old_break = @break
@break = @close.length == 0
return unless old_break != @break
# Store it in the database - if there's now a break, end the current link. Otherwise, open one.
begin
if @break
$DATABASE.query "UPDATE link_history SET end_date = CURRENT_TIMESTAMP() WHERE end_date = 0;"
else
$DATABASE.query "INSERT INTO link_history (start_date, end_date) VALUES (CURRENT_TIMESTAMP(), 0);"
end
rescue
STDERR.puts "SQL Update failed!"
STDERR.send :p, $!
end
select_camera and live_camera
end
def disable camera
debug "Disabling #{camera}"
camera = @atem.inputs[camera]
@close.delete camera
reload
end
def select_camera
begin
@new_camera = (@wide + @close).sample
if @break
@new_camera = @slate
raise "Done"
end
if @wide.include? @current_camera
if Random.rand(3) == 0
@new_camera = @wide.sample
raise "Done"
end
highest = [nil, $AUDIO_THRESHOLD]
p @close.length
@close.each do | cam |
maxim = [cam.audio.levels[:left_peak], cam.audio.levels[:right_peak]].max
highest = [cam, maxim] if maxim > highest[1]
end
if highest[0] != nil
p highest
@new_camera = highest[0]
raise "Done"
end
end
if @close.include? @current_camera
if Random.rand(3) == 0
@new_camera = @wide.sample
raise "Done"
end
@new_camera = @close.sample
raise "Done"
end
@new_camera = @wide.sample
rescue
p $!
p $?
end
debug "Selected camera #{@new_camera.name}"
@new_camera.preview unless @current_camera == @new_camera
end
def live_camera
debug "#{@new_camera.name} is live"
@new_camera.program unless @current_camera == @new_camera
@current_camera = @new_camera
end
def reset_peaks
@atem.reset_audio_peaks
end
private
def info message
puts "[ INFO ] #{message}"
end
def debug message
puts "[ DEBUG ] #{message}" if $debug
end
end
$debug = true
# v = VisionMixer.new $IP, ['Pres', 'Gst'], ['Wide'], 'MP1'
v = VisionMixer.new $IP, [], ['Wide'], 'MP1'
Inputs.new ['Pres', 'Gst', 'Gst'], v
v.loop!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment