Files @ 07bac5061d69
Branch filter:

Location: light9/flax/curvecalc - annotation

drewp
evaluates curves based on input time from ascoltami; outputs dmx
45b12307c695
45b12307c695
45b12307c695
07bac5061d69
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
07bac5061d69
07bac5061d69
45b12307c695
07bac5061d69
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
07bac5061d69
45b12307c695
45b12307c695
45b12307c695
07bac5061d69
45b12307c695
07bac5061d69
07bac5061d69
45b12307c695
45b12307c695
07bac5061d69
45b12307c695
07bac5061d69
07bac5061d69
07bac5061d69
07bac5061d69
07bac5061d69
07bac5061d69
07bac5061d69
07bac5061d69
07bac5061d69
07bac5061d69
45b12307c695
07bac5061d69
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
07bac5061d69
45b12307c695
07bac5061d69
07bac5061d69
45b12307c695
07bac5061d69
45b12307c695
07bac5061d69
07bac5061d69
07bac5061d69
07bac5061d69
07bac5061d69
45b12307c695
07bac5061d69
07bac5061d69
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
07bac5061d69
45b12307c695
45b12307c695
07bac5061d69
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
07bac5061d69
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
07bac5061d69
45b12307c695
07bac5061d69
07bac5061d69
07bac5061d69
45b12307c695
07bac5061d69
07bac5061d69
45b12307c695
45b12307c695
45b12307c695
07bac5061d69
45b12307c695
07bac5061d69
07bac5061d69
07bac5061d69
45b12307c695
07bac5061d69
07bac5061d69
07bac5061d69
45b12307c695
07bac5061d69
07bac5061d69
07bac5061d69
45b12307c695
45b12307c695
45b12307c695
07bac5061d69
07bac5061d69
07bac5061d69
07bac5061d69
07bac5061d69
07bac5061d69
07bac5061d69
07bac5061d69
07bac5061d69
07bac5061d69
07bac5061d69
07bac5061d69
07bac5061d69
45b12307c695
45b12307c695
45b12307c695
07bac5061d69
45b12307c695
45b12307c695
45b12307c695
07bac5061d69
45b12307c695
07bac5061d69
07bac5061d69
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
#!/usr/bin/python

from __future__ import division
import xmlrpclib,time,bisect,socket,sys,textwrap
import Tkinter as tk
from dispatch import dispatcher
from twisted.internet import reactor,tksupport
from twisted.web.xmlrpc import Proxy

sys.path.append("../light8")
import dmxclient
import Submaster
from TLUtility import make_attributes_from_args


class Curve:
    """curve does not know its name. see Curveset"""
    points = None # x-sorted list of (x,y)
    def __init__(self):
        self.points = []

        self.points = [(0,0),(1,1),(9,1),(10,0)]
        
    def eval(self,t):
        i = bisect.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

    __call__=eval

class Curveview(tk.Canvas):
    def __init__(self,master,curve,**kw):
        self.curve=curve
        tk.Canvas.__init__(self,master,height=130,closeenough=5,**kw)
        self.selected_points=[] # idx of points being dragged
        self.update()
    def screen_from_world(self,p):
        return p[0]*30+5,120-p[1]*100
    def world_from_screen(self,x,y):
        return (x-5)/30,(120-y)/100
    def update(self):
        self.delete('curve')
        linepts=[]
        for p in self.curve.points:
            linepts.extend(self.screen_from_world(p))
        self.create_line(*linepts,**{'tags':'curve'})
        for i,p in enumerate(self.curve.points):
            rad=3
            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'))
            self.tag_bind(dot,"<ButtonPress-1>",
                          lambda ev,i=i: self.dotpress(ev,i))
            self.bind("<Motion>",
                          lambda ev,i=i: self.dotmotion(ev,i))
            self.bind("<ButtonRelease-1>",
                          lambda ev,i=i: self.dotrelease(ev,i))
        
    def dotpress(self,ev,dotidx):
        self.selected_points=[dotidx]

    def dotmotion(self,ev,dotidx):
        cp = self.curve.points
        
        for idx in self.selected_points:
            newp = self.world_from_screen(ev.x,ev.y)
            if idx>0 and newp[0]<=cp[idx-1][0]:
                continue
            if idx<len(cp)-1 and newp[0]>=cp[idx+1][0]:
                continue
            
            cp[idx] = newp
        
        self.update()
    def dotrelease(self,ev,dotidx):
        self.selected_points=[]
        print "press",dotidx

        
class Curveset:
    curves = None # curvename : curve
    def __init__(self):
        self.curves = {}
    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()

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)
        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')
        tk.Label(f,text="curve %r"%name).pack(side='left')
        cv = Curveview(f,self.curveset.curves[name])
        cv.pack(side='right')
        self.curves[name] = cv

