comparison flax/CueFaders.py @ 167:79bc84310e80

changes from tonight's rehearsal: changes from tonight's rehearsal: - CueFader is closer to actually running the show, computes DMX levels to send. - KeyboardComposer is not a dummy. Use DMXDUMMY=1 to disable it. - Submaster: subs can now be "temporary" -- i.e. they shouldn't be saved or loaded. to save a temporary sub, make a copy of it with a proper name since the computed name will be ugly. Also, get_normalized_copy() and crossfade() methods added. linear_fade helper (shouldn't be in Submaster, probably) added too. - dmxchanedit: longer labels - cuelist1 now has some bogus data in it and some crap removed - dmxclient: now listens to the $DMXHOST and $DMXDUMMY env variables. - patchdata: now up to date with this year's show - danshow subs song{01..19}: removed. maybe we'll re-add them in an archive directory.
author dmcc
date Tue, 08 Jul 2003 16:19:55 +0000
parents e0c227168519
children f8b5cb5fbeed
comparison
equal deleted inserted replaced
166:7ccf1d10804b 167:79bc84310e80
1 from __future__ import division, nested_scopes 1 from __future__ import division, nested_scopes
2 import Tix as Tk 2 import Tix as Tk
3 import time 3 import time
4 from TreeDict import TreeDict, allow_class_to_be_pickled 4 from TreeDict import TreeDict, allow_class_to_be_pickled
5 from TLUtility import enumerate 5 from TLUtility import enumerate
6 import Submaster
6 7
7 cue_state_indicator_colors = { 8 cue_state_indicator_colors = {
8 # bg fg 9 # bg fg
9 'prev' : ('blue', 'white'), 10 'prev' : ('blue', 'white'),
10 'cur' : ('yellow', 'black'), 11 'cur' : ('yellow', 'black'),
77 self.timer_entry = Tk.Control(self, step=0.5, min=0, integer=0) 78 self.timer_entry = Tk.Control(self, step=0.5, min=0, integer=0)
78 self.timer_entry.entry.configure(textvariable=self.timer_var, width=5, 79 self.timer_entry.entry.configure(textvariable=self.timer_var, width=5,
79 bg='black', fg='white') 80 bg='black', fg='white')
80 self.timer_entry.pack(fill='y', side='left') 81 self.timer_entry.pack(fill='y', side='left')
81 self.disabled = (self.button['state'] == 'disabled') 82 self.disabled = (self.button['state'] == 'disabled')
83 self.fading = 0
82 def start_fade(self, end_level=1): 84 def start_fade(self, end_level=1):
83 try: 85 try:
84 fade_time = float(self.timer_var.get()) 86 fade_time = float(self.timer_var.get())
85 except ValueError: 87 except ValueError:
86 # TODO figure out how to handle this 88 # since we use a control now, i don't think we need to worry about
89 # validation any more.
87 print "can't fade -- bad time" 90 print "can't fade -- bad time"
88 return 91 return
89 92
90 self.start_time = time.time() 93 self.start_time = time.time()
91 self.start_level = self.scale_to_fade.scale_var.get() 94 self.start_level = self.scale_to_fade.scale_var.get()
92 self.end_level = end_level 95 self.end_level = end_level
93 self.fade_length = fade_time 96 self.fade_length = fade_time
97 self.fading = 1
94 self.do_fade() 98 self.do_fade()
95 def do_fade(self): 99 def do_fade(self):
96 diff = time.time() - self.start_time 100 diff = time.time() - self.start_time
97 if diff < self.fade_length: 101 if diff < self.fade_length:
98 percent = diff / self.fade_length 102 percent = diff / self.fade_length
100 (percent * (self.end_level - self.start_level)) 104 (percent * (self.end_level - self.start_level))
101 self.scale_to_fade.scale_var.set(newlevel) 105 self.scale_to_fade.scale_var.set(newlevel)
102 106
103 if newlevel != self.end_level: 107 if newlevel != self.end_level:
104 self.after(10, self.do_fade) 108 self.after(10, self.do_fade)
109 else:
110 self.fading = 0
105 else: 111 else:
106 self.scale_to_fade.scale_var.set(self.end_level) 112 self.scale_to_fade.scale_var.set(self.end_level)
113 self.fading = 0
107 def disable(self): 114 def disable(self):
108 if not self.disabled: 115 if not self.disabled:
109 self.button['state'] = 'disabled' 116 self.button['state'] = 'disabled'
110 self.disabled = 1 117 self.disabled = 1
111 def enable(self): 118 def enable(self):
114 self.disabled = 0 121 self.disabled = 0
115 def set_time(self, time): 122 def set_time(self, time):
116 self.timer_var.set(time) 123 self.timer_var.set(time)
117 def get_time(self): 124 def get_time(self):
118 return self.timer_var.get() 125 return self.timer_var.get()
126 def is_fading(self):
127 return self.fading
119 128
120 class CueFader(Tk.Frame): 129 class CueFader(Tk.Frame):
121 def __init__(self, master, cuelist): 130 def __init__(self, master, cuelist):
122 Tk.Frame.__init__(self, master, bg='black') 131 Tk.Frame.__init__(self, master, bg='black')
123 self.cuelist = cuelist 132 self.cuelist = cuelist
187 self.autoshift(name, scale) 196 self.autoshift(name, scale)
188 197
189 scale.scale.bind("<ButtonPress>", button_press) 198 scale.scale.bind("<ButtonPress>", button_press)
190 scale.scale.bind("<ButtonRelease>", button_release) 199 scale.scale.bind("<ButtonRelease>", button_release)
191 faderframe.pack(side='bottom', fill='both', expand=1) 200 faderframe.pack(side='bottom', fill='both', expand=1)
201 self.cues_as_subs = {}
192 def get_scale_desc(self, val, name): 202 def get_scale_desc(self, val, name):
193 go_button = self.go_buttons.get(name) 203 go_button = self.go_buttons.get(name)
194 if go_button: 204 if go_button:
195 time = go_button.get_time() 205 time = go_button.get_time()
196 return "%0.2f%%, %0.1fs left" % (val, time - ((val / 100.0) * time)) 206 return "%0.2f%%, %0.1fs left" % (val, time - ((val / 100.0) * time))
208 return 218 return
209 219
210 for scale_name, scale in self.scales.items(): 220 for scale_name, scale in self.scales.items():
211 scale.scale.set(0) 221 scale.scale.set(0)
212 self.cuelist.shift((-1, 1)[name == 'Next']) 222 self.cuelist.shift((-1, 1)[name == 'Next'])
223
224 # now load the subs to fade between
225 for cue, name in zip(self.cuelist.get_current_cues(),
226 ('Prev', 'Cur', 'Next')):
227 self.cues_as_subs[name] = cue.get_levels_as_sub()
228 print "cues_as_subs", self.cues_as_subs
213 def autoshift(self, name, scale): 229 def autoshift(self, name, scale):
214 scale_val = scale.scale_var.get() 230 scale_val = scale.scale_var.get()
215 231
216 if scale_val == 1: 232 if scale_val == 1:
217 if self.auto_shift.get(): 233 if self.auto_shift.get():
235 self.go_buttons[d].disable() 251 self.go_buttons[d].disable()
236 else: 252 else:
237 # undo above work 253 # undo above work
238 self.scales[d].enable() 254 self.scales[d].enable()
239 self.go_buttons[d].enable() 255 self.go_buttons[d].enable()
256
257 cur_sub = self.cues_as_subs.get('Cur')
258 if cur_sub:
259 other_sub = self.cues_as_subs[name]
260 # print 'fade between %s and %s (%.2f)' % (cur_sub, other_sub, scale_val)
261 self.current_levels_as_sub = cur_sub.crossfade(other_sub, scale_val)
262 print "current levels", self.current_levels_as_sub.get_dmx_list()
263 # print
240 def opposite_direction(self, d): 264 def opposite_direction(self, d):
241 if d == 'Next': 265 if d == 'Next':
242 return 'Prev' 266 return 'Prev'
243 else: 267 else:
244 return 'Next' 268 return 'Next'
245 269
246 class Cue: 270 class Cue:
247 """A Cue has a name, a time, and any number of other attributes.""" 271 """A Cue has a name, a time, and any number of other attributes."""
248 def __init__(self, name, time=3, **attrs): 272 def __init__(self, name, time=3, sub_levels='', **attrs):
249 self.name = name 273 self.name = name
250 self.time = time 274 self.time = time
275 self.sub_levels = sub_levels
251 self.__dict__.update(attrs) 276 self.__dict__.update(attrs)
252 def __repr__(self): 277 def __repr__(self):
253 return "<Cue %s, length %s>" % (self.name, self.time) 278 return "<Cue %s, length %s>" % (self.name, self.time)
279 def get_levels_as_sub(self):
280 """Get this Cue as a combined Submaster, normalized. This method
281 should not be called constantly, since it is somewhat expensive. It
282 will reload the submasters from disk, combine all subs together, and
283 then compute the normalized form."""
284 subdict = {}
285 try:
286 print self, self.sub_levels
287 for line in self.sub_levels.split(','):
288 line = line.strip()
289 # print 'line', line
290 sub, scale = line.split(':')
291 # print 'sub', sub, 'scale', scale
292 sub = sub.strip()
293 scale = float(scale)
294 subdict[sub] = scale
295 # print 'subdict', subdict
296 except (ValueError, AttributeError):
297 print "parsing error when computing sub for", self
298
299 s = Submaster.Submasters()
300 newsub = Submaster.sub_maxes(*[s[sub] * scale
301 for sub, scale in subdict.items()])
302 return newsub.get_normalized_copy()
254 303
255 empty_cue = Cue('empty') 304 empty_cue = Cue('empty')
256 305
257 allow_class_to_be_pickled(Cue) 306 allow_class_to_be_pickled(Cue)
258 307
264 try: 313 try:
265 self.treedict.load(filename) 314 self.treedict.load(filename)
266 except IOError: 315 except IOError:
267 self.treedict.cues = [] 316 self.treedict.cues = []
268 self.cues = self.treedict.cues 317 self.cues = self.treedict.cues
269 self.current_cue_index = 0 318 self.current_cue_index = -1
270 self.next_pointer = None 319 self.next_pointer = 0
271 self.prev_pointer = None 320 self.prev_pointer = None
272 321
273 import atexit 322 import atexit
274 atexit.register(self.save) 323 atexit.register(self.save)
275 def add_cue(self, cue, index=None): 324 def add_cue(self, cue, index=None):
463 self.master.title("Editing '%s'" % self.cue.name) 512 self.master.title("Editing '%s'" % self.cue.name)
464 except AttributeError: 513 except AttributeError:
465 pass 514 pass
466 def setup_editing_forms(self): 515 def setup_editing_forms(self):
467 self.variables = {} 516 self.variables = {}
468 for row, field in enumerate(('name', 'time', 'page', 'desc')): 517 for row, field in enumerate(('name', 'time', 'page', 'desc', 'sub_levels')):
469 lab = Tk.Label(self, text=field, fg='white', bg='black') 518 lab = Tk.Label(self, text=field, fg='white', bg='black')
470 lab.grid(row=row, column=0, sticky='nsew') 519 lab.grid(row=row, column=0, sticky='nsew')
471 520
472 entryvar = Tk.StringVar() 521 entryvar = Tk.StringVar()
473 entry = Tk.Entry(self, fg='white', bg='black', 522 entry = Tk.Entry(self, fg='white', bg='black',
486 535
487 entryvar.trace('w', field_changed) 536 entryvar.trace('w', field_changed)
488 self.columnconfigure(1, weight=1) 537 self.columnconfigure(1, weight=1)
489 def fill_in_cue_info(self): 538 def fill_in_cue_info(self):
490 self.enable_callbacks = 0 539 self.enable_callbacks = 0
491 for row, field in enumerate(('name', 'time', 'page', 'desc')): 540 for row, field in enumerate(('name', 'time', 'page', 'desc', 'sub_levels')):
492 text = '' 541 text = ''
493 if self.cue: 542 if self.cue:
494 try: 543 try:
495 text = getattr(self.cue, field) 544 text = getattr(self.cue, field)
496 except AttributeError: 545 except AttributeError: