diff --git a/bin/curvecalc b/bin/curvecalc --- a/bin/curvecalc +++ b/bin/curvecalc @@ -24,6 +24,7 @@ log = logging.getLogger() import run_local from light9 import showconfig, prof, networking +from light9.rdfdb import clientsession from light9.curvecalc.curve import Curveset from light9.curvecalc import curveview from light9.curvecalc.musicaccess import Music, currentlyPlayingSong @@ -39,8 +40,8 @@ class SubtermExists(ValueError): pass class Main(object): - def __init__(self, graph, opts, song, curveset, subterms, music): - self.graph, self.opts, self.song = graph, opts, song + def __init__(self, graph, opts, session, curveset, subterms, music): + self.graph, self.opts, self.session = graph, opts, session self.curveset, self.subterms, self.music = curveset, subterms, music self.lastSeenInputTime = 0 @@ -59,7 +60,9 @@ class Main(object): mainwin.connect("delete-event", lambda *args: reactor.crash()) def updateTitle(): # song will soon be a lookup on this curvecalc session - mainwin.set_title("curvecalc - %s" % graph.label(song)) + mainwin.set_title("curvecalc - %s" % + graph.label( + graph.value(session, L9['currentSong']))) graph.addHandler(updateTitle) mainwin.parse_geometry("1x1-0+0") @@ -158,8 +161,10 @@ class Main(object): master = self.wtree.get_object("subterms") [master.remove(c) for c in master.get_children()] - for st in self.graph.objects(self.song, L9['subterm']): - log.info("song %s has subterm %s", self.song, st) + song = self.graph.value(self.session, L9['currentSong']) + + for st in self.graph.objects(song, L9['subterm']): + log.info("song %s has subterm %s", song, st) add_one_subterm(self.graph, self.graph.value(st, L9['sub']), self.curveset, @@ -215,7 +220,9 @@ class Main(object): self.music.playOrPause(t=times[0] if times else None) def onSave(self, *args): - savekey(self.song, self.subterms, self.curveset) + with self.graph.currentState() as g: + savekey(g.value(self.session, L9['currentSong']), + self.subterms, self.curveset) def makeStatusLines(self, master): """various labels that listen for dispatcher signals""" @@ -284,6 +291,27 @@ class Main(object): reactor.callLater(1, self.refreshCurveView) +class MaxTime(object): + """ + looks up the time in seconds for the session's current song + """ + def __init__(self, graph, session): + self.graph, self.session = graph, session + graph.addHandler(self.update) + + def update(self): + song = self.graph.value(self.session, L9['currentSong']) + if song is None: + self.maxtime = 0 + return + musicfilename = showconfig.songOnDisk(song) + self.maxtime = wavelength(musicfilename) + log.info("new max time %r", self.maxtime) + dispatcher.send("max time", maxtime=self.maxtime) + + def get(self): + return self.maxtime + def main(): startTime = time.time() parser = optparse.OptionParser() @@ -298,38 +326,51 @@ def main(): help="live reload of themes and code") parser.add_option("--startup-only", action='store_true', help="quit after loading everything (for timing tests)") + clientsession.add_option(parser) opts, args = parser.parse_args() logging.basicConfig(format="%(asctime)s %(levelname)-5s %(name)s %(filename)s:%(lineno)d: %(message)s") log.setLevel(logging.DEBUG if opts.debug else logging.INFO) log.debug("startup: music %s", time.time() - startTime) - try: - song = URIRef(args[0]) - except IndexError: - song = currentlyPlayingSong() + + + session = clientsession.getUri('curvecalc', opts) music = Music() graph = SyncedGraph("curvecalc") + try: + song = URIRef(args[0]) + graph.patchObject(context=session, + subject=session, + predicate=L9['currentSong'], + newObject=song) + except IndexError: + pass + curveset = Curveset(sliders=opts.sliders) subterms = [] - curveset.load(basename=os.path.join( - showconfig.curvesDir(), - showconfig.songFilenameFromURI(song)), - skipMusic=opts.skip_music) - + def curvesetReload(): + # not sure if this clears right or not yet + song = graph.value(session, L9['currentSong']) + if song is None: + return + curveset.load(basename=os.path.join( + showconfig.curvesDir(), + showconfig.songFilenameFromURI(song)), + skipMusic=opts.skip_music) + graph.addHandler(curvesetReload) + log.debug("startup: output %s", time.time() - startTime) out = Output(subterms, music) - musicfilename = showconfig.songOnDisk(song) - maxtime = wavelength(musicfilename) - dispatcher.connect(lambda: maxtime, "get max time", weak=False) + mt = MaxTime(graph, session) + dispatcher.connect(lambda: mt.get(), "get max time", weak=False) - start = Main(graph, opts, song, curveset, subterms, music) + start = Main(graph, opts, session, curveset, subterms, music) - dispatcher.send("max time", maxtime=maxtime) dispatcher.send("show all") if opts.startup_only: @@ -346,8 +387,9 @@ def main(): if not times: request.setResponseCode(404) return "not hovering over any time" - - return json.dumps({"song":song, "hoverTime" : times[0]}) + with graph.currentState() as g: + song = g.value(session, L9['currentSong']) + return json.dumps({"song": song, "hoverTime" : times[0]}) raise NotImplementedError() reactor.listenTCP(networking.curveCalc.port, diff --git a/light9/curvecalc/curve.py b/light9/curvecalc/curve.py --- a/light9/curvecalc/curve.py +++ b/light9/curvecalc/curve.py @@ -140,6 +140,7 @@ class Curveset(object): self.sliderIgnoreInputUntil = {} else: self.sliders = None + self.markers = Markers() def sorter(self, name): return (not name in ['music', 'smooth_music'], name) @@ -159,7 +160,6 @@ class Curveset(object): curvename = curvename.replace('-','_') self.add_curve(curvename,c) - self.markers = Markers() try: self.markers.load("%s.markers" % basename) except IOError: diff --git a/light9/curvecalc/curveview.py b/light9/curvecalc/curveview.py --- a/light9/curvecalc/curveview.py +++ b/light9/curvecalc/curveview.py @@ -617,9 +617,12 @@ class Curveview(object): points=goocanvas.Points([(0,0), (0,0)]), line_width=2, stroke_color='red') - self.timelineLine.set_property('points', goocanvas.Points([ - self.screen_from_world((t, 0)), - self.screen_from_world((t, 1))])) + try: + pts = [self.screen_from_world((t, 0)), + self.screen_from_world((t, 1))] + except ZeroDivisionError: + pts = [(-1, -1), (-1, -1)] + self.timelineLine.set_property('points', goocanvas.Points(pts)) self._time = t if self.knobEnabled: @@ -733,11 +736,15 @@ class Curveview(object): tic(endtime - postPad, "post %.1f" % (endtime - postPad)) def _draw_one_tic(self,t,label): - x = self.screen_from_world((t,0))[0] + try: + x = self.screen_from_world((t,0))[0] + if not 0 <= x < self.size.width: + return + x = max(5, x) # cheat left-edge stuff onscreen + except ZeroDivisionError: + x = -100 + ht = self.size.height - if not 0 <= x < self.size.width: - return - x = max(5, x) # cheat left-edge stuff onscreen goocanvas.polyline_new_line(self.curveGroup, x, ht, x, ht - 20, @@ -759,7 +766,10 @@ class Curveview(object): step = int(len(visible_points) / maxPointsToDraw) linewidth = .8 for p in visible_points[::step]: - x,y = self.screen_from_world(p) + try: + x,y = self.screen_from_world(p) + except ZeroDivisionError: + x = y = -100 linepts.append((int(x) + .5, int(y) + .5)) if self.curve.muted: @@ -768,7 +778,10 @@ class Curveview(object): fill = 'white' if area: - base = self.screen_from_world((0, 0))[1] + try: + base = self.screen_from_world((0, 0))[1] + except ZeroDivisionError: + base = -100 base = base + linewidth / 2 goocanvas.Polyline(parent=self.curveGroup, points=goocanvas.Points( @@ -791,7 +804,10 @@ class Curveview(object): for i,p in zip(visible_idxs,visible_points): rad=3 worldp = p - p = self.screen_from_world(p) + try: + p = self.screen_from_world(p) + except ZeroDivisionError: + p = (-100, -100) dot = goocanvas.Rect(parent=self.curveGroup, x=int(p[0] - rad) + .5, y=int(p[1] - rad) + .5, diff --git a/light9/curvecalc/subterm.py b/light9/curvecalc/subterm.py --- a/light9/curvecalc/subterm.py +++ b/light9/curvecalc/subterm.py @@ -40,8 +40,8 @@ class Expr(object): def chan(name): return Submaster.Submaster( - leveldict={Patch.get_dmx_channel(name) : 1.0}, - temporary=True) + name=name, + levels={Patch.get_dmx_channel(name) : 1.0}) glo['chan'] = chan def smooth_random(speed=1): @@ -126,7 +126,7 @@ class Subterm: return self.submaster * subexpr_eval except Exception, e: dispatcher.send("expr_error", sender=self.subexpr, exc=str(e)) - return Submaster.Submaster('Error: %s' % str(e), temporary=True) + return Submaster.Submaster(name='Error: %s' % str(e), levels={}) def __repr__(self): return "" % (self.submaster, self.subexpr) @@ -139,7 +139,7 @@ def createSubtermGraph(song, subterms): """rdf graph describing the subterms, readable by add_subterms_for_song""" graph = Graph() for subterm in subterms: - assert subterm.submaster.name, "submaster has no name" + assert subterm.submaster.name, "submaster %r has no name" % subterm.submaster uri = URIRef(song + "/subterm/" + subterm.submaster.name) graph.add((song, L9['subterm'], uri)) graph.add((uri, RDF.type, L9['Subterm'])) @@ -149,10 +149,10 @@ def createSubtermGraph(song, subterms): return graph def savekey(song, subterms, curveset): - print "saving", song + log.info("saving %r", song) g = createSubtermGraph(song, subterms) g.serialize(graphPathForSubterms(song), format="nt") curveset.save(basename=os.path.join(showconfig.curvesDir(), showconfig.songFilenameFromURI(song))) - print "saved" + log.info("saved") diff --git a/light9/curvecalc/zoomcontrol.py b/light9/curvecalc/zoomcontrol.py --- a/light9/curvecalc/zoomcontrol.py +++ b/light9/curvecalc/zoomcontrol.py @@ -138,9 +138,13 @@ class ZoomControl(object): self.redrawzoom() - def input_time(self,val): + def input_time(self, val): + """move time cursor to this time""" self.lastTime = val - x = self.can_for_t(self.lastTime) + try: + x = self.can_for_t(self.lastTime) + except ZeroDivisionError: + x = -100 self.time.set_property("points", goocanvas.Points([(x, 0), (x, self.size.height)])) @@ -182,8 +186,12 @@ class ZoomControl(object): return y1, y2 = 3, self.size.height - 3 lip = 6 - scan = self.can_for_t(self.start) - ecan = self.can_for_t(self.end) + try: + scan = self.can_for_t(self.start) + ecan = self.can_for_t(self.end) + except ZeroDivisionError: + # todo: set the zoom to some clear null state + return self.leftbrack.set_property("points", goocanvas.Points([ (scan + lip, y1),