Files @ 4682f604b245
Branch filter:

Location: light9/light8/Lightboard.py - annotation

drewp@bigasterisk.com
dead code
afbdae5e1359
45b12307c695
45b12307c695
45b12307c695
ddd3c8f04640
0969d8a6729d
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
233fe8cefa36
233fe8cefa36
6f9898f00c9c
45b12307c695
45b12307c695
0bf7e664f913
45b12307c695
45b12307c695
45b12307c695
45b12307c695
0bf7e664f913
45b12307c695
45b12307c695
afbdae5e1359
45b12307c695
afbdae5e1359
45b12307c695
2dfae9ed1cda
15ead14b4dd1
45b12307c695
47bda76f5236
47bda76f5236
47bda76f5236
45b12307c695
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
0969d8a6729d
0969d8a6729d
45b12307c695
45b12307c695
45b12307c695
57b3c454465a
45b12307c695
45b12307c695
45b12307c695
afbdae5e1359
afbdae5e1359
45b12307c695
2f2eb802e93d
ddd3c8f04640
ddd3c8f04640
45b12307c695
45b12307c695
e04f7b552bcd
45b12307c695
45b12307c695
45b12307c695
e04f7b552bcd
0969d8a6729d
45b12307c695
45b12307c695
45b12307c695
45b12307c695
2f2eb802e93d
45b12307c695
0969d8a6729d
0969d8a6729d
0969d8a6729d
0969d8a6729d
35e0c467a292
0969d8a6729d
233fe8cefa36
233fe8cefa36
ddd3c8f04640
ddd3c8f04640
0969d8a6729d
45b12307c695
e04f7b552bcd
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
45b12307c695
e04f7b552bcd
0969d8a6729d
45b12307c695
45b12307c695
45b12307c695
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
45b12307c695
e04f7b552bcd
45b12307c695
45b12307c695
45b12307c695
e04f7b552bcd
e04f7b552bcd
2dfae9ed1cda
47bda76f5236
45b12307c695
e04f7b552bcd
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
e04f7b552bcd
e04f7b552bcd
e04f7b552bcd
e04f7b552bcd
e04f7b552bcd
e04f7b552bcd
45b12307c695
45b12307c695
45b12307c695
45b12307c695
e04f7b552bcd
e04f7b552bcd
45b12307c695
45b12307c695
45b12307c695
ddd3c8f04640
45b12307c695
ddd3c8f04640
45b12307c695
ddd3c8f04640
45b12307c695
45b12307c695
ddd3c8f04640
a995fd1a8f03
a995fd1a8f03
ddd3c8f04640
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
57b3c454465a
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
57b3c454465a
57b3c454465a
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
0969d8a6729d
0969d8a6729d
0969d8a6729d
233fe8cefa36
d5deeed83228
d5deeed83228
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
2dfae9ed1cda
609cb9ae53b1
45b12307c695
609cb9ae53b1
45b12307c695
2f2eb802e93d
2f2eb802e93d
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
e04f7b552bcd
45b12307c695
47bda76f5236
47bda76f5236
47bda76f5236
45b12307c695
2dfae9ed1cda
2dfae9ed1cda
2dfae9ed1cda
2dfae9ed1cda
2dfae9ed1cda
2dfae9ed1cda
6f9898f00c9c
afbdae5e1359
45b12307c695
2f2eb802e93d
2f2eb802e93d
2f2eb802e93d
2f2eb802e93d
2f2eb802e93d
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
e04f7b552bcd
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
0969d8a6729d
45b12307c695
45b12307c695
35e0c467a292
45b12307c695
45b12307c695
ddd3c8f04640
45b12307c695
ddd3c8f04640
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
45b12307c695
ddd3c8f04640
45b12307c695
0bf7e664f913
45b12307c695
45b12307c695
45b12307c695
45b12307c695
2dfae9ed1cda
2dfae9ed1cda
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
47bda76f5236
ddd3c8f04640
ddd3c8f04640
ddd3c8f04640
ddd3c8f04640
ddd3c8f04640
ddd3c8f04640
ddd3c8f04640
ddd3c8f04640
ddd3c8f04640
ddd3c8f04640
ddd3c8f04640
ddd3c8f04640
ddd3c8f04640
ddd3c8f04640
ddd3c8f04640
15ead14b4dd1
15ead14b4dd1
15ead14b4dd1
15ead14b4dd1
15ead14b4dd1
15ead14b4dd1
ddd3c8f04640
ddd3c8f04640
ddd3c8f04640
from __future__ import nested_scopes,division

