Changeset - dacbb278d91d
[Not reviewed]
default
0 5 0
drewp@bigasterisk.com - 12 years ago 2013-03-26 16:50:48
drewp@bigasterisk.com
curvecalc port to SyncedGraph. starts up ok, saving is broken
Ignore-this: ef920ab36bc7959f94d9154a9f582c27
5 files changed with 109 insertions and 43 deletions:
0 comments (0 inline, 0 general)
bin/curvecalc
Show inline comments
 
@@ -21,12 +21,13 @@ import louie as dispatcher
 
from rdflib import URIRef, Graph, Literal, RDF, RDFS
 
import logging
 
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
 
from light9.wavelength import wavelength
 
from light9.namespaces import L9
 
from light9.curvecalc.subterm import savekey, graphPathForSubterms
 
@@ -36,14 +37,14 @@ from light9.gtkpyconsole import togglePy
 
from light9.rdfdb.syncedgraph import SyncedGraph
 

	
 
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
 

	
 
        wtree = self.wtree = gtk.Builder()
 
        wtree.add_from_file("light9/curvecalc/curvecalc.glade")
 
        mainwin = wtree.get_object("MainWindow")
 
@@ -56,13 +57,15 @@ class Main(object):
 
            self.refreshTheme()
 
        mainwin.show_all()
 

	
 
        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")
 

	
 
        # this is the only one i found that would set the size right,
 
        # but it's a minimum size, which i don't really want
 
        mainwin.set_size_request(1678, 922)
 
@@ -155,14 +158,16 @@ class Main(object):
 
            self.curveset.new_curve(newname)
 

	
 
    def add_subterms_for_song(self):
 
        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,
 
                            self.subterms,
 
                            master,
 
                            self.graph.value(st, L9['expression']))
 
@@ -212,13 +217,15 @@ class Main(object):
 
        # of them may be able to pick this up
 
        results = dispatcher.send("onPlayPause")
 
        times = [t for listener, t in results if t is not None]
 
        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"""
 
        for row, (signame, textfilter) in enumerate([
 
            ('input time', lambda t: "%.2fs"%t),
 
            ('output levels',
 
@@ -281,12 +288,33 @@ class Main(object):
 
                print "reload failed:"
 
                traceback.print_exc()
 
        if self.opts.reload:
 
            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()
 
    parser.set_usage("%prog [opts] [songURI]")
 
    parser.add_option("--sliders", action='store_true',
 
                      help='use hardware sliders')
 
@@ -295,44 +323,57 @@ def main():
 
    parser.add_option("--debug", action="store_true",
 
                      help="log at DEBUG")
 
    parser.add_option("--reload", action="store_true",
 
                      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:
 
        log.debug("quitting now because of --startup-only")
 
        return
 

	
 
@@ -343,14 +384,15 @@ def main():
 
            if request.path == '/hoverTime':
 
                results = dispatcher.send("onPlayPause")
 
                times = [t for listener, t in results if t is not None]
 
                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,
 
                      server.Site(Hover()))
 

	
 

	
light9/curvecalc/curve.py
Show inline comments
 
@@ -137,12 +137,13 @@ class Curveset(object):
 
            dispatcher.connect(self.knobOut, "knob out")
 
            self.lastSliderTime = {} # num : time
 
            self.sliderSuppressOutputUntil = {} # num : time
 
            self.sliderIgnoreInputUntil = {}
 
        else:
 
            self.sliders = None
 
        self.markers = Markers()
 

	
 
    def sorter(self, name):
 
        return (not name in ['music', 'smooth_music'], name)
 

	
 
    def load(self,basename, skipMusic=False):
 
        """find all files that look like basename-curvename and add
 
@@ -156,13 +157,12 @@ class Curveset(object):
 
                continue
 
            c=Curve()
 
            c.load(filename)
 
            curvename = curvename.replace('-','_')
 
            self.add_curve(curvename,c)
 

	
 
        self.markers = Markers()
 
        try:
 
            self.markers.load("%s.markers" % basename)
 
        except IOError:
 
            print "no marker file found"
 
            
 
    def save(self,basename):
light9/curvecalc/curveview.py
Show inline comments
 
@@ -614,15 +614,18 @@ class Curveview(object):
 
            self.timelineGroup = goocanvas.Group(parent=self.root)
 
            self.timelineLine = goocanvas.Polyline(
 
                parent=self.timelineGroup,
 
                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:
 
            self.delete('knob')
 
            prevKey = self.curve.point_before(t)
 
            if prevKey is not None:
 
@@ -730,17 +733,21 @@ class Curveview(object):
 
        if endtimes:
 
            endtime = endtimes[0][1]
 
            tic(endtime, "end %.1f"%endtime)
 
            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,
 
                                    line_width=.5,
 
                                    stroke_color='gray70')
 
        goocanvas.Text(parent=self.curveGroup,
 
@@ -756,22 +763,28 @@ class Curveview(object):
 
        linewidth = 1.5
 
        maxPointsToDraw = self.size.width / 2
 
        if len(visible_points) > maxPointsToDraw:
 
            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:
 
            fill = 'grey34'
 
        else:
 
            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(
 
                                   [(linepts[0][0], base)] +
 
                                   linepts +
 
                                   [(linepts[-1][0], base)]),
 
@@ -788,13 +801,16 @@ class Curveview(object):
 
                
 
            
 
    def _draw_handle_points(self,visible_idxs,visible_points):
 
        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,
 
                                 width=rad * 2, height=rad * 2,
 
                                 stroke_color='gray90',
 
                                 fill_color='blue',
light9/curvecalc/subterm.py
Show inline comments
 
@@ -37,14 +37,14 @@ class Expr(object):
 
                return smoove((t - left) / (right - left))
 
            return t > x
 
        glo['aft'] = lambda x, smooth=0: aft(t, x, smooth)
 

	
 
        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):
 
            """1 = new stuff each second, <1 is slower, fade-ier"""
 
            x = (t * speed) % len(self._smooth_random_items)
 
            x1 = int(x)
 
@@ -123,36 +123,36 @@ class Subterm:
 
            else:
 
                # otherwise, return our submaster multiplied by the value 
 
                # returned
 
                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 "<Subterm %s %s>" % (self.submaster, self.subexpr)
 

	
 

	
 
def graphPathForSubterms(song):
 
    return showconfig.subtermsForSong(showconfig.songFilenameFromURI(song)) + ".n3"
 

	
 
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']))
 
        graph.add((uri, RDFS.label, Literal(subterm.submaster.name)))
 
        graph.add((uri, L9['sub'], L9['sub/%s' % subterm.submaster.name]))
 
        graph.add((uri, L9['expression'], Literal(subterm.subexpr.expr)))
 
    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")
light9/curvecalc/zoomcontrol.py
Show inline comments
 
@@ -135,15 +135,19 @@ class ZoomControl(object):
 
            t = self.lastTime
 
        self.start = t - 2
 
        self.end = self.maxtime
 

	
 
        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)]))
 
        
 
    def press(self,ev,attr):
 
        self.adjustingattr = attr
 
@@ -179,14 +183,18 @@ class ZoomControl(object):
 
        self.size = self.widget.get_allocation()
 
        dispatcher.send("zoom changed")
 
        if not hasattr(self,'created'):
 
            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),
 
            (scan, y1),
 
            (scan, y2),
 
            (scan + lip, y2)]))
0 comments (0 inline, 0 general)