changeset 2185:bf07831a5339

refactor
author drewp@bigasterisk.com
date Fri, 19 May 2023 18:20:19 -0700
parents 7a6739063595
children 04612ba3fe45
files light9/collector/weblisteners.py light9/effect/effecteval.py light9/effect/sequencer/eval_faders.py light9/effect/sequencer/sequencer.py light9/effect/sequencer/service.py light9/effect/simple_outputs.py
diffstat 6 files changed, 121 insertions(+), 132 deletions(-) [+]
line wrap: on
line diff
--- a/light9/collector/weblisteners.py	Fri May 19 18:18:58 2023 -0700
+++ b/light9/collector/weblisteners.py	Fri May 19 18:20:19 2023 -0700
@@ -39,8 +39,7 @@
         self.clients = [(c, t) for c, t in self.clients if c != client]
         log.info('delClient %s, %s left', client, len(self.clients))
 
-    def outputAttrsSet(self, dev: DeviceUri, attrs: Dict[OutputAttr, Any], outputMap: Dict[Tuple[DeviceUri, OutputAttr], Tuple[OutputUri,
-                                                                                                                               DmxMessageIndex]]):
+    def outputAttrsSet(self, dev: DeviceUri, attrs: Dict[OutputAttr, Any], outputMap: Dict[Tuple[DeviceUri, OutputAttr], Tuple[OutputUri, DmxMessageIndex]]):
         """called often- don't be slow"""
         self.pendingMessageForDev[dev] = (attrs, outputMap)
         # maybe put on a stack for flusher or something
--- a/light9/effect/effecteval.py	Fri May 19 18:18:58 2023 -0700
+++ b/light9/effect/effecteval.py	Fri May 19 18:20:19 2023 -0700
@@ -20,10 +20,10 @@
 
 
 def literalColor(rnorm, gnorm, bnorm):
-    return Literal(
-        rgb_to_hex([int(rnorm * 255),
-                    int(gnorm * 255),
-                    int(bnorm * 255)]))
+    return Literal(rgb_to_hex((
+        int(rnorm * 255),  #
+        int(gnorm * 255),  # 
+        int(bnorm * 255))))
 
 
 def literalColorHsv(h, s, v):
