implement 3d parameters

This commit is contained in:
onyx-and-iris 2026-01-17 12:29:10 +00:00
parent ecbdd2778f
commit ad88286509
7 changed files with 186 additions and 11 deletions

View File

@ -11,7 +11,7 @@ class TestPublicPacketLower:
def test_it_gets_an_rt0_data_packet(self): def test_it_gets_an_rt0_data_packet(self):
assert vban.public_packets[0].voicemeetertype in ( assert vban.public_packets[0].voicemeetertype in (
kind.name for kind in kinds.kinds_all kind.name for kind in kinds.all
) )

View File

@ -111,4 +111,4 @@ def request_kind_map(kind_id):
return KIND_obj return KIND_obj
kinds_all = list(request_kind_map(kind_id.name.lower()) for kind_id in KindId) all = list(request_kind_map(kind_id.name.lower()) for kind_id in KindId)

View File

@ -1,7 +1,7 @@
from functools import partial from functools import partial
from .enums import NBS from .enums import NBS
from .util import cache_bool, cache_string from .util import cache_bool, cache_float, cache_string
def channel_bool_prop(param): def channel_bool_prop(param):
@ -97,3 +97,46 @@ def action_fn(param, val=1):
self.setter(param, val) self.setter(param, val)
return fdo return fdo
def xy_prop(param):
"""meta function for XY pad parameters"""
@partial(cache_float, param=param)
def fget(self):
cmd = self._cmd(param)
self.logger.debug(f'getter: {cmd}')
_type, axis = param.split('_')
if self.public_packets[NBS.one] is None:
return 0.0
x, y = getattr(
self.public_packets[NBS.one].strips[self.index], f'position_{_type.lower()}'
)
return x if axis == 'x' else y
def fset(self, val):
self.setter(param, val)
return property(fget, fset)
def send_prop(param):
"""meta function for send parameters"""
@partial(cache_float, param=param)
def fget(self):
cmd = self._cmd(param)
self.logger.debug(f'getter: {cmd}')
if self.public_packets[NBS.one] is None:
return 0.0
val = getattr(self.public_packets[NBS.one].strips[self.index], f'send_{param}')
match param:
case 'reverb' | 'fx1':
return val[0]
case 'delay' | 'fx2':
return val[1]
def fset(self, val):
self.setter(param, val)
return property(fget, fset)

View File

@ -365,6 +365,45 @@ class VbanVMParamStrip:
def mode(self) -> int: def mode(self) -> int:
return int.from_bytes(self._mode, 'little') return int.from_bytes(self._mode, 'little')
@property
def position_pan(self) -> tuple[int, int]:
return (
round(int.from_bytes(self._pos3D_x, 'little', signed=True) * 0.01, 2),
round(int.from_bytes(self._pos3D_y, 'little', signed=True) * 0.01, 2),
)
@property
def position_color(self) -> tuple[int, int]:
return (
round(int.from_bytes(self._posColor_x, 'little', signed=True) * 0.01, 2),
round(int.from_bytes(self._posColor_y, 'little', signed=True) * 0.01, 2),
)
@property
def position_fx(self) -> tuple[int, int]:
return (
round(int.from_bytes(self._posMod_x, 'little', signed=True) * 0.01, 2),
round(int.from_bytes(self._posMod_y, 'little', signed=True) * 0.01, 2),
)
@property
def send_reverb(self) -> tuple[float, float]:
return (
round(int.from_bytes(self._send_reverb, 'little', signed=True) * 0.01, 2),
round(int.from_bytes(self._send_delay, 'little', signed=True) * 0.01, 2),
)
send_delay = send_reverb
@property
def send_fx1(self) -> tuple[float, float]:
return (
round(int.from_bytes(self._send_fx1, 'little', signed=True) * 0.01, 2),
round(int.from_bytes(self._send_fx2, 'little', signed=True) * 0.01, 2),
)
send_fx2 = send_fx1
@property @property
def eqgains(self) -> tuple[float, float, float]: def eqgains(self) -> tuple[float, float, float]:
return tuple( return tuple(

View File

@ -2,10 +2,16 @@ import time
from abc import abstractmethod from abc import abstractmethod
from typing import Union from typing import Union
from . import kinds
from .enums import NBS, EQGains from .enums import NBS, EQGains
from .iremote import IRemote from .iremote import IRemote
from .kinds import kinds_all from .meta import (
from .meta import channel_bool_prop, channel_label_prop, strip_output_prop channel_bool_prop,
channel_label_prop,
send_prop,
strip_output_prop,
xy_prop,
)
class Strip(IRemote): class Strip(IRemote):
@ -53,10 +59,11 @@ class Strip(IRemote):
class PhysicalStrip(Strip): class PhysicalStrip(Strip):
@classmethod @classmethod
def make(cls, remote, index): def make(cls, remote, index, is_phys):
EFFECTS_cls = _make_effects_mixins(is_phys)[remote.kind.name]
return type( return type(
f'PhysicalStrip{remote.kind}', f'PhysicalStrip{remote.kind}',
(cls,), (cls, EFFECTS_cls),
{ {
'comp': StripComp(remote, index), 'comp': StripComp(remote, index),
'gate': StripGate(remote, index), 'gate': StripGate(remote, index),
@ -254,6 +261,20 @@ class StripEQ(IRemote):
class VirtualStrip(Strip): class VirtualStrip(Strip):
@classmethod
def make(cls, remote, i, is_phys):
"""
Factory method for VirtualStrip.
Returns a VirtualStrip class.
"""
EFFECTS_cls = _make_effects_mixins(is_phys)[remote.kind.name]
return type(
'VirtualStrip',
(cls, EFFECTS_cls),
{},
)
def __str__(self): def __str__(self):
return f'{type(self).__name__}{self.index}' return f'{type(self).__name__}{self.index}'
@ -432,10 +453,64 @@ def _make_channelout_mixin(kind):
_make_channelout_mixins = { _make_channelout_mixins = {
kind.name: _make_channelout_mixin(kind) for kind in kinds_all kind.name: _make_channelout_mixin(kind) for kind in kinds.all
} }
def _make_effects_mixin(kind, is_phys):
"""creates an effects mixin for a kind"""
def _make_xy_cls():
pan = {param: xy_prop(param) for param in ['pan_x', 'pan_y']}
color = {param: xy_prop(param) for param in ['color_x', 'color_y']}
fx = {param: xy_prop(param) for param in ['fx_x', 'fx_y']}
if is_phys:
return type(
'XYPhys',
(),
{
**pan,
**color,
**fx,
},
)
return type(
'XYVirt',
(),
{**pan},
)
def _make_sends_cls():
if is_phys:
return type(
'FX',
(),
{
**{
param: send_prop(param)
for param in ['reverb', 'delay', 'fx1', 'fx2']
},
# **{
# f'post{param}': bool_prop(f'post{param}')
# for param in ['reverb', 'delay', 'fx1', 'fx2']
# },
},
)
return type('FX', (), {})
if kind.name == 'basic':
steps = (_make_xy_cls,)
elif kind.name == 'banana':
steps = (_make_xy_cls,)
elif kind.name == 'potato':
steps = (_make_xy_cls, _make_sends_cls)
return type(f'Effects{kind}', tuple(step() for step in steps), {})
def _make_effects_mixins(is_phys):
return {kind.name: _make_effects_mixin(kind, is_phys) for kind in kinds.all}
def strip_factory(is_phys_strip, remote, i) -> Union[PhysicalStrip, VirtualStrip]: def strip_factory(is_phys_strip, remote, i) -> Union[PhysicalStrip, VirtualStrip]:
""" """
Factory method for strips Factory method for strips
@ -444,7 +519,11 @@ def strip_factory(is_phys_strip, remote, i) -> Union[PhysicalStrip, VirtualStrip
Returns a physical or virtual strip subclass Returns a physical or virtual strip subclass
""" """
STRIP_cls = PhysicalStrip.make(remote, i) if is_phys_strip else VirtualStrip STRIP_cls = (
PhysicalStrip.make(remote, i, is_phys_strip)
if is_phys_strip
else VirtualStrip.make(remote, i, is_phys_strip)
)
CHANNELOUTMIXIN_cls = _make_channelout_mixins[remote.kind.name] CHANNELOUTMIXIN_cls = _make_channelout_mixins[remote.kind.name]
GAINLAYERMIXIN_cls = _make_gainlayer_mixin(remote, i) GAINLAYERMIXIN_cls = _make_gainlayer_mixin(remote, i)

View File

@ -29,6 +29,20 @@ def cache_string(func, param):
return wrapper return wrapper
def cache_float(func, param):
"""Check cache for a float prop"""
def wrapper(*args, **kwargs):
self, *rem = args
if self._cmd(param) in self._remote.cache:
return round(self._remote.cache.pop(self._cmd(param)), 2)
if self._remote.sync:
self._remote.clear_dirty()
return func(*args, **kwargs)
return wrapper
def depth(d): def depth(d):
if isinstance(d, dict): if isinstance(d, dict):
return 1 + (max(map(depth, d.values())) if d else 0) return 1 + (max(map(depth, d.values())) if d else 0)

View File

@ -1,7 +1,7 @@
from abc import abstractmethod from abc import abstractmethod
from . import kinds
from .iremote import IRemote from .iremote import IRemote
from .kinds import kinds_all
class VbanStream(IRemote): class VbanStream(IRemote):
@ -194,7 +194,7 @@ def _make_stream_pair(remote, kind):
def _make_stream_pairs(remote): def _make_stream_pairs(remote):
return {kind.name: _make_stream_pair(remote, kind) for kind in kinds_all} return {kind.name: _make_stream_pair(remote, kind) for kind in kinds.all}
class Vban: class Vban: