diff --git a/bin/ascoltami b/bin/ascoltami --- a/bin/ascoltami +++ b/bin/ascoltami @@ -32,6 +32,8 @@ from twisted.web import xmlrpc, server import run_local from light9 import networking, showconfig, wavelength +from light9.namespaces import L9, MUS +from light9.uihelpers import toplevelat from pympd import Mpd @@ -131,9 +133,12 @@ class Player: if self.state.get() != stat.state: self.state.set(stat.state) - if self.state.get() != stat.state: - self.state.set(stat.state) - + if hasattr(stat, 'time_elapsed'): + elapsed = stat.time_elapsed + songnum = stat.song + total = stat.time_total + if self.mpd_is_lying and elapsed < 3: + self.mpd_is_lying = False # mpd lies about elapsed, song, and total during the last # .5sec of each song. so we coast through that part @@ -269,16 +274,13 @@ class GoButton: -def buildsonglist(root,songfiles,player): +def buildsonglist(root, graph, songs, player): songlist=tk.Frame(root,bd=2,relief='raised',bg='black') - prefixlen=len(os.path.commonprefix(songfiles)) - # include to the last os.sep- dont crop path elements in the middle - prefixlen=songfiles[0].rfind(os.sep)+1 - maxsfwidth=max([len(x[prefixlen:]) for x in songfiles]) + maxsfwidth=max([len(graph.label(song)) for song in songs]) - for i,sf in enumerate(songfiles): - b=tk.Button(songlist,text=sf[prefixlen:],width=maxsfwidth, + for i,song in enumerate(songs): + b=tk.Button(songlist,text=graph.label(song),width=maxsfwidth, anchor='w',pady=0,bd=0,relief='flat', font="arial 14 bold") b.bind("",lambda ev,b=b: @@ -299,7 +301,7 @@ def buildsonglist(root,songfiles,player) def color_buttons(x, y, z, song=song, b=b): name = player.filename_var.get() - if name == sf[prefixlen:]: + if name == graph.value(song, L9['showPath']): b['bg'] = 'grey50' else: b['bg'] = 'black' @@ -460,15 +462,20 @@ class ControlButtons(tk.Frame): ############################ -if len(songfiles)<1: - songfiles = [f for f in os.listdir(showconfig.musicDir()) - if f.endswith('wav')] - songfiles.sort() +def main(): + global graph + parser = OptionParser() + graph = showconfig.getGraph() (options, songfiles) = parser.parse_args() -songlist = buildsonglist(root,songfiles,player) -songlist.pack(fill='both',exp=1) + if len(songfiles)<1: + graph = showconfig.getGraph() + playList = graph.value(L9['show/dance2007'], L9['playList']) + songs = list(graph.items(playList)) + else: + raise NotImplementedError("don't know how to make rdf song nodes from cmdline song paths") + root=tk.Tk() root.wm_title("ascoltami") @@ -476,7 +483,8 @@ songlist.pack(fill='both',exp=1) root.config(bg="black") player=Player() - songlist = buildsonglist(root, songfiles, player) + songlist = buildsonglist(root, graph, songs, player) + songlist.pack(fill='both',exp=1) seeker = Seeker(root, player) diff --git a/bin/subcomposer b/bin/subcomposer --- a/bin/subcomposer +++ b/bin/subcomposer @@ -3,7 +3,10 @@ from __future__ import division, nested_scopes import sys,os,time,atexit import Tkinter as tk -from dispatch import dispatcher +try: + from dispatch import dispatcher +except ImportError: + import louie as dispatcher import run_local from light9.dmxchanedit import Levelbox @@ -16,9 +19,9 @@ class Subcomposer(tk.Frame): self.dmxdummy = dmxdummy self.numchannels = numchannels - self.levels = [0]*68 # levels should never get overwritten, just edited + self.levels = [0]*512 # levels should never get overwritten, just edited - self.levelbox = Levelbox(self) + self.levelbox = Levelbox(self, num_channels=numchannels) self.levelbox.pack(side='top') # the dmx levels we edit and output, range is 0..1 (dmx chan 1 is # the 0 element) @@ -134,7 +137,7 @@ if __name__ == "__main__": root.wm_title("subcomposer") root.tk_setPalette("#004633") - sc = Subcomposer(root, dmxdummy=0) + sc = Subcomposer(root, dmxdummy=0, numchannels=276) sc.pack() tk.Label(root,text="Bindings: B1 adjust level; B3 instant bump", diff --git a/light9/Patch.py b/light9/Patch.py --- a/light9/Patch.py +++ b/light9/Patch.py @@ -1,6 +1,9 @@ import os +from rdflib import RDF +from light9.namespaces import L9 from light9 import showconfig + def resolve_name(channelname): "Ensure that we're talking about the primary name of the light." return get_channel_name(get_dmx_channel(channelname)) @@ -29,21 +32,18 @@ def get_channel_name(dmxnum): def reload_data(): global patch, reverse_patch - - loc = {} - execfile(showconfig.patchData(), loc) - - loadedpatch = loc['patch'] patch = {} reverse_patch = {} - for k, v in loadedpatch.items(): - if type(k) is tuple: - for name in k: - patch[name] = v - reverse_patch[v] = k[0] - else: - patch[k] = v - reverse_patch[v] = k + + graph = showconfig.getGraph() + + for chan in graph.subjects(RDF.type, L9['Channel']): + name = graph.label(chan) + # int() shouldn't be required, but some code in subcomposer + # ignores channel numbers if they're not int + addr = int(graph.value(chan, L9['dmxAddress'])) + patch[name] = addr + reverse_patch[addr] = name # importing patch will load initial data reload_data() diff --git a/light9/Submaster.py b/light9/Submaster.py --- a/light9/Submaster.py +++ b/light9/Submaster.py @@ -1,5 +1,8 @@ from __future__ import division import os +from rdflib.Graph import Graph +from rdflib import RDFS, Literal, BNode +from light9.namespaces import L9, XSD from light9.TLUtility import dict_scale, dict_max from light9 import Patch, showconfig try: @@ -25,21 +28,18 @@ class Submaster: try: oldlevels = self.levels.copy() self.levels.clear() - subfile = file(showconfig.subFile(self.name)) - for line in subfile.readlines(): - if not line.strip(): # if line is only whitespace - continue # "did i say newspace?" + patchGraph = showconfig.getGraph() + graph = Graph() + graph.parse(showconfig.subFile(self.name), format="nt") + subUri = L9['sub/%s' % self.name] + for lev in graph.objects(subUri, L9['lightLevel']): + chan = graph.value(lev, L9['channel']) + val = graph.value(lev, L9['level']) + name = patchGraph.label(chan) + self.levels[name] = float(val) - try: - name, val = line.split(':') - name = name.strip() - self.levels[name] = float(val) - except ValueError: - print "(%s) Error with this line: %s" % (self.name, - line[:-1]) - - if (not quiet) and (oldlevels != self.levels): - print "sub %s changed" % self.name + if (not quiet) and (oldlevels != self.levels): + print "sub %s changed" % self.name except IOError: print "Can't read file for sub: %s" % self.name def save(self): @@ -47,12 +47,18 @@ class Submaster: print "not saving temporary sub named",self.name return - subfile = file(showconfig.subFile(self.name), 'w') - names = self.levels.keys() - names.sort() - for name in names: - val = self.levels[name] - subfile.write("%s : %s\n" % (name, val)) + graph = Graph() + subUri = L9['sub/%s' % self.name] + graph.add((subUri, RDFS.label, Literal(self.name))) + for chan in self.levels.keys(): + lev = BNode() + graph.add((subUri, L9['lightLevel'], lev)) + graph.add((lev, L9['channel'], L9['dmx/%s' % chan])) + graph.add((lev, L9['level'], + Literal(self.levels[chan], datatype=XSD['decimal']))) + + graph.serialize(showconfig.subFile(self.name), format="nt") + def set_level(self, channelname, level, save=1): self.levels[Patch.resolve_name(channelname)] = level if save: diff --git a/light9/dmxchanedit.py b/light9/dmxchanedit.py --- a/light9/dmxchanedit.py +++ b/light9/dmxchanedit.py @@ -9,7 +9,10 @@ import Tkinter as tk import time from light9 import Patch from light9.uihelpers import make_frame, colorlabel, eventtoparent -from dispatch import dispatcher +try: + from dispatch import dispatcher +except ImportError: + import louie as dispatcher # this font makes each label take 16ms to create, so startup is slow. # with default font, each labl takes about .5ms to create. @@ -37,13 +40,15 @@ class Onelevel(tk.Frame): # channel number -- will turn yellow when being altered self.num_lab = tk.Label(self, text=str(channelnum), width=3, bg='grey40', - fg='white', font=stdfont, + fg='white', + font=stdfont, padx=0, pady=0, bd=0, height=1) self.num_lab.pack(side='left') # text description of channel self.desc_lab=tk.Label(self, text=Patch.get_channel_name(channelnum), - width=14, font=stdfont, + width=14, + font=stdfont, anchor='w', padx=0, pady=0, bd=0, height=1, bg='black', fg='white') @@ -123,12 +128,13 @@ class Levelbox(tk.Frame): stdfont = tkFont.Font(size=9) self.levels = [] # Onelevel objects - frames = (make_frame(self), make_frame(self)) + rows = 48 + frames = [make_frame(self) for x in range((num_channels // rows) + 1)] for channel in range(1, num_channels+1): - + print "setup chan", channel # frame for this channel - f = Onelevel(frames[channel > (num_channels/2)],channel) + f = Onelevel(frames[channel // rows],channel) self.levels.append(f) f.pack(side='top') diff --git a/light9/namespaces.py b/light9/namespaces.py --- a/light9/namespaces.py +++ b/light9/namespaces.py @@ -2,3 +2,4 @@ from rdflib import Namespace L9 = Namespace("http://light9.bigasterisk.com/") MUS = Namespace("http://light9.bigasterisk.com/music/") +XSD = Namespace("http://www.w3.org/2001/XMLSchema#") diff --git a/light9/networking.py b/light9/networking.py --- a/light9/networking.py +++ b/light9/networking.py @@ -6,7 +6,7 @@ from ConfigParser import SafeConfigParse def dmxServerUrl(): #host = os.getenv('DMXHOST', 'localhost') #url = "http://%s:8030" % host - return "http://spot:%s" % dmxServerPort() + return "http://localhost:%s" % dmxServerPort() def dmxServerPort(): return 8030 diff --git a/light9/showconfig.py b/light9/showconfig.py --- a/light9/showconfig.py +++ b/light9/showconfig.py @@ -15,9 +15,6 @@ def root(): "LIGHT9_SHOW env variable has not been set to the show root") return r -def musicDir(): - return path.join(root(),"music_local") - def songInMpd(song): """mpd only works off its own musicroot, which for me is @@ -67,9 +64,6 @@ def subFile(subname): def subsDir(): return path.join(root(),'subs') -def patchData(): - return path.join(root(),"patchdata.py") - def prePostSong(): graph = getGraph() return [graph.value(MUS['preSong'], L9['showPath']),