refactor meta functions

add channel_bool_prop and channel_label_prop to strip/bus
self.identifier in strip bus now returning only class name

add psuedo decorators cache_bool and cache_string to util.

fix bug with cache
todo. add to cache on multi-set
This commit is contained in:
onyx-and-iris 2022-04-29 02:57:47 +01:00
parent 98c15967d1
commit 3aebd90920
6 changed files with 99 additions and 138 deletions

View File

@ -1,8 +1,7 @@
from .errors import VMCMDErrors from .errors import VMCMDErrors
from . import channel
from .channel import Channel from .channel import Channel
from . import kinds from . import kinds
from .meta import bus_mode_prop, bus_bool_prop from .meta import bus_mode_prop, channel_bool_prop, channel_label_prop
class OutputBus(Channel): class OutputBus(Channel):
@ -22,34 +21,20 @@ class OutputBus(Channel):
{ {
"levels": BusLevel(remote, index), "levels": BusLevel(remote, index),
"mode": BusModeMixin(remote, index), "mode": BusModeMixin(remote, index),
**{param: channel_bool_prop(param) for param in ["mute", "mono"]},
}, },
) )
return OB_cls(remote, index, *args, **kwargs) return OB_cls(remote, index, *args, **kwargs)
@property @property
def identifier(self): def identifier(self):
return f"Bus[{self.index}]" return "bus"
mute = bus_bool_prop("mute") eq = channel_bool_prop("eq.On")
mono = bus_bool_prop("mono") eq_ab = channel_bool_prop("eq.ab")
eq = bus_bool_prop("eq.On") label = channel_label_prop()
eq_ab = bus_bool_prop("eq.ab")
@property
def label(self) -> str:
val = self.getter("label")
if val is None:
val = self.public_packet.buslabels[self.index]
return val
@label.setter
def label(self, val: str):
if not isinstance(val, str):
raise VMCMDErrors("label is a string parameter")
self.setter("label", val)
@property @property
def gain(self) -> float: def gain(self) -> float:
@ -62,10 +47,10 @@ class OutputBus(Channel):
else: else:
return ((1 << 16) - 1) - val return ((1 << 16) - 1) - val
val = self.getter("gain") val = round(self.getter("gain"), 1)
if val is None: if val is None:
val = round((fget() * 0.01), 1) val = round((fget() * 0.01), 1)
return round(val, 1) return val
@gain.setter @gain.setter
def gain(self, val: float): def gain(self, val: float):

View File

@ -11,7 +11,7 @@ class Modes:
_mute: hex = 0x00000001 _mute: hex = 0x00000001
_solo: hex = 0x00000002 _solo: hex = 0x00000002
_mono: hex = 0x00000004 _mono: hex = 0x00000004
_mutec: hex = 0x00000008 _mc: hex = 0x00000008
_amix: hex = 0x00000010 _amix: hex = 0x00000010
_repeat: hex = 0x00000020 _repeat: hex = 0x00000020
@ -85,13 +85,13 @@ class Channel(abc.ABC):
self._modes = Modes() self._modes = Modes()
def getter(self, param): def getter(self, param):
cmd = f"{self.identifier}.{param}" cmd = f"{self.identifier}[{self.index}].{param}"
if cmd in self._remote.cache: if cmd in self._remote.cache:
return self._remote.cache.pop(f"{self.identifier}.{param}") return self._remote.cache.pop(cmd)
def setter(self, param, val): def setter(self, param, val):
"""Sends a string request RT packet.""" """Sends a string request RT packet."""
self._remote.set_rt(f"{self.identifier}", param, val) self._remote.set_rt(f"{self.identifier}[{self.index}]", param, val)
@abc.abstractmethod @abc.abstractmethod
def identifier(self): def identifier(self):

View File

