vban-cmd-python/vban_cmd/config.py
onyx-and-iris c74d827154 update strip.{comp,gate,eq} and bus.eq
add gain=0.0 to bus params.

`Path.home() / ".config" / "vban-cmd" / kind.name` added to loader
2023-06-25 01:43:26 +01:00

208 lines
5.5 KiB
Python

import itertools
import logging
from pathlib import Path
from .error import VBANCMDError
try:
import tomllib
except ModuleNotFoundError:
import tomli as tomllib
from .kinds import request_kind_map as kindmap
logger = logging.getLogger(__name__)
class TOMLStrBuilder:
"""builds a config profile, as a string, for the toml parser"""
def __init__(self, kind):
self.kind = kind
self.higher = itertools.chain(
[f"strip-{i}" for i in range(kind.num_strip)],
[f"bus-{i}" for i in range(kind.num_bus)],
)
def init_config(self, profile=None):
self.virt_strip_params = (
[
"mute = false",
"mono = false",
"solo = false",
"gain = 0.0",
]
+ [f"A{i} = false" for i in range(1, self.kind.phys_out + 1)]
+ [f"B{i} = false" for i in range(1, self.kind.virt_out + 1)]
)
self.phys_strip_params = self.virt_strip_params + [
"comp.knob = 0.0",
"gate.knob = 0.0",
"denoiser.knob = 0.0",
"eq.on = false",
]
self.bus_float = ["gain = 0.0"]
self.bus_params = [
"mono = false",
"eq.on = false",
"mute = false",
"gain = 0.0",
]
if profile == "reset":
self.reset_config()
def reset_config(self):
self.phys_strip_params = list(
map(lambda x: x.replace("B1 = false", "B1 = true"), self.phys_strip_params)
)
self.virt_strip_params = list(
map(lambda x: x.replace("A1 = false", "A1 = true"), self.virt_strip_params)
)
def build(self, profile="reset"):
self.init_config(profile)
toml_str = str()
for eachclass in self.higher:
toml_str += f"[{eachclass}]\n"
toml_str = self.join(eachclass, toml_str)
return toml_str
def join(self, eachclass, toml_str):
kls, index = eachclass.split("-")
match kls:
case "strip":
toml_str += ("\n").join(
self.phys_strip_params
if int(index) < self.kind.phys_in
else self.virt_strip_params
)
case "bus":
toml_str += ("\n").join(self.bus_params)
case _:
pass
return toml_str + "\n"
class TOMLDataExtractor:
def __init__(self, file):
with open(file, "rb") as f:
self._data = tomllib.load(f)
@property
def data(self):
return self._data
@data.setter
def data(self, value):
self._data = value
def dataextraction_factory(file):
"""
factory function for parser
this opens the possibility for other parsers to be added
"""
if file.suffix == ".toml":
extractor = TOMLDataExtractor
else:
raise ValueError("Cannot extract data from {}".format(file))
return extractor(file)
class SingletonType(type):
"""ensure only a single instance of Loader object"""
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(SingletonType, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class Loader(metaclass=SingletonType):
"""
invokes the parser
checks if config already in memory
loads data into memory if not found
"""
def __init__(self, kind):
self._kind = kind
self.logger = logger.getChild(self.__class__.__name__)
self._configs = dict()
self.defaults(kind)
self.parser = None
def defaults(self, kind):
self.builder = TOMLStrBuilder(kind)
toml_str = self.builder.build()
self.register("reset", tomllib.loads(toml_str))
def parse(self, identifier, data):
if identifier in self._configs:
self.logger.info(
f"config file with name {identifier} already in memory, skipping.."
)
return False
self.parser = dataextraction_factory(data)
return True
def register(self, identifier, data=None):
self._configs[identifier] = data if data else self.parser.data
self.logger.info(f"config {self.name}/{identifier} loaded into memory")
def deregister(self):
self._configs.clear()
self.defaults(self._kind)
@property
def configs(self):
return self._configs
@property
def name(self):
return self._kind.name
def loader(kind):
"""
traverses defined paths for config files
directs the loader
returns configs loaded into memory
"""
logger_loader = logger.getChild("loader")
loader = Loader(kind)
for path in (
Path.cwd() / "configs" / kind.name,
Path.home() / ".config" / "vban-cmd" / kind.name,
Path.home() / "Documents" / "Voicemeeter" / "configs" / kind.name,
):
if path.is_dir():
logger_loader.info(f"Checking [{path}] for TOML config files:")
for file in path.glob("*.toml"):
identifier = file.with_suffix("").stem
if loader.parse(identifier, file):
loader.register(identifier)
return loader.configs
def request_config(kind_id: str):
"""
config entry point.
Returns all configs loaded into memory for a kind
"""
try:
configs = loader(kindmap(kind_id))
except KeyError:
raise VBANCMDError(f"Unknown Voicemeeter kind {kind_id}")
return configs