diff --git a/vban_cmd/factory.py b/vban_cmd/factory.py index b34256d..086c01c 100644 --- a/vban_cmd/factory.py +++ b/vban_cmd/factory.py @@ -11,6 +11,7 @@ from .error import VBANCMDError from .kinds import KindMapClass from .kinds import request_kind_map as kindmap from .macrobutton import MacroButton +from .recorder import Recorder from .strip import request_strip_obj as strip from .vban import request_vban_obj as vban from .vbancmd import VbanCmd @@ -26,7 +27,7 @@ class FactoryBuilder: """ BuilderProgress = IntEnum( - 'BuilderProgress', 'strip bus command macrobutton vban', start=0 + 'BuilderProgress', 'strip bus command macrobutton vban recorder', start=0 ) def __init__(self, factory, kind: KindMapClass): @@ -38,6 +39,7 @@ class FactoryBuilder: 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 recorder for {self._factory}', ) self.logger = logger.getChild(self.__class__.__name__) @@ -72,6 +74,10 @@ class FactoryBuilder: self._factory.vban = vban(self._factory) return self + def make_recorder(self): + self._factory.recorder = Recorder.make(self._factory) + return self + class FactoryBase(VbanCmd): """Base class for factories, subclasses VbanCmd.""" @@ -166,7 +172,7 @@ class BananaFactory(FactoryBase): @property def steps(self) -> Iterable: """steps required to build the interface for a kind""" - return self._steps + return self._steps + (self.builder.make_recorder,) class PotatoFactory(FactoryBase): @@ -188,7 +194,7 @@ class PotatoFactory(FactoryBase): @property def steps(self) -> Iterable: """steps required to build the interface for a kind""" - return self._steps + return self._steps + (self.builder.make_recorder,) def vbancmd_factory(kind_id: str, **kwargs) -> VbanCmd: diff --git a/vban_cmd/recorder.py b/vban_cmd/recorder.py new file mode 100644 index 0000000..bb6a0b2 --- /dev/null +++ b/vban_cmd/recorder.py @@ -0,0 +1,136 @@ +import os +import re + +from .error import VBANCMDError +from .iremote import IRemote +from .meta import action_fn + + +class Recorder(IRemote): + """ + Implements the common interface + + Defines concrete implementation for recorder + """ + + @classmethod + def make(cls, remote): + """ + Factory function for recorder class. + + Returns a Recorder class of a kind. + """ + Recorder_cls = type( + f'Recorder{remote.kind}', + (cls,), + { + **{ + param: action_fn(param) + for param in [ + 'play', + 'stop', + 'pause', + 'replay', + 'record', + 'ff', + 'rew', + ] + }, + }, + ) + return Recorder_cls(remote) + + def __str__(self): + return f'{type(self).__name__}' + + @property + def identifier(self) -> str: + return 'recorder' + + @property + def samplerate(self) -> int: + return + + @samplerate.setter + def samplerate(self, val: int): + opts = (22050, 24000, 32000, 44100, 48000, 88200, 96000, 176400, 192000) + if val not in opts: + self.logger.warning(f'samplerate got: {val} but expected a value in {opts}') + self.setter('samplerate', val) + + @property + def bitresolution(self) -> int: + return + + @bitresolution.setter + def bitresolution(self, val: int): + opts = (8, 16, 24, 32) + if val not in opts: + self.logger.warning( + f'bitresolution got: {val} but expected a value in {opts}' + ) + self.setter('bitresolution', val) + + @property + def channel(self) -> int: + return + + @channel.setter + def channel(self, val: int): + if not 1 <= val <= 8: + self.logger.warning(f'channel got: {val} but expected a value from 1 to 8') + self.setter('channel', val) + + @property + def kbps(self): + return + + @kbps.setter + def kbps(self, val: int): + opts = (32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320) + if val not in opts: + self.logger.warning(f'kbps got: {val} but expected a value in {opts}') + self.setter('kbps', val) + + @property + def gain(self) -> float: + return + + @gain.setter + def gain(self, val: float): + self.setter('gain', val) + + def load(self, file: os.PathLike): + try: + self.setter('load', str(file)) + except UnicodeError: + raise VBANCMDError('File full directory must be a raw string') + + def goto(self, time_str): + def get_sec(): + """Get seconds from time string""" + h, m, s = time_str.split(':') + return int(h) * 3600 + int(m) * 60 + int(s) + + time_str = str(time_str) # coerce the type + if ( + re.match( + r'^(?:[01]\d|2[0123]):(?:[012345]\d):(?:[012345]\d)$', + time_str, + ) + is not None + ): + self.setter('goto', get_sec()) + else: + self.logger.warning( + "goto expects a string that matches the format 'hh:mm:ss'" + ) + + def filetype(self, val: str): + opts = {'wav': 1, 'aiff': 2, 'bwf': 3, 'mp3': 100} + try: + self.setter('filetype', opts[val.lower()]) + except KeyError: + self.logger.warning( + f'filetype got: {val} but expected a value in {list(opts.keys())}' + )