Mercurial > code > home > repos > light9
annotate 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 |
rev | line source |
---|---|
0 | 1 from __future__ import division |
2 from TLUtility import dict_scale, dict_max | |
3 | |
4 import sys | |
5 sys.path.append('../light8') | |
6 | |
7 import Patch | |
8 | |
9 class Submaster: | |
10 "Contain a dictionary of levels, but you didn't need to know that" | |
167 | 11 def __init__(self, name, leveldict=None, temporary=0): |
0 | 12 self.name = name |
167 | 13 self.temporary = temporary |
0 | 14 if leveldict: |
15 self.levels = leveldict | |
16 else: | |
17 self.levels = {} | |
18 self.reload() | |
19 def reload(self): | |
167 | 20 if self.temporary: |
21 return | |
0 | 22 try: |
23 self.levels.clear() | |
24 subfile = file("subs/%s" % self.name) | |
25 for line in subfile.readlines(): | |
26 if not line.strip(): # if line is only whitespace | |
27 continue # "did i say newspace?" | |
28 | |
29 try: | |
30 name, val = line.split(':') | |
31 name = name.strip() | |
32 self.levels[name] = float(val) | |
33 except ValueError: | |
34 print "(%s) Error with this line: %s" % (self.name, | |
35 line[:-1]) | |
36 except IOError: | |
37 print "Can't read file for sub: %s" % self.name | |
38 def save(self): | |
167 | 39 if self.temporary: |
40 return | |
41 | |
0 | 42 subfile = file("subs/%s" % self.name, 'w') |
43 names = self.levels.keys() | |
44 names.sort() | |
45 for name in names: | |
46 val = self.levels[name] | |
47 subfile.write("%s : %s\n" % (name, val)) | |
48 def set_level(self, channelname, level, save=1): | |
49 self.levels[Patch.resolve_name(channelname)] = level | |
50 if save: | |
51 self.save() | |
52 def set_all_levels(self, leveldict): | |
53 self.levels.clear() | |
54 for k, v in leveldict.items(): | |
55 self.set_level(k, v, save=0) | |
56 self.save() | |
57 def get_levels(self): | |
58 return self.levels | |
59 def __mul__(self, scalar): | |
60 return Submaster("%s*%s" % (self.name, scalar), | |
167 | 61 dict_scale(self.levels, scalar), temporary=1) |
0 | 62 __rmul__ = __mul__ |
63 def max(self, *othersubs): | |
64 return sub_maxes(self, *othersubs) | |
65 def __repr__(self): | |
138 | 66 levels = ' '.join(["%s:%.2f" % item for item in self.levels.items()]) |
67 return "<'%s': [%s]>" % (self.name, levels) | |
0 | 68 def get_dmx_list(self): |
69 leveldict = self.get_levels() # gets levels of sub contents | |
70 | |
71 levels = [0] * 68 | |
72 for k, v in leveldict.items(): | |
138 | 73 dmxchan = Patch.get_dmx_channel(k) - 1 |
74 levels[dmxchan] = max(v, levels[dmxchan]) | |
0 | 75 |
76 return levels | |
138 | 77 def normalize_patch_names(self): |
167 | 78 """Use only the primary patch names.""" |
138 | 79 # possibly busted -- don't use unless you know what you're doing |
80 self.set_all_levels(self.levels.copy()) | |
167 | 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 | |
0 | 113 |
114 def sub_maxes(*subs): | |
115 return Submaster("max(%r)" % (subs,), | |
167 | 116 dict_max(*[sub.levels for sub in subs]), temporary=1) |
0 | 117 |
118 class Submasters: | |
119 "Collection o' Submaster objects" | |
120 def __init__(self): | |
121 self.submasters = {} | |
122 | |
123 import os | |
124 files = os.listdir('subs') | |
125 | |
126 for filename in files: | |
138 | 127 # we don't want these files |
128 if filename.startswith('.') or filename.endswith('~') or \ | |
129 filename.startswith('CVS'): | |
0 | 130 continue |
131 self.submasters[filename] = Submaster(filename) | |
132 def get_all_subs(self): | |
133 "All Submaster objects" | |
165
1fe54442db38
get_all_subs sorts, and puts some elements at the end
drewp
parents:
138
diff
changeset
|
134 l = self.submasters.items() |
1fe54442db38
get_all_subs sorts, and puts some elements at the end
drewp
parents:
138
diff
changeset
|
135 l.sort() |
1fe54442db38
get_all_subs sorts, and puts some elements at the end
drewp
parents:
138
diff
changeset
|
136 l = [x[1] for x in l] |
1fe54442db38
get_all_subs sorts, and puts some elements at the end
drewp
parents:
138
diff
changeset
|
137 songs = [] |
1fe54442db38
get_all_subs sorts, and puts some elements at the end
drewp
parents:
138
diff
changeset
|
138 notsongs = [] |
1fe54442db38
get_all_subs sorts, and puts some elements at the end
drewp
parents:
138
diff
changeset
|
139 for s in l: |
1fe54442db38
get_all_subs sorts, and puts some elements at the end
drewp
parents:
138
diff
changeset
|
140 if s.name.startswith('song'): |
1fe54442db38
get_all_subs sorts, and puts some elements at the end
drewp
parents:
138
diff
changeset
|
141 songs.append(s) |
1fe54442db38
get_all_subs sorts, and puts some elements at the end
drewp
parents:
138
diff
changeset
|
142 else: |
1fe54442db38
get_all_subs sorts, and puts some elements at the end
drewp
parents:
138
diff
changeset
|
143 notsongs.append(s) |
1fe54442db38
get_all_subs sorts, and puts some elements at the end
drewp
parents:
138
diff
changeset
|
144 combined = notsongs + songs |
1fe54442db38
get_all_subs sorts, and puts some elements at the end
drewp
parents:
138
diff
changeset
|
145 return combined |
0 | 146 def get_sub_by_name(self, name): |
147 "Makes a new sub if there isn't one." | |
148 return self.submasters.get(name, Submaster(name)) | |
149 __getitem__ = get_sub_by_name | |
150 | |
151 if __name__ == "__main__": | |
152 Patch.reload_data() | |
153 s = Submasters() | |
154 print s.get_all_subs() | |
138 | 155 if 0: # turn this on to normalize all subs |
156 for sub in s.get_all_subs(): | |
157 print "before", sub | |
158 sub.normalize_patch_names() | |
159 sub.save() | |
160 print "after", sub |