from typing import Optional from . import kinds from .iremote import IRemote 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 '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 '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: self.logger.warning(f'sr got: {val} but expected a value in {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 VmGui: _launched = None @property def launched(self) -> bool: return self._launched @launched.setter def launched(self, val: bool): self._launched = val @property def launched_by_api(self): return not self.launched