comparison flax/curvecalc @ 202:97e21bc387fe

loading and saving loading and saving fixed the hanging bug in update()
author drewp
date Wed, 16 Jun 2004 14:22:48 +0000
parents f5d3492981ab
children 3905d3c92aaa
comparison
equal deleted inserted replaced
201:e4a711d9a338 202:97e21bc387fe
3 """ 3 """
4 todo: curveview should preserve more objects, for speed maybe 4 todo: curveview should preserve more objects, for speed maybe
5 5
6 """ 6 """
7 from __future__ import division 7 from __future__ import division
8 import xmlrpclib,time,socket,sys,textwrap,math 8 import xmlrpclib,time,socket,sys,textwrap,math,glob
9 from bisect import bisect_left,bisect,bisect_right 9 from bisect import bisect_left,bisect,bisect_right
10 import Tkinter as tk 10 import Tkinter as tk
11 from dispatch import dispatcher 11 from dispatch import dispatcher
12 from twisted.internet import reactor,tksupport 12 from twisted.internet import reactor,tksupport
13 from twisted.web.xmlrpc import Proxy 13 from twisted.web.xmlrpc import Proxy
23 """curve does not know its name. see Curveset""" 23 """curve does not know its name. see Curveset"""
24 points = None # x-sorted list of (x,y) 24 points = None # x-sorted list of (x,y)
25 def __init__(self): 25 def __init__(self):
26 self.points = [] 26 self.points = []
27 27
28 self.points = [(0,0),(1,1),(9,1),(10,0)] 28 def load(self,filename):
29 for x in range(11,500): 29 for line in file(filename):
30 self.points.append((x,.5)) 30 self.points.append(tuple([float(a) for a in line.split()]))
31 self.points.sort()
32 dispatcher.send("points changed",sender=self)
33
34 def save(self,filename):
35 f = file(filename,'w')
36 for p in self.points:
37 f.write("%s %s\n" % p)
38 f.close()
31 39
32 def eval(self,t): 40 def eval(self,t):
33 i = bisect_left(self.points,(t,None))-1 41 i = bisect_left(self.points,(t,None))-1
34 42
35 if self.points[i][0]>t: 43 if self.points[i][0]>t:
53 self.selected_points=[] # idx of points being dragged 61 self.selected_points=[] # idx of points being dragged
54 self.update() 62 self.update()
55 self.bind("<Enter>",self.focus) 63 self.bind("<Enter>",self.focus)
56 dispatcher.connect(self.input_time,"input time") 64 dispatcher.connect(self.input_time,"input time")
57 dispatcher.connect(self.update,"zoom changed") 65 dispatcher.connect(self.update,"zoom changed")
66 dispatcher.connect(self.update,"points changed",sender=self.curve)
58 self.bind("<Configure>",self.update) 67 self.bind("<Configure>",self.update)
59 def screen_from_world(self,p): 68 def screen_from_world(self,p):
60 start,end = self.zoom 69 start,end = self.zoom
61 ht = self.winfo_height() 70 ht = self.winfo_height()
62 return (p[0]-start)/(end-start)*self.winfo_width(), (ht-5)-p[1]*(ht-10) 71 return (p[0]-start)/(end-start)*self.winfo_width(), (ht-5)-p[1]*(ht-10)
79 self.world_from_screen(self.winfo_width(),0)[0]) 88 self.world_from_screen(self.winfo_width(),0)[0])
80 89
81 visleftidx = max(0,bisect_left(cp,(visible_x[0],None))-1) 90 visleftidx = max(0,bisect_left(cp,(visible_x[0],None))-1)
82 visrightidx = min(len(cp)-1,bisect_left(cp,(visible_x[1],None))+1) 91 visrightidx = min(len(cp)-1,bisect_left(cp,(visible_x[1],None))+1)
83 92
84 visible_points = cp[visleftidx:visrightidx] 93 visible_points = cp[visleftidx:visrightidx+1]
85 94
86 self.delete('curve') 95 self.delete('curve')
87 linepts=[] 96 linepts=[]
88 for p in visible_points: 97 for p in visible_points:
89 linepts.extend(self.screen_from_world(p)) 98 linepts.extend(self.screen_from_world(p))
99 if not linepts:
100 return
90 line = self.create_line(*linepts,**{'tags':'curve'}) 101 line = self.create_line(*linepts,**{'tags':'curve'})
91 102
92 # canvas doesnt have keyboard focus, so i can't easily change the 103 # canvas doesnt have keyboard focus, so i can't easily change the
93 # cursor when ctrl is pressed 104 # cursor when ctrl is pressed
94 # def curs(ev): 105 # def curs(ev):
95 # print ev.state 106 # print ev.state
96 # self.bind("<KeyPress>",curs) 107 # self.bind("<KeyPress>",curs)
97 # self.bind("<KeyRelease-Control_L>",lambda ev: curs(0)) 108 # self.bind("<KeyRelease-Control_L>",lambda ev: curs(0))
98 self.tag_bind(line,"<Control-ButtonPress-1>",self.newpoint) 109 self.tag_bind(line,"<Control-ButtonPress-1>",self.newpoint)
99 110
100 self.dots = {} # idx : canvas rectangle 111 self.dots = {} # idx : canvas rectangle
101 112
102 if len(visible_points)<50: ###self.zoom[1]-self.zoom[0]<30 or len(visible_points)<: 113 if len(visible_points)<50:
103 for i,p in enumerate(visible_points): 114 for i,p in enumerate(visible_points):
104 rad=3 115 rad=3
105 p = self.screen_from_world(p) 116 p = self.screen_from_world(p)
106 # if p[0]-prevx<10:
107 # # too close- skip the dots
108 # continue
109 dot = self.create_rectangle(p[0]-rad,p[1]-rad,p[0]+rad,p[1]+rad, 117 dot = self.create_rectangle(p[0]-rad,p[1]-rad,p[0]+rad,p[1]+rad,
110 outline='black',fill='blue', 118 outline='black',fill='blue',
111 tags=('curve','point')) 119 tags=('curve','point'))
112 self.tag_bind(dot,"<ButtonPress-1>", 120 self.tag_bind(dot,"<ButtonPress-1>",
113 lambda ev,i=i: self.dotpress(ev,i)) 121 lambda ev,i=i: self.dotpress(ev,i))
143 def dotmotion(self,ev,dotidx): 151 def dotmotion(self,ev,dotidx):
144 cp = self.curve.points 152 cp = self.curve.points
145 153
146 moved=0 154 moved=0
147 for idx in self.selected_points: 155 for idx in self.selected_points:
148 newp = self.world_from_screen(ev.x,ev.y) 156 x,y = self.world_from_screen(ev.x,ev.y)
149 if idx>0 and newp[0]<=cp[idx-1][0]: 157 y = max(0,min(1,y))
158 if idx>0 and x<=cp[idx-1][0]:
150 continue 159 continue
151 if idx<len(cp)-1 and newp[0]>=cp[idx+1][0]: 160 if idx<len(cp)-1 and x>=cp[idx+1][0]:
152 continue 161 continue
153 moved=1 162 moved=1
154 cp[idx] = newp 163 cp[idx] = (x,y)
155 if moved: 164 if moved:
156 self.update() 165 self.update()
157 def unselect(self): 166 def unselect(self):
158 self.selected_points=[] 167 self.selected_points=[]
159 self.highlight_selected_dots() 168 self.highlight_selected_dots()
163 172
164 class Curveset: 173 class Curveset:
165 curves = None # curvename : curve 174 curves = None # curvename : curve
166 def __init__(self): 175 def __init__(self):
167 self.curves = {} 176 self.curves = {}
177 def load(self,basename):
178 """find all files that look like basename-curvename and add
179 curves with their contents"""
180 for filename in glob.glob("%s-*"%basename):
181 curvename = filename[filename.rfind('-')+1:]
182 c=Curve()
183 c.load(filename)
184 self.add_curve(curvename,c)
185 def save(self,basename):
186 """writes a file for each curve with a name
187 like basename-curvename"""
188 for name,cur in self.curves.items():
189 cur.save("%s-%s" % (basename,name))
168 def add_curve(self,name,curve): 190 def add_curve(self,name,curve):
169 self.curves[name] = curve 191 self.curves[name] = curve
170 dispatcher.send("add_curve",sender=self,name=name) 192 dispatcher.send("add_curve",sender=self,name=name)
171 def globalsdict(self): 193 def globalsdict(self):
172 return self.curves.copy() 194 return self.curves.copy()
194 def current_time(self): 216 def current_time(self):
195 """return deferred which gets called with the current time""" 217 """return deferred which gets called with the current time"""
196 if self.player is None: 218 if self.player is None:
197 self.player = Proxy("http://spot:8040") 219 self.player = Proxy("http://spot:8040")
198 d = self.player.callRemote("songlength") 220 d = self.player.callRemote("songlength")
199 def sendmax(l): 221 d.addCallback(lambda l: dispatcher.send("max time",maxtime=l))
200 dispatcher.send("max time",maxtime=l) 222 d = self.player.callRemote("songname")
201 d.addCallback(sendmax) 223 d.addCallback(lambda n: dispatcher.send("songname",name=n))
202 d = self.player.callRemote('gettime') 224 d = self.player.callRemote('gettime')
203 def sendtime(t): 225 def sendtime(t):
204 dispatcher.send("input time",val=t) 226 dispatcher.send("input time",val=t)
205 return t # pass along to the real receiver 227 return t # pass along to the real receiver
206 def error(e): 228 def error(e):
283 scaledsubs.append(scl) 305 scaledsubs.append(scl)
284 out = Submaster.sub_maxes(*scaledsubs) 306 out = Submaster.sub_maxes(*scaledsubs)
285 dispatcher.send("output levels",val=out.get_levels()) 307 dispatcher.send("output levels",val=out.get_levels())
286 dmxclient.outputlevels(out.get_dmx_list(),twisted=1) 308 dmxclient.outputlevels(out.get_dmx_list(),twisted=1)
287 309
288 def statuslines(master): 310 def create_status_lines(master):
289 for signame,textfilter in [ 311 for signame,textfilter in [
290 ('input time',lambda t: "%.2fs"%t), 312 ('input time',lambda t: "%.2fs"%t),
291 ('output levels', 313 ('output levels',
292 lambda levels: textwrap.fill("; ".join(["%s:%.2f"%(n,v) 314 lambda levels: textwrap.fill("; ".join(["%s:%.2f"%(n,v)
293 for n,v in 315 for n,v in
298 l.pack(side='top',fill='x') 320 l.pack(side='top',fill='x')
299 dispatcher.connect(lambda val,l=l,sn=signame,tf=textfilter: 321 dispatcher.connect(lambda val,l=l,sn=signame,tf=textfilter:
300 l.config(text=sn+": "+tf(val)), 322 l.config(text=sn+": "+tf(val)),
301 signame,weak=0) 323 signame,weak=0)
302 324
325 def savesubterms(filename,subterms):
326 f = file(filename,'w')
327 for st in subterms:
328 f.write("%s %s\n" % (st.sub.name,st.subexpr.expr))
329 f.close()
330
331 def save(song,subterms,curveset):
332 savesubterms("subterms/"+song,subterms)
333 curveset.save(basename="curves/"+song)
303 334
304 ####################################################################### 335 #######################################################################
305 root=tk.Tk() 336 root=tk.Tk()
306 root.wm_geometry("790x930") 337 root.wm_geometry("790x930")
307 #root.tk_focusFollowsMouse() 338 #root.tk_focusFollowsMouse()
308 339
309 m=Music() 340 music=Music()
310 341
311 zc = Zoomcontrol(root) 342 zc = Zoomcontrol(root)
312 zc.pack(side='top',fill='x') 343 zc.pack(side='top',fill='x')
313 344
314 cs = Curveset() 345 curveset = Curveset()
315 csv = Curvesetview(root,cs) 346 csv = Curvesetview(root,curveset)
316 csv.pack(side='top',fill='both',exp=1) 347 csv.pack(side='top',fill='both',exp=1)
317 348
318 for loop in range(6): 349 song = "16mix.wav"
319 cs.add_curve('c'+str(loop+1),Curve()) 350
351 curveset.load(basename="curves/"+song)
320 352
321 subterms = [] 353 subterms = []
322 for subname in "zip_orange","zip_red": 354 for line in file("subterms/"+song):
323 355 subname,expr = line.strip().split(" ",1)
324 se = Subexpr(cs) 356
325 if subname=='zip_orange': 357 term = Subterm()
326 se.expr="c1(t)+c2(t)+c3(t)+c4(t)+c5(t)" 358
359 sexpr = Subexpr(curveset)
360 sexpr.expr = expr
327 361
328 st=Subterm() 362 term.sub = Submaster.Submaster(subname)
329 st.sub=Submaster.Submaster(subname) 363 term.subexpr = sexpr
330 st.subexpr=se 364 subterms.append(term)
331 365
332 stv=Subtermview(root,st) 366 stv=Subtermview(root,term)
333 stv.pack(side='top',fill='x') 367 stv.pack(side='top',fill='x')
334 subterms.append(st)
335 368
336 out = Output(subterms) 369 out = Output(subterms)
337 370
338 statuslines(root) 371 #save(song,subterms,curveset)
372
373 create_status_lines(root)
339 374
340 recent_t=[] 375 recent_t=[]
376 later = None
341 def update(): 377 def update():
342 d = m.current_time() 378 global later
379 d = music.current_time()
343 d.addCallback(update2) 380 d.addCallback(update2)
344 d.addErrback(updateerr) 381 d.addErrback(updateerr)
345 def updateerr(e): 382 def updateerr(e):
346 reactor.callLater(1,update) 383 global later
384 print "err",e
385 if later and not later.cancelled and not later.called: later.cancel()
386 later = reactor.callLater(1,update)
347 def update2(t): 387 def update2(t):
348 global recent_t 388 global recent_t,later
349 reactor.callLater(.001,update) 389
390 if later and not later.cancelled and not later.called: later.cancel()
391 later = reactor.callLater(.01,update)
350 392
351 recent_t = recent_t[-50:]+[t] 393 recent_t = recent_t[-50:]+[t]
352 period = (recent_t[-1]-recent_t[0])/len(recent_t) 394 period = (recent_t[-1]-recent_t[0])/len(recent_t)
353 dispatcher.send("update period",val=period) 395 dispatcher.send("update period",val=period)
354 out.send_dmx(t) 396 out.send_dmx(t)