Files @ 79bc84310e80
Branch filter:

Location: light9/flax/Subcomposer.py - annotation

dmcc
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.
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
f433e95f2e42
45b12307c695
45b12307c695
c31601504358
c31601504358
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
c31601504358
45b12307c695
45b12307c695
45b12307c695
45b12307c695
c31601504358
c31601504358
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
f433e95f2e42
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
f433e95f2e42
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
c31601504358
c31601504358
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
c31601504358
45b12307c695
c31601504358
c31601504358
c31601504358
c31601504358
c31601504358
c31601504358
c31601504358
c31601504358
c31601504358
c31601504358
c31601504358
c31601504358
c31601504358
c31601504358
c31601504358
c31601504358
c31601504358
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
6a1f4becb1db
45b12307c695
f433e95f2e42
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
#!/usr/bin/python

from __future__ import division, nested_scopes
import Tkinter as tk
from dmxchanedit import Levelbox
import sys,os,time,atexit
sys.path.append("../light8")
import dmxclient
import Patch
import Submaster

import dispatcher

class Subcomposer(tk.Frame):
    def __init__(self, master, levelboxopts=None, dmxdummy=0, numchannels=68,
        use_persistentlevels=0):
        tk.Frame.__init__(self, master, bg='black')
        self.dmxdummy = dmxdummy
        self.numchannels = numchannels

        self.levels = [0]*68 # levels should never get overwritten, just edited

        self.levelbox = Levelbox(self)
        self.levelbox.pack(side='top')
        # the dmx levels we edit and output, range is 0..1 (dmx chan 1 is
        # the 0 element)
        self.levelbox.setlevels(self.levels)

        self.savebox = Savebox(self, self.levels, cmd=self.savenewsub)
        self.savebox.pack(side='top')

        self.loadbox = Savebox(self, self.levels, verb="Load", cmd=self.loadsub)
        self.loadbox.pack(side='top')

        def alltozero():
            self.set_levels([0] * self.numchannels)
            dispatcher.send("levelchanged")

        tk.Button(self, text="all to zero", command=alltozero).pack(side='top')

        dispatcher.connect(self.levelchanged,"levelchanged")
        dispatcher.connect(self.sendupdate,"levelchanged")

        if use_persistentlevels:
            self.persistentlevels()

        self.lastupdate=0 # time we last sent to dmx

        self.lastsent=[] # copy of levels

    def persistentlevels(self):
        """adjusts levels from subcomposer.savedlevels, if possible; and
        arranges to save the levels in that file upon exit"""    
        self.load_levels()
        atexit.register(self.save_levels)
    def save_levels(self, *args):
        levelfile = file("subcomposer.savedlevels","w")
        levelfile.write(" ".join(map(str, self.levels)))
    def load_levels(self):
        try:
            levelfile = file("subcomposer.savedlevels","r")
            levels = map(float, levelfile.read().split())
            self.set_levels(levels)
        except IOError:
            pass
    def levelchanged(self, channel=None, newlevel=None):
        if channel is not None and newlevel is not None:
            if channel>len(self.levels):
                return
            self.levels[channel-1]=max(0,min(1,float(newlevel)))
        self.levelbox.setlevels(self.levels)
    def savenewsub(self, subname):
        leveldict={}
        for i,lev in zip(range(len(self.levels)),self.levels):
            if lev!=0:
                leveldict[Patch.get_channel_name(i+1)]=lev
        
        s=Submaster.Submaster(subname,leveldict)
        s.save()
    def loadsub(self, subname):
        """puts a sub into the levels, replacing old level values"""
        s=Submaster.Submasters().get_sub_by_name(subname)
        self.levels[:]=[0]*68
        self.levels[:]=s.get_dmx_list()
        dispatcher.send("levelchanged")
    def sendupdate(self):
        if not self.dmxdummy:
            dmxclient.outputlevels(self.levels)
            self.lastupdate = time.time()
            self.lastsent = self.levels[:]
    def considersendupdate(self, use_after_loop=0):
        """If use_after_loop is true, it is the period of the after loop."""
        if self.lastsent != self.levels or time.time() > self.lastupdate + 1:
            self.sendupdate()
        if use_after_loop:
            self.after(use_after_loop, self.considersendupdate, use_after_loop)
    def set_levels(self, levels):
        self.levels[:] = levels
        dispatcher.send("levelchanged")

def Savebox(master, levels, verb="Save", cmd=None):
    f=tk.Frame(master,bd=2,relief='raised')
    tk.Label(f,text="Sub name:").pack(side='left')
    e=tk.Entry(f)
    e.pack(side='left',exp=1,fill='x')
    def cb(*args):
        subname=e.get()
        cmd(levels,subname)
        print "sub",verb,subname
    e.bind("<Return>",cb)
    tk.Button(f,text=verb,command=cb).pack(side='left')
    return f

def open_sub_editing_window(subname, use_mainloop=1, dmxdummy=0):
    if use_mainloop:
        toplevel = tk.Tk()
    else:
        toplevel = tk.Toplevel()
    if dmxdummy: 
        dummy_str = ' (dummy)'
    else:
        dummy_str = ''
    toplevel.title("Subcomposer: %s%s" % (subname, dummy_str))
    sc = Subcomposer(toplevel, use_persistentlevels=0, dmxdummy=dmxdummy)
    sc.pack(fill='both', expand=1)
    sc.loadsub(subname)
    sc.considersendupdate(use_after_loop=10)
    if use_mainloop:
        tk.mainloop()
    
#############################

if __name__ == "__main__":
    root=tk.Tk()
    root.config(bg='black')
    root.tk_setPalette("#004633")

    sc = Subcomposer(root, dmxdummy=1)
    sc.pack()

    while 1:
        if 0:
            for i in range(20): # don't let Tk take all the time
                tk._tkinter.dooneevent()
            print "loop"
        else:
            root.update()
        
        sc.considersendupdate()
        time.sleep(.01)