Mercurial > code > home > repos > light9
annotate bin/effecteval @ 1064:c5e44bab7c9a
greplin.scales api fix
Ignore-this: b622bd759e9c0011fd427c2c72333d45
author | Drew Perttula <drewp@bigasterisk.com> |
---|---|
date | Mon, 02 Jun 2014 01:21:03 +0000 |
parents | 473db8bebb8f |
children | dc474426845d |
rev | line source |
---|---|
1018
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
1 #!bin/python |
1053
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
2 from __future__ import division |
1018
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
3 from run_local import log |
1053
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
4 from twisted.internet import reactor |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
5 from twisted.internet.defer import inlineCallbacks, returnValue |
1027
a38414bd3929
hacking on effecteval
Drew Perttula <drewp@bigasterisk.com>
parents:
1019
diff
changeset
|
6 import cyclone.web, cyclone.websocket, cyclone.httpclient |
1052
b370618ce723
split EffectNode out of effecteval
Drew Perttula <drewp@bigasterisk.com>
parents:
1051
diff
changeset
|
7 import sys, optparse, logging, subprocess, json, time, traceback |
1051
be016cd5e5c5
effecteval names its new curve after the sub you drop on it
Drew Perttula <drewp@bigasterisk.com>
parents:
1044
diff
changeset
|
8 from rdflib import URIRef, Literal |
1018
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
9 |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
10 sys.path.append(".") |
1033
b5ee7aa9341a
effecteval now runs effects in the background, following the current song, and sends dmx output
Drew Perttula <drewp@bigasterisk.com>
parents:
1027
diff
changeset
|
11 from light9 import networking, showconfig, Submaster, dmxclient |
1018
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
12 from light9.rdfdb.syncedgraph import SyncedGraph |
1052
b370618ce723
split EffectNode out of effecteval
Drew Perttula <drewp@bigasterisk.com>
parents:
1051
diff
changeset
|
13 from light9.namespaces import L9, RDF, RDFS |
1044
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
14 from light9.rdfdb.patch import Patch |
1052
b370618ce723
split EffectNode out of effecteval
Drew Perttula <drewp@bigasterisk.com>
parents:
1051
diff
changeset
|
15 from light9.effecteval.effect import EffectNode |
1053
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
16 from light9.greplin_cyclone import StatsForCyclone |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
17 from greplin import scales |
1018
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
18 |
1060
473db8bebb8f
install a copy of cycloneerr.py
Drew Perttula <drewp@bigasterisk.com>
parents:
1055
diff
changeset
|
19 from lib.cycloneerr import PrettyErrorHandler |
1018
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
20 |
1054
4595a82f5a90
effecteval has a delete button on effect rows
Drew Perttula <drewp@bigasterisk.com>
parents:
1053
diff
changeset
|
21 class EffectEdit(PrettyErrorHandler, cyclone.web.RequestHandler): |
1018
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
22 def get(self): |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
23 self.write(open("light9/effecteval/effect.html").read()) |
1054
4595a82f5a90
effecteval has a delete button on effect rows
Drew Perttula <drewp@bigasterisk.com>
parents:
1053
diff
changeset
|
24 def delete(self): |
4595a82f5a90
effecteval has a delete button on effect rows
Drew Perttula <drewp@bigasterisk.com>
parents:
1053
diff
changeset
|
25 graph = self.settings.graph |
4595a82f5a90
effecteval has a delete button on effect rows
Drew Perttula <drewp@bigasterisk.com>
parents:
1053
diff
changeset
|
26 uri = URIRef(self.get_argument('uri')) |
4595a82f5a90
effecteval has a delete button on effect rows
Drew Perttula <drewp@bigasterisk.com>
parents:
1053
diff
changeset
|
27 with graph.currentState(tripleFilter=(None, L9['effect'], uri)) as g: |
4595a82f5a90
effecteval has a delete button on effect rows
Drew Perttula <drewp@bigasterisk.com>
parents:
1053
diff
changeset
|
28 song = ctx = list(g.subjects(L9['effect'], uri))[0] |
4595a82f5a90
effecteval has a delete button on effect rows
Drew Perttula <drewp@bigasterisk.com>
parents:
1053
diff
changeset
|
29 self.settings.graph.patch(Patch(delQuads=[ |
4595a82f5a90
effecteval has a delete button on effect rows
Drew Perttula <drewp@bigasterisk.com>
parents:
1053
diff
changeset
|
30 (song, L9['effect'], uri, ctx), |
4595a82f5a90
effecteval has a delete button on effect rows
Drew Perttula <drewp@bigasterisk.com>
parents:
1053
diff
changeset
|
31 ])) |
1055
6ce00faec207
move sequentialUri to the graph lib
Drew Perttula <drewp@bigasterisk.com>
parents:
1054
diff
changeset
|
32 |
1044
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
33 class SongEffects(PrettyErrorHandler, cyclone.web.RequestHandler): |
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
34 def post(self): |
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
35 song = URIRef(self.get_argument('uri')) |
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
36 drop = URIRef(self.get_argument('drop')) |
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
37 ctx = song |
1055
6ce00faec207
move sequentialUri to the graph lib
Drew Perttula <drewp@bigasterisk.com>
parents:
1054
diff
changeset
|
38 graph = self.settings.graph |
6ce00faec207
move sequentialUri to the graph lib
Drew Perttula <drewp@bigasterisk.com>
parents:
1054
diff
changeset
|
39 effect = graph.sequentialUri(song + "/effect/e-") |
6ce00faec207
move sequentialUri to the graph lib
Drew Perttula <drewp@bigasterisk.com>
parents:
1054
diff
changeset
|
40 curve = graph.sequentialUri(song + "/curve/c-") |
1051
be016cd5e5c5
effecteval names its new curve after the sub you drop on it
Drew Perttula <drewp@bigasterisk.com>
parents:
1044
diff
changeset
|
41 |
1055
6ce00faec207
move sequentialUri to the graph lib
Drew Perttula <drewp@bigasterisk.com>
parents:
1054
diff
changeset
|
42 with graph.currentState( |
1051
be016cd5e5c5
effecteval names its new curve after the sub you drop on it
Drew Perttula <drewp@bigasterisk.com>
parents:
1044
diff
changeset
|
43 tripleFilter=(drop, RDFS.label, None)) as g: |
be016cd5e5c5
effecteval names its new curve after the sub you drop on it
Drew Perttula <drewp@bigasterisk.com>
parents:
1044
diff
changeset
|
44 dropSubLabel = g.label(drop) |
be016cd5e5c5
effecteval names its new curve after the sub you drop on it
Drew Perttula <drewp@bigasterisk.com>
parents:
1044
diff
changeset
|
45 |
1055
6ce00faec207
move sequentialUri to the graph lib
Drew Perttula <drewp@bigasterisk.com>
parents:
1054
diff
changeset
|
46 graph.patch(Patch(addQuads=[ |
1051
be016cd5e5c5
effecteval names its new curve after the sub you drop on it
Drew Perttula <drewp@bigasterisk.com>
parents:
1044
diff
changeset
|
47 (song, L9['curve'], curve, ctx), |
1044
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
48 (song, L9['effect'], effect, ctx), |
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
49 (effect, RDF.type, L9['Effect'], ctx), |
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
50 (effect, L9['code'], |
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
51 Literal('out = sub(%s, intensity=%s)' % (drop.n3(), curve.n3())), |
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
52 ctx), |
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
53 (curve, RDF.type, L9['Curve'], ctx), |
1051
be016cd5e5c5
effecteval names its new curve after the sub you drop on it
Drew Perttula <drewp@bigasterisk.com>
parents:
1044
diff
changeset
|
54 (curve, RDFS.label, Literal('sub %s' % dropSubLabel), ctx), |
1044
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
55 (curve, L9['points'], Literal('0 0'), ctx), |
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
56 ])) |
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
57 |
1043
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
58 class SongEffectsUpdates(cyclone.websocket.WebSocketHandler): |
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
59 def connectionMade(self, *args, **kwargs): |
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
60 self.graph = self.settings.graph |
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
61 self.graph.addHandler(self.updateClient) |
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
62 |
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
63 def updateClient(self): |
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
64 # todo: abort if client is gone |
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
65 playlist = self.graph.value(showconfig.showUri(), L9['playList']) |
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
66 songs = list(self.graph.items(playlist)) |
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
67 out = [] |
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
68 for s in songs: |
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
69 out.append({'uri': s, 'label': self.graph.label(s)}) |
1054
4595a82f5a90
effecteval has a delete button on effect rows
Drew Perttula <drewp@bigasterisk.com>
parents:
1053
diff
changeset
|
70 out[-1]['effects'] = [{'uri': uri} for uri in sorted(self.graph.objects(s, L9['effect']))] |
1043
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
71 self.sendMessage({'songs': out}) |
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
72 |
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
73 |
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
74 class EffectUpdates(cyclone.websocket.WebSocketHandler): |
1018
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
75 """ |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
76 stays alive for the life of the effect page |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
77 """ |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
78 def connectionMade(self, *args, **kwargs): |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
79 log.info("websocket opened") |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
80 self.uri = URIRef(self.get_argument('uri')) |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
81 self.sendMessage({'hello': repr(self)}) |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
82 |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
83 self.graph = self.settings.graph |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
84 self.graph.addHandler(self.updateClient) |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
85 |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
86 def updateClient(self): |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
87 # todo: if client has dropped, abort and don't get any more |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
88 # graph updates |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
89 self.sendMessage({'code': self.graph.value(self.uri, L9['code'])}) |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
90 |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
91 def connectionLost(self, reason): |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
92 log.info("websocket closed") |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
93 |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
94 def messageReceived(self, message): |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
95 log.info("got message %s" % message) |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
96 # write a patch back to the graph |
1027
a38414bd3929
hacking on effecteval
Drew Perttula <drewp@bigasterisk.com>
parents:
1019
diff
changeset
|
97 |
1019 | 98 |
99 class EffectEval(PrettyErrorHandler, cyclone.web.RequestHandler): | |
1027
a38414bd3929
hacking on effecteval
Drew Perttula <drewp@bigasterisk.com>
parents:
1019
diff
changeset
|
100 @inlineCallbacks |
1019 | 101 def get(self): |
1033
b5ee7aa9341a
effecteval now runs effects in the background, following the current song, and sends dmx output
Drew Perttula <drewp@bigasterisk.com>
parents:
1027
diff
changeset
|
102 # return dmx list for that effect |
1019 | 103 uri = URIRef(self.get_argument('uri')) |
1027
a38414bd3929
hacking on effecteval
Drew Perttula <drewp@bigasterisk.com>
parents:
1019
diff
changeset
|
104 response = yield cyclone.httpclient.fetch( |
a38414bd3929
hacking on effecteval
Drew Perttula <drewp@bigasterisk.com>
parents:
1019
diff
changeset
|
105 networking.musicPlayer.path('time')) |
a38414bd3929
hacking on effecteval
Drew Perttula <drewp@bigasterisk.com>
parents:
1019
diff
changeset
|
106 songTime = json.loads(response.body)['t'] |
1033
b5ee7aa9341a
effecteval now runs effects in the background, following the current song, and sends dmx output
Drew Perttula <drewp@bigasterisk.com>
parents:
1027
diff
changeset
|
107 |
b5ee7aa9341a
effecteval now runs effects in the background, following the current song, and sends dmx output
Drew Perttula <drewp@bigasterisk.com>
parents:
1027
diff
changeset
|
108 node = EffectNode(self.settings.graph, uri) |
b5ee7aa9341a
effecteval now runs effects in the background, following the current song, and sends dmx output
Drew Perttula <drewp@bigasterisk.com>
parents:
1027
diff
changeset
|
109 outSub = node.eval(songTime) |
b5ee7aa9341a
effecteval now runs effects in the background, following the current song, and sends dmx output
Drew Perttula <drewp@bigasterisk.com>
parents:
1027
diff
changeset
|
110 self.write(json.dumps(outSub.get_dmx_list())) |
b5ee7aa9341a
effecteval now runs effects in the background, following the current song, and sends dmx output
Drew Perttula <drewp@bigasterisk.com>
parents:
1027
diff
changeset
|
111 |
b5ee7aa9341a
effecteval now runs effects in the background, following the current song, and sends dmx output
Drew Perttula <drewp@bigasterisk.com>
parents:
1027
diff
changeset
|
112 |
b5ee7aa9341a
effecteval now runs effects in the background, following the current song, and sends dmx output
Drew Perttula <drewp@bigasterisk.com>
parents:
1027
diff
changeset
|
113 # Completely not sure where the effect background loop should |
b5ee7aa9341a
effecteval now runs effects in the background, following the current song, and sends dmx output
Drew Perttula <drewp@bigasterisk.com>
parents:
1027
diff
changeset
|
114 # go. Another process could own it, and get this request repeatedly: |
1019 | 115 class SongEffectsEval(PrettyErrorHandler, cyclone.web.RequestHandler): |
116 def get(self): | |
117 song = URIRef(self.get_argument('song')) | |
118 effects = effectsForSong(self.settings.graph, song) | |
1033
b5ee7aa9341a
effecteval now runs effects in the background, following the current song, and sends dmx output
Drew Perttula <drewp@bigasterisk.com>
parents:
1027
diff
changeset
|
119 raise NotImplementedError |
1019 | 120 self.write(maxDict(effectDmxDict(e) for e in effects)) |
121 # return dmx dict for all effects in the song, already combined | |
1033
b5ee7aa9341a
effecteval now runs effects in the background, following the current song, and sends dmx output
Drew Perttula <drewp@bigasterisk.com>
parents:
1027
diff
changeset
|
122 |
1053
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
123 class EffectLoop(object): |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
124 """maintains a collection of the current EffectNodes, gets time from |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
125 music player, sends dmx""" |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
126 def __init__(self, graph, stats): |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
127 self.graph, self.stats = graph, stats |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
128 self.currentSong = None |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
129 self.currentEffects = [] |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
130 self.graph.addHandler(self.setEffects) |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
131 self.period = 1 / 30 |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
132 self.coastSecs = .3 # main reason to keep this low is to notice play/pause |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
133 |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
134 self.songTimeFromRequest = 0 |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
135 self.requestTime = 0 # unix sec for when we fetched songTime |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
136 reactor.callLater(self.period, self.sendLevels) |
1033
b5ee7aa9341a
effecteval now runs effects in the background, following the current song, and sends dmx output
Drew Perttula <drewp@bigasterisk.com>
parents:
1027
diff
changeset
|
137 |
1053
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
138 def setEffects(self): |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
139 self.currentEffects = [] |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
140 if self.currentSong is None: |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
141 return |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
142 |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
143 for effectUri in self.graph.objects(self.currentSong, L9['effect']): |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
144 self.currentEffects.append(EffectNode(self.graph, effectUri)) |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
145 |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
146 @inlineCallbacks |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
147 def getSongTime(self): |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
148 now = time.time() |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
149 if now - self.requestTime < self.coastSecs: |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
150 estimated = self.songTimeFromRequest |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
151 if self.currentSong is not None and self.currentPlaying: |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
152 estimated += now - self.requestTime |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
153 returnValue((estimated, self.currentSong)) |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
154 else: |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
155 response = json.loads((yield cyclone.httpclient.fetch( |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
156 networking.musicPlayer.path('time'))).body) |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
157 self.requestTime = now |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
158 self.currentPlaying = response['playing'] |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
159 self.songTimeFromRequest = response['t'] |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
160 returnValue( |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
161 (response['t'], (response['song'] and URIRef(response['song'])))) |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
162 |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
163 @inlineCallbacks |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
164 def sendLevels(self): |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
165 t1 = time.time() |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
166 try: |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
167 with self.stats.sendLevels.time(): |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
168 with self.stats.getMusic.time(): |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
169 songTime, song = yield self.getSongTime() |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
170 |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
171 if song != self.currentSong: |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
172 self.currentSong = song |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
173 # this may be piling on the handlers |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
174 self.graph.addHandler(self.setEffects) |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
175 |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
176 if song is None: |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
177 return |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
178 |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
179 outSubs = [] |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
180 for e in self.currentEffects: |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
181 outSubs.append(e.eval(songTime)) |
1044
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
182 out = Submaster.sub_maxes(*outSubs) |
1053
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
183 |
1044
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
184 dmx = out.get_dmx_list() |
1033
b5ee7aa9341a
effecteval now runs effects in the background, following the current song, and sends dmx output
Drew Perttula <drewp@bigasterisk.com>
parents:
1027
diff
changeset
|
185 |
1044
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
186 if log.isEnabledFor(logging.DEBUG): |
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
187 log.debug("send dmx: %r", out.get_levels()) |
1053
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
188 |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
189 with self.stats.writeDmx.time(): |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
190 yield dmxclient.outputlevels(dmx, twisted=True) |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
191 |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
192 elapsed = time.time() - t1 |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
193 dt = max(0, self.period - elapsed) |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
194 except Exception: |
1064
c5e44bab7c9a
greplin.scales api fix
Drew Perttula <drewp@bigasterisk.com>
parents:
1060
diff
changeset
|
195 self.stats.errors += 1 |
1053
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
196 traceback.print_exc() |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
197 dt = 1 |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
198 |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
199 reactor.callLater(dt, self.sendLevels) |
1033
b5ee7aa9341a
effecteval now runs effects in the background, following the current song, and sends dmx output
Drew Perttula <drewp@bigasterisk.com>
parents:
1027
diff
changeset
|
200 |
1018
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
201 class App(object): |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
202 def __init__(self, show): |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
203 self.show = show |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
204 self.graph = SyncedGraph("effectEval") |
1043
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
205 self.graph.initiallySynced.addCallback(self.launch) |
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
206 |
1053
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
207 self.stats = scales.collection('/', |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
208 scales.PmfStat('sendLevels'), |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
209 scales.PmfStat('getMusic'), |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
210 scales.PmfStat('writeDmx'), |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
211 scales.IntStat('errors'), |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
212 ) |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
213 |
1043
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
214 def launch(self, *args): |
1053
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
215 self.loop = EffectLoop(self.graph, self.stats) |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
216 |
1018
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
217 SFH = cyclone.web.StaticFileHandler |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
218 self.cycloneApp = cyclone.web.Application(handlers=[ |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
219 (r'/()', SFH, |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
220 {'path': 'light9/effecteval', 'default_filename': 'index.html'}), |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
221 (r'/effect', EffectEdit), |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
222 (r'/(websocket\.js)', SFH, {'path': 'light9/rdfdb/web/'}), |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
223 (r'/effect\.js', StaticCoffee, {'src': 'light9/effecteval/effect.coffee'}), |
1041
a4632a7b2e17
upgrade knockout and jquery, simplify the static/ dirs for all web services
Drew Perttula <drewp@bigasterisk.com>
parents:
1033
diff
changeset
|
224 (r'/index\.js', StaticCoffee, {'src': 'light9/effecteval/index.coffee'}), |
a4632a7b2e17
upgrade knockout and jquery, simplify the static/ dirs for all web services
Drew Perttula <drewp@bigasterisk.com>
parents:
1033
diff
changeset
|
225 (r'/effectUpdates', EffectUpdates), |
a4632a7b2e17
upgrade knockout and jquery, simplify the static/ dirs for all web services
Drew Perttula <drewp@bigasterisk.com>
parents:
1033
diff
changeset
|
226 (r'/songEffectsUpdates', SongEffectsUpdates), |
1018
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
227 (r'/static/(.*)', SFH, {'path': 'static/'}), |
1019 | 228 (r'/effect/eval', EffectEval), |
1044
a2081b9adfe4
effecteval now takes dropped subs and makes new effects out of them
Drew Perttula <drewp@bigasterisk.com>
parents:
1043
diff
changeset
|
229 (r'/songEffects', SongEffects), |
1019 | 230 (r'/songEffects/eval', SongEffectsEval), |
1053
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
231 (r'/stats', StatsForCyclone), |
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
232 ], debug=True, graph=self.graph, stats=self.stats) |
1043
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
233 reactor.listenTCP(networking.effectEval.port, self.cycloneApp) |
aa45e5379c5a
effecteval improvements. displays current song+effect tree
Drew Perttula <drewp@bigasterisk.com>
parents:
1041
diff
changeset
|
234 log.info("listening on %s" % networking.effectEval.port) |
1053
9937e2e3d17b
effecteval faster loop, stats page
Drew Perttula <drewp@bigasterisk.com>
parents:
1052
diff
changeset
|
235 |
1018
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
236 class StaticCoffee(PrettyErrorHandler, cyclone.web.RequestHandler): |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
237 def initialize(self, src): |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
238 super(StaticCoffee, self).initialize() |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
239 self.src = src |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
240 def get(self): |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
241 self.set_header('Content-Type', 'application/javascript') |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
242 self.write(subprocess.check_output([ |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
243 '/usr/bin/coffee', '--compile', '--print', self.src])) |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
244 |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
245 |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
246 if __name__ == "__main__": |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
247 parser = optparse.OptionParser() |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
248 parser.add_option('--show', |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
249 help='show URI, like http://light9.bigasterisk.com/show/dance2008', |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
250 default=showconfig.showUri()) |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
251 parser.add_option("-v", "--verbose", action="store_true", |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
252 help="logging.DEBUG") |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
253 parser.add_option("--twistedlog", action="store_true", |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
254 help="twisted logging") |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
255 (options, args) = parser.parse_args() |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
256 |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
257 log.setLevel(logging.DEBUG if options.verbose else logging.INFO) |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
258 |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
259 if not options.show: |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
260 raise ValueError("missing --show http://...") |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
261 |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
262 app = App(URIRef(options.show)) |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
263 if options.twistedlog: |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
264 from twisted.python import log as twlog |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
265 twlog.startLogging(sys.stderr) |
e28a443bd153
initial effecteval that can propagate changes from the graph to a web page
drewp@bigasterisk.com
parents:
diff
changeset
|
266 reactor.run() |