diff --git a/bin/curvecalc b/bin/curvecalc --- a/bin/curvecalc +++ b/bin/curvecalc @@ -14,301 +14,14 @@ import twisted from twisted.web.xmlrpc import Proxy import run_local -from light9 import Submaster, dmxclient +from light9 import Submaster, dmxclient, networking from light9.TLUtility import make_attributes_from_args from light9.zoomcontrol import Zoomcontrol +from light9.curve import Curve, Curveview, Curveset, Curvesetview sys.path.append("../../semprini") from lengther import wavelength # for measuring duration of .wav -class Curve: - """curve does not know its name. see Curveset""" - points = None # x-sorted list of (x,y) - def __init__(self): - self.points = [(0,0),(10,0)] - - def load(self,filename): - self.points[:]=[] - for line in file(filename): - self.points.append(tuple([float(a) for a in line.split()])) - self.points.sort() - dispatcher.send("points changed",sender=self) - - def save(self,filename): - if filename.endswith('-music') or filename.endswith('_music'): - print "not saving music track" - return - f = file(filename,'w') - for p in self.points: - f.write("%s %s\n" % p) - f.close() - - def eval(self,t): - i = bisect_left(self.points,(t,None))-1 - - if self.points[i][0]>t: - return self.points[i][1] - if i>=len(self.points)-1: - return self.points[i][1] - - p1,p2 = self.points[i],self.points[i+1] - frac = (t-p1[0])/(p2[0]-p1[0]) - y = p1[1]+(p2[1]-p1[1])*frac - return y - - def insert_pt(self,new_pt): - i = bisect(self.points,(new_pt[0],None)) - self.points.insert(i,new_pt) - __call__=eval - -class Curveview(tk.Canvas): - def __init__(self,master,curve,**kw): - self.curve=curve - self._time = 0 - tk.Canvas.__init__(self,master,width=10,height=10, - relief='sunken',bd=1, - closeenough=5,takefocus=1, **kw) - self.selected_points=[] # idx of points being dragged - self.update() - # self.bind("",self.focus) - dispatcher.connect(self.input_time,"input time") - dispatcher.connect(self.update,"zoom changed") - dispatcher.connect(self.update,"points changed",sender=self.curve) - self.bind("",self.update) - for x in range(1, 6): - def add_kb_marker_point(evt, x=x): - print "add_kb_marker_point", evt - self.add_point((self.current_time(), (x - 1) / 4.0)) - - self.bind("" % x, add_kb_marker_point) - - - for butnum,factor in (5, 1.5),(4, 1/1.5): - self.bind(""%butnum, - lambda ev,factor=factor: - dispatcher.send("zoom about mouse", - t=self.world_from_screen(ev.x,0)[0], - factor=factor)) - self.bind("",lambda ev: - dispatcher.send("see time", - t=self.current_time())) - def current_time(self): - return self._time - - def screen_from_world(self,p): - start,end = self.zoom - ht = self.winfo_height() - return (p[0]-start)/(end-start)*self.winfo_width(), (ht-5)-p[1]*(ht-10) - def world_from_screen(self,x,y): - start,end = self.zoom - ht = self.winfo_height() - return x/self.winfo_width()*(end-start)+start, ((ht-5)-y)/(ht-10) - - def input_time(self,val): - t=val - pts = self.screen_from_world((val,0))+self.screen_from_world((val,1)) - self.delete('timecursor') - self.create_line(*pts,**dict(width=2,fill='red',tags=('timecursor',))) - self._time = t - def update(self,*args): - - self.zoom = dispatcher.send("zoom area")[0][1] - cp = self.curve.points - - visible_x = (self.world_from_screen(0,0)[0], - self.world_from_screen(self.winfo_width(),0)[0]) - - visleftidx = max(0,bisect_left(cp,(visible_x[0],None))-1) - visrightidx = min(len(cp)-1,bisect_left(cp,(visible_x[1],None))+1) - - visible_points = cp[visleftidx:visrightidx+1] - visible_idxs = range(visleftidx,visrightidx+1) - - self.delete('curve') - - self._draw_markers(visible_x) - - self._draw_line(visible_idxs,visible_points) - - self.dots = {} # idx : canvas rectangle - - if len(visible_points)<50: - self._draw_handle_points(visible_idxs,visible_points) - - def _draw_markers(self,visible_x): - mark = self._draw_one_marker - - mark(0,"0") - t1,t2=visible_x - if t2-t1<30: - for t in range(int(t1),int(t2)+1): - mark(t,str(t)) - mark(-4,"-4") - - endtimes = dispatcher.send("get max time") - if endtimes: - endtime = endtimes[0][1] - mark(endtime,"end %.1f"%endtime) - mark(endtime+10,"post %.1f"%(endtime+10)) - - def _draw_one_marker(self,t,label): - x = self.screen_from_world((t,0))[0] - self.create_line(x,self.winfo_height(),x,self.winfo_height()-20, - tags=('curve',)) - self.create_text(x,self.winfo_height()-20,text=label,anchor='s', - tags=('curve',)) - - - def _draw_line(self,visible_idxs,visible_points): - linepts=[] - step=1 - linewidth=2 - if len(visible_points)>800: - step = int(len(visible_points)/800) - linewidth=1 - for p in visible_points[::step]: - linepts.extend(self.screen_from_world(p)) - if len(linepts)<4: - return - line = self.create_line(*linepts,**dict(width=linewidth,tags='curve')) - - # canvas doesnt have keyboard focus, so i can't easily change the - # cursor when ctrl is pressed - # def curs(ev): - # print ev.state - # self.bind("",curs) - # self.bind("",lambda ev: curs(0)) - self.tag_bind(line,"",self.newpointatmouse) - - - def _draw_handle_points(self,visible_idxs,visible_points): - for i,p in zip(visible_idxs,visible_points): - rad=3 - worldp = p - p = self.screen_from_world(p) - dot = self.create_rectangle(p[0]-rad,p[1]-rad,p[0]+rad,p[1]+rad, - outline='black',fill='blue', - tags=('curve','point', 'handle%d' % i)) - if worldp[1] == 0: - rad += 3 - dot2 = self.create_oval(p[0]-rad,p[1]-rad, - p[0]+rad,p[1]+rad, - outline='darkgreen', - tags=('curve','point', 'handle%d' % i)) - self.tag_bind('handle%d' % i,"", - lambda ev,i=i: self.dotpress(ev,i)) - self.bind("", - lambda ev,i=i: self.dotmotion(ev,i)) - self.bind("", - lambda ev,i=i: self.dotrelease(ev,i)) - self.dots[i]=dot - - self.highlight_selected_dots() - - - def newpointatmouse(self, ev): - p = self.world_from_screen(ev.x,ev.y) - x, y = p - y = max(0, y) - y = min(1, y) - p = x, y - self.add_point(p) - - def add_point(self, p): - self.unselect() - self.curve.insert_pt(p) - self.update() - - def highlight_selected_dots(self): - for i,d in self.dots.items(): - if i in self.selected_points: - self.itemconfigure(d,fill='red') - else: - self.itemconfigure(d,fill='blue') - - def dotpress(self,ev,dotidx): - self.selected_points=[dotidx] - self.highlight_selected_dots() - - def dotmotion(self,ev,dotidx): - cp = self.curve.points - moved=0 - for idx in self.selected_points: - x,y = self.world_from_screen(ev.x,ev.y) - y = max(0,min(1,y)) - if idx>0 and x<=cp[idx-1][0]: - continue - if idx=cp[idx+1][0]: - continue - moved=1 - cp[idx] = (x,y) - if moved: - self.update() - def unselect(self): - self.selected_points=[] - self.highlight_selected_dots() - - def dotrelease(self,ev,dotidx): - self.unselect() - -class Curveset: - curves = None # curvename : curve - def __init__(self): - self.curves = {} - def load(self,basename): - """find all files that look like basename-curvename and add - curves with their contents""" - for filename in glob.glob("%s-*"%basename): - curvename = filename[filename.find('-')+1:] - c=Curve() - c.load(filename) - curvename = curvename.replace('-','_') - self.add_curve(curvename,c) - def save(self,basename): - """writes a file for each curve with a name - like basename-curvename""" - for name,cur in self.curves.items(): - cur.save("%s-%s" % (basename,name)) - def add_curve(self,name,curve): - self.curves[name] = curve - dispatcher.send("add_curve",sender=self,name=name) - def globalsdict(self): - return self.curves.copy() - def new_curve(self,name): - if name=="": - print "no name given" - return - while name in self.curves: - name=name+"-1" - - self.add_curve(name,Curve()) - - -class Curvesetview(tk.Frame): - curves = None # curvename : Curveview - def __init__(self,master,curveset,**kw): - self.curves = {} - self.curveset = curveset - tk.Frame.__init__(self,master,**kw) - - f = tk.Frame(self,relief='raised',bd=1) - f.pack(side='top',fill='x') - tk.Button(f,text="new curve named:", - command=lambda: self.curveset.new_curve(self.newcurvename.get())).pack(side='left') - self.newcurvename = tk.StringVar() - tk.Entry(f,textvariable=self.newcurvename).pack(side='left', - fill='x',exp=1) - - - dispatcher.connect(self.add_curve,"add_curve",sender=self.curveset) - def add_curve(self,name): - f = tk.Frame(self,relief='raised',bd=1) - f.pack(side='top',fill='both',exp=1) - tk.Label(f,text="curve %r"%name,width=15).pack(side='left') - cv = Curveview(f,self.curveset.curves[name]) - cv.pack(side='right',fill='both',exp=1) - self.curves[name] = cv - class Music: def __init__(self): self.player=None # xmlrpc Proxy to player @@ -317,7 +30,7 @@ class Music: def current_time(self): """return deferred which gets called with the current time""" if self.player is None: - self.player = Proxy("http://miles:8040") + self.player = Proxy(networking.musicUrl()) # d = self.player.callRemote("songlength") # d.addCallback(lambda l: dispatcher.send("max time",maxtime=l)) # d = self.player.callRemote("songname")