mirror of
https://github.com/onyx-and-iris/vban-cmd-python.git
synced 2024-11-15 17:10:46 +00:00
6c914dafbe
add login, logout functions to base class. add caching to setters and fetch caching to getters. add isdirty function to rt packet dataclass for defining dirty flag. remove sync kwarg.
197 lines
7.4 KiB
Python
197 lines
7.4 KiB
Python
from dataclasses import dataclass
|
|
|
|
VBAN_SERVICE_RTPACKETREGISTER=32
|
|
VBAN_SERVICE_RTPACKET=33
|
|
MAX_PACKET_SIZE = 1436
|
|
HEADER_SIZE = (4+1+1+1+1+16+4)
|
|
|
|
@dataclass
|
|
class VBAN_VMRT_Packet_Data:
|
|
""" RT Packet Data """
|
|
_voicemeeterType: bytes
|
|
_reserved: bytes
|
|
_buffersize: bytes
|
|
_voicemeeterVersion: bytes
|
|
_optionBits: bytes
|
|
_samplerate: bytes
|
|
_inputLeveldB100: bytes
|
|
_outputLeveldB100: bytes
|
|
_TransportBit: bytes
|
|
_stripState: bytes
|
|
_busState: bytes
|
|
_stripGaindB100Layer1: bytes
|
|
_stripGaindB100Layer2: bytes
|
|
_stripGaindB100Layer3: bytes
|
|
_stripGaindB100Layer4: bytes
|
|
_stripGaindB100Layer5: bytes
|
|
_stripGaindB100Layer6: bytes
|
|
_stripGaindB100Layer7: bytes
|
|
_stripGaindB100Layer8: bytes
|
|
_busGaindB100: bytes
|
|
_stripLabelUTF8c60: bytes
|
|
_busLabelUTF8c60: bytes
|
|
|
|
def isdirty(self, other):
|
|
""" defines the dirty flag """
|
|
if \
|
|
self._stripState == other._stripState and \
|
|
self._busState == other._busState and \
|
|
self._stripLabelUTF8c60 == other._stripLabelUTF8c60 and \
|
|
self._busLabelUTF8c60 == other._busLabelUTF8c60 and \
|
|
self._stripGaindB100Layer1 == other._stripGaindB100Layer1 and \
|
|
self._busGaindB100 == other._busGaindB100:
|
|
return False
|
|
return True
|
|
|
|
@property
|
|
def voicemeetertype(self) -> str:
|
|
""" returns voicemeeter type as a string """
|
|
type_ = ('basic', 'banana', 'potato')
|
|
return type_[int.from_bytes(self._voicemeeterType, 'little')-1]
|
|
@property
|
|
def voicemeeterversion(self) -> tuple:
|
|
""" returns voicemeeter version as a string """
|
|
return tuple(reversed(tuple(int.from_bytes(self._voicemeeterVersion[i:i+1], 'little') for i in range(4))))
|
|
@property
|
|
def samplerate(self) -> int:
|
|
""" returns samplerate as an int """
|
|
return int.from_bytes(self._samplerate, 'little')
|
|
@property
|
|
def inputlevels(self) -> tuple:
|
|
""" returns the entire level array across all inputs """
|
|
return tuple(((1 << 16) - 1) - int.from_bytes(self._inputLeveldB100[i:i+2], 'little') for i in range(0, 68, 2))
|
|
@property
|
|
def outputlevels(self) -> tuple:
|
|
""" returns the entire level array across all outputs """
|
|
return tuple(((1 << 16) - 1) - int.from_bytes(self._outputLeveldB100[i:i+2], 'little') for i in range(0, 128, 2))
|
|
@property
|
|
def stripstate(self) -> tuple:
|
|
""" returns tuple of strip states accessable through bit modes """
|
|
return tuple(self._stripState[i:i+4] for i in range(0, 32, 4))
|
|
@property
|
|
def busstate(self) -> tuple:
|
|
""" returns tuple of bus states accessable through bit modes """
|
|
return tuple(self._busState[i:i+4] for i in range(0, 32, 4))
|
|
|
|
"""
|
|
these functions return an array of gainlayers[i] across all strips
|
|
ie stripgainlayer1 = [strip[0].gainlayer[0], strip[1].gainlayer[0], strip[2].gainlayer[0]...]
|
|
"""
|
|
@property
|
|
def stripgainlayer1(self) -> tuple:
|
|
return tuple(((1 << 16) - 1) - int.from_bytes(self._stripGaindB100Layer1[i:i+2], 'little') for i in range(0, 16, 2))
|
|
@property
|
|
def stripgainlayer2(self) -> tuple:
|
|
return tuple(((1 << 16) - 1) - int.from_bytes(self._stripGaindB100Layer2[i:i+2], 'little') for i in range(0, 16, 2))
|
|
@property
|
|
def stripgainlayer3(self) -> tuple:
|
|
return tuple(((1 << 16) - 1) - int.from_bytes(self._stripGaindB100Layer3[i:i+2], 'little') for i in range(0, 16, 2))
|
|
@property
|
|
def stripgainlayer4(self) -> tuple:
|
|
return tuple(((1 << 16) - 1) - int.from_bytes(self._stripGaindB100Layer4[i:i+2], 'little') for i in range(0, 16, 2))
|
|
@property
|
|
def stripgainlayer5(self) -> tuple:
|
|
return tuple(((1 << 16) - 1) - int.from_bytes(self._stripGaindB100Layer5[i:i+2], 'little') for i in range(0, 16, 2))
|
|
@property
|
|
def stripgainlayer6(self) -> tuple:
|
|
return tuple(((1 << 16) - 1) - int.from_bytes(self._stripGaindB100Layer6[i:i+2], 'little') for i in range(0, 16, 2))
|
|
@property
|
|
def stripgainlayer7(self) -> tuple:
|
|
return tuple(((1 << 16) - 1) - int.from_bytes(self._stripGaindB100Layer7[i:i+2], 'little') for i in range(0, 16, 2))
|
|
@property
|
|
def stripgainlayer8(self) -> tuple:
|
|
return tuple(((1 << 16) - 1) - int.from_bytes(self._stripGaindB100Layer8[i:i+2], 'little') for i in range(0, 16, 2))
|
|
|
|
@property
|
|
def busgain(self) -> tuple:
|
|
""" returns tuple of bus gains """
|
|
return tuple(((1 << 16) - 1) - int.from_bytes(self._busGaindB100[i:i+2], 'little') for i in range(0, 16, 2))
|
|
@property
|
|
def striplabels(self) -> tuple:
|
|
""" returns tuple of strip labels """
|
|
return tuple(self._stripLabelUTF8c60[i:i+60].decode().strip('\x00') for i in range(0, 480, 60))
|
|
@property
|
|
def buslabels(self) -> tuple:
|
|
""" returns tuple of bus labels """
|
|
return tuple(self._busLabelUTF8c60[i:i+60].decode().strip('\x00') for i in range(0, 480, 60))
|
|
|
|
@dataclass
|
|
class VBAN_VMRT_Packet_Header:
|
|
""" RT PACKET header (expected from Voicemeeter server) """
|
|
name='Voicemeeter-RTP'
|
|
vban: bytes='VBAN'.encode()
|
|
format_sr: bytes=(0x60).to_bytes(1, 'little')
|
|
format_nbs: bytes=(0).to_bytes(1, 'little')
|
|
format_nbc: bytes=(VBAN_SERVICE_RTPACKET).to_bytes(1, 'little')
|
|
format_bit: bytes=(0).to_bytes(1, 'little')
|
|
streamname: bytes=name.encode('ascii') + bytes(16-len(name))
|
|
|
|
@property
|
|
def header(self):
|
|
header = self.vban
|
|
header += self.format_sr
|
|
header += self.format_nbs
|
|
header += self.format_nbc
|
|
header += self.format_bit
|
|
header += self.streamname
|
|
assert len(header) == HEADER_SIZE-4, f'Header expected {HEADER_SIZE-4} bytes'
|
|
return header
|
|
|
|
@dataclass
|
|
class RegisterRTHeader:
|
|
""" REGISTER RT PACKET header """
|
|
name='Register RTP'
|
|
timeout=15
|
|
vban: bytes='VBAN'.encode()
|
|
format_sr: bytes=(0x60).to_bytes(1, 'little')
|
|
format_nbs: bytes=(0).to_bytes(1, 'little')
|
|
format_nbc: bytes=(VBAN_SERVICE_RTPACKETREGISTER).to_bytes(1, 'little')
|
|
format_bit: bytes=(timeout & 0x000000FF).to_bytes(1, 'little') # timeout
|
|
streamname: bytes=name.encode('ascii') + bytes(16-len(name))
|
|
framecounter: bytes=(0).to_bytes(4, 'little')
|
|
|
|
@property
|
|
def header(self):
|
|
header = self.vban
|
|
header += self.format_sr
|
|
header += self.format_nbs
|
|
header += self.format_nbc
|
|
header += self.format_bit
|
|
header += self.streamname
|
|
header += self.framecounter
|
|
assert len(header) == HEADER_SIZE, f'Header expected {HEADER_SIZE} bytes'
|
|
return header
|
|
|
|
@dataclass
|
|
class TextRequestHeader:
|
|
""" VBAN-TEXT request header """
|
|
name: str
|
|
bps_index: int
|
|
channel: int
|
|
vban: bytes='VBAN'.encode()
|
|
nbs: bytes=(0).to_bytes(1, 'little')
|
|
bit: bytes=(0x10).to_bytes(1, 'little')
|
|
framecounter: bytes=(0).to_bytes(4, 'little')
|
|
|
|
@property
|
|
def sr(self):
|
|
return (0x40 + self.bps_index).to_bytes(1, 'little')
|
|
@property
|
|
def nbc(self):
|
|
return (self.channel).to_bytes(1, 'little')
|
|
@property
|
|
def streamname(self):
|
|
return self.name.encode() + bytes(16-len(self.name))
|
|
|
|
@property
|
|
def header(self):
|
|
header = self.vban
|
|
header += self.sr
|
|
header += self.nbs
|
|
header += self.nbc
|
|
header += self.bit
|
|
header += self.streamname
|
|
header += self.framecounter
|
|
assert len(header) == HEADER_SIZE, f'Header expected {HEADER_SIZE} bytes'
|
|
return header
|