2018-10-20 15:55:24 -04:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
2018-10-20 19:06:35 -04:00
|
|
|
"""OscCommentMacroListener.py: Hog 4 comment macro antlr4 listener for OSC."""
|
|
|
|
|
|
|
|
__author__ = "Kevin Matz"
|
|
|
|
__copyright__ = "Copyright 2018, Company 235, LLC"
|
|
|
|
__credits__ = ["Kevin Matz"]
|
|
|
|
|
|
|
|
__license__ = "MIT"
|
2018-10-21 14:22:02 -04:00
|
|
|
__version__ = "3.9"
|
2018-10-20 19:06:35 -04:00
|
|
|
__maintainer__ = "Kevin Matz"
|
|
|
|
__email__ = "kevin@company235.com"
|
|
|
|
|
|
|
|
__status__ = "Prototype"
|
|
|
|
|
|
|
|
|
2018-10-21 14:14:56 -04:00
|
|
|
import logging
|
2018-10-26 16:21:48 -04:00
|
|
|
from pythonosc import osc_message_builder
|
|
|
|
from time import sleep
|
2018-10-20 15:55:24 -04:00
|
|
|
|
2019-11-17 13:27:08 -05:00
|
|
|
try:
|
|
|
|
# include reletive path imports when a module
|
|
|
|
from .CommentMacroParser import CommentMacroParser
|
|
|
|
from .CommentMacroListener import CommentMacroListener
|
|
|
|
except ImportError:
|
|
|
|
# include directly when called directly
|
|
|
|
from CommentMacroParser import CommentMacroParser
|
|
|
|
from CommentMacroListener import CommentMacroListener
|
|
|
|
|
2018-10-28 18:27:25 -04:00
|
|
|
logger = logging.getLogger('__main__')
|
2018-10-21 14:14:56 -04:00
|
|
|
|
2018-10-20 15:55:24 -04:00
|
|
|
|
|
|
|
# https://raw.githubusercontent.com/jszheng/py3antlr4book/master/bin/pygrun
|
|
|
|
# this is a python version of TestRig
|
|
|
|
def beautify_lisp_string(in_string):
|
|
|
|
__author__ = 'jszheng'
|
|
|
|
indent_size = 2
|
|
|
|
add_indent = ' ' * indent_size
|
|
|
|
out_string = in_string[0] # no indent for 1st (
|
|
|
|
indent = ''
|
|
|
|
for i in range(1, len(in_string) - 1):
|
|
|
|
if in_string[i] == '(' and in_string[i + 1] != ' ':
|
|
|
|
indent += add_indent
|
|
|
|
out_string += "\n" + indent + '('
|
|
|
|
elif in_string[i] == ')':
|
|
|
|
out_string += ')'
|
|
|
|
if len(indent) > 0:
|
|
|
|
indent = indent.replace(add_indent, '', 1)
|
|
|
|
else:
|
|
|
|
out_string += in_string[i]
|
|
|
|
return out_string
|
|
|
|
|
|
|
|
|
2018-10-26 16:19:04 -04:00
|
|
|
class HogDevice():
|
|
|
|
# button state constants
|
|
|
|
buttonDOWN = 1
|
|
|
|
buttonUP = 0
|
|
|
|
|
|
|
|
def __init__(self, servers):
|
|
|
|
self.servers = servers
|
|
|
|
|
|
|
|
def button_press(self, device, path, delay=0.05):
|
|
|
|
self.send_message(device, path, HogDevice.buttonDOWN) # button down
|
|
|
|
sleep(delay)
|
|
|
|
self.send_message(device, path, HogDevice.buttonUP) # button up
|
|
|
|
|
|
|
|
# utility function to send simple messages with one argument
|
|
|
|
def send_message(self, device, path, arg):
|
|
|
|
msg = osc_message_builder.OscMessageBuilder(address=path)
|
|
|
|
msg.add_arg(arg)
|
|
|
|
self.send(device, msg.build())
|
|
|
|
|
|
|
|
# send python-osc messages
|
|
|
|
def send(self, device, msg):
|
|
|
|
if device is None:
|
2018-10-28 10:02:51 -04:00
|
|
|
osc = list(self.servers.values())[0] # first configured server
|
2018-10-26 16:19:04 -04:00
|
|
|
else:
|
2018-10-28 10:02:51 -04:00
|
|
|
if (device.nodeType().getText().lower() != 'h'):
|
2018-10-26 16:19:04 -04:00
|
|
|
logger.error("ERROR: Only Hog type devices are supported.")
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
try:
|
2018-10-28 10:02:51 -04:00
|
|
|
osc = self.servers[device.number().value]
|
2018-10-26 16:19:04 -04:00
|
|
|
except KeyError:
|
2018-10-28 10:02:51 -04:00
|
|
|
logger.error("ERROR: Net# " + str(device.number().value) +
|
2018-10-26 16:19:04 -04:00
|
|
|
" not found.")
|
|
|
|
return
|
|
|
|
try:
|
|
|
|
osc.send(msg)
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(e)
|
|
|
|
|
|
|
|
|
2018-10-20 15:55:24 -04:00
|
|
|
class OscCommentMacroListener(CommentMacroListener):
|
2018-10-21 15:52:14 -04:00
|
|
|
def __init__(self, servers):
|
2018-10-26 16:21:48 -04:00
|
|
|
self.osc = HogDevice(servers)
|
2018-10-21 00:30:21 -04:00
|
|
|
|
2018-10-28 17:27:05 -04:00
|
|
|
def exitWait(self, ctx: CommentMacroParser.WaitContext):
|
2018-10-28 17:35:16 -04:00
|
|
|
logger.info("Waiting " + str(ctx.number().value) + " seconds.")
|
2018-10-28 17:27:05 -04:00
|
|
|
sleep(ctx.number().value)
|
|
|
|
|
2018-10-26 16:19:04 -04:00
|
|
|
def enterStatement(self, ctx: CommentMacroParser.StatementContext):
|
2018-10-20 23:38:11 -04:00
|
|
|
# print the lisp tree of this macro
|
2018-10-21 15:52:14 -04:00
|
|
|
lisp_tree_str = ctx.toStringTree(recog=ctx.parser)
|
2018-10-28 17:07:20 -04:00
|
|
|
logger.debug(beautify_lisp_string(lisp_tree_str))
|
2018-10-20 15:55:24 -04:00
|
|
|
|
2018-10-25 12:52:22 -04:00
|
|
|
def enterTarget(self, ctx: CommentMacroParser.TargetContext):
|
|
|
|
ctx.targets = []
|
|
|
|
|
|
|
|
def exitTarget(self, ctx: CommentMacroParser.TargetContext):
|
2018-10-26 16:19:04 -04:00
|
|
|
ctx.targets = set(ctx.targets)
|
2018-10-26 15:26:18 -04:00
|
|
|
if isinstance(ctx.parentCtx, CommentMacroParser.TargetContext):
|
|
|
|
ctx.parentCtx.targets.extend(ctx.targets) # add to parent targets
|
2018-10-25 12:52:22 -04:00
|
|
|
|
2018-10-20 18:01:29 -04:00
|
|
|
def exitNumber(self, ctx: CommentMacroParser.NumberContext):
|
2018-10-25 16:26:15 -04:00
|
|
|
try:
|
|
|
|
ctx.value = int(ctx.getText())
|
|
|
|
except ValueError:
|
|
|
|
ctx.value = float(ctx.getText())
|
2018-10-20 18:01:29 -04:00
|
|
|
if isinstance(ctx.parentCtx, CommentMacroParser.TargetContext):
|
2018-10-20 18:10:21 -04:00
|
|
|
ctx.parentCtx.targets.append(ctx.value)
|
2018-10-20 18:01:29 -04:00
|
|
|
|
|
|
|
def exitSpan(self, ctx: CommentMacroParser.SpanContext):
|
2018-10-29 23:19:18 -04:00
|
|
|
lower = min(ctx.n1.value, ctx.n2.value)
|
|
|
|
upper = max(ctx.n1.value, ctx.n2.value)
|
|
|
|
while lower <= upper:
|
|
|
|
ctx.parentCtx.targets.append(lower)
|
|
|
|
lower += 1
|
2018-10-26 16:19:04 -04:00
|
|
|
|
|
|
|
def exitMasterGo(self, ctx: CommentMacroParser.MasterGoContext):
|
2018-10-28 10:02:51 -04:00
|
|
|
if ctx.target() is None:
|
2018-10-26 16:19:04 -04:00
|
|
|
logger.info("Main GO")
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.button_press(ctx.device(), "/hog/hardware/maingo")
|
2018-10-26 16:19:04 -04:00
|
|
|
return
|
2018-10-28 10:02:51 -04:00
|
|
|
for i in ctx.target().targets:
|
2018-10-26 16:19:04 -04:00
|
|
|
if isinstance(i, int) is not True:
|
|
|
|
logger.warn("GO MASTER macro targets must be intigers. "
|
|
|
|
+ str(i) + " is not an intigers.")
|
|
|
|
continue
|
|
|
|
if (i < 0):
|
|
|
|
logger.warn("Master "+str(i)+" is not greater than 0.")
|
|
|
|
continue
|
|
|
|
master = str(i)
|
|
|
|
logger.info("GO on master " + master)
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.button_press(ctx.device(), "/hog/hardware/go/" + master)
|
2018-10-26 16:19:04 -04:00
|
|
|
|
|
|
|
def exitMasterHalt(self, ctx: CommentMacroParser.MasterHaltContext):
|
2018-10-28 10:02:51 -04:00
|
|
|
if ctx.target() is None:
|
2018-10-26 16:19:04 -04:00
|
|
|
logger.info("Main HALT")
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.button_press(ctx.device(), "/hog/hardware/mainhalt")
|
2018-10-26 16:19:04 -04:00
|
|
|
return
|
2018-10-28 10:02:51 -04:00
|
|
|
for i in ctx.target().targets:
|
2018-10-26 16:19:04 -04:00
|
|
|
if isinstance(i, int) is not True:
|
|
|
|
logger.warn("GO MASTER macro targets must be intigers. "
|
|
|
|
+ str(i) + " is not an intigers.")
|
|
|
|
continue
|
|
|
|
if (i < 0):
|
|
|
|
logger.warn("Master "+str(i)+" is not greater than 0.")
|
|
|
|
continue
|
|
|
|
master = str(i)
|
|
|
|
logger.info("HALT on master " + master)
|
2018-10-28 18:20:00 -04:00
|
|
|
self.osc.button_press(ctx.device(), "/hog/hardware/pause/"+master)
|
2018-10-26 16:19:04 -04:00
|
|
|
|
|
|
|
def exitMasterAssert(self, ctx: CommentMacroParser.MasterAssertContext):
|
2018-10-28 18:20:00 -04:00
|
|
|
if ctx.target()is not None:
|
2018-10-26 16:19:04 -04:00
|
|
|
logger.error("ERROR: limited to asserting current master only.")
|
|
|
|
return
|
|
|
|
logger.info("ASSERT on current master.")
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.button_press(ctx.device(), "/hog/hardware/assert")
|
2018-10-26 16:19:04 -04:00
|
|
|
|
|
|
|
def exitMasterRelease(self, ctx: CommentMacroParser.MasterReleaseContext):
|
2018-10-28 16:58:01 -04:00
|
|
|
if ctx.target() is not None:
|
2018-10-26 16:19:04 -04:00
|
|
|
logger.error("ERROR: limited to releasing current master only.")
|
|
|
|
return
|
|
|
|
logger.info("RELEASE on current master.")
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.button_press(ctx.device(), "/hog/hardware/release")
|
2018-10-26 16:19:04 -04:00
|
|
|
|
|
|
|
def exitMasterFade(self, ctx: CommentMacroParser.MasterFadeContext):
|
2018-10-28 10:02:51 -04:00
|
|
|
if ctx.target()is None:
|
2018-10-28 16:59:21 -04:00
|
|
|
logger.error("ERROR: limited to fading specified masters only.")
|
|
|
|
return
|
2018-10-29 01:21:19 -04:00
|
|
|
level = ctx.number().value
|
2018-10-26 16:19:04 -04:00
|
|
|
if (level < 0 or level > 100):
|
|
|
|
logger.error("Level must be between 0 and 100.")
|
|
|
|
return
|
2018-10-28 10:02:51 -04:00
|
|
|
for i in ctx.target().targets:
|
2018-10-26 16:19:04 -04:00
|
|
|
if isinstance(i, int) is not True:
|
|
|
|
logger.warn("FADE MASTER macro targets must be intigers. "
|
|
|
|
+ str(i) + " is not an intigers.")
|
|
|
|
continue
|
|
|
|
if (i < 0):
|
|
|
|
logger.warn("Master "+str(i)+" is not greater than 0.")
|
|
|
|
continue
|
|
|
|
master = str(i)
|
|
|
|
logger.info("Fade Master "+master+" to "+str(level)+"%")
|
|
|
|
level *= 255 / 100 # percent in Macro, 0>255 in OSC
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.send_message(ctx.device(),
|
2018-10-26 16:19:04 -04:00
|
|
|
"/hog/hardware/fader/" + master,
|
|
|
|
level)
|
|
|
|
|
|
|
|
def exitFadeGrandMaster(self,
|
|
|
|
ctx: CommentMacroParser.FadeGrandMasterContext):
|
2018-10-28 10:02:51 -04:00
|
|
|
level = ctx.number().value
|
2018-10-26 16:19:04 -04:00
|
|
|
if (level < 0 or level > 100):
|
|
|
|
logger.error("Level must be between 0 and 100.")
|
|
|
|
return
|
|
|
|
logger.info("Fading Grand Master to " + str(level) + "%")
|
|
|
|
level *= 255 / 100 # percent in Macro, 0>255 in OSC
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.send_message(ctx.device(), "/hog/hardware/fader/0", level)
|
2018-10-26 16:19:04 -04:00
|
|
|
|
|
|
|
def exitMasterChoose(self, ctx: CommentMacroParser.MasterChooseContext):
|
2018-10-28 10:02:51 -04:00
|
|
|
if (ctx.number().value < 0):
|
2018-10-26 16:19:04 -04:00
|
|
|
logger.error("Master must be greater than 0.")
|
|
|
|
return
|
2018-10-28 10:02:51 -04:00
|
|
|
master = str(ctx.number().value)
|
2018-10-26 16:19:04 -04:00
|
|
|
logger.info("Choose Master " + master)
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.button_press(ctx.device(), "/hog/hardware/choose/" + master)
|
2018-10-26 16:19:04 -04:00
|
|
|
|
|
|
|
def exitReleaseAll(self, ctx: CommentMacroParser.ReleaseAllContext):
|
|
|
|
logger.info("Release All")
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.send_message(ctx.device(), "/hog/hardware/pig",
|
2018-10-26 16:19:04 -04:00
|
|
|
self.osc.buttonDOWN)
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.button_press(ctx.device(), "/hog/hardware/release")
|
|
|
|
self.osc.send_message(ctx.device(), "/hog/hardware/pig",
|
2018-10-26 16:19:04 -04:00
|
|
|
self.osc.buttonUP)
|
|
|
|
|
|
|
|
def exitListGo(self, ctx: CommentMacroParser.ListGoContext):
|
2018-10-28 10:02:51 -04:00
|
|
|
for i in ctx.target().targets:
|
2018-10-26 16:29:43 -04:00
|
|
|
logger.info("Go on List " + str(i))
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.send_message(ctx.device(), "/hog/playback/go/0", i)
|
2018-10-26 16:29:43 -04:00
|
|
|
|
|
|
|
def exitListGoto(self, ctx: CommentMacroParser.ListGotoContext):
|
2018-10-28 10:02:51 -04:00
|
|
|
for i in ctx.target().targets:
|
|
|
|
list = str(i) + "." + str(ctx.number().value)
|
2018-10-26 16:19:04 -04:00
|
|
|
logger.info("Go on List " + str(list))
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.send_message(ctx.device(), "/hog/playback/go/0", list)
|
2018-10-26 16:19:04 -04:00
|
|
|
|
|
|
|
def exitListHalt(self, ctx: CommentMacroParser.ListHaltContext):
|
2018-10-28 10:02:51 -04:00
|
|
|
for i in ctx.target().targets:
|
2018-10-26 16:19:04 -04:00
|
|
|
logger.info("Halting List " + str(i))
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.send_message(ctx.device(), "/hog/playback/halt/0", i)
|
2018-10-26 16:19:04 -04:00
|
|
|
|
|
|
|
def exitListRelese(self, ctx: CommentMacroParser.ListReleseContext):
|
2018-10-28 10:02:51 -04:00
|
|
|
for i in ctx.target().targets:
|
2018-10-26 16:19:04 -04:00
|
|
|
logger.info("Releasing List " + str(i))
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.send_message(ctx.device(), "/hog/playback/release/0", i)
|
2018-10-26 16:19:04 -04:00
|
|
|
|
|
|
|
def exitSceneGo(self, ctx: CommentMacroParser.SceneGoContext):
|
2018-10-28 10:02:51 -04:00
|
|
|
for i in ctx.target().targets:
|
2018-10-26 16:19:04 -04:00
|
|
|
logger.info("Go on Scene " + str(i))
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.send_message(ctx.device(), "/hog/playback/go/1", i)
|
2018-10-26 16:19:04 -04:00
|
|
|
|
|
|
|
def exitSceneHalt(self, ctx: CommentMacroParser.SceneHaltContext):
|
2018-10-28 10:02:51 -04:00
|
|
|
for i in ctx.target().targets:
|
2018-10-26 16:19:04 -04:00
|
|
|
logger.info("Halt Scene " + str(i))
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.send_message(ctx.device(), "/hog/playback/halt/1", i)
|
2018-10-26 16:19:04 -04:00
|
|
|
|
|
|
|
def exitSceneRelease(self, ctx: CommentMacroParser.SceneReleaseContext):
|
2018-10-28 10:02:51 -04:00
|
|
|
for i in ctx.target().targets:
|
2018-10-26 16:19:04 -04:00
|
|
|
logger.info("Release Scene " + str(i))
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.send_message(ctx.device(), "/hog/playback/release/1", i)
|
2018-10-26 16:19:04 -04:00
|
|
|
|
|
|
|
def exitMacroGo(self, ctx: CommentMacroParser.MacroGoContext):
|
2018-10-28 10:02:51 -04:00
|
|
|
for i in ctx.target().targets:
|
2018-10-26 16:19:04 -04:00
|
|
|
logger.info("Go on Macro " + str(i))
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.send_message(ctx.device(), "/hog/playback/go/2", i)
|
2018-10-26 16:19:04 -04:00
|
|
|
|
|
|
|
def exitMacroHalt(self, ctx: CommentMacroParser.MacroHaltContext):
|
2018-10-28 10:02:51 -04:00
|
|
|
for i in ctx.target().targets:
|
2018-10-26 16:19:04 -04:00
|
|
|
logger.info("Pause Macro " + str(i))
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.send_message(ctx.device(), "/hog/playback/halt/2", i)
|
2018-10-26 16:19:04 -04:00
|
|
|
|
|
|
|
def exitMacroStop(self, ctx: CommentMacroParser.MacroStopContext):
|
2018-10-28 10:02:51 -04:00
|
|
|
for i in ctx.target().targets:
|
2018-10-26 16:19:04 -04:00
|
|
|
logger.info("Stop Macro " + str(i))
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.send_message(ctx.device(), "/hog/playback/release/2", i)
|
2018-10-26 16:19:04 -04:00
|
|
|
|
|
|
|
def exitPageNext(self, ctx: CommentMacroParser.PageNextContext):
|
|
|
|
logger.info("Next Page")
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.button_press(ctx.device(), "/hog/hardware/nextpage")
|
2018-10-26 16:19:04 -04:00
|
|
|
|
|
|
|
def exitPagePrev(self, ctx: CommentMacroParser.PagePrevContext):
|
|
|
|
logger.info("Prev Page")
|
2018-10-28 10:02:51 -04:00
|
|
|
self.osc.button_press(ctx.device(), "/hog/hardware/backpage")
|