mirror of
https://github.com/onyx-and-iris/vban-cmd-python.git
synced 2026-01-24 17:27:48 +00:00
upd the interface to read/write multiple private/public packets.
{VirtualStrip}.bass/mid/treble implemented reading from public packet NBS=1
This commit is contained in:
parent
51394c0076
commit
96e9d6f4fd
@ -1,17 +1,11 @@
|
|||||||
import time
|
import time
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from enum import IntEnum
|
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
from .enums import NBS, BusModes
|
||||||
from .iremote import IRemote
|
from .iremote import IRemote
|
||||||
from .meta import bus_mode_prop, channel_bool_prop, channel_label_prop
|
from .meta import bus_mode_prop, channel_bool_prop, channel_label_prop
|
||||||
|
|
||||||
BusModes = IntEnum(
|
|
||||||
'BusModes',
|
|
||||||
'normal amix bmix repeat composite tvmix upmix21 upmix41 upmix61 centeronly lfeonly rearonly',
|
|
||||||
start=0,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Bus(IRemote):
|
class Bus(IRemote):
|
||||||
"""
|
"""
|
||||||
@ -31,7 +25,7 @@ class Bus(IRemote):
|
|||||||
@property
|
@property
|
||||||
def gain(self) -> float:
|
def gain(self) -> float:
|
||||||
def fget():
|
def fget():
|
||||||
val = self.public_packet.busgain[self.index]
|
val = self.public_packets[NBS.zero].busgain[self.index]
|
||||||
if 0 <= val <= 1200:
|
if 0 <= val <= 1200:
|
||||||
return val * 0.01
|
return val * 0.01
|
||||||
return (((1 << 16) - 1) - val) * -0.01
|
return (((1 << 16) - 1) - val) * -0.01
|
||||||
@ -109,7 +103,7 @@ class BusLevel(IRemote):
|
|||||||
)
|
)
|
||||||
return tuple(
|
return tuple(
|
||||||
fget(i)
|
fget(i)
|
||||||
for i in self._remote._get_levels(self.public_packet)[1][
|
for i in self._remote._get_levels(self.public_packets[NBS.zero])[1][
|
||||||
self.range[0] : self.range[-1]
|
self.range[0] : self.range[-1]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -157,7 +151,12 @@ def _make_bus_mode_mixin():
|
|||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
states = [
|
states = [
|
||||||
(int.from_bytes(self.public_packet.busstate[self.index], 'little') & val)
|
(
|
||||||
|
int.from_bytes(
|
||||||
|
self.public_packets[NBS.zero].busstate[self.index], 'little'
|
||||||
|
)
|
||||||
|
& val
|
||||||
|
)
|
||||||
>> 4
|
>> 4
|
||||||
for val in self._modes.modevals
|
for val in self._modes.modevals
|
||||||
]
|
]
|
||||||
|
|||||||
15
vban_cmd/enums.py
Normal file
15
vban_cmd/enums.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
from enum import IntEnum
|
||||||
|
|
||||||
|
|
||||||
|
class NBS(IntEnum):
|
||||||
|
zero = 0
|
||||||
|
one = 1
|
||||||
|
|
||||||
|
|
||||||
|
BusModes = IntEnum(
|
||||||
|
'BusModes',
|
||||||
|
'normal amix bmix repeat composite tvmix upmix21 upmix41 upmix61 centeronly lfeonly rearonly',
|
||||||
|
start=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
EQGains = IntEnum('EQGains', 'bass mid treble', start=0)
|
||||||
@ -116,9 +116,9 @@ class IRemote(metaclass=ABCMeta):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def public_packet(self):
|
def public_packets(self):
|
||||||
"""Returns an RT data packet."""
|
"""Returns an RT data packet."""
|
||||||
return self._remote.public_packet
|
return self._remote.public_packets
|
||||||
|
|
||||||
def apply(self, data):
|
def apply(self, data):
|
||||||
"""Sets all parameters of a dict for the channel."""
|
"""Sets all parameters of a dict for the channel."""
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
|
from .enums import NBS
|
||||||
from .util import cache_bool, cache_string
|
from .util import cache_bool, cache_string
|
||||||
|
|
||||||
|
|
||||||
@ -13,7 +14,7 @@ def channel_bool_prop(param):
|
|||||||
return (
|
return (
|
||||||
not int.from_bytes(
|
not int.from_bytes(
|
||||||
getattr(
|
getattr(
|
||||||
self.public_packet,
|
self.public_packets[NBS.zero],
|
||||||
f'{"strip" if "strip" in type(self).__name__.lower() else "bus"}state',
|
f'{"strip" if "strip" in type(self).__name__.lower() else "bus"}state',
|
||||||
)[self.index],
|
)[self.index],
|
||||||
'little',
|
'little',
|
||||||
@ -34,7 +35,7 @@ def channel_label_prop():
|
|||||||
@partial(cache_string, param='label')
|
@partial(cache_string, param='label')
|
||||||
def fget(self) -> str:
|
def fget(self) -> str:
|
||||||
return getattr(
|
return getattr(
|
||||||
self.public_packet,
|
self.public_packets[NBS.zero],
|
||||||
f'{"strip" if "strip" in type(self).__name__.lower() else "bus"}labels',
|
f'{"strip" if "strip" in type(self).__name__.lower() else "bus"}labels',
|
||||||
)[self.index]
|
)[self.index]
|
||||||
|
|
||||||
@ -52,7 +53,9 @@ def strip_output_prop(param):
|
|||||||
cmd = self._cmd(param)
|
cmd = self._cmd(param)
|
||||||
self.logger.debug(f'getter: {cmd}')
|
self.logger.debug(f'getter: {cmd}')
|
||||||
return (
|
return (
|
||||||
not int.from_bytes(self.public_packet.stripstate[self.index], 'little')
|
not int.from_bytes(
|
||||||
|
self.public_packets[NBS.zero].stripstate[self.index], 'little'
|
||||||
|
)
|
||||||
& getattr(self._modes, f'_bus{param.lower()}')
|
& getattr(self._modes, f'_bus{param.lower()}')
|
||||||
== 0
|
== 0
|
||||||
)
|
)
|
||||||
@ -71,7 +74,12 @@ def bus_mode_prop(param):
|
|||||||
cmd = self._cmd(param)
|
cmd = self._cmd(param)
|
||||||
self.logger.debug(f'getter: {cmd}')
|
self.logger.debug(f'getter: {cmd}')
|
||||||
return [
|
return [
|
||||||
(int.from_bytes(self.public_packet.busstate[self.index], 'little') & val)
|
(
|
||||||
|
int.from_bytes(
|
||||||
|
self.public_packets[NBS.zero].busstate[self.index], 'little'
|
||||||
|
)
|
||||||
|
& val
|
||||||
|
)
|
||||||
>> 4
|
>> 4
|
||||||
for val in self._modes.modevals
|
for val in self._modes.modevals
|
||||||
] == self.modestates[param]
|
] == self.modestates[param]
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import time
|
|||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
from .enums import NBS, EQGains
|
||||||
from .iremote import IRemote
|
from .iremote import IRemote
|
||||||
from .kinds import kinds_all
|
from .kinds import kinds_all
|
||||||
from .meta import channel_bool_prop, channel_label_prop, strip_output_prop
|
from .meta import channel_bool_prop, channel_label_prop, strip_output_prop
|
||||||
@ -34,7 +35,7 @@ class Strip(IRemote):
|
|||||||
def gain(self) -> float:
|
def gain(self) -> float:
|
||||||
val = self.getter('gain')
|
val = self.getter('gain')
|
||||||
if val is None:
|
if val is None:
|
||||||
val = self.gainlayer[0].gain
|
val = max(layer.gain for layer in self.gainlayer)
|
||||||
return round(val, 1)
|
return round(val, 1)
|
||||||
|
|
||||||
@gain.setter
|
@gain.setter
|
||||||
@ -262,12 +263,48 @@ class VirtualStrip(Strip):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def k(self) -> int:
|
def k(self) -> int:
|
||||||
return
|
if self.public_packets[NBS.one] is None:
|
||||||
|
return 0
|
||||||
|
return self.public_packets[NBS.one].strips[self.index].karaoke
|
||||||
|
|
||||||
@k.setter
|
@k.setter
|
||||||
def k(self, val: int):
|
def k(self, val: int):
|
||||||
self.setter('karaoke', val)
|
self.setter('karaoke', val)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def bass(self) -> float:
|
||||||
|
if self.public_packets[NBS.one] is None:
|
||||||
|
return 0.0
|
||||||
|
return self.public_packets[NBS.one].strips[self.index].eqgains[EQGains.bass]
|
||||||
|
|
||||||
|
@bass.setter
|
||||||
|
def bass(self, val: float):
|
||||||
|
self.setter('EQGain1', val)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mid(self) -> float:
|
||||||
|
if self.public_packets[NBS.one] is None:
|
||||||
|
return 0.0
|
||||||
|
return self.public_packets[NBS.one].strips[self.index].eqgains[EQGains.mid]
|
||||||
|
|
||||||
|
@mid.setter
|
||||||
|
def mid(self, val: float):
|
||||||
|
self.setter('EQGain2', val)
|
||||||
|
|
||||||
|
med = mid
|
||||||
|
|
||||||
|
@property
|
||||||
|
def treble(self) -> float:
|
||||||
|
if self.public_packets[NBS.one] is None:
|
||||||
|
return 0.0
|
||||||
|
return self.public_packets[NBS.one].strips[self.index].eqgains[EQGains.treble]
|
||||||
|
|
||||||
|
@treble.setter
|
||||||
|
def treble(self, val: float):
|
||||||
|
self.setter('EQGain3', val)
|
||||||
|
|
||||||
|
high = treble
|
||||||
|
|
||||||
def appgain(self, name: str, gain: float):
|
def appgain(self, name: str, gain: float):
|
||||||
self.setter('AppGain', f'("{name}", {gain})')
|
self.setter('AppGain', f'("{name}", {gain})')
|
||||||
|
|
||||||
@ -305,7 +342,7 @@ class StripLevel(IRemote):
|
|||||||
)
|
)
|
||||||
return tuple(
|
return tuple(
|
||||||
fget(i)
|
fget(i)
|
||||||
for i in self._remote._get_levels(self.public_packet)[0][
|
for i in self._remote._get_levels(self.public_packets[NBS.zero])[0][
|
||||||
self.range[0] : self.range[-1]
|
self.range[0] : self.range[-1]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -350,9 +387,9 @@ class GainLayer(IRemote):
|
|||||||
@property
|
@property
|
||||||
def gain(self) -> float:
|
def gain(self) -> float:
|
||||||
def fget():
|
def fget():
|
||||||
val = getattr(self.public_packet, f'stripgainlayer{self._i + 1}')[
|
val = getattr(
|
||||||
self.index
|
self.public_packets[NBS.zero], f'stripgainlayer{self._i + 1}'
|
||||||
]
|
)[self.index]
|
||||||
if 0 <= val <= 1200:
|
if 0 <= val <= 1200:
|
||||||
return val * 0.01
|
return val * 0.01
|
||||||
return (((1 << 16) - 1) - val) * -0.01
|
return (((1 << 16) - 1) - val) * -0.01
|
||||||
|
|||||||
@ -82,3 +82,11 @@ def deep_merge(dict1, dict2):
|
|||||||
yield k, dict1[k]
|
yield k, dict1[k]
|
||||||
else:
|
else:
|
||||||
yield k, dict2[k]
|
yield k, dict2[k]
|
||||||
|
|
||||||
|
|
||||||
|
def bump_framecounter(framecounter: int) -> int:
|
||||||
|
"""Increment framecounter with rollover at 0xFFFFFFFF."""
|
||||||
|
if framecounter > 0xFFFFFFFF:
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
return framecounter + 1
|
||||||
|
|||||||
@ -7,11 +7,12 @@ from pathlib import Path
|
|||||||
from queue import Queue
|
from queue import Queue
|
||||||
from typing import Iterable, Union
|
from typing import Iterable, Union
|
||||||
|
|
||||||
|
from .enums import NBS
|
||||||
from .error import VBANCMDError
|
from .error import VBANCMDError
|
||||||
from .event import Event
|
from .event import Event
|
||||||
from .packet import RequestHeader
|
from .packet import RequestHeader
|
||||||
from .subject import Subject
|
from .subject import Subject
|
||||||
from .util import deep_merge, script
|
from .util import bump_framecounter, deep_merge, script
|
||||||
from .worker import Producer, Subscriber, Updater
|
from .worker import Producer, Subscriber, Updater
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -37,12 +38,9 @@ class VbanCmd(metaclass=ABCMeta):
|
|||||||
for attr, val in kwargs.items():
|
for attr, val in kwargs.items():
|
||||||
setattr(self, attr, val)
|
setattr(self, attr, val)
|
||||||
|
|
||||||
self.packet_request = RequestHeader(
|
self._framecounter = 0
|
||||||
name=self.streamname,
|
|
||||||
bps_index=self.BPS_OPTS.index(self.bps),
|
|
||||||
channel=self.channel,
|
|
||||||
)
|
|
||||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
self.subject = self.observer = Subject()
|
self.subject = self.observer = Subject()
|
||||||
self.cache = {}
|
self.cache = {}
|
||||||
self._pdirty = False
|
self._pdirty = False
|
||||||
@ -124,37 +122,49 @@ class VbanCmd(metaclass=ABCMeta):
|
|||||||
|
|
||||||
def _set_rt(self, cmd: str, val: Union[str, float]):
|
def _set_rt(self, cmd: str, val: Union[str, float]):
|
||||||
"""Sends a string request command over a network."""
|
"""Sends a string request command over a network."""
|
||||||
|
req_packet = RequestHeader.to_bytes(
|
||||||
|
name=self.streamname,
|
||||||
|
bps_index=self.BPS_OPTS.index(self.bps),
|
||||||
|
channel=self.channel,
|
||||||
|
framecounter=self._framecounter,
|
||||||
|
)
|
||||||
self.sock.sendto(
|
self.sock.sendto(
|
||||||
self.packet_request.header + f'{cmd}={val};'.encode(),
|
req_packet + f'{cmd}={val};'.encode(),
|
||||||
(socket.gethostbyname(self.ip), self.port),
|
(socket.gethostbyname(self.ip), self.port),
|
||||||
)
|
)
|
||||||
self.packet_request.framecounter = (
|
self._framecounter = bump_framecounter(self._framecounter)
|
||||||
int.from_bytes(self.packet_request.framecounter, 'little') + 1
|
|
||||||
).to_bytes(4, 'little')
|
|
||||||
self.cache[cmd] = val
|
self.cache[cmd] = val
|
||||||
|
|
||||||
@script
|
@script
|
||||||
def sendtext(self, script):
|
def sendtext(self, script):
|
||||||
"""Sends a multiple parameter string over a network."""
|
"""Sends a multiple parameter string over a network."""
|
||||||
|
req_packet = RequestHeader.to_bytes(
|
||||||
|
name=self.streamname,
|
||||||
|
bps_index=self.BPS_OPTS.index(self.bps),
|
||||||
|
channel=self.channel,
|
||||||
|
framecounter=self._framecounter,
|
||||||
|
)
|
||||||
self.sock.sendto(
|
self.sock.sendto(
|
||||||
self.packet_request.header + script.encode(),
|
req_packet + script.encode(),
|
||||||
(socket.gethostbyname(self.ip), self.port),
|
(socket.gethostbyname(self.ip), self.port),
|
||||||
)
|
)
|
||||||
self.packet_request.framecounter = (
|
self._framecounter = bump_framecounter(self._framecounter)
|
||||||
int.from_bytes(self.packet_request.framecounter, 'little') + 1
|
|
||||||
).to_bytes(4, 'little')
|
|
||||||
self.logger.debug(f'sendtext: {script}')
|
self.logger.debug(f'sendtext: {script}')
|
||||||
time.sleep(self.DELAY)
|
time.sleep(self.DELAY)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self) -> str:
|
def type(self) -> str:
|
||||||
"""Returns the type of Voicemeeter installation."""
|
"""Returns the type of Voicemeeter installation."""
|
||||||
return self.public_packet.voicemeetertype
|
return self.public_packets[NBS.zero].voicemeetertype
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def version(self) -> str:
|
def version(self) -> str:
|
||||||
"""Returns Voicemeeter's version as a string"""
|
"""Returns Voicemeeter's version as a string"""
|
||||||
return '{0}.{1}.{2}.{3}'.format(*self.public_packet.voicemeeterversion)
|
return '{0}.{1}.{2}.{3}'.format(
|
||||||
|
*self.public_packets[NBS.zero].voicemeeterversion
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pdirty(self):
|
def pdirty(self):
|
||||||
@ -167,8 +177,8 @@ class VbanCmd(metaclass=ABCMeta):
|
|||||||
return self._ldirty
|
return self._ldirty
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def public_packet(self):
|
def public_packets(self):
|
||||||
return self._public_packet
|
return self._public_packets
|
||||||
|
|
||||||
def clear_dirty(self) -> None:
|
def clear_dirty(self) -> None:
|
||||||
while self.pdirty:
|
while self.pdirty:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user