@ -1,20 +1,22 @@
from .util import cache_bool, cache_string
from .errors import VMCMDErrors from .errors import VMCMDErrors
from time import sleep
from functools import partial
def strip_bool_prop(param): def channel_bool_prop(param):
"""A strip bool prop.""" """A channel bool prop. (strip|bus)"""
@partial(cache_bool, param=param)
def fget(self): def fget(self):
val = self.getter(param) return (
if val is None: not int.from_bytes(
val = ( getattr(self.public_packet, f"{self.identifier}state")[self.index],
not int.from_bytes(self.public_packet.stripstate[self.index], "little") "little",
)
& getattr(self._modes, f"_{param}") & getattr(self._modes, f"_{param}")
== 0 == 0
) )
return val
return val == 1
def fset(self, val): def fset(self, val):
if not isinstance(val, bool) and val not in (0, 1): if not isinstance(val, bool) and val not in (0, 1):
@ -24,41 +26,31 @@ def strip_bool_prop(param):
return property(fget, fset) return property(fget, fset)
def bus_bool_prop(param): def channel_label_prop():
"""A bus bool prop.""" """A channel label prop. (strip|bus)"""
def fget(self): @partial(cache_string, param="label")
val = self.getter(param) def fget(self) -> str:
if val is None: return getattr(self.public_packet, f"{self.identifier}labels")[self.index]
val = (
not int.from_bytes(self.public_packet.busstate[self.index], "little")
& getattr(self._modes, f'_{param.replace(".", "_").lower()}')
== 0
)
return val
return val == 1
def fset(self, val): def fset(self, val: str):
if not isinstance(val, bool) and val not in (0, 1): if not isinstance(val, str):
raise VMCMDErrors(f"{param} is a boolean parameter") raise VMCMDErrors("label is a string parameter")
self.setter(param, 1 if val else 0) self.setter("label", val)
return property(fget, fset) return property(fget, fset)
def strip_output_prop(param): def strip_output_prop(param):
"""A strip output prop.""" """A strip output prop. (A1-A5, B1-B3)"""
@partial(cache_bool, param=param)
def fget(self): def fget(self):
val = self.getter(param) return (
if val is None:
val = (
not int.from_bytes(self.public_packet.stripstate[self.index], "little") not int.from_bytes(self.public_packet.stripstate[self.index], "little")
& getattr(self._modes, f"_bus{param.lower()}") & getattr(self._modes, f"_bus{param.lower()}")
== 0 == 0
) )
return val
return val == 1
def fset(self, val): def fset(self, val):
if not isinstance(val, bool) and val not in (0, 1): if not isinstance(val, bool) and val not in (0, 1):
@ -71,9 +63,8 @@ def strip_output_prop(param):
def bus_mode_prop(param): def bus_mode_prop(param):
"""A bus mode prop.""" """A bus mode prop."""
@partial(cache_bool, param=f"mode.{param}")
def fget(self): def fget(self):
val = self.getter(f"mode.{param}")
if val is None:
modelist = { modelist = {
"amix": (1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1), "amix": (1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1),
"repeat": (0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2), "repeat": (0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2),
@ -92,9 +83,8 @@ def bus_mode_prop(param):
for val in self._modes.modevals for val in self._modes.modevals
) )
if param == "normal": if param == "normal":
return not any(val for val in vals) return not any(vals)
return tuple(round(val / 16) for val in vals) == modelist[param] return tuple(round(val / 16) for val in vals) == modelist[param]
return val == 1
def fset(self, val): def fset(self, val):
if not isinstance(val, bool) and val not in (0, 1): if not isinstance(val, bool) and val not in (0, 1):

View File

