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 import effecteval
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
uri: URIRef
effect: EffectUri
setEffectAttr: EffectAttr
value: Optional[float]=None # mutable
def __post_init__(self):
self.ee = effecteval.EffectEval2(self.graph, self.effect)
class FaderEval:
"""peer to Sequencer, but this one takes the current :Fader settings -> sendToCollector
"""
def __init__(self,
graph: SyncedGraph,
):
self.graph = graph
self.faders: List[Fader] = []
log.info('fader adds handler')
self.graph.addHandler(self._compile)
self.lastLoopSucceeded = False
def onCodeChange(self):
log.debug('seq.onCodeChange')
self.graph.addHandler(self._compile)
@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, 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)])
if f.value < .001:
continue
faderEffectOutputs.append(f.ee.compute(effectSettings))
# ee = effecteval.EffectEval(self.graph, f.effectClass, self.simpleOutputs)
# deviceSettings, report = ee.outputFromEffect(
# effectSettings,
# songTime=now, # probably wrong
# noteTime=now, # wrong
# )
# log.info(f' 𝅘𝅥𝅮 {uriTail(f.uri)}: {effectSettings=} -> {deviceSettings=}')
# if deviceSettings:
# notesSettings.append(deviceSettings)
return DeviceSettings.merge(self.graph, faderEffectOutputs)