Mercurial > code > home > repos > light9
comparison flax/Submaster.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 | 1fe54442db38 |
children | 3905d3c92aaa |
comparison
equal
deleted
inserted
replaced
166:7ccf1d10804b | 167:79bc84310e80 |
---|---|
6 | 6 |
7 import Patch | 7 import Patch |
8 | 8 |
9 class Submaster: | 9 class Submaster: |
10 "Contain a dictionary of levels, but you didn't need to know that" | 10 "Contain a dictionary of levels, but you didn't need to know that" |
11 def __init__(self, name, leveldict=None): | 11 def __init__(self, name, leveldict=None, temporary=0): |
12 self.name = name | 12 self.name = name |
13 self.temporary = temporary | |
13 if leveldict: | 14 if leveldict: |
14 self.levels = leveldict | 15 self.levels = leveldict |
15 else: | 16 else: |
16 self.levels = {} | 17 self.levels = {} |
17 self.reload() | 18 self.reload() |
18 def reload(self): | 19 def reload(self): |
20 if self.temporary: | |
21 return | |
19 try: | 22 try: |
20 self.levels.clear() | 23 self.levels.clear() |
21 subfile = file("subs/%s" % self.name) | 24 subfile = file("subs/%s" % self.name) |
22 for line in subfile.readlines(): | 25 for line in subfile.readlines(): |
23 if not line.strip(): # if line is only whitespace | 26 if not line.strip(): # if line is only whitespace |
31 print "(%s) Error with this line: %s" % (self.name, | 34 print "(%s) Error with this line: %s" % (self.name, |
32 line[:-1]) | 35 line[:-1]) |
33 except IOError: | 36 except IOError: |
34 print "Can't read file for sub: %s" % self.name | 37 print "Can't read file for sub: %s" % self.name |
35 def save(self): | 38 def save(self): |
39 if self.temporary: | |
40 return | |
41 | |
36 subfile = file("subs/%s" % self.name, 'w') | 42 subfile = file("subs/%s" % self.name, 'w') |
37 names = self.levels.keys() | 43 names = self.levels.keys() |
38 names.sort() | 44 names.sort() |
39 for name in names: | 45 for name in names: |
40 val = self.levels[name] | 46 val = self.levels[name] |
50 self.save() | 56 self.save() |
51 def get_levels(self): | 57 def get_levels(self): |
52 return self.levels | 58 return self.levels |
53 def __mul__(self, scalar): | 59 def __mul__(self, scalar): |
54 return Submaster("%s*%s" % (self.name, scalar), | 60 return Submaster("%s*%s" % (self.name, scalar), |
55 dict_scale(self.levels, scalar)) | 61 dict_scale(self.levels, scalar), temporary=1) |
56 __rmul__ = __mul__ | 62 __rmul__ = __mul__ |
57 def max(self, *othersubs): | 63 def max(self, *othersubs): |
58 return sub_maxes(self, *othersubs) | 64 return sub_maxes(self, *othersubs) |
59 def __repr__(self): | 65 def __repr__(self): |
60 levels = ' '.join(["%s:%.2f" % item for item in self.levels.items()]) | 66 levels = ' '.join(["%s:%.2f" % item for item in self.levels.items()]) |
67 dmxchan = Patch.get_dmx_channel(k) - 1 | 73 dmxchan = Patch.get_dmx_channel(k) - 1 |
68 levels[dmxchan] = max(v, levels[dmxchan]) | 74 levels[dmxchan] = max(v, levels[dmxchan]) |
69 | 75 |
70 return levels | 76 return levels |
71 def normalize_patch_names(self): | 77 def normalize_patch_names(self): |
78 """Use only the primary patch names.""" | |
72 # possibly busted -- don't use unless you know what you're doing | 79 # possibly busted -- don't use unless you know what you're doing |
73 self.set_all_levels(self.levels.copy()) | 80 self.set_all_levels(self.levels.copy()) |
81 def get_normalized_copy(self): | |
82 """Get a copy of this sumbaster that only uses the primary patch | |
83 names. The levels will be the same.""" | |
84 newsub = Submaster("%s (normalized)" % self.name, temporary=1) | |
85 newsub.set_all_levels(self.levels) | |
86 return newsub | |
87 def crossfade(self, othersub, amount): | |
88 """Returns a new sub that is a crossfade between this sub and | |
89 another submaster. | |
90 | |
91 NOTE: You should only crossfade between normalized submasters.""" | |
92 otherlevels = othersub.get_levels() | |
93 keys_set = {} | |
94 for k in self.levels.keys() + otherlevels.keys(): | |
95 keys_set[k] = 1 | |
96 all_keys = keys_set.keys() | |
97 | |
98 xfaded_sub = Submaster("xfade", temporary=1) | |
99 for k in all_keys: | |
100 xfaded_sub.set_level(k, | |
101 linear_fade(self.levels.get(k, 0), | |
102 otherlevels.get(k, 0), | |
103 amount)) | |
104 | |
105 return xfaded_sub | |
106 | |
107 def linear_fade(start, end, amount): | |
108 """Fades between two floats by an amount. amount is a float between | |
109 0 and 1. If amount is 0, it will return the start value. If it is 1, | |
110 the end value will be returned.""" | |
111 level = start + (amount * (end - start)) | |
112 return level | |
74 | 113 |
75 def sub_maxes(*subs): | 114 def sub_maxes(*subs): |
76 return Submaster("max(%r)" % (subs,), | 115 return Submaster("max(%r)" % (subs,), |
77 dict_max(*[sub.levels for sub in subs])) | 116 dict_max(*[sub.levels for sub in subs]), temporary=1) |
78 | 117 |
79 class Submasters: | 118 class Submasters: |
80 "Collection o' Submaster objects" | 119 "Collection o' Submaster objects" |
81 def __init__(self): | 120 def __init__(self): |
82 self.submasters = {} | 121 self.submasters = {} |