Mercurial > code > home > repos > light9
changeset 1043:aa45e5379c5a
effecteval improvements. displays current song+effect tree
Ignore-this: 94a007b1206c45483d74878fb35248d
author | Drew Perttula <drewp@bigasterisk.com> |
---|---|
date | Wed, 28 May 2014 05:57:08 +0000 |
parents | 717774b8a4a6 |
children | a2081b9adfe4 |
files | bin/effecteval light9/effecteval/effect.coffee light9/effecteval/effect.html light9/effecteval/index.coffee light9/effecteval/index.html |
diffstat | 5 files changed, 81 insertions(+), 35 deletions(-) [+] |
line wrap: on
line diff
--- a/bin/effecteval Wed May 28 05:55:58 2014 +0000 +++ b/bin/effecteval Wed May 28 05:57:08 2014 +0000 @@ -20,7 +20,23 @@ 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 @@ 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 @@ 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 @@ 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 @@ (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 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()
--- a/light9/effecteval/effect.coffee Wed May 28 05:55:58 2014 +0000 +++ b/light9/effecteval/effect.coffee Wed May 28 05:57:08 2014 +0000 @@ -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
--- a/light9/effecteval/effect.html Wed May 28 05:55:58 2014 +0000 +++ b/light9/effecteval/effect.html Wed May 28 05:57:08 2014 +0000 @@ -5,7 +5,7 @@ <meta charset="utf-8" /> </head> <body> - effect page for URI (pull from param) + <a href="./">Effects</a> / <a data-bind="attr: {href: uri}, text: uri"></a> <div>code: <input type="text" size="100" data-bind="value: code"></input></div>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/light9/effecteval/index.coffee Wed May 28 05:57:08 2014 +0000 @@ -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
--- a/light9/effecteval/index.html Wed May 28 05:55:58 2014 +0000 +++ b/light9/effecteval/index.html Wed May 28 05:57:08 2014 +0000 @@ -7,9 +7,13 @@ <body> All effect instances: <!-- subscribe to a query of all effects and their songs --> - <ul> - <li><a href="effect?uri=http://ex/effect/song1/openingLook">song1 -> opening look</a></li> - <li><a href="effect?uri=http://ex/effect/song1/full">song1 -> full</a></li> + <ul data-bind="foreach: songs"> + <li> + <a data-bind="attr: {href: uri}">Song <span data-bind="text: label"></span></a> + </li> + <ul data-bind="foreach: effects"> + <li><a data-bind="attr: {href: 'effect?'+jQuery.param({uri: $data})}, text: $data"></a></li> + </ul> </ul> <script src="static/jquery-2.1.1.min.js"></script> <script src="static/knockout-3.1.0.js"></script>