@ -1,8 +1,7 @@
from .errors import VMCMDErrors from .errors import VMCMDErrors
from . import channel
from .channel import Channel from .channel import Channel
from . import kinds from . import kinds
from .meta import strip_output_prop, strip_bool_prop from .meta import strip_output_prop, channel_bool_prop, channel_label_prop
class InputStrip(Channel): class InputStrip(Channel):
@ -22,19 +21,19 @@ class InputStrip(Channel):
(InputStrip, GainLayerMixin), (InputStrip, GainLayerMixin),
{ {
"levels": StripLevel(remote, index), "levels": StripLevel(remote, index),
**{
param: channel_bool_prop(param)
for param in ["mono", "solo", "mute"]
},
}, },
) )
return IS_cls(remote, index, **kwargs) return IS_cls(remote, index, **kwargs)
@property @property
def identifier(self): def identifier(self):
return f"Strip[{self.index}]" return "strip"
mono = strip_bool_prop("mono") label = channel_label_prop()
solo = strip_bool_prop("solo")
mute = strip_bool_prop("mute")
@property @property
def limit(self) -> int: def limit(self) -> int:
@ -44,25 +43,12 @@ class InputStrip(Channel):
def limit(self, val: int): def limit(self, val: int):
self.setter("limit", val) self.setter("limit", val)
@property
def label(self) -> str:
val = self.getter("label")
if val is None:
val = self.public_packet.striplabels[self.index]
return val
@label.setter
def label(self, val: str):
if not isinstance(val, str):
raise VMCMDErrors("label is a string parameter")
self.setter("label", val)
@property @property
def gain(self) -> float: def gain(self) -> float:
val = self.getter("gain") val = round(self.getter("gain"), 1)
if val is None: if val is None:
val = self.gainlayer[0].gain val = self.gainlayer[0].gain
return round(val, 1) return val
@gain.setter @gain.setter
def gain(self, val: float): def gain(self, val: float):
@ -96,23 +82,7 @@ class PhysicalInputStrip(InputStrip):
class VirtualInputStrip(InputStrip): class VirtualInputStrip(InputStrip):
@property mc = channel_bool_prop("mc")
def mc(self) -> bool:
val = self.getter("mc")
if val is None:
val = (
not int.from_bytes(self.public_packet.stripstate[self.index], "little")
& getattr(self._modes, f"_mutec")
== 0
)
return val
return val == 1
@mc.setter
def mc(self, val: bool):
if not isinstance(val, bool) and val not in (0, 1):
raise VMCMDErrors("mc is a boolean parameter")
self.setter("mc", 1 if val else 0)
mono = mc mono = mc
@ -169,11 +139,10 @@ class GainLayer(InputStrip):
else: else:
return ((1 << 16) - 1) - val return ((1 << 16) - 1) - val
val = self.getter(f"GainLayer[{self._i}]") val = round(self.getter(f"GainLayer[{self._i}]"), 1)
if val is None: if val is None:
val = round((fget() * 0.01), 1) val = round((fget() * 0.01), 1)
return val return val
return round(val, 1)
@gain.setter @gain.setter
def gain(self, val: float): def gain(self, val: float):

View File

@ -1,5 +1,6 @@
from pathlib import Path from pathlib import Path
PROJECT_DIR = str(Path(__file__).parents[1]) PROJECT_DIR = str(Path(__file__).parents[1])
@ -7,14 +8,29 @@ def project_path():
return PROJECT_DIR return PROJECT_DIR
def cache(func): def cache_bool(func, param):
"""check if recently cached was an updated value""" """Check cache for a bool prop"""
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
# setup cache check self, *rem = args
res = func(*args, **kwargs) cmd = f"{self.identifier}[{self.index}].{param}"
# update cache if cmd in self._remote.cache:
return res print(self._remote.cache[cmd] == 1)
return self._remote.cache.pop(cmd) == 1
return func(*args, **kwargs)
return wrapper
def cache_string(func, param):
"""Check cache for a string prop"""
def wrapper(*args, **kwargs):
self, *rem = args
cmd = f"{self.identifier}[{self.index}].{param}"
if cmd in self._remote.cache:
return self._remote.cache.pop(cmd)
return func(*args, **kwargs)
return wrapper return wrapper

View File

@ -194,7 +194,7 @@ class VbanCmd(abc.ABC):
val: Optional[Union[int, float]] = None, val: Optional[Union[int, float]] = None,
): ):
"""Sends a string request command over a network.""" """Sends a string request command over a network."""
cmd = id_ if not param and val else f"{id_}.{param}={val}" cmd = id_ if not param else f"{id_}.{param}={val}"
if self._sendrequest_string_socket in self.ready_to_write: if self._sendrequest_string_socket in self.ready_to_write:
self._sendrequest_string_socket.sendto( self._sendrequest_string_socket.sendto(
self._text_header.header + cmd.encode(), self._text_header.header + cmd.encode(),
@ -202,6 +202,7 @@ class VbanCmd(abc.ABC):
) )
count = int.from_bytes(self._text_header.framecounter, "little") + 1 count = int.from_bytes(self._text_header.framecounter, "little") + 1
self._text_header.framecounter = count.to_bytes(4, "little") self._text_header.framecounter = count.to_bytes(4, "little")
if param:
self.cache[f"{id_}.{param}"] = val self.cache[f"{id_}.{param}"] = val
if self._sync or self.in_apply: if self._sync or self.in_apply:
sleep(self._delay) sleep(self._delay)