Mercurial > code > home > repos > light9
annotate flax/curvecalc @ 196:07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
author | drewp |
---|---|
date | Wed, 16 Jun 2004 10:52:26 +0000 |
parents | 45b12307c695 |
children | ba2677823b35 |
rev | line source |
---|---|
0 | 1 #!/usr/bin/python |
2 | |
3 from __future__ import division | |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
4 import xmlrpclib,time,bisect,socket,sys,textwrap |
0 | 5 import Tkinter as tk |
6 from dispatch import dispatcher | |
7 from twisted.internet import reactor,tksupport | |
8 from twisted.web.xmlrpc import Proxy | |
9 | |
10 sys.path.append("../light8") | |
11 import dmxclient | |
12 import Submaster | |
13 from TLUtility import make_attributes_from_args | |
14 | |
15 | |
16 class Curve: | |
17 """curve does not know its name. see Curveset""" | |
18 points = None # x-sorted list of (x,y) | |
19 def __init__(self): | |
20 self.points = [] | |
21 | |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
22 self.points = [(0,0),(1,1),(9,1),(10,0)] |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
23 |
0 | 24 def eval(self,t): |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
25 i = bisect.bisect_left(self.points,(t,None))-1 |
0 | 26 |
27 if self.points[i][0]>t: | |
28 return self.points[i][1] | |
29 if i>=len(self.points)-1: | |
30 return self.points[i][1] | |
31 | |
32 p1,p2 = self.points[i],self.points[i+1] | |
33 frac = (t-p1[0])/(p2[0]-p1[0]) | |
34 y = p1[1]+(p2[1]-p1[1])*frac | |
35 return y | |
36 | |
37 __call__=eval | |
38 | |
39 class Curveview(tk.Canvas): | |
40 def __init__(self,master,curve,**kw): | |
41 self.curve=curve | |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
42 tk.Canvas.__init__(self,master,height=130,closeenough=5,**kw) |
0 | 43 self.selected_points=[] # idx of points being dragged |
44 self.update() | |
45 def screen_from_world(self,p): | |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
46 return p[0]*30+5,120-p[1]*100 |
0 | 47 def world_from_screen(self,x,y): |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
48 return (x-5)/30,(120-y)/100 |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
49 def update(self): |
0 | 50 self.delete('curve') |
51 linepts=[] | |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
52 for p in self.curve.points: |
0 | 53 linepts.extend(self.screen_from_world(p)) |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
54 self.create_line(*linepts,**{'tags':'curve'}) |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
55 for i,p in enumerate(self.curve.points): |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
56 rad=3 |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
57 p = self.screen_from_world(p) |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
58 dot = self.create_rectangle(p[0]-rad,p[1]-rad,p[0]+rad,p[1]+rad, |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
59 outline='black',fill='blue', |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
60 tags=('curve','point')) |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
61 self.tag_bind(dot,"<ButtonPress-1>", |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
62 lambda ev,i=i: self.dotpress(ev,i)) |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
63 self.bind("<Motion>", |
0 | 64 lambda ev,i=i: self.dotmotion(ev,i)) |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
65 self.bind("<ButtonRelease-1>", |
0 | 66 lambda ev,i=i: self.dotrelease(ev,i)) |
67 | |
68 def dotpress(self,ev,dotidx): | |
69 self.selected_points=[dotidx] | |
70 | |
71 def dotmotion(self,ev,dotidx): | |
72 cp = self.curve.points | |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
73 |
0 | 74 for idx in self.selected_points: |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
75 newp = self.world_from_screen(ev.x,ev.y) |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
76 if idx>0 and newp[0]<=cp[idx-1][0]: |
0 | 77 continue |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
78 if idx<len(cp)-1 and newp[0]>=cp[idx+1][0]: |
0 | 79 continue |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
80 |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
81 cp[idx] = newp |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
82 |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
83 self.update() |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
84 def dotrelease(self,ev,dotidx): |
0 | 85 self.selected_points=[] |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
86 print "press",dotidx |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
87 |
0 | 88 |
89 class Curveset: | |
90 curves = None # curvename : curve | |
91 def __init__(self): | |
92 self.curves = {} | |
93 def add_curve(self,name,curve): | |
94 self.curves[name] = curve | |
95 dispatcher.send("add_curve",sender=self,name=name) | |
96 def globalsdict(self): | |
97 return self.curves.copy() | |
98 | |
99 class Curvesetview(tk.Frame): | |
100 curves = None # curvename : Curveview | |
101 def __init__(self,master,curveset,**kw): | |
102 self.curves = {} | |
103 self.curveset = curveset | |
104 tk.Frame.__init__(self,master,**kw) | |
105 dispatcher.connect(self.add_curve,"add_curve",sender=self.curveset) | |
106 def add_curve(self,name): | |
107 f = tk.Frame(self,relief='raised',bd=1) | |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
108 f.pack(side='top') |
0 | 109 tk.Label(f,text="curve %r"%name).pack(side='left') |
110 cv = Curveview(f,self.curveset.curves[name]) | |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
111 cv.pack(side='right') |
0 | 112 self.curves[name] = cv |
113 | |
114 class Music: | |
115 def __init__(self): | |
116 self.player=None # xmlrpc Proxy to player | |
117 self.recenttime=0 | |
118 def current_time(self): | |
119 """return deferred which gets called with the current time""" | |
120 if self.player is None: | |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
121 self.player = Proxy("http://spot:8040") |
0 | 122 d = self.player.callRemote('gettime') |
123 def sendtime(t): | |
124 dispatcher.send("input time",val=t) | |
125 return t # pass along to the real receiver | |
126 def error(e): | |
127 pass#self.player=None | |
128 d.addCallback(sendtime) | |
129 return d | |
130 | |
131 class Subexpr: | |
132 curveset = None | |
133 def __init__(self,curveset): | |
134 self.curveset = curveset | |
135 self.lasteval = None | |
136 self.expr="" | |
137 def eval(self,t): | |
138 if self.expr=="": | |
139 dispatcher.send("expr_error",sender=self,exc="no expr, using 0") | |
140 return 0 | |
141 glo = self.curveset.globalsdict() | |
142 glo['t'] = t | |
143 try: | |
144 self.lasteval = eval(self.expr,glo) | |
145 except Exception,e: | |
146 dispatcher.send("expr_error",sender=self,exc=e) | |
147 else: | |
148 dispatcher.send("expr_error",sender=self,exc="no errors") | |
149 return self.lasteval | |
150 | |
151 def expr(): | |
152 doc = "python expression for level as a function of t, using curves" | |
153 def fget(self): | |
154 return self._expr | |
155 def fset(self, value): | |
156 self._expr = value | |
157 dispatcher("expr_changed",sender=self) | |
158 return locals() | |
159 expr = property(**expr()) | |
160 | |
161 class Subexprview(tk.Frame): | |
162 def __init__(self,master,se,**kw): | |
163 self.subexpr=se | |
164 tk.Frame.__init__(self,master,**kw) | |
165 self.evar = tk.StringVar() | |
166 e = self.ent = tk.Entry(master,textvariable=self.evar) | |
167 e.pack(side='left',fill='both',exp=1) | |
168 self.expr_changed() | |
169 self.evar.trace_variable('w',self.evar_changed) | |
170 dispatcher.connect(self.expr_changed,"expr_changed", | |
171 sender=self.subexpr) | |
172 self.error = tk.Label(master) | |
173 self.error.pack(side='left') | |
174 dispatcher.connect(lambda exc: self.error.config(text=str(exc)), | |
175 "expr_error",sender=self.subexpr,weak=0) | |
176 def expr_changed(self): | |
177 if self.subexpr.expr!=self.evar.get(): | |
178 self.evar.set(self.subexpr.expr) | |
179 def evar_changed(self,*args): | |
180 self.subexpr.expr = self.evar.get() | |
181 | |
182 class Subterm: | |
183 """one Submaster and its Subexpr""" | |
184 def scaled(self,t): | |
185 return self.sub * self.subexpr.eval(t) | |
186 | |
187 class Subtermview(tk.Frame): | |
188 def __init__(self,master,st,**kw): | |
189 self.subterm = st | |
190 tk.Frame.__init__(self,master,bd=1,relief='raised',**kw) | |
191 tk.Label(self,text="sub %r" % self.subterm.sub.name).pack(side='left') | |
192 sev=Subexprview(self,self.subterm.subexpr) | |
193 sev.pack(side='left',fill='both',exp=1) | |
194 | |
195 class Output: | |
196 def __init__(self,subterms): | |
197 make_attributes_from_args('subterms') | |
198 def send_dmx(self,t): | |
199 | |
200 scaledsubs=[] | |
201 for st in self.subterms: | |
202 scl = st.scaled(t) | |
203 scaledsubs.append(scl) | |
204 out = Submaster.sub_maxes(*scaledsubs) | |
205 dispatcher.send("output levels",val=out.get_levels()) | |
206 dmxclient.outputlevels(out.get_dmx_list(),twisted=1) | |
207 | |
208 | |
209 ####################################################################### | |
210 root=tk.Tk() | |
211 | |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
212 m=Music() |
0 | 213 |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
214 cs = Curveset() |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
215 csv = Curvesetview(root,cs) |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
216 csv.pack() |
0 | 217 |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
218 for loop in range(6): |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
219 cs.add_curve('c'+str(loop+1),Curve()) |
0 | 220 |
221 | |
222 subterms = [] | |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
223 for subname in "zip_orange","zip_red": |
0 | 224 |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
225 se = Subexpr(cs) |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
226 if subname=='zip_orange': |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
227 se.expr="c1(t)+c2(t)+c3(t)+c4(t)+c5(t)" |
0 | 228 |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
229 st=Subterm() |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
230 st.sub=Submaster.Submaster(subname) |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
231 st.subexpr=se |
0 | 232 |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
233 stv=Subtermview(root,st) |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
234 stv.pack(side='top',fill='x',exp=1) |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
235 subterms.append(st) |
0 | 236 |
237 out = Output(subterms) | |
238 | |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
239 for signame,textfilter in [ |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
240 ('input time',lambda t: "%.2fs"%t), |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
241 ('output levels', |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
242 lambda levels: textwrap.fill("; ".join(["%s:%.2f"%(n,v) |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
243 for n,v in levels.items()]),100)), |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
244 ('update period',lambda t: "%.1fms"%(t*1000)), |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
245 ]: |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
246 l = tk.Label(root,anchor='w') |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
247 l.pack(side='top',fill='x') |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
248 dispatcher.connect(lambda val,l=l,sn=signame,tf=textfilter: |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
249 l.config(text=sn+": "+tf(val)), |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
250 signame,weak=0) |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
251 |
0 | 252 |
253 recent_t=[] | |
254 def update(): | |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
255 d = m.current_time() |
0 | 256 d.addCallback(update2) |
257 d.addErrback(updateerr) | |
258 def updateerr(e): | |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
259 reactor.callLater(1,update) |
0 | 260 def update2(t): |
196
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
261 global recent_t |
07bac5061d69
evaluates curves based on input time from ascoltami; outputs dmx
drewp
parents:
0
diff
changeset
|
262 reactor.callLater(.001,update) |
0 | 263 |
264 recent_t = recent_t[-50:]+[t] | |
265 period = (recent_t[-1]-recent_t[0])/len(recent_t) | |
266 dispatcher.send("update period",val=period) | |
267 out.send_dmx(t) | |
268 update() | |
269 | |
270 tksupport.install(root,ms=10) | |
271 if 0: | |
272 sys.path.append("/home/drewp/projects/editor/pour") | |
273 from utils import runstats | |
274 runstats("reactor.run()") | |
275 else: | |
276 reactor.run() |