comparison light8/Lightboard.py @ 56:2af6698b0566

pulled Lightboard out of rsn.py (and fixed all the dependency problems i could find) pulled Lightboard out of rsn.py (and fixed all the dependency problems i could find) made some exceptions print better
author drewp
date Tue, 09 Jul 2002 05:28:21 +0000
parents 45b12307c695
children 2508c6b7a4e0
comparison
equal deleted inserted replaced
55:5e8c505bcc2c 56:2af6698b0566
1 from __future__ import nested_scopes,division 1 from __future__ import nested_scopes
2 2
3 from Tix import * 3 from Tix import *
4 from time import sleep
4 from signal import signal, SIGINT 5 from signal import signal, SIGINT
5 from time import time 6 import sys, cPickle
6 import sys, cPickle, random 7
7 8 import io
8 from uihelpers import * 9 from uihelpers import *
9 from panels import * 10 from panels import *
10 from Xfader import * 11 from Xfader import *
11 from subediting import Subediting 12 from subediting import Subediting
12 from Fader import Fader 13 from Fader import Fader
13 from ExternalInput import ExternalSliders 14 import stage
14 import io, stage, Subs, Patch, ExtSliderMapper 15 import Subs, Patch
15 import dmxclient
16 16
17 class Pickles: 17 class Pickles:
18 def __init__(self, scalelevels, subs=None, windowpos=None): 18 def __init__(self, scalelevels, subs=None):
19 self.scalelevels = dict([(name, lev.get()) 19 self.scalelevels = dict([(name, lev.get())
20 for name, lev in scalelevels.items()]) 20 for name, lev in scalelevels.items()])
21 self.substate = dict([(name, subobj.get_state()) 21 self.substate = dict([(name, subobj.get_state())
22 for name, subobj in subs]) 22 for name, subobj in subs])
23 self.windowpos = windowpos 23 # print "substate", self.substate
24 24
25 class Lightboard: 25 class Lightboard:
26 def __init__(self, master, DUMMY): 26 def __init__(self, master, parportdmx, DUMMY):
27 self.master = master 27 self.master = master
28 28 self.parportdmx = parportdmx
29 self.DUMMY = DUMMY 29 self.DUMMY = DUMMY
30 self.jostle_mode = 0 30
31 self.lastline = None 31 self.channel_levels = []
32
33 self.channel_levels = [] # these are actually the labels for the
34 # channel levels, and should probably be moved
35 # to panels.Leveldisplay
36 self.scalelevels = {} 32 self.scalelevels = {}
37 33 self.xfader = Xfader(self.scalelevels) # doesn't draw any UI yet-- look for self.xfader.setupwidget()
38 self.lastsublevels = {} # to determine which subs changed
39 self.unchangedeffect = {} # dict of levels for lights that didn't
40 # change last time
41 self.lastunchangedgroup = {}
42
43 # doesn't draw any UI yet-- look for self.xfader.setupwidget()
44 self.xfader = Xfader(self.scalelevels)
45 self.oldlevels = [None] * 68 # never replace this; just clear it 34 self.oldlevels = [None] * 68 # never replace this; just clear it
46 self.subediting = Subediting(currentoutputlevels=self.oldlevels) 35 self.subediting = Subediting(currentoutputlevels=self.oldlevels)
47 36
48 self.windowpos = 0
49 self.get_data() 37 self.get_data()
50 self.buildinterface() 38 self.buildinterface()
51 self.load() 39 self.load()
52
53 print "Light 8.8: Entering backgroundloop"
54 self.backgroundloop() 40 self.backgroundloop()
55 self.updatestagelevels()
56 self.rec_file = open('light9.log', 'a')
57 self.record_start()
58 41
59 def buildinterface(self): 42 def buildinterface(self):
60 print "Light 8.8: Constructing interface..."
61 for w in self.master.winfo_children(): 43 for w in self.master.winfo_children():
62 w.destroy() 44 w.destroy()
63 45
64 print "\tstage" 46 stage_tl = toplevelat(22,30)
65 stage_tl = toplevelat('stage')
66 s = stage.Stage(stage_tl) 47 s = stage.Stage(stage_tl)
67 stage.createlights(s) 48 stage.createlights(s)
68 s.setsubediting(self.subediting) 49 s.setsubediting(self.subediting)
69 s.pack() 50 s.pack()
70 self.stage = s # save it 51
71 52 sub_tl = toplevelat(0,0)
72 sub_tl = toplevelat('sub') 53 effect_tl = toplevelat(462,4)
73 scene_tl = toplevelat('scenes') 54
74 effect_tl = toplevelat('effect') 55 self.subpanels = Subpanels(sub_tl, effect_tl, self, self.scalelevels,
75 56 Subs, self.xfader, self.changelevel,
76 print "\tslider patching -- It can't be turned off!" 57 self.subediting, Subs.longestsubname())
77 mapping_tl = toplevelat('mapping') 58
78 self.slidermapper = ExtSliderMapper.ExtSliderMapper(mapping_tl, 59 leveldisplay_tl = toplevelat(873,400)
79 self.scalelevels,
80 ExternalSliders(),
81 self)
82 self.slidermapper.pack()
83
84 print "\tsubmaster control"
85 self.subpanels = Subpanels(sub_tl, effect_tl, scene_tl, self,
86 self.scalelevels, Subs, self.xfader,
87 self.changelevel, self.subediting,
88 Subs.longestsubname())
89
90 for n, lev in self.scalelevels.items():
91 self.lastsublevels[n] = lev.get()
92
93 print "\tlevel display"
94 leveldisplay_tl = toplevelat('leveldisplay')
95 leveldisplay_tl.bind('<Escape>', sys.exit) 60 leveldisplay_tl.bind('<Escape>', sys.exit)
96 61
97 self.leveldisplay = Leveldisplay(leveldisplay_tl, self.channel_levels) 62 self.leveldisplay = Leveldisplay(leveldisplay_tl, self.channel_levels)
98 # I don't think we need this 63 for i in range(0,len(self.channel_levels)):
99 # for i in range(0,len(self.channel_levels)): 64 self.channel_levels[i].config(text=self.oldlevels[i])
100 # self.channel_levels[i].config(text=self.oldlevels[i]) 65 colorlabel(self.channel_levels[i])
101 # colorlabel(self.channel_levels[i]) 66
102
103 print "\tconsole"
104 Console(self) 67 Console(self)
105 68
106 # root frame 69 # root frame
107 print "\tcontrol panel" 70 controlpanel = Controlpanel(self.master, self.xfader, self.refresh, self.quit)
108 self.master.configure(bg='black')
109 controlpanel = Controlpanel(self.master, self.xfader, self.refresh,
110 self.quit, self.toggle_jostle, self.nonzerosubs)
111 71
112 print "\tcrossfader"
113 xf=Frame(self.master) 72 xf=Frame(self.master)
114 xf.pack(side='right') 73 xf.pack(side='right')
115 74
116 self.master.bind('<q>', self.quit) 75 self.master.bind('<q>', self.quit)
117 self.master.bind('<r>', self.refresh) 76 self.master.bind('<r>', self.refresh)
119 leveldisplay_tl.bind('<r>', self.refresh) 78 leveldisplay_tl.bind('<r>', self.refresh)
120 79
121 self.xfader.setupwidget(xf) 80 self.xfader.setupwidget(xf)
122 controlpanel.pack() 81 controlpanel.pack()
123 82
124 print "\tcue fader (skipped)" 83 cuefader_tl = toplevelat(78, 480)
125 # cuefader_tl = toplevelat('cuefader') 84 cuefader = Fader(cuefader_tl, Subs.cues, self.scalelevels)
126 # cuefader = Fader(cuefader_tl, Subs.cues, self.scalelevels) 85 cuefader.pack()
127 # cuefader.pack()
128 print "Light 8.8: Everything's under control"
129
130 86
131 def get_data(self,*args): 87 def get_data(self,*args):
132 Subs.reload_data(self.DUMMY) 88 Subs.reload_data(self.DUMMY)
133 Patch.reload_data(self.DUMMY) 89 Patch.reload_data(self.DUMMY)
134 print "Light 8.8:", len(Patch.patch), "dimmers patched" 90 print "Patch:", Patch.patch
135 print "Light 8.8:", len(Subs.subs), "submasters loaded" 91 print "Subs:", ', '.join(Subs.subs.keys())
136 92
137 def refresh(self, *args): 93 def refresh(self, *args):
138 'rebuild interface, reload data' 94 'rebuild interface, reload data'
139 print "Light 8.8: Refresh initiated. Cross your fingers."
140 self.get_data() 95 self.get_data()
141 print "Light 8.8: Subediting refreshed"
142 self.subediting.refresh() 96 self.subediting.refresh()
143 print "Light 8.8: Rebuilding interface..."
144 self.buildinterface() 97 self.buildinterface()
145 bindkeys(self.master,'<Escape>', self.quit) 98 bindkeys(self.master,'<Escape>', self.quit)
146 print "Light 8.8: Setting up slider patching..."
147 self.slidermapper.setup()
148 # self.master.tk_setPalette('gray40')
149 print "Light 8.8: Now back to your regularly scheduled Light 8"
150 99
151 def stageassub(self): 100 def stageassub(self):
152 """returns the current onstage lighting as a levels 101 """returns the current onstage lighting as a levels
153 dictionary, skipping the zeros, and using names where 102 dictionary, skipping the zeros, and using names where
154 possible""" 103 possible"""
155 levs=self.oldlevels 104 levs=self.oldlevels
156 105
157 return dict([(Patch.get_channel_name(i),l) for i,l 106 return dict([(Patch.get_channel_name(i),l) for i,l
158 in zip(range(1,len(levs)+1),levs) 107 in zip(range(1,len(levs)+1),levs)
159 if l>0]) 108 if l>0])
160 def save_sub(self, name, levels, refresh=1): 109 def save_sub(self, name, levels):
161 if not name: 110 if not name:
162 print "Enter sub name in console." 111 print "Enter sub name in console."
163 return 112 return
164 113
165 st = '' 114 st = ''
177 filename = 'Config.py' 126 filename = 'Config.py'
178 f = open(filename, 'a') 127 f = open(filename, 'a')
179 f.write(st) 128 f.write(st)
180 f.close() 129 f.close()
181 print 'Added sub:', st 130 print 'Added sub:', st
182 if refresh: 131 self.refresh()
183 self.refresh()
184 132
185 # this is called on a loop, and ALSO by the Scales 133 # this is called on a loop, and ALSO by the Scales
186 def changelevel(self, *args): 134 def changelevel(self, *args):
187 'Amp trims slider' 135 'Amp trims slider'
188 136
189 # load levels from external sliders
190 extlevels = self.slidermapper.get_levels()
191 for name, val in extlevels.items():
192 if name in self.scalelevels:
193 sl = self.scalelevels[name]
194 sl.set(val)
195
196 # newstart = time()
197
198 # learn what changed
199 unchangedgroup = {}
200 changedgroup = {}
201 for name, lastlevel in self.lastsublevels.items():
202 newlevel = self.scalelevels[name].get()
203 if lastlevel != newlevel:
204 changedgroup[name] = newlevel
205 else:
206 unchangedgroup[name] = newlevel
207
208 changedeffect = {}
209 if not changedgroup:
210 # should load levels from last time
211 pass
212 else:
213 # calculate effect of new group. this should take no time if
214 # nothing changed
215 for name, level in changedgroup.items():
216 newlevels = Subs.subs[name].get_levels(level=level)
217 for (ch, fadelev) in newlevels.items():
218 changedeffect[ch-1] = \
219 max(changedeffect.get(ch-1, 0), fadelev)
220
221 if unchangedgroup != self.lastunchangedgroup:
222 # unchanged group changed! (confusing, huh?)
223 # this means: the static subs from the last time are not the same
224 # as they are this time, so we recalculate effect of unchanged group
225 self.unchangedeffect = {}
226 for name, level in unchangedgroup.items():
227 newlevels = Subs.subs[name].get_levels(level=level)
228 for (ch, fadelev) in newlevels.items():
229 self.unchangedeffect[ch-1] = \
230 max(self.unchangedeffect.get(ch-1, 0), fadelev)
231 self.lastunchangedgroup = unchangedgroup
232
233 # record sublevels for future generations (iterations, that is)
234 for name in self.lastsublevels:
235 self.lastsublevels[name] = self.scalelevels[name]
236
237 # merge effects together
238 levels = [0] * 68
239 if changedeffect:
240 levels = [int(max(changedeffect.get(ch, 0),
241 self.unchangedeffect.get(ch, 0)))
242 for ch in range(0, 68)]
243 else:
244 levels = [int(self.unchangedeffect.get(ch, 0))
245 for ch in range(0, 68)]
246
247 '''
248 newend = time()
249
250 levels_opt = levels
251
252 oldstart = time()
253 # i tried to optimize this to a dictionary, but there was no speed
254 # improvement
255 levels = [0] * 68 137 levels = [0] * 68
256 for name, s in Subs.subs.items(): 138 for name, s in Subs.subs.items():
257 sublevel = self.scalelevels[name].get() 139 newlevels = s.get_levels(level=self.scalelevels[name].get())
258 newlevels = s.get_levels(level=sublevel)
259 self.lastsublevels[name] = sublevel # XXX remove
260 for (ch, fadelev) in newlevels.items(): 140 for (ch, fadelev) in newlevels.items():
261 levels[ch-1] = max(levels[ch-1], fadelev) 141 levels[ch-1] = max(levels[ch-1], fadelev)
142
262 levels = [int(l) for l in levels] 143 levels = [int(l) for l in levels]
263 oldend = time() 144
264
265 newtime = newend - newstart
266 oldtime = oldend - oldstart
267 print "new", newtime, 'old', (oldend - oldstart), 'sup', \
268 oldtime / newtime
269
270 if levels != levels_opt:
271 raise "not equal"
272 # for l, lo in zip(levels, levels_opt):
273 # print l, lo
274 '''
275
276 for lev,lab,oldlev,numlab in zip(levels, self.channel_levels, 145 for lev,lab,oldlev,numlab in zip(levels, self.channel_levels,
277 self.oldlevels, 146 self.oldlevels,
278 self.leveldisplay.number_labels): 147 self.leveldisplay.number_labels):
279 if lev != oldlev: 148 if lev != oldlev:
280 lab.config(text="%d" % lev) # update labels in lev display 149 lab.config(text="%d" % lev)
281 colorlabel(lab) # recolor labels 150 colorlabel(lab)
282 if lev < oldlev: 151 if lev < oldlev:
283 numlab['bg'] = 'blue' 152 numlab['bg'] = 'blue'
284 else: 153 else:
285 numlab['bg'] = 'red' 154 numlab['bg'] = 'red'
286 else: 155 else:
287 numlab['bg'] = 'grey40' 156 numlab['bg'] = 'lightPink'
288 157
289 # replace the elements in oldlevels - don't make a new list 158 self.oldlevels[:] = levels[:] # replace the elements in oldlevels - don't make a new list (Subediting is watching it)
290 # (Subediting is watching it)
291 self.oldlevels[:] = levels[:]
292 159
293 if self.jostle_mode: 160 self.parportdmx.sendlevels(levels)
294 delta = random.randrange(-1, 2, 1) # (-1, 0, or 1)
295 # print "delta", delta
296 levels = [min(100, max(x + delta, 0)) for x in levels]
297 # print "jostled", levels
298
299 dmxclient.outputlevels([l/100 for l in levels])
300 # self.parportdmx.sendlevels(levels)
301
302 def updatestagelevels(self):
303 self.master.after(100, self.updatestagelevels)
304 for lev, idx in zip(self.oldlevels, xrange(0, 68 + 1)):
305 self.stage.updatelightlevel(Patch.get_channel_name(idx + 1), lev)
306 161
307 def load(self): 162 def load(self):
308 try: 163 try:
309 filename = '/tmp/light9.prefs' 164 filename = '/tmp/light9.prefs'
310 if self.DUMMY: 165 if self.DUMMY:
311 filename += '.dummy' 166 filename += '.dummy'
312 print "Light 8.8: Loading from", filename 167 print "Loading from", filename
313 file = open(filename, 'r') 168 file = open(filename, 'r')
314 p = cPickle.load(file) 169 p = cPickle.load(file)
315 for s, v in p.scalelevels.items(): 170 for s, v in p.scalelevels.items():
316 try: 171 try:
317 self.scalelevels[s].set(v) 172 self.scalelevels[s].set(v)
326 print "IOError: Couldn't load prefs (%s): %s" % (filename,e) 181 print "IOError: Couldn't load prefs (%s): %s" % (filename,e)
327 except EOFError, e: 182 except EOFError, e:
328 print "EOFrror: Couldn't load prefs (%s): %s" % (filename,e) 183 print "EOFrror: Couldn't load prefs (%s): %s" % (filename,e)
329 except Exception,e: 184 except Exception,e:
330 print "Couldn't load prefs (%s): %s" % (filename,e) 185 print "Couldn't load prefs (%s): %s" % (filename,e)
331 self.slidermapper.setup()
332 186
333 def backgroundloop(self, *args): 187 def backgroundloop(self, *args):
334 self.master.after(150, self.backgroundloop, ()) 188 self.master.after(50, self.backgroundloop, ())
335 self.changelevel() 189 self.changelevel()
336 def quit(self, *args): 190 def quit(self, *args):
337 print "Light 8.8: And that's my cue to exit..."
338 self.save() 191 self.save()
339 self.record_end()
340 self.master.destroy() 192 self.master.destroy()
341 sys.exit() 193 sys.exit()
342 def save(self, *args): 194 def save(self, *args):
343 filename = '/tmp/light9.prefs' 195 filename = '/tmp/light9.prefs'
344 if self.DUMMY: 196 if self.DUMMY:
345 filename += '.dummy' 197 filename += '.dummy'
346 print "Light 8.8: Saving to", filename 198 print "Saving to", filename
347 file = open(filename, 'w') 199 file = open(filename, 'w')
348
349 try: 200 try:
350 cPickle.dump(Pickles(self.scalelevels, Subs.subs.items()), file) 201 cPickle.dump(Pickles(self.scalelevels, Subs.subs.items()), file)
351 except cPickle.UnpickleableError: 202 except cPickle.UnpickleableError:
352 print "UnpickleableError! There's yer problem." 203 print "UnpickleableError! There's yer problem."
353 def toggle_jostle(self, *args):
354 self.jostle_mode = not self.jostle_mode
355 if self.jostle_mode:
356 print 'Light 8.8: Perhaps we can jost-le your memory?'
357 else:
358 print 'Light 8.8: He remembers! (jostle off)'
359 def nonzerosubs(self, *args):
360 print "Light 8.8: Active subs:"
361 for n, dv in self.scalelevels.items():
362 if dv.get() > 0:
363 print "%-.4f: %s" % (dv.get(), n)
364 def record_start(self):
365 print "Light 8.8: Recorder started"
366 self.rec_file.write("%s:\t%s\n" % (time(), "--- Start ---"))
367 self.record_stamp()
368 def record_end(self):
369 print "Light 8.8: Recorder shutdown"
370 self.rec_file.write("%s:\t%s\n" % (time(), "--- End ---"))
371 def record_stamp(self):
372 'Record the current submaster levels, continue this loop'
373 levels = []
374 for n, v in self.scalelevels.items():
375 lev = v.get()
376 if lev:
377 levels.append('%s\t%s' % (n, lev))
378
379
380 newdata = '\t'.join(levels)
381 if newdata!=self.lastline:
382 template = "%s:\t%s\n" % (time(), newdata)
383 self.rec_file.write(template)
384 self.lastline = newdata
385 self.master.after(100, self.record_stamp)
386 def highlight_sub(self, name, color):
387 self.subediting.colorsub(name, color)