Compare commits

..

No commits in common. "84fdd94559d8076760e4ce9da92bc264a45c0010" and "ce7cda100fe810f550857c5450e13f010fb43d1e" have entirely different histories.

3 changed files with 31 additions and 132 deletions

View File

@ -842,7 +842,7 @@ True iff a level has been updated.
### Errors ### Errors
- `errors.VMError`: Base custom exception class. - `errors.VMError`: Exception raised when general errors occur.
- `errors.InstallError`: Exception raised when installation errors occur. - `errors.InstallError`: Exception raised when installation errors occur.
- `errors.CAPIError`: Exception raised when the C-API returns error values. - `errors.CAPIError`: Exception raised when the C-API returns error values.
- The following attributes are available: - The following attributes are available:

View File

@ -1,8 +1,6 @@
import argparse import argparse
import logging import logging
import time import time
from abc import ABC, abstractmethod
from enum import IntEnum
from pyparsing import ( from pyparsing import (
Combine, Combine,
@ -12,88 +10,24 @@ from pyparsing import (
Suppress, Suppress,
Word, Word,
alphanums, alphanums,
alphas,
nums, nums,
) )
import voicemeeterlib import voicemeeterlib
logging.basicConfig(level=logging.DEBUG) logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
argparser = argparse.ArgumentParser(description="creates a basic dsl") argparser = argparse.ArgumentParser(description="creates a basic dsl")
argparser.add_argument("-i", action="store_true") argparser.add_argument("-i", action="store_true")
args = argparser.parse_args() args = argparser.parse_args()
ParamKinds = IntEnum(
"ParamKinds",
"bool float string",
)
class Strategy(ABC):
def __init__(self, target, param, val):
self.target = target
self.param = param
self.val = val
@abstractmethod
def run(self):
pass
class BoolStrategy(Strategy):
def run(self):
setattr(self.target, self.param, self.strtobool(self.val))
def strtobool(self, val):
"""Convert a string representation of truth to it's numeric form."""
val = val.lower()
if val in ("y", "yes", "t", "true", "on", "1"):
return 1
elif val in ("n", "no", "f", "false", "off", "0"):
return 0
else:
raise ValueError("invalid truth value %r" % (val,))
class FloatStrategy(Strategy):
def run(self):
setattr(self.target, self.param, float(self.val))
class StringStrategy(Strategy):
def run(self):
setattr(self.target, self.param, " ".join(self.val))
class Context:
def __init__(self, strategy: Strategy) -> None:
self._strategy = strategy
@property
def strategy(self) -> Strategy:
return self._strategy
@strategy.setter
def strategy(self, strategy: Strategy) -> None:
self._strategy = strategy
def run(self):
self.strategy.run()
class Parser: class Parser:
IS_STRING = ("label",)
def __init__(self, vm): def __init__(self, vm):
self.logger = logger.getChild(self.__class__.__name__)
self.vm = vm self.vm = vm
self.kls = Group(OneOrMore(Word(alphanums))) self.kls = Group(OneOrMore(Word(alphanums)))
self.token = Suppress("->") self.token = Suppress("->")
self.param = Group(OneOrMore(Word(alphanums))) self.param = Word(alphanums)
self.value = Combine( self.value = Combine(
Optional("-") + Word(nums) + Optional(".") + Optional(Word(nums)) Optional("-") + Word(nums) + Optional(".") + Optional(Word(nums))
) | Group(OneOrMore(Word(alphanums))) ) | Group(OneOrMore(Word(alphanums)))
@ -105,64 +39,27 @@ class Parser:
+ Optional(self.value) + Optional(self.value)
) )
def converter(self, cmds): def parse(self, cmds):
"""determines the kind of parameter from the parsed string"""
res = list() res = list()
for cmd in cmds: for cmd in cmds:
self.logger.debug(f"running command: {cmd}") if len(self.event.parseString(cmd)) == 2:
match cmd_parsed := self.event.parseString(cmd): kls, param = self.event.parseString(cmd)
case [[kls, index], [param]]: target = getattr(self.vm, kls[0])[int(kls[-1])]
target = getattr(self.vm, kls)[int(index)]
res.append(getattr(target, param)) res.append(getattr(target, param))
case [[kls, index], [param], val] if param in self.IS_STRING: elif len(self.event.parseString(cmd)) == 3:
target = getattr(self.vm, kls)[int(index)] kls, param, val = self.event.parseString(cmd)
context = self._get_context(ParamKinds.string, target, param, val) target = getattr(self.vm, kls[0])[int(kls[-1])]
context.run() if "".join(val) in ["off", "on"]:
case [[kls, index], [param], [val] | val]: setattr(target, param, bool(["off", "on"].index("".join(val))))
target = getattr(self.vm, kls)[int(index)] elif param in ["gain", "comp", "gate", "limit", "audibility"]:
try: setattr(target, param, float("".join(val)))
context = self._get_context(ParamKinds.bool, target, param, val) elif param in ["label"]:
context.run() setattr(target, param, " ".join(val))
except ValueError as e:
self.logger.error(f"{e}... switching to float strategy")
context.strategy = FloatStrategy(target, param, val)
context.run()
case [
[kls, index],
[secondary, param],
[val] | val,
]:
primary = getattr(self.vm, kls)[int(index)]
target = getattr(primary, secondary)
try:
context = self._get_context(ParamKinds.bool, target, param, val)
context.run()
except ValueError as e:
self.logger.error(f"{e}... switching to float strategy")
context.strategy = FloatStrategy(target, param, val)
context.run()
case _:
self.logger.error(
f"unable to determine the kind of parameter from {cmd_parsed}"
)
time.sleep(0.05) time.sleep(0.05)
return res return res
def _get_context(self, kind, *args):
"""
determines a strategy for a kind of parameter and passes it to the context.
"""
match kind:
case ParamKinds.bool:
context = Context(BoolStrategy(*args))
case ParamKinds.float:
context = Context(FloatStrategy(*args))
case ParamKinds.string:
context = Context(StringStrategy(*args))
return context
def interactive_mode(parser): def interactive_mode(parser):
while cmd := input("Please enter command (Press <Enter> to exit)\n"): while cmd := input("Please enter command (Press <Enter> to exit)\n"):
@ -173,23 +70,25 @@ def interactive_mode(parser):
def main(): def main():
# fmt: off # fmt: off
cmds = ( cmds = (
"strip 0 -> mute -> true", "strip 0 -> mute", "bus 0 -> mute -> true", "strip 0 -> mute -> on", "strip 0 -> mute", "bus 0 -> mute -> on",
"strip 0 -> mute -> false", "bus 0 -> mute -> true", "strip 3 -> solo -> true", "strip 0 -> mute -> off", "bus 0 -> mute -> on", "strip 3 -> solo -> on",
"strip 3 -> solo -> false", "strip 1 -> A1 -> true", "strip 1 -> A1", "strip 3 -> solo -> off", "strip 1 -> A1 -> on", "strip 1 -> A1",
"strip 1 -> A1 -> false", "strip 1 -> A1", "strip 3 -> eq on -> true", "strip 1 -> A1 -> off", "strip 1 -> A1", "bus 3 -> eq -> on",
"bus 3 -> eq on -> false", "strip 4 -> gain -> 1.2", "strip 0 -> gain -> -8.2", "bus 3 -> eq -> off", "strip 4 -> gain -> 1.2", "strip 0 -> gain -> -8.2",
"strip 0 -> gain", "strip 1 -> label -> rode podmic", "strip 2 -> limit -> -28", "strip 0 -> gain", "strip 1 -> label -> rode podmic", "strip 2 -> limit -> -28",
"strip 2 -> limit", "strip 3 -> comp knob -> 3.8" "strip 2 -> limit",
) )
# fmt: on # fmt: on
with voicemeeterlib.api("potato") as vm: KIND_ID = "banana"
with voicemeeterlib.api(KIND_ID) as vm:
parser = Parser(vm) parser = Parser(vm)
if args.i: if args.i:
interactive_mode(parser) interactive_mode(parser)
return return
if res := parser.converter(cmds): if res := parser.parse(cmds):
print(res) print(res)

View File

@ -1,5 +1,5 @@
class VMError(Exception): class VMError(Exception):
"""Base voicemeeterlib exception class.""" """Base VM Exception class. Raised when general errors occur."""
class InstallError(VMError): class InstallError(VMError):