diff --git a/light8/Lightboard.py b/light8/Lightboard.py --- a/light8/Lightboard.py +++ b/light8/Lightboard.py @@ -4,7 +4,6 @@ from Tix import * from time import sleep from signal import signal, SIGINT import sys, cPickle -# import shelve import io from uihelpers import * @@ -35,8 +34,6 @@ class Lightboard: self.oldlevels = [None] * 68 # never replace this; just clear it self.subediting = Subediting(currentoutputlevels=self.oldlevels) - # self.shelf = shelve.open('/tmp/light9.newprefs') - # self.windowpos = self.shelf.get('window', {}) self.windowpos = 0 self.get_data() self.buildinterface() @@ -150,11 +147,15 @@ class Lightboard: levels[ch-1] = max(levels[ch-1], fadelev) levels = [int(l) for l in levels] + lenlevels = len(levels) + changed = [] # list of changed levels - for lev,lab,oldlev,numlab in zip(levels, self.channel_levels, + for lev,lab,oldlev,numlab,idx in zip(levels, self.channel_levels, self.oldlevels, - self.leveldisplay.number_labels): + self.leveldisplay.number_labels, + xrange(1, lenlevels + 2)): if lev != oldlev: + changed.extend((idx, lev)) lab.config(text="%d" % lev) # update labels in lev display colorlabel(lab) # recolor labels if lev < oldlev: @@ -164,9 +165,12 @@ class Lightboard: else: numlab['bg'] = 'lightPink' - self.oldlevels[:] = levels[:] # replace the elements in oldlevels - don't make a new list (Subediting is watching it) + # replace the elements in oldlevels - don't make a new list + # (Subediting is watching it) + self.oldlevels[:] = levels[:] - self.parportdmx.sendlevels(levels) + # self.parportdmx.sendlevels(levels) + self.parportdmx.sendupdates(changed) def updatestagelevels(self): self.master.after(100, self.updatestagelevels) diff --git a/light8/Subs.py b/light8/Subs.py --- a/light8/Subs.py +++ b/light8/Subs.py @@ -170,11 +170,19 @@ class Sub: self.dimmers = dimmers # needed? self.is_effect = callable(self.levels) self.slideradjuster = SliderAdjuster() + self.namecache = {} if self.is_effect: self.params = Params() self.generator = self.levels(self.params, self.slideradjuster) self.generator.next() self.color = color + def resolve_name(self, ch_name): + if ch_name in self.namecache: + return self.namecache[ch_name] + else: + resolved = get_dmx_channel(ch_name) + self.namecache[ch_name] = resolved + return resolved def set_slider_var(self, slidervar): if self.is_effect: self.slideradjuster.var = slidervar @@ -191,7 +199,8 @@ class Sub: def set_state(self, statedict): self.__dict__.update(statedict) def get_levels(self, level): - """returns a scaled version of the levels in the sub; channel names are resolved to numbers""" + """returns a scaled version of the levels in the sub; channel names + are resolved to numbers""" d = {} if level == 0: self.slideradjuster.atzero = 1 @@ -199,10 +208,12 @@ class Sub: if self.is_effect: # effect d = self.generator.next() self.slideradjuster.atzero = 0 + return dict([(get_dmx_channel(ch), float(lev) * float(level)) + for ch, lev in d.items()]) else: # dictionary (standard) d = self.levels - return dict([(get_dmx_channel(ch), float(lev) * float(level)) - for ch, lev in d.items()]) + return dict([(self.resolve_name(ch), float(lev) * float(level)) + for ch, lev in d.items()]) # # methods for Subediting to use diff --git a/light8/io.py b/light8/io.py --- a/light8/io.py +++ b/light8/io.py @@ -1,15 +1,113 @@ from parport import * +import socket, os + +lastlevels = {} + +def gethostlist(host): + return lastlevels[host] + +def parselist(levels): + newlist = [0] * 68 + # levels has at least one pair + ch, lev = None, None + while len(levels) >= 2: + ch, lev = levels.pop(0), levels.pop(0) + + # off by one errors -- i hate them sooo much + newlist[int(ch) - 1] = int(lev) + return newlist + +def sethostlist(host, changes): + if not changes: return + global lastlevels + if host not in lastlevels: + lastlevels[host] = [0] * 68 -class ParportDMX: - def __init__(self, dummy=1, dimmers=68): + lastlevels[host] = parselist(changes) + ''' + # changes has at least one pair + ch, lev = None, None + while len(changes) >= 2: + ch, lev = changes.pop(0), changes.pop(0) + + # off by one errors -- i hate them sooo much + lastlevels[host][ch - 1] = lev + ''' + + +def sendlevels(levels): + print "sendlevels: i'm a level hobo:", levels + levels = levels + [0] + # if levels[14] > 0: levels[14] = 100 # non-dim + print "sendlevels: wait for it... length =", len(levels) + outstart() + for p in range(1, 68 + 2): + outbyte(levels[p-1]*255 / 100) + print "sendlevels: done" + +class ParportDMX: # ethdmx client or standalone server + def __init__(self, dummy=1, dimmers=68, machine_name='localhost', + standalone=0): self.dimmers = dimmers self.dummy = dummy if not dummy: getparport() - def sendlevels(self, levels): - if self.dummy: return - levels = list(levels) + [0] - # if levels[14] > 0: levels[14] = 100 # non-dim - outstart() - for p in range(1, self.dimmers + 2): - outbyte(levels[p-1]*255 / 100) + + self.standalone = standalone + self.machine_name = machine_name + + def sendupdates(self, levels): + if (not self.dummy) and levels: + print "update:", levels + + if self.standalone: + print "standalone sendlevels", levels + sendlevels(parselist(levels)) + return + + pid = os.getpid() + s = ('%d ' % pid) + ' '.join([str(l) for l in levels]) + '\n' + # print "sending", s + self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.sock.connect((self.machine_name, + socket.getservbyname('ethdmx', 'tcp'))) + self.sock.send(s) + + # response = self.sock.recv(100) + # print "response", response + # if response != 'ACK\n': + # raise "Didn't get ACK from DMX server" + +if __name__ == '__main__': + import SocketServer + getparport() + + class DMXHandler(SocketServer.StreamRequestHandler): + def handle(self): + global lastlevels + changed = self.rfile.readline(1000) + # self.wfile.write("ACK\n") + pairs = changed.split() + pid = pairs[0] + changes = pairs[1:] + + # print 'pairs', pairs + sethostlist(pid, changes) + + self.preplevels() + def preplevels(self): + global lastlevels + hosts = lastlevels.keys() + maxlevels = [0] * 68 + for h in hosts: + maxlevels = [max(hostlev, maxlev) + for hostlev, maxlev in zip(maxlevels, gethostlist(h))] + print "dmxhandler sending levels:", maxlevels + sendlevels(maxlevels) + + print "Running DMX over Ethernet socket server. Everything is under " + \ + "control." + + server = SocketServer.TCPServer(('', + socket.getservbyname('ethdmx', 'tcp')), DMXHandler) + server.serve_forever()