Changeset - fce46850ed8c
[Not reviewed]
default
0 2 0
Drew Perttula - 11 years ago 2014-06-03 08:24:30
drewp@bigasterisk.com
consolidate the curve load/save rdf code more
Ignore-this: f030683dca9c44308e336137d67b5467
2 files changed with 82 insertions and 51 deletions:
0 comments (0 inline, 0 general)
bin/effecteval
Show inline comments
 
#!bin/python
 
from __future__ import division
 
from run_local import log
 
from twisted.internet import reactor
 
from twisted.internet.defer import inlineCallbacks, returnValue
 
import cyclone.web, cyclone.websocket, cyclone.httpclient
 
import sys, optparse, logging, subprocess, json, time, traceback
 
from rdflib import URIRef, Literal
 

	
 
sys.path.append(".")
 
from light9 import networking, showconfig, Submaster, dmxclient
 
from light9.rdfdb.syncedgraph import SyncedGraph
 
from light9.curvecalc.curve import CurveResource
 
from light9.effecteval.effect import EffectNode
 
from light9.greplin_cyclone import StatsForCyclone
 
from light9.namespaces import L9, RDF, RDFS
 
from light9.rdfdb.patch import Patch
 
from light9.effecteval.effect import EffectNode
 
from light9.greplin_cyclone import StatsForCyclone
 
from light9.rdfdb.syncedgraph import SyncedGraph
 
from greplin import scales
 

	
 
from lib.cycloneerr import PrettyErrorHandler
 

	
 
class EffectEdit(PrettyErrorHandler, cyclone.web.RequestHandler):
 
    def get(self):
 
        self.write(open("light9/effecteval/effect.html").read())
 
    def delete(self):
 
        graph = self.settings.graph
 
        uri = URIRef(self.get_argument('uri'))
 
        with graph.currentState(tripleFilter=(None, L9['effect'], uri)) as g:
 
            song = ctx = list(g.subjects(L9['effect'], uri))[0]
 