class Music:
    def __init__(self):
        self.player=None # xmlrpc Proxy to player
        self.recenttime=0
    def current_time(self):
        """return deferred which gets called with the current time"""
        if self.player is None:
            self.player = Proxy("http://spot:8040")            
        d = self.player.callRemote('gettime')
        def sendtime(t):
            dispatcher.send("input time",val=t)
            return t # pass along to the real receiver
        def error(e):
            pass#self.player=None
        d.addCallback(sendtime)
        return d
        
class Subexpr:
    curveset = None
    def __init__(self,curveset):
        self.curveset = curveset
        self.lasteval = None
        self.expr=""
    def eval(self,t):
        if self.expr=="":
            dispatcher.send("expr_error",sender=self,exc="no expr, using 0")
            return 0
        glo = self.curveset.globalsdict()
        glo['t'] = t
        try:
            self.lasteval = eval(self.expr,glo)
        except Exception,e:
            dispatcher.send("expr_error",sender=self,exc=e)
        else:
            dispatcher.send("expr_error",sender=self,exc="no errors")
        return self.lasteval

    def expr():
        doc = "python expression for level as a function of t, using curves"
        def fget(self):
            return self._expr
        def fset(self, value):
            self._expr = value
            dispatcher("expr_changed",sender=self)
        return locals()
    expr = property(**expr())

class Subexprview(tk.Frame):
    def __init__(self,master,se,**kw):
        self.subexpr=se
        tk.Frame.__init__(self,master,**kw)
        self.evar = tk.StringVar()
        e = self.ent = tk.Entry(master,textvariable=self.evar)
        e.pack(side='left',fill='both',exp=1)
        self.expr_changed()
        self.evar.trace_variable('w',self.evar_changed)
        dispatcher.connect(self.expr_changed,"expr_changed",
                           sender=self.subexpr)
        self.error = tk.Label(master)
        self.error.pack(side='left')
        dispatcher.connect(lambda exc: self.error.config(text=str(exc)),
                           "expr_error",sender=self.subexpr,weak=0)
    def expr_changed(self):
        if self.subexpr.expr!=self.evar.get():
            self.evar.set(self.subexpr.expr)
    def evar_changed(self,*args):
        self.subexpr.expr = self.evar.get()

class Subterm:
    """one Submaster and its Subexpr"""
    def scaled(self,t):
        return self.sub * self.subexpr.eval(t)

class Subtermview(tk.Frame):
    def __init__(self,master,st,**kw):
        self.subterm = st
        tk.Frame.__init__(self,master,bd=1,relief='raised',**kw)
        tk.Label(self,text="sub %r" % self.subterm.sub.name).pack(side='left')
        sev=Subexprview(self,self.subterm.subexpr)
        sev.pack(side='left',fill='both',exp=1)

class Output:
    def __init__(self,subterms):
        make_attributes_from_args('subterms')
    def send_dmx(self,t):

        scaledsubs=[]
        for st in self.subterms:
            scl = st.scaled(t)
            scaledsubs.append(scl)
        out = Submaster.sub_maxes(*scaledsubs)
        dispatcher.send("output levels",val=out.get_levels())
        dmxclient.outputlevels(out.get_dmx_list(),twisted=1)


#######################################################################
root=tk.Tk()

m=Music()

cs = Curveset()
csv = Curvesetview(root,cs)
csv.pack()

for loop in range(6):
    cs.add_curve('c'+str(loop+1),Curve())


subterms = []
for subname in "zip_orange","zip_red":

    se = Subexpr(cs)
    if subname=='zip_orange':
        se.expr="c1(t)+c2(t)+c3(t)+c4(t)+c5(t)"
    
    st=Subterm()
    st.sub=Submaster.Submaster(subname)
    st.subexpr=se
    
    stv=Subtermview(root,st)
    stv.pack(side='top',fill='x',exp=1)
    subterms.append(st)

out = Output(subterms)

for signame,textfilter in [
    ('input time',lambda t: "%.2fs"%t),
    ('output levels',
     lambda levels: textwrap.fill("; ".join(["%s:%.2f"%(n,v)
                                             for n,v in levels.items()]),100)),
    ('update period',lambda t: "%.1fms"%(t*1000)),
    ]:
    l = tk.Label(root,anchor='w')
    l.pack(side='top',fill='x')
    dispatcher.connect(lambda val,l=l,sn=signame,tf=textfilter:
                       l.config(text=sn+": "+tf(val)),
                       signame,weak=0)
    

recent_t=[]
def update():
    d = m.current_time()
    d.addCallback(update2)
    d.addErrback(updateerr)
def updateerr(e):
    reactor.callLater(1,update)
def update2(t):
    global recent_t
    reactor.callLater(.001,update)

    recent_t = recent_t[-50:]+[t]
    period = (recent_t[-1]-recent_t[0])/len(recent_t)
    dispatcher.send("update period",val=period)
    out.send_dmx(t)
update()

tksupport.install(root,ms=10)
if 0:
    sys.path.append("/home/drewp/projects/editor/pour")
    from utils import runstats
    runstats("reactor.run()")
else:
    reactor.run()