# HG changeset patch # User Drew Perttula # Date 2014-05-28 05:57:08 # Node ID aa45e5379c5a77079894fb7eafb8b6cccd1ee28c # Parent 717774b8a4a6284e8d629a635050588de0c5d3fb effecteval improvements. displays current song+effect tree Ignore-this: 94a007b1206c45483d74878fb35248d diff --git a/bin/effecteval b/bin/effecteval --- a/bin/effecteval +++ b/bin/effecteval @@ -20,7 +20,23 @@ class EffectEdit(cyclone.web.RequestHand def get(self): self.write(open("light9/effecteval/effect.html").read()) -class EffectData(cyclone.websocket.WebSocketHandler): +class SongEffectsUpdates(cyclone.websocket.WebSocketHandler): + def connectionMade(self, *args, **kwargs): + self.graph = self.settings.graph + self.graph.addHandler(self.updateClient) + + def updateClient(self): + # todo: abort if client is gone + playlist = self.graph.value(showconfig.showUri(), L9['playList']) + songs = list(self.graph.items(playlist)) + out = [] + for s in songs: + out.append({'uri': s, 'label': self.graph.label(s)}) + out[-1]['effects'] = sorted(self.graph.objects(s, L9['effect'])) + self.sendMessage({'songs': out}) + + +class EffectUpdates(cyclone.websocket.WebSocketHandler): """ stays alive for the life of the effect page """ @@ -68,8 +84,14 @@ class EffectNode(object): intensityCurve = uriFromCode(m.group(2)) self.curve = Curve() + + # read from disk ok? how do we know to reread? start with + # mtime. the mtime check could be done occasionally so on + # average we read at most one curve's mtime per effectLoop. + self.curve.set_from_string(self.graph.value(intensityCurve, L9['points'])) - + + def eval(self, songTime): # consider http://waxeye.org/ for a parser that can be used in py and js level = self.curve.eval(songTime) @@ -107,27 +129,29 @@ def effectLoop(graph): t1 = time.time() response = json.loads((yield cyclone.httpclient.fetch( networking.musicPlayer.path('time'))).body) - song = URIRef(response['song']) - songTime = response['t'] - # Possibilities to make this shut up about graph copies: - # - implement the cheap readonly currentState response - # - do multiple little currentState calls (in this code) over just - # the required triples - # - use addHandler instead and only fire dmx when there is a data - # change (and also somehow call it when there is a time change) + if response['song'] is not None: + song = URIRef(response['song']) + songTime = response['t'] + # Possibilities to make this shut up about graph copies: + # - implement the cheap readonly currentState response + # - do multiple little currentState calls (in this code) over just + # the required triples + # - use addHandler instead and only fire dmx when there is a data + # change (and also somehow call it when there is a time change) - outSubs = [] - with graph.currentState(tripleFilter=(song, L9['effect'], None)) as g: - for effectUri in g.objects(song, L9['effect']): - node = EffectNode(graph, effectUri) - outSubs.append(node.eval(songTime)) - out = Submaster.sub_maxes(*outSubs) - # out.get_levels() for a more readable view - dmx = out.get_dmx_list() + outSubs = [] + with graph.currentState(tripleFilter=(song, L9['effect'], None)) as g: + for effectUri in g.objects(song, L9['effect']): + # these should be built once, not per (frequent) update + node = EffectNode(graph, effectUri) + outSubs.append(node.eval(songTime)) + out = Submaster.sub_maxes(*outSubs) + # out.get_levels() for a more readable view + dmx = out.get_dmx_list() - if log.isEnabledFor(logging.DEBUG): - log.debug("send dmx: %r", out.get_levels()) - yield dmxclient.outputlevels(dmx, twisted=True) + if log.isEnabledFor(logging.DEBUG): + log.debug("send dmx: %r", out.get_levels()) + yield dmxclient.outputlevels(dmx, twisted=True) loopTime = time.time() - t1 log.debug('loopTime %.1f ms', 1000 * loopTime) @@ -136,6 +160,10 @@ class App(object): def __init__(self, show): self.show = show self.graph = SyncedGraph("effectEval") + self.graph.initiallySynced.addCallback(self.launch) + + def launch(self, *args): + task.LoopingCall(effectLoop, self.graph).start(1) SFH = cyclone.web.StaticFileHandler self.cycloneApp = cyclone.web.Application(handlers=[ (r'/()', SFH, @@ -150,10 +178,8 @@ class App(object): (r'/effect/eval', EffectEval), (r'/songEffects/eval', SongEffectsEval), ], debug=True, graph=self.graph) - self.graph.initiallySynced.addCallback(self.launch) - - def launch(self, *args): - task.LoopingCall(effectLoop, self.graph).start(1) + reactor.listenTCP(networking.effectEval.port, self.cycloneApp) + log.info("listening on %s" % networking.effectEval.port) class StaticCoffee(PrettyErrorHandler, cyclone.web.RequestHandler): def initialize(self, src): @@ -185,6 +211,4 @@ if __name__ == "__main__": if options.twistedlog: from twisted.python import log as twlog twlog.startLogging(sys.stderr) - reactor.listenTCP(networking.effectEval.port, app.cycloneApp) - log.info("listening on %s" % networking.effectEval.port) reactor.run() diff --git a/light9/effecteval/effect.coffee b/light9/effecteval/effect.coffee --- a/light9/effecteval/effect.coffee +++ b/light9/effecteval/effect.coffee @@ -1,11 +1,16 @@ +qs = new QueryString() model = + uri: ko.observable(qs.value('uri')) code: ko.observable() -reconnectingWebSocket "ws://localhost:8070/effectData" + window.location.search, (msg) -> + +reconnectingWebSocket "ws://localhost:8070/effectUpdates" + window.location.search, (msg) -> console.log('effectData ' + JSON.stringify(msg)) # there's a shorter unpack thing - writeBack = ko.computed -> - console.log('sendback' ,{code: model.code()}) model.code(msg.code) - ko.applyBindings(model) + +writeBack = ko.computed -> + console.log('sendback' ,{code: model.code()}) + +ko.applyBindings(model) \ No newline at end of file diff --git a/light9/effecteval/effect.html b/light9/effecteval/effect.html --- a/light9/effecteval/effect.html +++ b/light9/effecteval/effect.html @@ -5,7 +5,7 @@ - effect page for URI (pull from param) + Effects /
code:
diff --git a/light9/effecteval/index.coffee b/light9/effecteval/index.coffee new file mode 100644 --- /dev/null +++ b/light9/effecteval/index.coffee @@ -0,0 +1,13 @@ +model = + songs: ko.observableArray([]) + +reconnectingWebSocket "ws://localhost:8070/songEffectsUpdates", (msg) -> + console.log(msg.songs) + model.songs(msg.songs) + +ko.applyBindings(model) + + # there's a shorter unpack thing + #writeBack = ko.computed -> + # console.log('sendback' ,{code: model.code()}) + \ No newline at end of file diff --git a/light9/effecteval/index.html b/light9/effecteval/index.html --- a/light9/effecteval/index.html +++ b/light9/effecteval/index.html @@ -7,9 +7,13 @@ All effect instances: -