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>