@@ -33,38 +34,37 @@ class EffectEdit(PrettyErrorHandler, cyc
 
class SongEffects(PrettyErrorHandler, cyclone.web.RequestHandler):
 
    def post(self):
 
        song = URIRef(self.get_argument('uri'))
 
        dropped = URIRef(self.get_argument('drop'))
 
        ctx = song
 
        graph = self.settings.graph
 
        effect = graph.sequentialUri(song + "/effect-")
 
        curve = graph.sequentialUri(song + "/curve-")
 

	
 
        with graph.currentState(
 
                tripleFilter=(dropped, RDFS.label, None)) as g:
 
            droppedSubLabel = g.label(dropped)
 
        
 
            
 
        cr = CurveResource(graph, curve)
 
        cr.newCurve(ctx, label=Literal('sub %s' % droppedSubLabel))
 
        cr.saveCurve()
 
        graph.patch(Patch(addQuads=[
 
            (song, L9['curve'], curve, ctx),
 
            (song, L9['effect'], effect, ctx),
 
            (effect, RDF.type, L9['Effect'], ctx),
 
            (effect, L9['code'],
 
             Literal('out = sub(%s, intensity=%s)' % (dropped.n3(), curve.n3())),
 
             ctx),
 
            (curve, RDF.type, L9['Curve'], ctx),
 
            (curve, RDFS.label, Literal('sub %s' % droppedSubLabel), ctx),
 
            ]))
 
        graph.patch(Patch(addQuads=[
 
            (curve, L9['points'], Literal('0 0'), Curve(uri=curve).curvePointsContext()),
 
            ]))
 
        
 
        
 
class SongEffectsUpdates(cyclone.websocket.WebSocketHandler):
 
    def connectionMade(self, *args, **kwargs):
 
        self.graph = self.settings.graph
 
        self.graph.addHandler(self.updateClient)
 
        
 
    def updateClient(self):
 
        # todo: abort if client is gone
 
        playlist = self.graph.value(showconfig.showUri(), L9['playList'])
 
        songs = list(self.graph.items(playlist))
 
        out = []
 
        for s in songs:
light9/curvecalc/curve.py
Show inline comments
 
@@ -29,27 +29,24 @@ class Curve(object):
 
        doc = "Whether to currently send levels (boolean, obviously)"
 
        def fget(self):
 
            return self._muted
 
        def fset(self, val):
 
            self._muted = val
 
            dispatcher.send('mute changed', sender=self)
 
        return locals()
 
    muted = property(**muted())
 

	
 
    def toggleMute(self):
 
        self.muted = not self.muted
 

	
 
    def curvePointsContext(self):
 
        return self.uri
 

	
 
    def load(self,filename):
 
        self.points[:]=[]
 
        for line in file(filename):
 
            x, y = line.split()
 
            self.points.append((float(x), ast.literal_eval(y)))
 
        self.points.sort()
 
        dispatcher.send("points changed",sender=self)
 

	
 
    def set_from_string(self, pts):
 
        self.points[:] = []
 
        vals = pts.split()
 
        pairs = zip(vals[0::2], vals[1::2])
 
@@ -142,29 +139,84 @@ class Curve(object):
 
        """(x,y) of the point left of x, or None"""
 
        leftidx = self.index_before(x)
 
        if leftidx is None:
 
            return None
 
        return self.points[leftidx]
 

	
 
    def index_before(self, x):
 
        leftidx = bisect(self.points, (x,None)) - 1
 
        if leftidx < 0:
 
            return None
 
        return leftidx
 

	
 
class CurveResource(object):
 
    """
 
    holds a Curve, deals with graphs
 
    """
 
    def __init__(self, graph, uri):
 
        self.graph, self.uri = graph, uri
 

	
 
    def curvePointsContext(self):
 
        return self.uri
 

	
 
    def newCurve(self, ctx, label):
 
        """
 
        Save type/label for a new :Curve resource.
 
        Pass the ctx where the main curve data (not the points) will go.
 
        """
 
        self.graph.patch(Patch(addQuads=[
 
            (self.uri, RDF.type, L9['Curve'], ctx),
 
            (self.uri, RDFS.label, label, ctx),
 
            ]))
 
        self.curve = Curve(self.uri)
 
        self.curve.points.extend([(0, 0)])
 
        self.saveCurve()
 
        
 
    def loadCurve(self):
 
        pts = self.graph.value(self.uri, L9['points'])
 
        self.curve = Curve(self.uri,
 
                           pointsStorage='file' if pts is None else 'graph')
 
        if pts is not None:
 
            self.curve.set_from_string(pts)
 
        else:
 
            diskPts = self.graph.value(self.uri, L9['pointsFile'])
 
            if diskPts is not None:
 
                self.curve.load(os.path.join(showconfig.curvesDir(), diskPts))
 
            else:
 
                log.warn("curve %s has no points", self.uri)
 

	
 
    def saveCurve(self):
 
        for p in self.getSavePatches():
 
            self.graph.patch(p)
 

	
 
    def getSavePatches(self):
 
        if self.curve.pointsStorage == 'file':
 
            log.warn("not saving file curves anymore- skipping %s" % self.uri)
 
            #cur.save("%s-%s" % (basename,name))
 
            return []
 
        elif self.curve.pointsStorage == 'graph':
 
            return [self.graph.getObjectPatch(
 
                self.curvePointsContext(),
 
                subject=self.uri,
 
                predicate=L9['points'],
 
                newObject=Literal(self.curve.points_as_string()))]
 
        else:
 
            raise NotImplementedError(self.curve.pointsStorage)
 

	
 
        
 
class Markers(Curve):
 
    """Marker is like a point but the y value is a string"""
 
    def eval(self):
 
        raise NotImplementedError()
 
    
 

	
 

	
 
def slope(p1,p2):
 
    if p2[0] == p1[0]:
 
        return 0
 
    return (p2[1] - p1[1]) / (p2[0] - p1[0])
 

	
 

	
 
class Sliders(BCF2000):
 
    def __init__(self, cb, knobCallback, knobButtonCallback):
 
        BCF2000.__init__(self)
 
        self.cb = cb
 
        self.knobCallback = knobCallback
 
@@ -222,73 +274,55 @@ class Curveset(object):
 
        self.curves.clear()
 
        self.curveName.clear()
 
        self.sliderCurve.clear()
 
        self.sliderNum.clear()
 
        self.markers = Markers(uri=None, pointsStorage='file')
 
        
 
        self.currentSong = self.graph.value(self.session, L9['currentSong'])
 
        if self.currentSong is None:
 
            return
 

	
 
        for uri in sorted(self.graph.objects(self.currentSong, L9['curve'])):
 
            try:
 
                self.loadCurve(uri)
 
                cr = CurveResource(self.graph, uri)
 
                cr.loadCurve()
 

	
 
                curvename = self.graph.label(uri)
 
                if not curvename:
 
                    raise ValueError("curve %r has no label" % uri)
 
                self.add_curve(curvename, cr.curve)
 

	
 
            except Exception as e:
 
                log.error("loading %s failed: %s", uri, e)
 
                
 
        basename = os.path.join(
 
            showconfig.curvesDir(),
 
            showconfig.songFilenameFromURI(self.currentSong))
 
        try:
 
            self.markers.load("%s.markers" % basename)
 
        except IOError:
 
            print "no marker file found"
 

	
 
    def loadCurve(self, uri):
 
        pts = self.graph.value(uri, L9['points'])
 
        c = Curve(uri, pointsStorage='file' if pts is None else 'graph')
 
        if pts is not None:
 
            c.set_from_string(pts)
 
        else:
 
            diskPts = self.graph.value(uri, L9['pointsFile'])
 
            if diskPts is not None:
 
                c.load(os.path.join(showconfig.curvesDir(), diskPts))
 
            else:
 
                log.warn("curve %s has no points", c.uri)
 

	
 
        curvename = self.graph.label(uri)
 
        if not curvename:
 
            raise ValueError("curve %r has no label" % uri)
 
        self.add_curve(curvename, c)
 
            
 
    def save(self):
 
        """writes a file for each curve with a name
 
        like basename-curvename, or saves them to the rdf graph"""
 
        basename=os.path.join(
 
            showconfig.curvesDir(),
 
            showconfig.songFilenameFromURI(self.currentSong))
 

	
 
        patches = []
 
        for label, curve in self.curves.items():
 
            if curve.pointsStorage == 'file':
 
                log.warn("not saving file curves anymore- skipping %s" % label)
 
                #cur.save("%s-%s" % (basename,name))
 
            elif curve.pointsStorage == 'graph':
 
                patches.append(self.graph.getObjectPatch(
 
                    curve.curvePointsContext(),
 
                    subject=curve.uri,
 
                    predicate=L9['points'],
 
                    newObject=Literal(curve.points_as_string())))
 
            else:
 
                raise NotImplementedError(curve.pointsStorage)
 
            cr = CurveResource(self.graph, curve.uri)
 
            cr.curve = curve
 
            patches.extend(cr.getSavePatches())
 

	
 
        self.markers.save("%s.markers" % basename)
 
        # this will cause reloads that will clear our curve list
 
        for p in patches:
 
            self.graph.patch(p)
 
            
 
    def sorter(self, name):
 
        return self.curves[name].uri
 
        
 
    def curveNamesInOrder(self):
 
        return sorted(self.curves.keys(), key=self.sorter)
 
            
 
@@ -323,38 +357,35 @@ class Curveset(object):
 
    def new_curve(self, name, renameIfExisting=True):
 
        if isinstance(name, Literal):
 
            name = str(name)
 
        if name=="":
 
            print "no name given"
 
            return
 
        if not renameIfExisting and name in self.curves:
 
            return
 
        while name in self.curves:
 
           name=name+"-1"
 

	
 
        uri = self.graph.sequentialUri(self.currentSong + '/curve-')
 
        c = Curve(uri)
 

	
 
        cr = CurveResource(self.graph, uri)
 
        cr.newCurve(ctx=self.currentSong, label=Literal(name))
 
        s, e = self.get_time_range()
 
        c.points.extend([(s, 0), (e, 0)])
 
        cr.curve.points.extend([(s, 0), (e, 0)])
 

	
 
        ctx = self.currentSong
 
        self.graph.patch(Patch(addQuads=[
 
            (self.currentSong, L9['curve'], uri, ctx),
 
            (uri, RDF.type, L9['Curve'], ctx),
 
            (uri, RDFS.label, Literal(name), ctx),
 
            ]))
 
        print "pts to", c.curvePointsContext()
 
        self.graph.patch(Patch(addQuads=[
 
            (uri, L9['points'], Literal(c.points_as_string()),
 
             c.curvePointsContext()),
 
            ]))
 
        cr.saveCurve()
 

	
 
    def hw_slider_in(self, num, value):
 
        try:
 
            curve = self.curves[self.sliderCurve[num]]
 
        except KeyError:
 
            return
 

	
 
        now = time.time()
 
        if now < self.sliderIgnoreInputUntil.get(num):
 
            return
 
        # don't make points too fast. This is the minimum spacing
 
        # between slider-generated points.
0 comments (0 inline, 0 general)