Files
@ 2df0dc79ce76
Branch filter:
Location: light9/light9/effect/sequencer.py
2df0dc79ce76
3.4 KiB
text/x-python
modernize polymer on index page. move live and timeline to subdirs
Ignore-this: 99a836d91ddbc8117abbe04788772409
Ignore-this: 99a836d91ddbc8117abbe04788772409
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | '''
copies from effectloop.py, which this should replace
'''
from __future__ import division
from rdflib import URIRef, Literal
from twisted.internet import reactor
from twisted.internet.defer import inlineCallbacks, returnValue, succeed
from webcolors import hex_to_rgb, rgb_to_hex
import time, json, logging, traceback, bisect
from light9.namespaces import L9, RDF, RDFS
from light9.vidref.musictime import MusicTime
log = logging.getLogger('sequencer')
class Note(object):
def __init__(self, graph, uri):
g = self.graph = graph
self.uri = uri
floatVal = lambda s, p: float(g.value(s, p).toPython())
originTime = floatVal(uri, L9['originTime'])
self.points = []
for curve in g.objects(uri, L9['curve']):
if g.value(curve, L9['attr']) != L9['strength']:
continue
for point in g.objects(curve, L9['point']):
self.points.append((
originTime + floatVal(point, L9['time']),
floatVal(point, L9['value'])))
self.points.sort()
for ds in g.objects(g.value(uri, L9['effectClass']), L9['deviceSetting']):
self.setting = (g.value(ds, L9['device']), g.value(ds, L9['attr']))
def activeAt(self, t):
return self.points[0][0] <= t <= self.points[-1][0]
def evalCurve(self, t):
i = bisect.bisect_left(self.points, (t, None)) - 1
if i == -1:
return self.points[0][1]
if self.points[i][0] > t:
return self.points[i][1]
if i >= len(self.points) - 1:
return self.points[i][1]
p1, p2 = self.points[i], self.points[i + 1]
frac = (t - p1[0]) / (p2[0] - p1[0])
y = p1[1] + (p2[1] - p1[1]) * frac
return y
def outputSettings(self, t):
c = int(255 * self.evalCurve(t))
color = [0, 0, 0]
if self.setting[1] == L9['red']: # throwaway
color[0] = c
elif self.setting[1] == L9['blue']:
color[2] = c
return [
# device, attr, lev
(self.setting[0],
URIRef("http://light9.bigasterisk.com/color"),
Literal(rgb_to_hex(color)))
]
class Sequencer(object):
def __init__(self, graph, sendToCollector):
self.graph = graph
self.sendToCollector = sendToCollector
self.music = MusicTime(period=.2, pollCurvecalc=False)
self.notes = {} # song: [notes]
self.graph.addHandler(self.compileGraph)
self.update()
def compileGraph(self):
"""rebuild our data from the graph"""
g = self.graph
for song in g.subjects(RDF.type, L9['Song']):
self.notes[song] = []
for note in g.objects(song, L9['note']):
self.notes[song].append(Note(g, note))
def update(self):
reactor.callLater(1/30, self.update)
musicState = self.music.getLatest()
song = URIRef(musicState['song']) if 'song' in musicState else None
if 't' not in musicState:
return
t = musicState['t']
settings = []
for note in self.notes.get(song, []):
# we have to send zeros to make past settings go
# away. might be better for collector not to merge our
# past requests, and then we can omit zeroed notes?
settings.extend(note.outputSettings(t))
self.sendToCollector(settings)
|