voicemeeter-api-python/voicemeeterlib/misc.py
onyx-and-iris 446848fe89 Event class added to misc.
defaultkwarg subs added. iniitialize event subscriptions.

base class observable thread now checks for currently registered events.

make capi call if polling strip/bus levels and ldirty not in events.
2022-08-02 09:17:11 +01:00

295 lines
6.7 KiB
Python

from typing import Optional
from .error import VMError
from .iremote import IRemote
from .kinds import kinds_all
class FX(IRemote):
def __str__(self):
return f"{type(self).__name__}"
@property
def identifier(self) -> str:
return "FX"
@property
def reverb(self) -> bool:
return self.getter("reverb.On") == 1
@reverb.setter
def reverb(self, val: bool):
self.setter("reverb.On", 1 if val else 0)
@property
def reverb_ab(self) -> bool:
return self.getter("reverb.ab") == 1
@reverb_ab.setter
def reverb_ab(self, val: bool):
self.setter("reverb.ab", 1 if val else 0)
@property
def delay(self) -> bool:
return self.getter("delay.On") == 1
@delay.setter
def delay(self, val: bool):
self.setter("delay.On", 1 if val else 0)
@property
def delay_ab(self) -> bool:
return self.getter("delay.ab") == 1
@delay_ab.setter
def delay_ab(self, val: bool):
self.setter("delay.ab", 1 if val else 0)
class Patch(IRemote):
@classmethod
def make(cls, remote):
"""
Factory method for Patch.
Mixes in required classes.
Returns a Patch class of a kind.
"""
ASIO_cls = _make_asio_mixins(remote)[remote.kind.name]
return type(
f"Patch{remote.kind}",
(cls, ASIO_cls),
{
"composite": tuple(Composite(remote, i) for i in range(8)),
"insert": tuple(Insert(remote, i) for i in range(remote.kind.insert)),
},
)(remote)
def __str__(self):
return f"{type(self).__name__}"
@property
def identifier(self) -> str:
return f"patch"
@property
def postfadercomp(self) -> bool:
return self.getter("postfadercomposite") == 1
@postfadercomp.setter
def postfadercomp(self, val: bool):
self.setter("postfadercomposite", 1 if val else 0)
@property
def postfxinsert(self) -> bool:
return self.getter("postfxinsert") == 1
@postfxinsert.setter
def postfxinsert(self, val: bool):
self.setter("postfxinsert", 1 if val else 0)
class Asio(IRemote):
@property
def identifier(self) -> str:
return f"patch"
class AsioIn(Asio):
def get(self) -> int:
return int(self.getter(f"asio[{self.index}]"))
def set(self, val: int):
self.setter(f"asio[{self.index}]", val)
class AsioOut(Asio):
def __init__(self, remote, i, param):
IRemote.__init__(self, remote, i)
self._param = param
def get(self) -> int:
return int(self.getter(f"out{self._param}[{self.index}]"))
def set(self, val: int):
self.setter(f"out{self._param}[{self.index}]", val)
def _make_asio_mixin(remote, kind):
"""Creates an ASIO mixin for a kind"""
asio_in, asio_out = kind.asio
return type(
f"ASIO{kind}",
(IRemote,),
{
"asio": tuple(AsioIn(remote, i) for i in range(asio_in)),
**{
param: tuple(AsioOut(remote, i, param) for i in range(asio_out))
for param in ["A2", "A3", "A4", "A5"]
},
},
)
def _make_asio_mixins(remote):
return {kind.name: _make_asio_mixin(remote, kind) for kind in kinds_all}
class Composite(IRemote):
@property
def identifier(self) -> str:
return "patch"
def get(self) -> int:
return int(self.getter(f"composite[{self.index}]"))
def set(self, val: int):
self.setter(f"composite[{self.index}]", val)
class Insert(IRemote):
@property
def identifier(self) -> str:
return "patch"
@property
def on(self) -> bool:
return self.getter(f"insert[{self.index}]") == 1
@on.setter
def on(self, val: bool):
self.setter(f"insert[{self.index}]", 1 if val else 0)
class Option(IRemote):
@classmethod
def make(cls, remote):
"""
Factory method for Option.
Mixes in required classes.
Returns a Option class of a kind.
"""
return type(
f"Option{remote.kind}",
(cls,),
{
"delay": tuple(Delay(remote, i) for i in range(remote.kind.phys_out)),
},
)(remote)
def __str__(self):
return f"{type(self).__name__}"
@property
def identifier(self) -> str:
return "option"
@property
def sr(self) -> int:
return int(self.getter("sr"))
@sr.setter
def sr(self, val: int):
opts = (44100, 48000, 88200, 96000, 176400, 192000)
if val not in opts:
raise VMError(f"Expected one of: {opts}")
self.setter("sr", val)
@property
def asiosr(self) -> bool:
return self.getter("asiosr") == 1
@asiosr.setter
def asiosr(self, val: bool):
self.setter("asiosr", 1 if val else 0)
@property
def monitoronsel(self) -> bool:
return self.getter("monitoronsel") == 1
@monitoronsel.setter
def monitoronsel(self, val: bool):
self.setter("monitoronsel", 1 if val else 0)
def buffer(self, driver, buffer):
self.setter(f"buffer.{driver}", buffer)
class Delay(IRemote):
@property
def identifier(self) -> str:
return "option"
def get(self) -> int:
return int(self.getter(f"delay[{self.index}]"))
def set(self, val: int):
self.setter(f"delay[{self.index}]", val)
class Midi:
def __init__(self):
self._channel = None
self.cache = {}
self._most_recent = None
@property
def channel(self) -> int:
return self._channel
@property
def current(self) -> int:
return self._most_recent
def get(self, key: int) -> Optional[int]:
return self.cache.get(key)
def _set(self, key: int, velocity: int):
self.cache[key] = velocity
class Event:
def __init__(self, subs: dict):
self.subs = subs
def info(self, msg):
info = (
f"{msg} events",
f"Now listening for {', '.join(self.get())} events",
)
print("\n".join(info))
@property
def pdirty(self):
return self.subs["pdirty"]
@property
def mdirty(self):
return self.subs["mdirty"]
@property
def midi(self):
return self.subs["midi"]
@property
def ldirty(self):
return self.subs["ldirty"]
def get(self) -> list:
return [k for k, v in self.subs.items() if v]
def any(self) -> bool:
return any(self.subs.values())
def add(self, event):
self.subs[event] = True
self.info(f"{event} added to")
def remove(self, event):
self.subs[event] = False
self.info(f"{event} removed from")