diff --git a/bin/curvecalc b/bin/curvecalc --- a/bin/curvecalc +++ b/bin/curvecalc @@ -10,7 +10,7 @@ todo: curveview should preserve more obj """ from __future__ import division -import xmlrpclib,time,socket,sys,textwrap,math,glob,random,os,optparse +import xmlrpclib,time,socket,sys,textwrap,math,glob,random,os,optparse,traceback from bisect import bisect_left,bisect,bisect_right import Tkinter as tk try: @@ -28,20 +28,14 @@ logging.basicConfig(format="%(asctime)s log.setLevel(logging.DEBUG) import run_local -from light9 import Submaster, dmxclient, networking, showconfig, prof +from light9 import Submaster, dmxclient, networking, showconfig, prof, Patch from light9.TLUtility import make_attributes_from_args, dict_subset from light9.zoomcontrol import Zoomcontrol from light9.curve import Curve, Curveview, Curveset, Curvesetview from light9.wavelength import wavelength from light9.uihelpers import toplevelat from light9.namespaces import L9 - import light9.Effects -fx_dict = light9.Effects.__dict__ -all_fx = fx_dict['__all__'] -expr_helpers = dict_subset(fx_dict, all_fx) -del fx_dict -del all_fx class Music: def __init__(self): @@ -72,23 +66,20 @@ class Music: def seekplay_or_pause(self,t): self.player.callRemote('seekplay_or_pause',t) + +class Expr(object): + """singleton, provides functions for use in subterm expressions, + e.g. chases""" + def __init__(self): + self.effectGlobals = light9.Effects.configExprGlobals() + + def exprGlobals(self, startDict, t): + """globals dict for use by expressions""" + + glo = startDict.copy() -class Subexpr: - curveset = None - def __init__(self,curveset,expr=""): - self.curveset = curveset - self.lasteval = None - self.expr=expr - self._smooth_random_items = [random.random() for x in range(100)] - def eval(self,t): - if self.expr=="": - dispatcher.send("expr_error",sender=self,exc="no expr, using 0") - return 0 - glo = self.curveset.globalsdict() - glo['t'] = t - # add in functions from Effects - glo.update(expr_helpers) + glo.update(self.effectGlobals) glo['nsin'] = lambda x: (math.sin(x * (2 * math.pi)) + 1) / 2 glo['ncos'] = lambda x: (math.cos(x * (2 * math.pi)) + 1) / 2 @@ -97,6 +88,12 @@ class Subexpr: glo['aft'] = lambda x: x < t glo['smoove'] = lambda x: -2 * (x ** 3) + 3 * (x ** 2) + def chan(name): + return Submaster.Submaster( + leveldict={Patch.get_dmx_channel(name) : 1.0}, + temporary=True) + glo['chan'] = chan + def smooth_random(speed=1): """1 = new stuff each second, <1 is slower, fade-ier""" x = (t * speed) % len(self._smooth_random_items) @@ -116,6 +113,26 @@ class Subexpr: glo['noise'] = smooth_random glo['notch'] = notch_random + return glo + +exprglo = Expr() + +class Subexpr: + curveset = None + def __init__(self,curveset,expr=""): + self.curveset = curveset + self.lasteval = None + self.expr=expr + self._smooth_random_items = [random.random() for x in range(100)] + def eval(self,t): + if self.expr=="": + dispatcher.send("expr_error",sender=self,exc="no expr, using 0") + return 0 + glo = self.curveset.globalsdict() + glo['t'] = t + + glo = exprglo.exprGlobals(glo, t) + try: self.lasteval = eval(self.expr,glo) except Exception,e: @@ -280,9 +297,6 @@ def add_one_subterm(graph, subUri, curve if expr is None: expr = '%s(t)' % subname - print "req to add %r" % subUri - for s in graph.triples((subUri, None, None)): - print s term = Subterm(Submaster.Submaster(graph=graph, sub=subUri), Subexpr(curveset,expr)) subterms.append(term) @@ -423,7 +437,7 @@ root.bind("", lambda evt: create_status_lines(root) for helpline in ["Bindings: C-s save subterms; Esc see current time; S-Esc see curtime to end; Mousewheel zoom; C-p play/pause music at mouse", "Curve point bindings: B1 drag point; C-B1 curve add point; S-B1 sketch points; Del selected points; 1..5 add point at time; B1 drag select points", - "Available in functions: nsin/ncos period=amp=1; within(a,b) bef(x) aft(x) compare to time; smoove(x) cubic smoothstep; curvename(t) eval curve"]: + "Available in functions: nsin/ncos period=amp=1; within(a,b) bef(x) aft(x) compare to time; smoove(x) cubic smoothstep; chan(name); curvename(t) eval curve"]: tk.Label(root,text=helpline, font="Helvetica -12 italic", anchor='w').pack(side='top',fill='x') diff --git a/light9/Effects.py b/light9/Effects.py --- a/light9/Effects.py +++ b/light9/Effects.py @@ -1,24 +1,40 @@ import random import light9.Submaster as Submaster from chase import chase as chase_logic - -thirds = 'third-l', 'third-c', 'third-r' -thirds_bounce = 'third-l', 'third-c', 'third-r', 'third-c' -backs = ['back%d' % d for d in range(1, 11)] -rand_flutter = ['scoop-l', 'scoop-c', 'scoop-r', 'down-c', 'down-l', 'down-r', 'cyc', 'zip_blue', 'zip_red', 'zip_green', 'zip_orange'] + backs -rand_flutter *= 10 -random.shuffle(rand_flutter) - -# don't forget to update this! -__all__ = ['chase', 'thirds', 'thirds_bounce', 'rand_flutter', 'backs'] +import showconfig +from rdflib import RDF +from light9 import Patch +from light9.namespaces import L9 def chase(t, ontime=0.5, offset=0.2, onval=1.0, offval=0.0, names=None, combiner=max): - """names is list of sub or channel names""" + """names is list of URIs. returns a submaster that chases through + the inputs""" sub_vals = {} chase_vals = chase_logic(t, ontime, offset, onval, offval, names, combiner) - for name, value in chase_vals.items(): - sub = Submaster.get_sub_by_name(name) - sub_vals[sub] = value + lev = {} + for uri, value in chase_vals.items(): + try: + dmx = Patch.dmx_from_uri(uri) + except KeyError: + print ("chase includes %r, which doesn't resolve to a dmx chan" % + uri) + continue + lev[dmx] = value - return Submaster.combine_subdict(sub_vals) + ret = Submaster.Submaster(leveldict=lev, temporary=True) + print ret + return ret + +def configExprGlobals(): + graph = showconfig.getGraph() + ret = {} + + for chaseUri in graph.subjects(RDF.type, L9['Chase']): + shortName = chaseUri.rsplit('/')[-1] + chans = graph.value(chaseUri, L9['channels']) + ret[shortName] = list(graph.items(chans)) + + ret['chase'] = chase + return ret + diff --git a/light9/Patch.py b/light9/Patch.py --- a/light9/Patch.py +++ b/light9/Patch.py @@ -34,11 +34,15 @@ def get_channel_name(dmxnum): def get_channel_uri(name): return uri_map[name] +def dmx_from_uri(uri): + return uri_patch[uri] + def reload_data(): - global patch, reverse_patch, uri_map + global patch, reverse_patch, uri_map, uri_patch patch = {} reverse_patch = {} uri_map = {} + uri_patch = {} graph = showconfig.getGraph() @@ -54,6 +58,8 @@ def reload_data(): for addr in graph.objects(output, L9['dmxAddress']): addrInt = int(addr) patch[name] = addrInt + uri_patch[chan] = addrInt + if which == 0: reverse_patch[addrInt] = name reverse_patch[addr] = name