# HG changeset patch
# User drewp@bigasterisk.com
# Date 2023-05-20 23:32:16
# Node ID ffae830fda129db31e295319717d3b7efe932050
# Parent 51c670ce5d502862df82281fe1e2bcae2a222e4a
reformat
diff --git a/light9/effect/effecteval.py b/light9/effect/effecteval.py
--- a/light9/effect/effecteval.py
+++ b/light9/effect/effecteval.py
@@ -1,21 +1,21 @@
-from dataclasses import dataclass
import logging
import math
import random
from colorsys import hsv_to_rgb
-from typing import Any, Dict, Tuple
-from light9.effect.simple_outputs import SimpleOutputs
-from light9.newtypes import DeviceAttr, DeviceUri, EffectAttr, EffectClass, VTUnion
+from dataclasses import dataclass
+from typing import Dict, Tuple
from noise import pnoise1
from PIL import Image
-from rdflib import Literal, Namespace, URIRef
+from rdfdb.syncedgraph.syncedgraph import SyncedGraph
+from rdflib import Literal, Namespace
from webcolors import hex_to_rgb, rgb_to_hex
from light9.effect.scale import scale
-from light9.effect.settings import BareEffectSettings, DeviceSettings, EffectSettings
+from light9.effect.settings import BareEffectSettings, EffectSettings
+from light9.effect.simple_outputs import SimpleOutputs
from light9.namespaces import DEV, L9
-from rdfdb.syncedgraph.syncedgraph import SyncedGraph
+from light9.newtypes import (DeviceAttr, DeviceUri, EffectAttr, EffectClass, VTUnion)
SKY = Namespace('http://light9.bigasterisk.com/theater/skyline/device/')
@@ -28,7 +28,7 @@ log.info("reload effecteval")
def literalColor(rnorm, gnorm, bnorm):
return Literal(rgb_to_hex((
int(rnorm * 255), #
- int(gnorm * 255), #
+ int(gnorm * 255), #
int(bnorm * 255))))
diff --git a/light9/effect/scale.py b/light9/effect/scale.py
--- a/light9/effect/scale.py
+++ b/light9/effect/scale.py
@@ -1,6 +1,7 @@
+from decimal import Decimal
+
from rdflib import Literal
-from decimal import Decimal
-from webcolors import rgb_to_hex, hex_to_rgb
+from webcolors import hex_to_rgb, rgb_to_hex
def scale(value, strength):
@@ -21,7 +22,7 @@ def scale(value, strength):
sr, sg, sb = [v / 255 for v in hex_to_rgb(strength)]
else:
sr = sg = sb = strength
- return rgb_to_hex([int(r * sr), int(g * sg), int(b * sb)])
+ return rgb_to_hex((int(r * sr), int(g * sg), int(b * sb)))
elif isinstance(value, (int, float)):
return value * strength
diff --git a/light9/effect/sequencer/eval_faders.py b/light9/effect/sequencer/eval_faders.py
--- a/light9/effect/sequencer/eval_faders.py
+++ b/light9/effect/sequencer/eval_faders.py
@@ -18,7 +18,7 @@ log = logging.getLogger('seq.fader')
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,
@@ -53,7 +53,7 @@ class FaderEval:
def compileGraph(self) -> None:
"""rebuild our data from the graph"""
self.notes = []
- for fader in self.graph.subjects(RDF.type, L9['Fader']):
+ for fader in self.graph.subjects(RDF.type, L9['Fader']):
def compileFader() -> Note:
return self.compileFader(cast(URIRef, fader))
@@ -64,9 +64,9 @@ class FaderEval:
@metrics('compile_fader').time()
def compileFader(self, fader: URIRef) -> Note:
- return Note(self.graph, cast(NoteUri, fader),
+ return Note(self.graph, cast(NoteUri, fader),
timed=False)
-
+
def computeOutput(self) -> DeviceSettings:
notesSettings = []
now = UnixTime(time.time())
@@ -78,7 +78,7 @@ class FaderEval:
ee = effecteval.EffectEval(self.graph, note.effectClass, self.simpleOutputs)
deviceSettings, report = ee.outputFromEffect(
- effectSettings,
+ effectSettings,
songTime=now, # probably wrong
noteTime=now, # wrong
)
diff --git a/light9/effect/sequencer/eval_faders_test.py b/light9/effect/sequencer/eval_faders_test.py
--- a/light9/effect/sequencer/eval_faders_test.py
+++ b/light9/effect/sequencer/eval_faders_test.py
@@ -1,10 +1,10 @@
from unittest import mock
+
from light9.effect.sequencer.eval_faders import FaderEval
from light9.effect.settings import DeviceSettings
from light9.mock_syncedgraph import MockSyncedGraph
from light9.namespaces import L9
-
PREFIXES = '''
@prefix : .
@prefix effect: .
@@ -16,46 +16,48 @@ PREFIXES = '''
'''
NOTE_GRAPH = PREFIXES + '''
- :brightness
- a :DeviceAttr;
- rdfs:label "brightness";
+ :brightness
+ a :DeviceAttr;
+ rdfs:label "brightness";
:dataType :scalar .
:strength
a :EffectAttr;
rdfs:label "strength" .
- :SimpleDimmer
- a :DeviceClass;
+ :SimpleDimmer
+ a :DeviceClass;
rdfs:label "SimpleDimmer";
:deviceAttr :brightness;
:attr [ :outputAttr :level; :dmxOffset 0 ] .
-
- :light1
+
+ :light1
a :SimpleDimmer;
:dmxUniverse dmxA:;
:dmxBase 178 .
- effect:effect1
- a :EffectClass;
+ effect:effect1
+ a :Effect;
:setting effect:effect1_set1 .
- effect:effect1_set1
- :device :light1;
- :deviceAttr :brightness;
+ effect:effect1_set1
+ :device :light1;
+ :deviceAttr :brightness;
:scaledValue 0.5 .
- :fade1
- a :Fader;
- :effectClass effect:effect1;
- :effectAttr :strength;
+ :fade1
+ a :Fader;
+ :effectClass effect:effect1;
+ :effectAttr :strength;
:value 0.6 .
'''
+
class TestFaderEval:
+
def test_faderValueScalesEffectSettings(self):
g = MockSyncedGraph(NOTE_GRAPH)
sender = mock.MagicMock()
-
+
f = FaderEval(g, sender)
devSettings = f.computeOutput()
assert devSettings == DeviceSettings(g, [(L9['light1'], L9['brightness'], 0.3)])
\ No newline at end of file
diff --git a/light9/effect/sequencer/note.py b/light9/effect/sequencer/note.py
--- a/light9/effect/sequencer/note.py
+++ b/light9/effect/sequencer/note.py
@@ -1,18 +1,16 @@
import bisect
-from dataclasses import dataclass
import logging
import time
+from dataclasses import dataclass
from decimal import Decimal
from typing import Any, Dict, List, Optional, Tuple, Union, cast
-from light9.effect.effecteval import EffectEval
-from light9.effect.settings import BareEffectSettings, DeviceSettings, EffectSettings
-from light9.effect.simple_outputs import SimpleOutputs
from rdfdb.syncedgraph.syncedgraph import SyncedGraph
-from rdflib import Literal, URIRef
+from rdflib import Literal
+from light9.effect.settings import BareEffectSettings
from light9.namespaces import L9
-from light9.newtypes import Curve, DeviceAttr, EffectAttr, EffectClass, NoteUri, VTUnion, typedValue
+from light9.newtypes import (Curve, EffectAttr, EffectClass, NoteUri, VTUnion, typedValue)
log = logging.getLogger('sequencer')
@@ -33,20 +31,20 @@ def prettyFormat(x: Union[float, str]):
@dataclass
class Note:
"""A Note outputs EffectAttr settings.
-
+
Sample graph:
:note1 a :Note; :curve :n1c1; :effectClass effect:allcolor;
It can animate the EffectAttr settings over time, in two ways:
- * a `timed note` has an envelope curve that animates
+ * a `timed note` has an envelope curve that animates
the :strength EffectAttr over time
- * an `untimed note` has no curve, a fixed strength, but
- still passes the wall clock time to its effect so the
+ * an `untimed note` has no curve, a fixed strength, but
+ still passes the wall clock time to its effect so the
effect can include animation. A `Fader` is an untimed note.
-
- This obj is immutable, I think, but the graph can change,
- which can affect the output. However, I think this doesn't
- do its own rebuilds, and it's up to the caller to addHandler
+
+ This obj is immutable, I think, but the graph can change,
+ which can affect the output. However, I think this doesn't
+ do its own rebuilds, and it's up to the caller to addHandler
around the creation of Note objects.
"""
graph: SyncedGraph
@@ -54,7 +52,7 @@ class Note:
# simpleOutputs: SimpleOutputs
timed: bool = True
- def __post_init__(self): # graph ok
+ def __post_init__(self): # graph ok
ec = self.graph.value(self.uri, L9['effectClass'])
if ec is None:
raise ValueError(f'note {self.uri} has no :effectClass')
@@ -70,10 +68,10 @@ class Note:
self.points.sort()
else:
self.points = []
- self.value = typedValue(float, self.graph, self.uri, L9['value'])
+ self.value = typedValue(float, self.graph, self.uri, L9['value'])
- def getBaseEffectSettings(self) -> BareEffectSettings: # graph ok
- """i think these are settings that are fixed over time,
+ def getBaseEffectSettings(self) -> BareEffectSettings: # graph ok
+ """i think these are settings that are fixed over time,
e.g. that you set in the note's body in the timeline editor
"""
out: Dict[EffectAttr, VTUnion] = {}
@@ -119,14 +117,14 @@ class Note:
return y
def outputCurrent(self): # no graph
-
+
return self._outputSettings(t=None, strength=self.value)
def _outputSettings(
self,
t: float | None,
strength: Optional[float] = None #
- ) -> Tuple[BareEffectSettings, Dict]: # no graph
+ ) -> Tuple[BareEffectSettings, Dict]: # no graph
if t is None:
if self.timed:
diff --git a/light9/effect/sequencer/note_test.py b/light9/effect/sequencer/note_test.py
--- a/light9/effect/sequencer/note_test.py
+++ b/light9/effect/sequencer/note_test.py
@@ -17,10 +17,10 @@ PREFIXES = '''
'''
FADER_GRAPH = PREFIXES + '''
- :fade1
- a :Fader;
- :effectClass effect:effect1;
- :effectAttr :strength;
+ :fade1
+ a :Fader;
+ :effectClass effect:effect1;
+ :effectAttr :strength;
:value 0.6 .
'''
@@ -36,39 +36,38 @@ class TestUntimedFaderNote:
NOTE_GRAPH = PREFIXES + '''
- :brightness
- a :DeviceAttr;
- rdfs:label "brightness";
- :dataType :scalar .
+ :brightness
+ a :DeviceAttr;
+ rdfs:label "brightness";
+ :dataType :scalar .
- :strength
- a :EffectAttr;
- rdfs:label "strength" .
+ :strength
+ a :EffectAttr;
+ rdfs:label "strength" .
+
+ :SimpleDimmer
+ a :DeviceClass;
+ rdfs:label "SimpleDimmer";
+ :deviceAttr :brightness;
+ :attr [ :outputAttr :level; :dmxOffset 0 ] .
- :SimpleDimmer
- a :DeviceClass;
- rdfs:label "SimpleDimmer";
- :deviceAttr :brightness;
- :attr [ :outputAttr :level; :dmxOffset 0 ] .
-
- dev:light1
- a :SimpleDimmer;
- :dmxUniverse dmxA:;
- :dmxBase 178 .
+ dev:light1
+ a :SimpleDimmer;
+ :dmxUniverse dmxA:;
+ :dmxBase 178 .
- effect:effect1
- a :EffectClass;
- :setting effect:effect1_set1 .
- effect:effect1_set1
- :device dev:light1;
- :deviceAttr :brightness;
- :scaledValue 0.5 .
- :fade1
- a :Fader;
- :effectClass effect:effect1;
- :effectAttr :strength;
- :value 0.6 .
-
+ effect:effect1
+ a :EffectClass;
+ :setting effect:effect1_set1 .
+ effect:effect1_set1
+ :device dev:light1;
+ :deviceAttr :brightness;
+ :scaledValue 0.5 .
+ :fade1
+ a :Fader;
+ :effectClass effect:effect1;
+ :effectAttr :strength;
+ :value 0.6 .
'''
diff --git a/light9/effect/sequencer/service.py b/light9/effect/sequencer/service.py
--- a/light9/effect/sequencer/service.py
+++ b/light9/effect/sequencer/service.py
@@ -45,23 +45,28 @@ async def changes():
async def send_page_updates(request):
return EventSourceResponse(changes())
+
###################################################################
-async def _send_one(faders:FaderEval):
+async def _send_one(faders: FaderEval):
ds = faders.computeOutput()
await sendToCollector('effectSequencer', session='0', settings=ds)
+
async def _forever(faders):
while True:
await _send_one(faders)
await asyncio.sleep(0.1)
+
def send_updates_forever(faders):
asyncio.create_task(_forever(faders))
+
####################################################################
+
def main():
session = 'effectSequencer'
graph = SyncedGraph(networking.rdfdb.url, "effectSequencer")
diff --git a/light9/effect/sequencer/service_test.py b/light9/effect/sequencer/service_test.py
--- a/light9/effect/sequencer/service_test.py
+++ b/light9/effect/sequencer/service_test.py
@@ -1,5 +1,5 @@
+import asyncio
-import asyncio
from light9.run_local import log
diff --git a/light9/effect/settings.py b/light9/effect/settings.py
--- a/light9/effect/settings.py
+++ b/light9/effect/settings.py
@@ -10,16 +10,16 @@ from __future__ import annotations
import decimal
import logging
from dataclasses import dataclass
-from typing import Any, Dict, Iterable, List, Sequence, Set, Tuple, Union, cast
-from light9.localsyncedgraph import LocalSyncedGraph
+from typing import Any, Dict, Iterable, List, Sequence, Set, Tuple, cast
import numpy
+from rdfdb.syncedgraph.syncedgraph import SyncedGraph
from rdflib import Literal, URIRef
from light9.collector.device import resolve
+from light9.localsyncedgraph import LocalSyncedGraph
from light9.namespaces import L9, RDF
-from light9.newtypes import DeviceAttr, DeviceUri, EffectAttr, HexColor, VTUnion
-from rdfdb.syncedgraph.syncedgraph import SyncedGraph
+from light9.newtypes import (DeviceAttr, DeviceUri, EffectAttr, HexColor, VTUnion)
log = logging.getLogger('settings')
diff --git a/light9/effect/settings_test.py b/light9/effect/settings_test.py
--- a/light9/effect/settings_test.py
+++ b/light9/effect/settings_test.py
@@ -1,18 +1,19 @@
+import unittest
from typing import cast
-import unittest
-from light9.newtypes import DeviceAttr, DeviceUri, HexColor, VTUnion
+
+from rdfdb.patch import Patch
from rdflib import Literal
-from rdfdb.patch import Patch
+
+from light9.effect.settings import DeviceSettings
from light9.localsyncedgraph import LocalSyncedGraph
-from light9.namespaces import L9, DEV
-from light9.effect.settings import DeviceSettings
+from light9.namespaces import DEV, L9
+from light9.newtypes import DeviceAttr, DeviceUri, HexColor, VTUnion
class TestDeviceSettings(unittest.TestCase):
def setUp(self):
- self.graph = LocalSyncedGraph(
- files=['test/cam/lightConfig.n3', 'test/cam/bg.n3'])
+ self.graph = LocalSyncedGraph(files=['test/cam/lightConfig.n3', 'test/cam/bg.n3'])
def testToVectorZero(self):
ds = DeviceSettings(self.graph, [])
@@ -31,14 +32,12 @@ class TestDeviceSettings(unittest.TestCa
self.assertFalse(s1 != s2)
def testMissingFieldsEqZero(self):
- self.assertEqual(
- DeviceSettings(self.graph, [
- (L9['aura1'], L9['rx'], 0),
- ]), DeviceSettings(self.graph, []))
+ self.assertEqual(DeviceSettings(self.graph, [
+ (L9['aura1'], L9['rx'], 0),
+ ]), DeviceSettings(self.graph, []))
def testFalseIfZero(self):
- self.assertTrue(
- DeviceSettings(self.graph, [(L9['aura1'], L9['rx'], 0.1)]))
+ self.assertTrue(DeviceSettings(self.graph, [(L9['aura1'], L9['rx'], 0.1)]))
self.assertFalse(DeviceSettings(self.graph, []))
def testFromResource(self):
@@ -56,27 +55,20 @@ class TestDeviceSettings(unittest.TestCa
]))
s = DeviceSettings.fromResource(self.graph, DeviceUri(L9['foo']))
- self.assertEqual(
- DeviceSettings(self.graph, [
- (L9['light1'], L9['brightness'], 0.1),
- (L9['light1'], L9['speed'], 0.2),
- ]), s)
+ self.assertEqual(DeviceSettings(self.graph, [
+ (L9['light1'], L9['brightness'], 0.1),
+ (L9['light1'], L9['speed'], 0.2),
+ ]), s)
def testToVector(self):
v = DeviceSettings(self.graph, [
(DeviceUri(DEV['aura1']), DeviceAttr(L9['rx']), 0.5),
(DeviceUri(DEV['aura1']), DeviceAttr(L9['color']), HexColor('#00ff00')),
]).toVector()
- self.assertEqual([
- 0, 1, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
- ], v)
+ self.assertEqual([0, 1, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], v)
def testFromVector(self):
- s = DeviceSettings.fromVector(self.graph, [
- 0, 1, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
- ])
+ s = DeviceSettings.fromVector(self.graph, [0, 1, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
self.assertEqual(
DeviceSettings(self.graph, [
@@ -86,7 +78,7 @@ class TestDeviceSettings(unittest.TestCa
def testAsList(self):
sets = [
- (DeviceUri(L9['light1']), DeviceAttr(L9['attr2']), cast(VTUnion,0.3)),
+ (DeviceUri(L9['light1']), DeviceAttr(L9['attr2']), cast(VTUnion, 0.3)),
(DeviceUri(L9['light1']), DeviceAttr(L9['attr1']), 0.5),
]
self.assertCountEqual(sets, DeviceSettings(self.graph, sets).asList())
@@ -132,22 +124,15 @@ ZOOM = L9['zoom']
class TestFromBlend(unittest.TestCase):
def setUp(self):
- self.graph = LocalSyncedGraph(
- files=['test/cam/lightConfig.n3', 'test/cam/bg.n3'])
+ self.graph = LocalSyncedGraph(files=['test/cam/lightConfig.n3', 'test/cam/bg.n3'])
def testSingle(self):
- self.assertEqual(
- DeviceSettings(self.graph, [(L1, ZOOM, 0.5)]),
- DeviceSettings.fromBlend(
- self.graph,
- [(1, DeviceSettings(self.graph, [(L1, ZOOM, 0.5)]))]))
+ self.assertEqual(DeviceSettings(self.graph, [(L1, ZOOM, 0.5)]),
+ DeviceSettings.fromBlend(self.graph, [(1, DeviceSettings(self.graph, [(L1, ZOOM, 0.5)]))]))
def testScale(self):
- self.assertEqual(
- DeviceSettings(self.graph, [(L1, ZOOM, 0.1)]),
- DeviceSettings.fromBlend(
- self.graph,
- [(.2, DeviceSettings(self.graph, [(L1, ZOOM, 0.5)]))]))
+ self.assertEqual(DeviceSettings(self.graph, [(L1, ZOOM, 0.1)]),
+ DeviceSettings.fromBlend(self.graph, [(.2, DeviceSettings(self.graph, [(L1, ZOOM, 0.5)]))]))
def testMixFloats(self):
self.assertEqual(
diff --git a/light9/effect/simple_outputs.py b/light9/effect/simple_outputs.py
--- a/light9/effect/simple_outputs.py
+++ b/light9/effect/simple_outputs.py
@@ -12,7 +12,7 @@ log = logging.getLogger('simple')
class SimpleOutputs:
"""
- Watches graph for effects that are just fading output attrs.
+ Watches graph for effects that are just fading output attrs.
Call `values` to get (dev,attr):value settings.
"""
@@ -25,7 +25,7 @@ class SimpleOutputs:
self.graph.addHandler(self.updateEffectsFromGraph)
def updateEffectsFromGraph(self):
- self.effectOutputs={}
+ self.effectOutputs = {}
for effect in self.graph.subjects(RDF.type, L9['Effect']):
log.debug(f' {effect=}')
settings = []
diff --git a/light9/newtypes.py b/light9/newtypes.py
--- a/light9/newtypes.py
+++ b/light9/newtypes.py
@@ -1,5 +1,6 @@
import decimal
-from typing import Tuple, NewType, Type, TypeVar, Union, cast
+from typing import NewType, Tuple, Type, TypeVar, Union, cast
+
from rdflib import URIRef
from rdflib.term import Node
@@ -12,7 +13,7 @@ DeviceClass = NewType('DeviceClass', URI
DmxIndex = NewType('DmxIndex', int) # 1..512
DmxMessageIndex = NewType('DmxMessageIndex', int) # 0..511
DeviceAttr = NewType('DeviceAttr', URIRef) # e.g. :rx
-EffectClass = NewType('EffectClass', URIRef) # e.g. effect:chase
+EffectClass = NewType('EffectClass', URIRef) # e.g. effect:chase
EffectAttr = NewType('EffectAttr', URIRef) # e.g. :chaseSpeed
NoteUri = NewType('NoteUri', URIRef)
OutputAttr = NewType('OutputAttr', URIRef) # e.g. :xFine
@@ -42,7 +43,7 @@ def _isSubclass2(t1: Type, t2: Type) ->
def typedValue(objType: Type[_ObjType], graph, subj, pred) -> _ObjType:
- """graph.value(subj, pred) with a given return type.
+ """graph.value(subj, pred) with a given return type.
If objType is not an rdflib.Node, we toPython() the value."""
obj = graph.value(subj, pred)
if obj is None: