Mercurial > code > home > repos > light9
view src/light9/effect/sequencer/eval_faders.py @ 2376:4556eebe5d73
topdir reorgs; let pdm have its src/ dir; separate vite area from light9/
author | drewp@bigasterisk.com |
---|---|
date | Sun, 12 May 2024 19:02:10 -0700 |
parents | light9/effect/sequencer/eval_faders.py@b0f56292fdae |
children | bbff83207963 |
line wrap: on
line source
import traceback import logging import time from dataclasses import dataclass from typing import List, Optional, cast from prometheus_client import Summary from rdfdb import SyncedGraph from rdflib import URIRef from rdflib.term import Node from light9.effect.effect_function_library import EffectFunctionLibrary from light9.effect.effecteval2 import EffectEval2 from light9.effect.settings import DeviceSettings, EffectSettings from light9.namespaces import L9, RDF from light9.newtypes import EffectAttr, EffectUri, UnixTime from light9.typedgraph import typedValue log = logging.getLogger('seq.fader') COMPILE = Summary('compile_graph_fader', 'compile') COMPUTE_ALL_FADERS = Summary('compute_all_faders', 'compile') @dataclass class Fader: graph: SyncedGraph lib: EffectFunctionLibrary uri: URIRef effect: EffectUri setEffectAttr: EffectAttr value: Optional[float] = None # mutable def __post_init__(self): self.ee = EffectEval2(self.graph, self.effect, self.lib) class FaderEval: """peer to Sequencer, but this one takes the current :Fader settings -> sendToCollector """ def __init__(self, graph: SyncedGraph, lib: EffectFunctionLibrary): self.graph = graph self.lib = lib self.faders: List[Fader] = [] self.grandMaster = 1.0 self.graph.addHandler(self._compile) self.graph.addHandler(self._compileGm) @COMPILE.time() def _compile(self) -> None: """rebuild our data from the graph""" self.faders = [] for fader in self.graph.subjects(RDF.type, L9['Fader']): try: self.faders.append(self._compileFader(fader)) except ValueError: pass # this could go in a second, smaller addHandler call to avoid rebuilding Fader objs constantly for f in self.faders: f.value = None try: setting = typedValue(Node, self.graph, f.uri, L9['setting']) except ValueError: continue try: f.value = typedValue(float, self.graph, setting, L9['value']) except ValueError: continue def _compileFader(self, fader: URIRef) -> Fader: effect = typedValue(EffectUri, self.graph, fader, L9['effect']) setting = typedValue(Node, self.graph, fader, L9['setting']) setAttr = typedValue(EffectAttr, self.graph, setting, L9['effectAttr']) return Fader(self.graph, self.lib, cast(URIRef, fader), effect, setAttr) def _compileGm(self): try: self.grandMaster = typedValue(float, self.graph, L9.grandMaster, L9.value) except ValueError: return @COMPUTE_ALL_FADERS.time() def computeOutput(self) -> DeviceSettings: faderEffectOutputs: List[DeviceSettings] = [] now = UnixTime(time.time()) for f in self.faders: try: if f.value is None: log.warning(f'{f.value=}; should be set during _compile. Skipping {f.uri}') continue v = f.value v *= self.grandMaster effectSettings = EffectSettings(self.graph, [(f.effect, f.setEffectAttr, v)]) ds = f.ee.compute(now, effectSettings) faderEffectOutputs.append(ds) except Exception: log.warning(f'on fader {f}') traceback.print_exc() continue merged = DeviceSettings.merge(self.graph, faderEffectOutputs) # please remove (after fixing stats display to show it) log.debug("computed %s faders in %.1fms", len(self.faders), (time.time() - now) * 1000) return merged