Files @ 92d97e17ca31
Branch filter:

Location: light9/light9/effect/sequencer/eval_faders.py

drewp@bigasterisk.com
big effecteval rewrite
import logging
import time
from dataclasses import dataclass
from typing import List, Optional, cast

from prometheus_client import Summary
from light9.effect.effect_function_library import EffectFunctionLibrary
from light9.effect.effecteval2 import EffectEval2

from rdfdb import SyncedGraph
from rdflib import URIRef
from rdflib.term import Node

from light9.effect.settings import DeviceSettings, EffectSettings
from light9.metrics import metrics
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', '')

@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.graph.addHandler(self._compile)
        self.lastLoopSucceeded = False

    @COMPILE.time()
    def _compile(self) -> None:
        """rebuild our data from the graph"""
        self.faders = []
        for fader in self.graph.subjects(RDF.type, L9['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'])
            self.faders.append(Fader(self.graph, self.lib, cast(URIRef, fader), effect, setAttr))

        # this could go in a second, smaller addHandler call to avoid rebuilding Fader objs constantly
        for f in self.faders:
            setting = typedValue(Node, self.graph, f.uri, L9['setting'])            
            f.value = typedValue(float, self.graph, setting, L9['value'])

    def computeOutput(self) -> DeviceSettings:
        faderEffectOutputs: List[DeviceSettings] = []
        now = UnixTime(time.time())
        for f in self.faders:
            if f.value is None:
                raise TypeError('f.value should be set by now')
            effectSettings = EffectSettings(self.graph, [(f.effect, f.setEffectAttr, f.value)])

            ds = f.ee.compute(now, effectSettings)
            faderEffectOutputs.append(ds)

        return DeviceSettings.merge(self.graph, faderEffectOutputs)