@@ -82,9 +82,7 @@
         the effect code.
         """
         # both callers need to apply note overrides
-        effectSettings = dict(
-            effectSettings
-        )  # we should make everything into nice float and Color objects too
+        effectSettings = dict(effectSettings)  # we should make everything into nice float and Color objects too
 
         strength = float(effectSettings[L9['strength']])
         if strength <= 0:
@@ -93,10 +91,7 @@
         report = {}
         out: Dict[Tuple[URIRef, URIRef], Any] = {}  # (dev, attr): value
 
-        out.update(
-            self.simpleOutputs.values(
-                self.effect, strength,
-                effectSettings.get(L9['colorScale'], None)))
+        out.update(self.simpleOutputs.values(self.effect, strength, effectSettings.get(L9['colorScale'], None)))
 
         if self.effect.startswith(L9['effect/']):
             tail = 'effect_' + self.effect[len(L9['effect/']):]
@@ -112,9 +107,7 @@
 
 
 def effect_Curtain(effectSettings, strength, songTime, noteTime):
-    return {(L9['device/lowPattern%s' % n], L9['color']):
-            literalColor(strength, strength, strength)
-            for n in range(301, 308 + 1)}
+    return {(L9['device/lowPattern%s' % n], L9['color']): literalColor(strength, strength, strength) for n in range(301, 308 + 1)}
 
 
 def effect_animRainbow(effectSettings, strength, songTime, noteTime):
@@ -124,10 +117,8 @@
     tr, tg, tb = hex_to_rgb(tint)
     for n in range(1, 5 + 1):
         scl = strength * nsin(songTime + n * .3)**3
-        col = literalColor(
-            scl * lerp(nsin(songTime + n * .2), tr / 255, tintStrength),
-            scl * lerp(nsin(songTime + n * .2 + .3), tg / 255, tintStrength),
-            scl * lerp(nsin(songTime + n * .3 + .6), tb / 255, tintStrength))
+        col = literalColor(scl * lerp(nsin(songTime + n * .2), tr / 255, tintStrength), scl * lerp(nsin(songTime + n * .2 + .3), tg / 255, tintStrength),
+                           scl * lerp(nsin(songTime + n * .3 + .6), tb / 255, tintStrength))
 
         dev = L9['device/aura%s' % n]
         out.update({
@@ -136,10 +127,8 @@
         })
         ang = songTime * 4
         out.update({
-            (dev, L9['rx']):
-            lerp(.27, .7, (n - 1) / 4) + .2 * math.sin(ang + n),
-            (dev, L9['ry']):
-            lerp(.46, .52, (n - 1) / 4) + .5 * math.cos(ang + n),
+            (dev, L9['rx']): lerp(.27, .7, (n - 1) / 4) + .2 * math.sin(ang + n),
+            (dev, L9['ry']): lerp(.46, .52, (n - 1) / 4) + .5 * math.cos(ang + n),
         })
     return out
 
@@ -160,10 +149,8 @@
         })
         ang = songTime * 4
         out.update({
-            (dev, L9['rx']):
-            lerp(.27, .8, (n - 1) / 4) + .2 * math.sin(ang + n),
-            (dev, L9['ry']):
-            lerp(.46, .52, (n - 1) / 4) + .4 * math.cos(ang + n),
+            (dev, L9['rx']): lerp(.27, .8, (n - 1) / 4) + .2 * math.sin(ang + n),
+            (dev, L9['ry']): lerp(.46, .52, (n - 1) / 4) + .4 * math.cos(ang + n),
         })
     return out
 
@@ -171,8 +158,7 @@
 def effect_qpan(effectSettings, strength, songTime, noteTime):
     dev = L9['device/q2']
     dur = 4
-    col = scale(scale('#ffffff', strength),
-                effectSettings.get(L9['colorScale']) or '#ffffff')
+    col = scale(scale('#ffffff', strength), effectSettings.get(L9['colorScale']) or '#ffffff')
     return {
         (dev, L9['color']): col,
         (dev, L9['focus']): 0.589,
@@ -189,10 +175,8 @@
     tr, tg, tb = hex_to_rgb(tint)
     for n in range(1, 5 + 1):
         scl = strength
-        col = literalColor(
-            scl * lerp(nsin(songTime + n * .2), tr / 255, tintStrength),
-            scl * lerp(nsin(songTime + n * .2 + .3), tg / 255, tintStrength),
-            scl * lerp(nsin(songTime + n * .3 + .6), tb / 255, tintStrength))
+        col = literalColor(scl * lerp(nsin(songTime + n * .2), tr / 255, tintStrength), scl * lerp(nsin(songTime + n * .2 + .3), tg / 255, tintStrength),
+                           scl * lerp(nsin(songTime + n * .3 + .6), tb / 255, tintStrength))
 
         dev = L9['device/aura%s' % n]
         out.update({
@@ -248,10 +232,8 @@
             (dev, L9['zoom']): effectSettings.get(L9['zoom'], .5),
         })
         out.update({
-            (dev, L9['rx']):
-            lerp(.3, .8, nsin(songTime / period + n / 4)),
-            (dev, L9['ry']):
-            effectSettings.get(L9['ry'], .2),
+            (dev, L9['rx']): lerp(.3, .8, nsin(songTime / period + n / 4)),
+            (dev, L9['ry']): effectSettings.get(L9['ry'], .2),
         })
     return out
 
@@ -269,16 +251,12 @@
     for n in range(1, 3 + 1):
         dev = L9['device/q%s' % n]
         out.update({
-            (dev, L9['color']):
-            scale(colmap[n], effectSettings.get(L9['strength'], 1)),
-            (dev, L9['zoom']):
-            effectSettings.get(L9['zoom'], .5),
+            (dev, L9['color']): scale(colmap[n], effectSettings.get(L9['strength'], 1)),
+            (dev, L9['zoom']): effectSettings.get(L9['zoom'], .5),
         })
         out.update({
-            (dev, L9['rx']):
-            lerp(.3, .8, nsin(songTime / period + n / 4)),
-            (dev, L9['ry']):
-            effectSettings.get(L9['ry'], .5),
+            (dev, L9['rx']): lerp(.3, .8, nsin(songTime / period + n / 4)),
+            (dev, L9['ry']): effectSettings.get(L9['ry'], .5),
         })
     return out
 
@@ -379,21 +357,18 @@
     offset = 0
     f = (((songTime + offset) * rate) % 1.0)
     c = (f < duty) * strength
-    col = rgb_to_hex([int(c * 255), int(c * 255), int(c * 255)])
+    col = rgb_to_hex((int(c * 255), int(c * 255), int(c * 255)))
     return {(L9['device/colorStrip'], L9['color']): Literal(col)}
 
 
 def effect_lightning(effectSettings, strength, songTime, noteTime):
     devs = [
-        L9['device/veryLow1'], L9['device/veryLow2'], L9['device/veryLow3'],
-        L9['device/veryLow4'], L9['device/veryLow5'], L9['device/backlight1'],
-        L9['device/backlight2'], L9['device/backlight3'],
-        L9['device/backlight4'], L9['device/backlight5'], L9['device/down2'],
-        L9['device/down3'], L9['device/down4'], L9['device/hexLow3'],
-        L9['device/hexLow5'], L9['device/postL1'], L9['device/postR1']
+        L9['device/veryLow1'], L9['device/veryLow2'], L9['device/veryLow3'], L9['device/veryLow4'], L9['device/veryLow5'], L9['device/backlight1'],
+        L9['device/backlight2'], L9['device/backlight3'], L9['device/backlight4'], L9['device/backlight5'], L9['device/down2'], L9['device/down3'],
+        L9['device/down4'], L9['device/hexLow3'], L9['device/hexLow5'], L9['device/postL1'], L9['device/postR1']
     ]
     out = {}
-    col = rgb_to_hex([int(255 * strength)] * 3)
+    col = rgb_to_hex((int(255 * strength),) * 3)
     for i, dev in enumerate(devs):
         n = noise(songTime * 8 + i * 6.543)
         if n > .4:
@@ -452,7 +427,7 @@
             out[(SKY[f'cycGreen{column}'], L9['brightness'])] = color[1]
             out[(SKY[f'cycBlue{column}'], L9['brightness'])] = color[2]
         else:
-            out[(dev, L9['color'])] = rgb_to_hex(map(_8bit, color))
+            out[(dev, L9['color'])] = rgb_to_hex(tuple(map(_8bit, color)))
     return out
 
 
@@ -527,13 +502,7 @@
     gamma = .6
     for dev in [SKY['strip1'], SKY['strip2'], SKY['strip3']]:
         out[(dev, L9['color'])] = scale(
-            rgb_to_hex(
-                (_8bit(r * math.pow(max(.01, noise(speed * songTime)), gamma)),
-                 _8bit(g *
-                       math.pow(max(.01, noise(speed * songTime + 10)), gamma)),
-                 _8bit(
-                     b *
-                     math.pow(max(.01, noise(speed * songTime + 20)), gamma)))),
-            strength)
+            rgb_to_hex((_8bit(r * math.pow(max(.01, noise(speed * songTime)), gamma)), _8bit(g * math.pow(max(.01, noise(speed * songTime + 10)), gamma)),
+                        _8bit(b * math.pow(max(.01, noise(speed * songTime + 20)), gamma)))), strength)
 
     return out
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/light9/effect/sequencer/eval_faders.py	Fri May 19 18:20:19 2023 -0700
@@ -0,0 +1,81 @@
+
+import asyncio
+import logging
+import time
+from typing import Callable, Coroutine, List, cast
+from light9.effect.sequencer.sequencer import Note
+
+from rdfdb.syncedgraph.syncedgraph import SyncedGraph
+from rdflib import URIRef
+
+from light9.effect import effecteval
+from light9.effect.settings import DeviceSettings
+from light9.effect.simple_outputs import SimpleOutputs
+from light9.metrics import metrics
+from light9.namespaces import L9, RDF
+from light9.newtypes import NoteUri
+
+log = logging.getLogger('sequencer')
+class FaderEval:
+    """peer to Sequencer, but this one takes the current :Fader settings -> sendToCollector
+    
+    The current faders become Notes in here, for more code reuse.
+    """
+    def __init__(self,
+                 graph: SyncedGraph,
+                 sendToCollector: Callable[[DeviceSettings], Coroutine[None ,None,None]],
+                 ):
+        self.graph = graph
+        self.sendToCollector = sendToCollector
+
+        # Notes without times- always on
+        self.notes: List[Note] = []
+
+        self.simpleOutputs = SimpleOutputs(self.graph)
+        self.graph.addHandler(self.compileGraph)
+        self.lastLoopSucceeded = False
+
+        # self.codeWatcher = CodeWatcher(onChange=self.onCodeChange)
+        log.info('startupdating task')
+        asyncio.create_task(self.startUpdating())
+
+    async def startUpdating(self):
+        await self.graph.addAsyncHandler(self.update)
+        log.info('startupdating task done')
+
+    def onCodeChange(self):
+        log.debug('seq.onCodeChange')
+        self.graph.addHandler(self.compileGraph)
+        #self.updateLoop()
+
+    @metrics('compile_graph_fader').time()
+    def compileGraph(self) -> None:
+        """rebuild our data from the graph"""
+        self.notes = []
+        for fader in self.graph.subjects(RDF.type, L9['Fader']):          
+            def compileFader() -> Note:
+                return self.compileFader(cast(URIRef, fader))
+
+            self.notes.append(compileFader())
+        if self.notes:
+            asyncio.create_task(self.startUpdating())
+
+
+    @metrics('compile_fader').time()
+    def compileFader(self, fader: URIRef) -> Note:
+        return Note(self.graph, NoteUri(cast(NoteUri, fader)), effecteval,
+                self.simpleOutputs, timed=False)
+    
+    @metrics('update_call_fader').time()
+    async def update(self):
+        settings = []
+        for note in self.notes:
+            effectValue = self.graph.value(note.uri, L9['value'])
+            if effectValue is None:
+                log.info(f'skip note {note}, no :value')
+                continue
+            s, report = note.outputSettings(t=time.time(), strength=float(effectValue))
+            settings.append(s)
+        devSettings = DeviceSettings.fromList(self.graph, settings)
+        with metrics('update_s3_send_fader').time():  # our measurement
+            sendSecs = await self.sendToCollector(devSettings)
--- a/light9/effect/sequencer/sequencer.py	Fri May 19 18:18:58 2023 -0700
+++ b/light9/effect/sequencer/sequencer.py	Fri May 19 18:20:19 2023 -0700
@@ -158,7 +158,7 @@
             self.onChange()
 
         # in case we got an event at the start of the write
-        reactor.callLater(.1, go)
+        reactor.callLater(.1, go) # type: ignore
 
 
 class Sequencer(object):
@@ -173,7 +173,7 @@
         metrics('update_loop_goal_fps').set(self.fps)
         metrics('update_loop_goal_latency').set(1 / self.fps)
         self.sendToCollector = sendToCollector
-        self.music = MusicTime(period=.2, pollCurvecalc=False)
+        self.music = MusicTime(period=.2)
 
         self.recentUpdateTimes: List[float] = []
         self.lastStatLog = 0.0
@@ -278,67 +278,3 @@
         # (sometimes it's None, not sure why, and neither is mypy)
         #if isinstance(sendSecs, float):
         #    metrics('update_s3_send_client').observe(sendSecs)
-
-class FaderEval:
-    """peer to Sequencer, but this one takes the current :Fader settings -> sendToCollector
-    
-    The current faders become Notes in here, for more code reuse.
-    """
-    def __init__(self,
-                 graph: SyncedGraph,
-                 sendToCollector: Callable[[DeviceSettings], Coroutine[None ,None,None]],
-                 ):
-        self.graph = graph
-        self.sendToCollector = sendToCollector
-
-        # Notes without times- always on
-        self.notes: List[Note] = []
-
-        self.simpleOutputs = SimpleOutputs(self.graph)
-        self.graph.addHandler(self.compileGraph)
-        self.lastLoopSucceeded = False
-
-        # self.codeWatcher = CodeWatcher(onChange=self.onCodeChange)
-        log.info('startupdating task')
-        asyncio.create_task(self.startUpdating())
-
-    async def startUpdating(self):
-        await self.graph.addAsyncHandler(self.update)
-        log.info('startupdating task done')
-
-    def onCodeChange(self):
-        log.debug('seq.onCodeChange')
-        self.graph.addHandler(self.compileGraph)
-        #self.updateLoop()
-
-    @metrics('compile_graph_fader').time()
-    def compileGraph(self) -> None:
-        """rebuild our data from the graph"""
-        self.notes = []
-        for fader in self.graph.subjects(RDF.type, L9['Fader']):          
-            def compileFader() -> Note:
-                return self.compileFader(cast(URIRef, fader))
-
-            self.notes.append(compileFader())
-        if self.notes:
-            asyncio.create_task(self.startUpdating())
-
-
-    @metrics('compile_fader').time()
-    def compileFader(self, fader: URIRef) -> Note:
-        return Note(self.graph, NoteUri(cast(NoteUri, fader)), effecteval,
-                self.simpleOutputs, timed=False)
-    
-    @metrics('update_call_fader').time()
-    async def update(self):
-        settings = []
-        for note in self.notes:
-            effectValue = self.graph.value(note.uri, L9['value'])
-            if effectValue is None:
-                log.info(f'skip note {note}, no :value')
-                continue
-            s, report = note.outputSettings(t=time.time(), strength=float(effectValue))
-            settings.append(s)
-        devSettings = DeviceSettings.fromList(self.graph, settings)
-        with metrics('update_s3_send_fader').time():  # our measurement
-            sendSecs = await self.sendToCollector(devSettings)
--- a/light9/effect/sequencer/service.py	Fri May 19 18:18:58 2023 -0700
+++ b/light9/effect/sequencer/service.py	Fri May 19 18:20:19 2023 -0700
@@ -9,7 +9,8 @@
 
 from light9 import networking
 from light9.collector.collector_client_asyncio import sendToCollector
-from light9.effect.sequencer.sequencer import FaderEval, Sequencer, StateUpdate
+from light9.effect.sequencer.eval_faders import FaderEval
+from light9.effect.sequencer.sequencer import Sequencer, StateUpdate
 from light9.effect.settings import DeviceSettings
 from light9.metrics import metrics
 from light9.run_local import log
--- a/light9/effect/simple_outputs.py	Fri May 19 18:18:58 2023 -0700
+++ b/light9/effect/simple_outputs.py	Fri May 19 18:20:19 2023 -0700
@@ -6,13 +6,16 @@
 
 
 class SimpleOutputs(object):
+    """
+    Watches graph for effects that are just fading output attrs. 
+    Call `values` to get (dev,attr):value settings.
+    """
 
     def __init__(self, graph):
         self.graph = graph
 
         # effect : [(dev, attr, value, isScaled)]
-        self.effectOutputs: Dict[URIRef, List[
-            Tuple[URIRef, URIRef, Any, bool]]] = {}
+        self.effectOutputs: Dict[URIRef, List[Tuple[URIRef, URIRef, Any, bool]]] = {}
 
         self.graph.addHandler(self.updateEffectsFromGraph)