from Tix import *
from signal import signal, SIGINT
from time import time
import sys, cPickle, random

from uihelpers import *
from panels import *
from Xfader import *
from subediting import Subediting
from Fader import Fader
from ExternalInput import ExternalSliders
import io, stage, Subs, Patch, ExtSliderMapper
import dmxclient

class Pickles:
    def __init__(self, scalelevels, subs=None, windowpos=None):
        self.scalelevels = dict([(name, lev.get()) 
            for name, lev in scalelevels.items()])
        self.substate = dict([(name, subobj.get_state())
            for name, subobj in subs])
        self.windowpos = windowpos

class Lightboard:
    def __init__(self, master, DUMMY):
        self.master = master

        self.DUMMY = DUMMY
        self.jostle_mode = 0
        self.lastline = None

        self.channel_levels = [] # these are actually the labels for the
                                 # channel levels, and should probably be moved
                                 # to panels.Leveldisplay
        self.scalelevels = {}

        self.lastsublevels = {}  # to determine which subs changed
        self.unchangedeffect = {} # dict of levels for lights that didn't 
                                  # change last time
        self.lastunchangedgroup = {}

        # doesn't draw any UI yet-- look for self.xfader.setupwidget()
        self.xfader = Xfader(self.scalelevels) 
        self.oldlevels = [None] * 68 # never replace this; just clear it
        self.subediting = Subediting(currentoutputlevels=self.oldlevels)

        self.windowpos = 0
        self.get_data()
        self.buildinterface()
        self.load()

        print "Light 8.8: Entering backgroundloop"
        self.backgroundloop()
        self.updatestagelevels()
        self.rec_file = open('light9.log', 'a')
        self.record_start()
        
    def buildinterface(self):
        print "Light 8.8: Constructing interface..."
        for w in self.master.winfo_children():
            w.destroy()

        print "\tstage"
        stage_tl = toplevelat('stage')
        s = stage.Stage(stage_tl)
        stage.createlights(s)
        s.setsubediting(self.subediting)
        s.pack()
        self.stage = s # save it

        sub_tl = toplevelat('sub')
        scene_tl = toplevelat('scenes')
        effect_tl = toplevelat('effect')

        print "\tslider patching -- It can't be turned off!"
        mapping_tl = toplevelat('mapping')
        self.slidermapper = ExtSliderMapper.ExtSliderMapper(mapping_tl, 
                                                            self.scalelevels, 
                                                            ExternalSliders(),
                                                            self)
        self.slidermapper.pack()

        print "\tsubmaster control"
        self.subpanels = Subpanels(sub_tl, effect_tl, scene_tl, self, 
                                   self.scalelevels, Subs, self.xfader, 
                                   self.changelevel, self.subediting, 
                                   Subs.longestsubname())

        for n, lev in self.scalelevels.items():
            self.lastsublevels[n] = lev.get()

        print "\tlevel display"
        leveldisplay_tl = toplevelat('leveldisplay')
        leveldisplay_tl.bind('<Escape>', sys.exit)

        self.leveldisplay = Leveldisplay(leveldisplay_tl, self.channel_levels)
        # I don't think we need this
        # for i in range(0,len(self.channel_levels)):
            # self.channel_levels[i].config(text=self.oldlevels[i])
            # colorlabel(self.channel_levels[i])

        print "\tconsole"
        Console(self)

        # root frame
        print "\tcontrol panel"
        self.master.configure(bg='black')
        controlpanel = Controlpanel(self.master, self.xfader, self.refresh, 
            self.quit, self.toggle_jostle, self.nonzerosubs)
        
        print "\tcrossfader"
        xf=Frame(self.master)
        xf.pack(side='right')

        self.master.bind('<q>', self.quit)
        self.master.bind('<r>', self.refresh)
        leveldisplay_tl.bind('<q>', self.quit)
        leveldisplay_tl.bind('<r>', self.refresh)

        self.xfader.setupwidget(xf)
        controlpanel.pack()

        print "\tcue fader (skipped)"
        # cuefader_tl = toplevelat('cuefader')
        # cuefader = Fader(cuefader_tl, Subs.cues, self.scalelevels)
        # cuefader.pack()
        print "Light 8.8: Everything's under control"


    def get_data(self,*args):
        Subs.reload_data(self.DUMMY)
        Patch.reload_data(self.DUMMY)
        print "Light 8.8:", len(Patch.patch), "dimmers patched"
        print "Light 8.8:", len(Subs.subs), "submasters loaded"

    def refresh(self, *args):
        'rebuild interface, reload data'
        print "Light 8.8: Refresh initiated.  Cross your fingers."
        self.get_data()
        print "Light 8.8: Subediting refreshed"
        self.subediting.refresh()
        print "Light 8.8: Rebuilding interface..."
        self.buildinterface()
        bindkeys(self.master,'<Escape>', self.quit)
        print "Light 8.8: Setting up slider patching..."
        self.slidermapper.setup()
        # self.master.tk_setPalette('gray40')
        print "Light 8.8: Now back to your regularly scheduled Light 8"

    def stageassub(self):
        """returns the current onstage lighting as a levels
        dictionary, skipping the zeros, and using names where
        possible"""
        levs=self.oldlevels
        
        return dict([(Patch.get_channel_name(i),l) for i,l
                     in zip(range(1,len(levs)+1),levs)
                     if l>0])
    def save_sub(self, name, levels, refresh=1):
        if not name:
            print "Enter sub name in console."
            return

        st = ''
        linebuf = 'subs["%s"] = {' % name
        for channame,lev in levels.items():
            if len(linebuf) > 60: 
                st += linebuf + '\n   '
                linebuf = ''

            linebuf += ' "%s" : %d,' % (channame, lev)
        st += linebuf + '}\n'
        if self.DUMMY:
            filename = 'ConfigDummy.py'
        else:
            filename = 'Config.py'
        f = open(filename, 'a')
        f.write(st)
        f.close()
        print 'Added sub:', st
        if refresh:
            self.refresh()

    # this is called on a loop, and ALSO by the Scales
    def changelevel(self, *args):
        'Amp trims slider'

        # load levels from external sliders
        extlevels = self.slidermapper.get_levels()
        for name, val in extlevels.items():
            if name in self.scalelevels:
                sl = self.scalelevels[name]
                sl.set(val)
        
        # newstart = time()

        # learn what changed
        unchangedgroup = {}
        changedgroup = {}
        for name, lastlevel in self.lastsublevels.items():
            newlevel = self.scalelevels[name].get()
            if lastlevel != newlevel:
                changedgroup[name] = newlevel
            else:
                unchangedgroup[name] = newlevel

        changedeffect = {}
        if not changedgroup:
            # should load levels from last time
            pass
        else:
            # calculate effect of new group.  this should take no time if 
            # nothing changed
            for name, level in changedgroup.items():
                newlevels = Subs.subs[name].get_levels(level=level)
                for (ch, fadelev) in newlevels.items():
                    changedeffect[ch-1] = \
                        max(changedeffect.get(ch-1, 0), fadelev)

        if unchangedgroup != self.lastunchangedgroup:
            # unchanged group changed! (confusing, huh?)
            # this means: the static subs from the last time are not the same 
            # as they are this time, so we recalculate effect of unchanged group
            self.unchangedeffect = {}
            for name, level in unchangedgroup.items():
                newlevels = Subs.subs[name].get_levels(level=level)
                for (ch, fadelev) in newlevels.items():
                    self.unchangedeffect[ch-1] = \
                        max(self.unchangedeffect.get(ch-1, 0), fadelev)
            self.lastunchangedgroup = unchangedgroup
                
        # record sublevels for future generations (iterations, that is)
        for name in self.lastsublevels:
            self.lastsublevels[name] = self.scalelevels[name]

        # merge effects together
        levels = [0] * 68
        if changedeffect:
            levels = [int(max(changedeffect.get(ch, 0), 
                              self.unchangedeffect.get(ch, 0)))
                        for ch in range(0, 68)]
        else:
            levels = [int(self.unchangedeffect.get(ch, 0))
                        for ch in range(0, 68)]

        '''
        newend = time()

        levels_opt = levels
        
        oldstart = time()
        # i tried to optimize this to a dictionary, but there was no speed
        # improvement
        levels = [0] * 68
        for name, s in Subs.subs.items():
            sublevel = self.scalelevels[name].get()
            newlevels = s.get_levels(level=sublevel)
            self.lastsublevels[name] = sublevel # XXX remove
            for (ch, fadelev) in newlevels.items():
                levels[ch-1] = max(levels[ch-1], fadelev)
        levels = [int(l) for l in levels]
        oldend = time()

        newtime = newend - newstart
        oldtime = oldend - oldstart
        print "new", newtime, 'old', (oldend - oldstart), 'sup', \
               oldtime / newtime
        
        if levels != levels_opt: 
            raise "not equal"
            # for l, lo in zip(levels, levels_opt):
                # print l, lo
        '''
        
        for lev,lab,oldlev,numlab in zip(levels, self.channel_levels, 
                                         self.oldlevels, 
                                         self.leveldisplay.number_labels):
            if lev != oldlev:
                lab.config(text="%d" % lev) # update labels in lev display
                colorlabel(lab)             # recolor labels
                if lev < oldlev:
                    numlab['bg'] = 'blue'
                else:
                    numlab['bg'] = 'red'
            else:
                numlab['bg'] = 'grey40'

        # replace the elements in oldlevels - don't make a new list 
        # (Subediting is watching it)
        self.oldlevels[:] = levels[:]
            
        if self.jostle_mode:
            delta = random.randrange(-1, 2, 1) # (-1, 0, or 1)
            # print "delta", delta
            levels = [min(100, max(x + delta, 0)) for x in levels]
            # print "jostled", levels

        dmxclient.outputlevels([l/100 for l in levels])
