# HG changeset patch # User Drew Perttula # Date 2007-06-10 08:09:08 # Node ID a6662d61ebcd1da96f8bd5cdebc7a7b6b19be232 # Parent c7478a778992261169bf5f99904866d895851347 SC, KC, CC now run and seem to load and save ok. CC does not have any rdf for its data files diff --git a/bin/curvecalc b/bin/curvecalc --- a/bin/curvecalc +++ b/bin/curvecalc @@ -1,6 +1,11 @@ #!/usr/bin/python """ +now launches like this: +% bin/curvecalc http://light9.bigasterisk.com/show/dance2007/song1 + + + todo: curveview should preserve more objects, for speed maybe """ @@ -289,12 +294,12 @@ def add_one_subterm(graph, sub, curveset return term -def sub_commands_tk(master, curveset, subterms, root, ssv): +def sub_commands_tk(master, curveset, subterms, root, ssv, graph): f=tk.Frame(master,relief='raised',bd=1) newname = tk.StringVar() def add_cmd(): - add_one_subterm(newname.get(), curveset, subterms, root, ssv, '') + add_one_subterm(graph, newname.get(), curveset, subterms, root, ssv, '') newname.set('') def reload_subs(): @@ -314,6 +319,9 @@ def add_subterms_for_song(graph, song, c add_one_subterm(graph, graph.value(st, L9['sub']), curveset, subterms, root, ssv, graph.value(st, L9['expression'])) +def songFilename(uri): + return uri.split('/')[-1] + ####################################################################### root=tk.Tk() root.tk_setPalette("gray50") @@ -348,10 +356,10 @@ musicfilename = showconfig.songOnDisk(so maxtime = wavelength(musicfilename) dispatcher.send("max time",maxtime=maxtime) dispatcher.connect(lambda: maxtime, "get max time",weak=0) -curveset.load(basename=os.path.join(showconfig.curvesDir(),song)) +curveset.load(basename=os.path.join(showconfig.curvesDir(), songFilename(song))) subterms = [] -sub_commands_tk(root, curveset, subterms, root, ssv).pack(side='top',fill='x') +sub_commands_tk(root, curveset, subterms, root, ssv, graph).pack(side='top',fill='x') add_subterms_for_song(graph, song, curveset, subterms, root, ssv) @@ -360,8 +368,8 @@ out = Output(subterms, music) def savekey(*args): print "saving",song - savesubterms(showconfig.subtermsForSong(song),subterms) - curveset.save(basename=os.path.join(showconfig.curvesDir(),song)) + savesubterms(showconfig.subtermsForSong(songFilename(song)), subterms) + curveset.save(basename=os.path.join(showconfig.curvesDir(), songFilename(song))) print "saved" root.bind("",savekey) diff --git a/bin/keyboardcomposer b/bin/keyboardcomposer --- a/bin/keyboardcomposer +++ b/bin/keyboardcomposer @@ -108,7 +108,14 @@ class KeyboardComposer(Frame, SubClient) self.sub_name.pack(side=LEFT) self.stop_frequent_update_time = 0 - self.sliders = Sliders(self.hw_slider_moved) + try: + self.sliders = Sliders(self.hw_slider_moved) + except IOError: + class _: + def valueOut(self, name, value): + pass + self.sliders = _() + print "no hw sliders found" def make_key_hints(self): keyhintrow = Frame(self) diff --git a/bin/subcomposer b/bin/subcomposer --- a/bin/subcomposer +++ b/bin/subcomposer @@ -20,7 +20,7 @@ class Subcomposer(tk.Frame): self.dmxdummy = dmxdummy self.numchannels = numchannels - self.levels = [0]*512 # levels should never get overwritten, just edited + self.levels = [0]*numchannels # levels should never get overwritten, just edited self.levelbox = Levelbox(self, num_channels=numchannels) self.levelbox.pack(side='top') @@ -31,8 +31,7 @@ class Subcomposer(tk.Frame): self.savebox = EntryCommand(self, cmd=self.savenewsub) self.savebox.pack(side='top') - self.loadbox = EntryCommand(self, verb="Load", - cmd=lambda x: self.loadsub(self.levels, x)) + self.loadbox = EntryCommand(self, verb="Load", cmd=self.loadsub) self.loadbox.pack(side='top') def alltozero(): @@ -76,18 +75,17 @@ class Subcomposer(tk.Frame): return self.levels[channel-1]=max(0,min(1,float(newlevel))) self.levelbox.setlevels(self.levels) - def savenewsub(self, levels, subname): + 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=Submaster.Submaster(subname,leveldict=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): @@ -119,7 +117,7 @@ class EntryCommand(tk.Frame): def action(self, *args): subname = self.entry.get() self.cmd(subname) - print "sub", verb, subname + print "sub", self.cmd, subname def set(self, text): self.entry.delete(0, 'end') diff --git a/light9/Submaster.py b/light9/Submaster.py --- a/light9/Submaster.py +++ b/light9/Submaster.py @@ -15,9 +15,35 @@ class Submaster: def __init__(self, name=None, graph=None, sub=None, - leveldict=None, temporary=0): + leveldict=None, temporary=False): + """sub is the URI for this submaster, graph is a graph where + we can learn about the sub. If graph is not provided, we look + in a file named name. + + name is the filename where we can load a graph about this URI + (see showconfig.subFile) + + passing name alone makes a new empty sub + + temporary means the sub won't get saved or loaded + + + pass: + name, temporary=True - no rdf involved + sub, filename - read sub URI from graph at filename + + name - new sub + sub - n + name, sub - new + + """ + if name is sub is leveldict is None: + raise TypeError("more args are needed") if sub is not None: name = graph.label(sub) + if graph is not None: + # old code was passing leveldict as second positional arg + assert isinstance(graph, Graph) self.name = name self.temporary = temporary if leveldict: @@ -27,9 +53,8 @@ class Submaster: self.reload(quiet=True) if not self.temporary: dispatcher.connect(self.reload, 'reload all subs') + def reload(self, quiet=False): - print "no submaster reload" - return if self.temporary: return try: @@ -58,15 +83,20 @@ class Submaster: subUri = L9['sub/%s' % self.name] graph.add((subUri, RDFS.label, Literal(self.name))) for chan in self.levels.keys(): + try: + chanUri = Patch.get_channel_uri(chan) + except KeyError: + print "saving dmx channels with no :Channel node is not supported yet. Give channel %s a URI for it to be saved. Omitting this channel from the sub." % chan + continue lev = BNode() graph.add((subUri, L9['lightLevel'], lev)) - graph.add((lev, L9['channel'], L9['dmx/%s' % chan])) + graph.add((lev, L9['channel'], chanUri)) 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): + def set_level(self, channelname, level, save=True): self.levels[Patch.resolve_name(channelname)] = level if save: self.save() @@ -81,7 +111,8 @@ class Submaster: return (not self.levels.values()) or not (max(self.levels.values()) > 0) def __mul__(self, scalar): return Submaster("%s*%s" % (self.name, scalar), - dict_scale(self.levels, scalar), temporary=1) + leveldict=dict_scale(self.levels, scalar), + temporary=True) __rmul__ = __mul__ def max(self, *othersubs): return sub_maxes(self, *othersubs) @@ -93,7 +124,7 @@ class Submaster: def get_dmx_list(self): leveldict = self.get_levels() # gets levels of sub contents - levels = [0] * 68 + levels = [] for k, v in leveldict.items(): if v == 0: continue @@ -102,6 +133,8 @@ class Submaster: except ValueError: print "error trying to compute dmx levels for submaster %s" % self.name raise + if dmxchan >= len(levels): + levels.extend([0] * (dmxchan - len(levels) + 1)) levels[dmxchan] = max(v, levels[dmxchan]) return levels @@ -135,8 +168,10 @@ class Submaster: return xfaded_sub def __cmp__(self, other): + raise NotImplementedError return cmp(repr(self), repr(other)) def __hash__(self): + raise NotImplementedError return hash(repr(self)) def linear_fade(start, end, amount): @@ -150,7 +185,7 @@ def sub_maxes(*subs): nonzero_subs = [s for s in subs if not s.no_nonzero()] name = "max(%s)" % ", ".join([repr(s) for s in nonzero_subs]) return Submaster(name, - dict_max(*[sub.levels for sub in nonzero_subs]), + leveldict=dict_max(*[sub.levels for sub in nonzero_subs]), temporary=1) def combine_subdict(subdict, name=None, permanent=False): @@ -182,6 +217,7 @@ class Submasters: filename.startswith('CVS'): continue self.submasters[filename] = Submaster(filename) + print "loaded subs", self.submasters def get_all_subs(self): "All Submaster objects" l = self.submasters.items() diff --git a/light9/curve.py b/light9/curve.py --- a/light9/curve.py +++ b/light9/curve.py @@ -130,6 +130,7 @@ class Curveview(tk.Canvas): def __init__(self,master,curve,**kw): self.curve=curve self._time = 0 + self.last_mouse_world = None tk.Canvas.__init__(self,master,width=10,height=10, relief='sunken',bd=1, closeenough=5,takefocus=1, **kw) diff --git a/light9/dmxchanedit.py b/light9/dmxchanedit.py --- a/light9/dmxchanedit.py +++ b/light9/dmxchanedit.py @@ -30,7 +30,7 @@ class Onelevel(tk.Frame): """a name/level pair""" def __init__(self, parent, channelnum): """channelnum is 1..68, like the real dmx""" - tk.Frame.__init__(self,parent) + tk.Frame.__init__(self,parent, height=20) self.channelnum=channelnum self.currentlevel=0 # the level we're displaying, 0..1 @@ -56,10 +56,16 @@ class Onelevel(tk.Frame): # current level of channel, shows intensity with color self.level_lab = tk.Label(self, width=3, bg='lightBlue', - font=stdfont, anchor='e', padx=1, pady=0, bd=0, height=1) self.level_lab.pack(side='left') + # setting the font in the label somehow makes tk run a low + # slower. Magically, startup is much faster if tk can layout + # the window with some standard font in the rows (so the row + # heights are all fixed and taller?), and then I replace the + # last font. Tk resizes the window faster than you can see, + # but startup is still fast. Very weird. + self.after(1, lambda: self.level_lab.config(font=stdfont)) self.setlevel(0) self.setupmousebindings() @@ -125,14 +131,13 @@ class Levelbox(tk.Frame): def __init__(self, parent, num_channels=68): tk.Frame.__init__(self,parent) global stdfont - stdfont = tkFont.Font(size=9) + stdfont = tkFont.Font(size=8) self.levels = [] # Onelevel objects 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 // rows],channel) diff --git a/readme b/readme new file mode 100644 --- /dev/null +++ b/readme @@ -0,0 +1,5 @@ +on dash: + +dash(pts/35):/my/dl/modified/mpd% src/mpd --no-daemon --verbose + + diff --git a/test/run_local.py b/test/run_local.py new file mode 100644 --- /dev/null +++ b/test/run_local.py @@ -0,0 +1,25 @@ +import shutil +import sys,os +sys.path.insert(0,os.path.join(os.path.dirname(__file__),"..")) + +os.environ['LIGHT9_SHOW'] = "_test_show" +try: + shutil.rmtree("_test_show") +except OSError: + pass +os.mkdir("_test_show") +f = open("_test_show/config.n3", "w") +f.write(""" +@prefix rdfs: . +@prefix : . +@prefix ch: . +@prefix dmx: . + +ch:frontLeft a :Channel; rdfs:label "frontLeft"; :altName "b1"; :output dmx:c1 . +ch:frontRight a :Channel; rdfs:label "frontRight"; :output dmx:c2 . + +dmx:c1 :dmxAddress 1 . +dmx:c2 :dmxAddress 2 . + +""") +f.close() diff --git a/test/subload.py b/test/subload.py new file mode 100644 --- /dev/null +++ b/test/subload.py @@ -0,0 +1,31 @@ +# run this with py.test +import run_local +import os, shutil +import py.test +from light9 import dmxclient, Patch, Submaster +from light9.namespaces import L9 + +def testCreateArgs(): + py.test.raises(TypeError, Submaster.Submaster) + assert Submaster.Submaster("newname", leveldict={}) + assert Submaster.Submaster(sub=L9['sub/newname']) + assert Submaster.Submaster(name="newname", sub=L9["sub/newname"]) + py.test.raises(ValueError, Submaster.Submaster(name="newname", + sub=L9["other/newname"])) + + # old code might try to pass leveldict positionally + py.test.raises(Exception, Submaster.Submaster("newname", {})) + +def testLevels(): + levels = {'1' : .5, '2' : 1} + s = Submaster.Submaster("newname", leveldict=levels) + assert s.get_levels() == levels + + s.set_level('3', .5, save=False) + assert s.get_levels()['3'] == .5 + + assert s.get_dmx_list()[:3] == [.5, 1, .5] + + + #s = Submaster.Submasters().get_sub_by_name("t1") + #assert s.get_dmx_list() == [0] diff --git a/test/test_patch.py b/test/test_patch.py new file mode 100644 --- /dev/null +++ b/test/test_patch.py @@ -0,0 +1,20 @@ +import run_local +from light9 import dmxclient, Patch, Submaster +from light9.namespaces import L9 + +def test(): + assert Patch.get_channel_name(1) == "frontLeft" + assert Patch.get_channel_name("1") == "frontLeft" + assert Patch.get_channel_name("frontLeft") == "frontLeft" + + assert Patch.get_dmx_channel(1) == 1 + assert Patch.get_dmx_channel("1") == 1 + assert Patch.get_dmx_channel("frontLeft") == 1 + + assert Patch.get_channel_name("b1") == "frontLeft" + assert Patch.get_dmx_channel("b1") == 1 + assert Patch.resolve_name("b1") == "frontLeft" + assert Patch.resolve_name("frontLeft") == "frontLeft" + + assert Patch.get_channel_uri("frontLeft") == L9['theater/skyline/channel/frontLeft'] +