4 Commits

3 changed files with 38 additions and 50 deletions

View File

@@ -1,5 +1,4 @@
import logging import logging
from enum import IntEnum
from functools import cached_property from functools import cached_property
from typing import Iterable from typing import Iterable
@@ -9,7 +8,7 @@ from .command import Command
from .config import request_config as configs from .config import request_config as configs
from .device import Device from .device import Device
from .error import VMError from .error import VMError
from .kinds import KindMapClass from .kinds import KindId, KindMapClass
from .kinds import request_kind_map as kindmap from .kinds import request_kind_map as kindmap
from .macrobutton import MacroButton from .macrobutton import MacroButton
from .recorder import Recorder from .recorder import Recorder
@@ -27,34 +26,11 @@ class FactoryBuilder:
Separates construction from representation. Separates construction from representation.
""" """
BuilderProgress = IntEnum(
'BuilderProgress',
'strip bus command macrobutton vban device option recorder patch fx',
start=0,
)
def __init__(self, factory, kind: KindMapClass): def __init__(self, factory, kind: KindMapClass):
self._factory = factory self._factory = factory
self.kind = kind self.kind = kind
self._info = (
f'Finished building strips for {self._factory}',
f'Finished building buses for {self._factory}',
f'Finished building commands for {self._factory}',
f'Finished building macrobuttons for {self._factory}',
f'Finished building vban in/out streams for {self._factory}',
f'Finished building device for {self._factory}',
f'Finished building option for {self._factory}',
f'Finished building recorder for {self._factory}',
f'Finished building patch for {self._factory}',
f'Finished building fx for {self._factory}',
)
self.logger = logger.getChild(self.__class__.__name__) self.logger = logger.getChild(self.__class__.__name__)
def _pinfo(self, name: str) -> None:
"""prints progress status for each step"""
name = name.split('_')[1]
self.logger.debug(self._info[int(getattr(self.BuilderProgress, name))])
def make_strip(self): def make_strip(self):
self._factory.strip = tuple( self._factory.strip = tuple(
strip(i < self.kind.phys_in, self._factory, i) strip(i < self.kind.phys_in, self._factory, i)
@@ -151,12 +127,14 @@ class BasicFactory(FactoryBase):
def __new__(cls, *args, **kwargs): def __new__(cls, *args, **kwargs):
if cls is BasicFactory: if cls is BasicFactory:
raise TypeError(f"'{cls.__name__}' does not support direct instantiation") ERR_MSG = f"'{cls.__name__}' does not support direct instantiation"
raise TypeError(ERR_MSG)
return object.__new__(cls) return object.__new__(cls)
def __init__(self, kind_id, **kwargs): def __init__(self, kind_id, **kwargs):
super().__init__(kind_id, **kwargs) super().__init__(kind_id, **kwargs)
[step()._pinfo(step.__name__) for step in self.steps] for step in self.steps:
step()
@property @property
def steps(self) -> Iterable: def steps(self) -> Iterable:
@@ -173,12 +151,14 @@ class BananaFactory(FactoryBase):
def __new__(cls, *args, **kwargs): def __new__(cls, *args, **kwargs):
if cls is BananaFactory: if cls is BananaFactory:
raise TypeError(f"'{cls.__name__}' does not support direct instantiation") ERR_MSG = f"'{cls.__name__}' does not support direct instantiation"
raise TypeError(ERR_MSG)
return object.__new__(cls) return object.__new__(cls)
def __init__(self, kind_id, **kwargs): def __init__(self, kind_id, **kwargs):
super().__init__(kind_id, **kwargs) super().__init__(kind_id, **kwargs)
[step()._pinfo(step.__name__) for step in self.steps] for step in self.steps:
step()
@property @property
def steps(self) -> Iterable: def steps(self) -> Iterable:
@@ -195,12 +175,14 @@ class PotatoFactory(FactoryBase):
def __new__(cls, *args, **kwargs): def __new__(cls, *args, **kwargs):
if cls is PotatoFactory: if cls is PotatoFactory:
raise TypeError(f"'{cls.__name__}' does not support direct instantiation") ERR_MSG = f"'{cls.__name__}' does not support direct instantiation"
raise TypeError(ERR_MSG)
return object.__new__(cls) return object.__new__(cls)
def __init__(self, kind_id: str, **kwargs): def __init__(self, kind_id: str, **kwargs):
super().__init__(kind_id, **kwargs) super().__init__(kind_id, **kwargs)
[step()._pinfo(step.__name__) for step in self.steps] for step in self.steps:
step()
@property @property
def steps(self) -> Iterable: def steps(self) -> Iterable:
@@ -226,7 +208,8 @@ def remote_factory(kind_id: str, **kwargs) -> Remote:
case 'potato': case 'potato':
_factory = PotatoFactory _factory = PotatoFactory
case _: case _:
raise ValueError(f"Unknown Voicemeeter kind '{kind_id}'") ERR_MSG = f'Unknown Voicemeeter kind {kind_id}, expected one of {[k.name.lower() for k in KindId]}'
raise ValueError(ERR_MSG)
return type(f'Remote{kind_id.capitalize()}', (_factory,), {})(kind_id, **kwargs) return type(f'Remote{kind_id.capitalize()}', (_factory,), {})(kind_id, **kwargs)
@@ -243,6 +226,6 @@ def request_remote_obj(kind_id: str, **kwargs) -> Remote:
try: try:
REMOTE_obj = remote_factory(kind_id, **kwargs) REMOTE_obj = remote_factory(kind_id, **kwargs)
except (ValueError, TypeError) as e: except (ValueError, TypeError) as e:
logger_entry.exception(f'{type(e).__name__}: {e}') logger_entry.error(f'{type(e).__name__}: {e}')
raise VMError(str(e)) from e raise VMError(str(e)) from e
return REMOTE_obj return REMOTE_obj

View File

@@ -1,15 +1,22 @@
import ctypes as ct import ctypes as ct
import platform import platform
import winreg
from pathlib import Path from pathlib import Path
from .error import InstallError from .error import InstallError, VMError
try:
import winreg
except ImportError as e:
ERR_MSG = 'winreg module not found, only Windows OS supported'
raise VMError(ERR_MSG) from e
# Defense against edge cases where winreg imports but we're not on Windows
if platform.system() != 'Windows':
ERR_MSG = f'Unsupported OS: {platform.system()}, only Windows OS supported'
raise VMError(ERR_MSG)
BITS = 64 if ct.sizeof(ct.c_void_p) == 8 else 32 BITS = 64 if ct.sizeof(ct.c_void_p) == 8 else 32
if platform.system() != 'Windows':
raise InstallError('Only Windows OS supported')
VM_KEY = 'VB:Voicemeeter {17359A74-1236-5467}' VM_KEY = 'VB:Voicemeeter {17359A74-1236-5467}'
REG_KEY = '\\'.join( REG_KEY = '\\'.join(
@@ -37,12 +44,14 @@ def get_vmpath():
try: try:
vm_parent = Path(get_vmpath()).parent vm_parent = Path(get_vmpath()).parent
except FileNotFoundError as e: except FileNotFoundError as e:
raise InstallError('Unable to fetch DLL path from the registry') from e ERR_MSG = 'Unable to fetch DLL path from the registry'
raise InstallError(ERR_MSG) from e
DLL_NAME = f'VoicemeeterRemote{"64" if BITS == 64 else ""}.dll' DLL_NAME = f'VoicemeeterRemote{"64" if BITS == 64 else ""}.dll'
dll_path = vm_parent.joinpath(DLL_NAME) dll_path = vm_parent.joinpath(DLL_NAME)
if not dll_path.is_file(): if not dll_path.is_file():
raise InstallError(f'Could not find {dll_path}') ERR_MSG = f'Could not find {dll_path}'
raise InstallError(ERR_MSG)
libc = ct.CDLL(str(dll_path)) libc = ct.WinDLL(str(dll_path))

View File

@@ -7,7 +7,7 @@ class Subject:
def __init__(self): def __init__(self):
"""Adds support for observers and callbacks""" """Adds support for observers and callbacks"""
self._observers = list() self._observers = []
self.logger = logger.getChild(self.__class__.__name__) self.logger = logger.getChild(self.__class__.__name__)
@property @property
@@ -34,15 +34,13 @@ class Subject:
for o in iterator: for o in iterator:
if o not in self._observers: if o not in self._observers:
self._observers.append(o) self._observers.append(o)
self.logger.info(f'{o} added to event observers')
else: else:
self.logger.error(f'Failed to add {o} to event observers') self.logger.debug(f'Observer {o} already in observers list')
except TypeError: except TypeError:
if observer not in self._observers: if observer not in self._observers:
self._observers.append(observer) self._observers.append(observer)
self.logger.info(f'{observer} added to event observers')
else: else:
self.logger.error(f'Failed to add {observer} to event observers') self.logger.debug(f'Observer {observer} already in observers list')
register = add register = add
@@ -54,15 +52,13 @@ class Subject:
for o in iterator: for o in iterator:
try: try:
self._observers.remove(o) self._observers.remove(o)
self.logger.info(f'{o} removed from event observers')
except ValueError: except ValueError:
self.logger.error(f'Failed to remove {o} from event observers') self.logger.debug(f'Observer {o} not found in observers list')
except TypeError: except TypeError:
try: try:
self._observers.remove(observer) self._observers.remove(observer)
self.logger.info(f'{observer} removed from event observers')
except ValueError: except ValueError:
self.logger.error(f'Failed to remove {observer} from event observers') self.logger.debug(f'Observer {observer} not found in observers list')
deregister = remove deregister = remove