#        self.parportdmx.sendlevels(levels)

    def updatestagelevels(self):
        self.master.after(100, self.updatestagelevels)
        for lev, idx in zip(self.oldlevels, xrange(0, 68 + 1)):
            self.stage.updatelightlevel(Patch.get_channel_name(idx + 1), lev)

    def load(self):
        try:
            filename = '/tmp/light9.prefs'
            if self.DUMMY:
                filename += '.dummy'
            print "Light 8.8: Loading from", filename
            file = open(filename, 'r')
            p = cPickle.load(file)
            for s, v in p.scalelevels.items():
                try:
                    self.scalelevels[s].set(v)
                except Exception,e:
                    print "Couldn't set %s -> %s: %s" % (s, v,e)
            for name, substate in p.substate.items():
                try:
                    Subs.subs[name].set_state(substate)
                except Exception, e:
                    print "Couldn't set sub %s state: %s" % (name,e)
        except IOError, e:
            print "IOError: Couldn't load prefs (%s): %s" % (filename,e)
        except EOFError, e:
            print "EOFrror: Couldn't load prefs (%s): %s" % (filename,e)
        except Exception,e:
            print "Couldn't load prefs (%s): %s" % (filename,e)
        self.slidermapper.setup()

    def backgroundloop(self, *args):
        self.master.after(150, self.backgroundloop, ())
        self.changelevel()
    def quit(self, *args):
        print "Light 8.8: And that's my cue to exit..."
        self.save()
        self.record_end()
        self.master.destroy()
        sys.exit()
    def save(self, *args):
        filename = '/tmp/light9.prefs'
        if self.DUMMY:
            filename += '.dummy'
        print "Light 8.8: Saving to", filename
        file = open(filename, 'w')

        try:
            cPickle.dump(Pickles(self.scalelevels, Subs.subs.items()), file)
        except cPickle.UnpickleableError:
            print "UnpickleableError!  There's yer problem."
    def toggle_jostle(self, *args):
        self.jostle_mode = not self.jostle_mode
        if self.jostle_mode:
            print 'Light 8.8: Perhaps we can jost-le your memory?'
        else:
            print 'Light 8.8: He remembers! (jostle off)'
    def nonzerosubs(self, *args):
        print "Light 8.8: Active subs:"
        for n, dv in self.scalelevels.items():
            if dv.get() > 0:
                print "%-.4f: %s" % (dv.get(), n)
    def record_start(self):
        print "Light 8.8: Recorder started"
        self.rec_file.write("%s:\t%s\n" % (time(), "--- Start ---"))
        self.record_stamp()
    def record_end(self):
        print "Light 8.8: Recorder shutdown"
        self.rec_file.write("%s:\t%s\n" % (time(), "--- End ---"))
    def record_stamp(self):
        'Record the current submaster levels, continue this loop'
        levels = []
        for n, v in self.scalelevels.items():
            lev = v.get()
            if lev:
                levels.append('%s\t%s' % (n, lev))


        newdata = '\t'.join(levels) 
        if newdata!=self.lastline:
            template = "%s:\t%s\n" % (time(), newdata)
            self.rec_file.write(template)
            self.lastline = newdata
        self.master.after(100, self.record_stamp)
    def highlight_sub(self, name, color):
        self.subediting.colorsub(name, color)